Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
0004  */
0005 
0006 #include <linux/bitops.h>
0007 #include <linux/i2c.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/irq.h>
0010 #include <linux/irqdomain.h>
0011 #include <linux/module.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_platform.h>
0014 #include <linux/pinctrl/consumer.h>
0015 #include <linux/regmap.h>
0016 #include <linux/slab.h>
0017 
0018 #include <dt-bindings/mfd/qcom-pm8008.h>
0019 
0020 #define I2C_INTR_STATUS_BASE        0x0550
0021 #define INT_RT_STS_OFFSET       0x10
0022 #define INT_SET_TYPE_OFFSET     0x11
0023 #define INT_POL_HIGH_OFFSET     0x12
0024 #define INT_POL_LOW_OFFSET      0x13
0025 #define INT_LATCHED_CLR_OFFSET      0x14
0026 #define INT_EN_SET_OFFSET       0x15
0027 #define INT_EN_CLR_OFFSET       0x16
0028 #define INT_LATCHED_STS_OFFSET      0x18
0029 
0030 enum {
0031     PM8008_MISC,
0032     PM8008_TEMP_ALARM,
0033     PM8008_GPIO1,
0034     PM8008_GPIO2,
0035     PM8008_NUM_PERIPHS,
0036 };
0037 
0038 #define PM8008_PERIPH_0_BASE    0x900
0039 #define PM8008_PERIPH_1_BASE    0x2400
0040 #define PM8008_PERIPH_2_BASE    0xC000
0041 #define PM8008_PERIPH_3_BASE    0xC100
0042 
0043 #define PM8008_TEMP_ALARM_ADDR  PM8008_PERIPH_1_BASE
0044 #define PM8008_GPIO1_ADDR   PM8008_PERIPH_2_BASE
0045 #define PM8008_GPIO2_ADDR   PM8008_PERIPH_3_BASE
0046 
0047 #define PM8008_STATUS_BASE  (PM8008_PERIPH_0_BASE | INT_LATCHED_STS_OFFSET)
0048 #define PM8008_MASK_BASE    (PM8008_PERIPH_0_BASE | INT_EN_SET_OFFSET)
0049 #define PM8008_UNMASK_BASE  (PM8008_PERIPH_0_BASE | INT_EN_CLR_OFFSET)
0050 #define PM8008_TYPE_BASE    (PM8008_PERIPH_0_BASE | INT_SET_TYPE_OFFSET)
0051 #define PM8008_ACK_BASE     (PM8008_PERIPH_0_BASE | INT_LATCHED_CLR_OFFSET)
0052 #define PM8008_POLARITY_HI_BASE (PM8008_PERIPH_0_BASE | INT_POL_HIGH_OFFSET)
0053 #define PM8008_POLARITY_LO_BASE (PM8008_PERIPH_0_BASE | INT_POL_LOW_OFFSET)
0054 
0055 #define PM8008_PERIPH_OFFSET(paddr) (paddr - PM8008_PERIPH_0_BASE)
0056 
0057 static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)};
0058 static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)};
0059 static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)};
0060 static unsigned int p3_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_3_BASE)};
0061 
0062 static struct regmap_irq_sub_irq_map pm8008_sub_reg_offsets[] = {
0063     REGMAP_IRQ_MAIN_REG_OFFSET(p0_offs),
0064     REGMAP_IRQ_MAIN_REG_OFFSET(p1_offs),
0065     REGMAP_IRQ_MAIN_REG_OFFSET(p2_offs),
0066     REGMAP_IRQ_MAIN_REG_OFFSET(p3_offs),
0067 };
0068 
0069 static unsigned int pm8008_virt_regs[] = {
0070     PM8008_POLARITY_HI_BASE,
0071     PM8008_POLARITY_LO_BASE,
0072 };
0073 
0074 enum {
0075     POLARITY_HI_INDEX,
0076     POLARITY_LO_INDEX,
0077     PM8008_NUM_VIRT_REGS,
0078 };
0079 
0080 static struct regmap_irq pm8008_irqs[] = {
0081     REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO,    PM8008_MISC,    BIT(0)),
0082     REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO,    PM8008_MISC,    BIT(1)),
0083     REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2,   PM8008_MISC,    BIT(2)),
0084     REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3,   PM8008_MISC,    BIT(3)),
0085     REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC,    BIT(4)),
0086     REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM,   PM8008_TEMP_ALARM, BIT(0)),
0087     REGMAP_IRQ_REG(PM8008_IRQ_GPIO1,    PM8008_GPIO1,   BIT(0)),
0088     REGMAP_IRQ_REG(PM8008_IRQ_GPIO2,    PM8008_GPIO2,   BIT(0)),
0089 };
0090 
0091 static int pm8008_set_type_virt(unsigned int **virt_buf,
0092                       unsigned int type, unsigned long hwirq,
0093                       int reg)
0094 {
0095     switch (type) {
0096     case IRQ_TYPE_EDGE_FALLING:
0097     case IRQ_TYPE_LEVEL_LOW:
0098         virt_buf[POLARITY_HI_INDEX][reg] &= ~pm8008_irqs[hwirq].mask;
0099         virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask;
0100         break;
0101 
0102     case IRQ_TYPE_EDGE_RISING:
0103     case IRQ_TYPE_LEVEL_HIGH:
0104         virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask;
0105         virt_buf[POLARITY_LO_INDEX][reg] &= ~pm8008_irqs[hwirq].mask;
0106         break;
0107 
0108     case IRQ_TYPE_EDGE_BOTH:
0109         virt_buf[POLARITY_HI_INDEX][reg] |= pm8008_irqs[hwirq].mask;
0110         virt_buf[POLARITY_LO_INDEX][reg] |= pm8008_irqs[hwirq].mask;
0111         break;
0112 
0113     default:
0114         return -EINVAL;
0115     }
0116 
0117     return 0;
0118 }
0119 
0120 static struct regmap_irq_chip pm8008_irq_chip = {
0121     .name           = "pm8008_irq",
0122     .main_status        = I2C_INTR_STATUS_BASE,
0123     .num_main_regs      = 1,
0124     .num_virt_regs      = PM8008_NUM_VIRT_REGS,
0125     .irqs           = pm8008_irqs,
0126     .num_irqs       = ARRAY_SIZE(pm8008_irqs),
0127     .num_regs       = PM8008_NUM_PERIPHS,
0128     .not_fixed_stride   = true,
0129     .sub_reg_offsets    = pm8008_sub_reg_offsets,
0130     .set_type_virt      = pm8008_set_type_virt,
0131     .status_base        = PM8008_STATUS_BASE,
0132     .mask_base      = PM8008_MASK_BASE,
0133     .unmask_base        = PM8008_UNMASK_BASE,
0134     .type_base      = PM8008_TYPE_BASE,
0135     .ack_base       = PM8008_ACK_BASE,
0136     .virt_reg_base      = pm8008_virt_regs,
0137     .num_type_reg       = PM8008_NUM_PERIPHS,
0138 };
0139 
0140 static struct regmap_config qcom_mfd_regmap_cfg = {
0141     .reg_bits   = 16,
0142     .val_bits   = 8,
0143     .max_register   = 0xFFFF,
0144 };
0145 
0146 static int pm8008_init(struct regmap *regmap)
0147 {
0148     int rc;
0149 
0150     /*
0151      * Set TEMP_ALARM peripheral's TYPE so that the regmap-irq framework
0152      * reads this as the default value instead of zero, the HW default.
0153      * This is required to enable the writing of TYPE registers in
0154      * regmap_irq_sync_unlock().
0155      */
0156     rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
0157     if (rc)
0158         return rc;
0159 
0160     /* Do the same for GPIO1 and GPIO2 peripherals */
0161     rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
0162     if (rc)
0163         return rc;
0164 
0165     rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0));
0166 
0167     return rc;
0168 }
0169 
0170 static int pm8008_probe_irq_peripherals(struct device *dev,
0171                     struct regmap *regmap,
0172                     int client_irq)
0173 {
0174     int rc, i;
0175     struct regmap_irq_type *type;
0176     struct regmap_irq_chip_data *irq_data;
0177 
0178     rc = pm8008_init(regmap);
0179     if (rc) {
0180         dev_err(dev, "Init failed: %d\n", rc);
0181         return rc;
0182     }
0183 
0184     for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) {
0185         type = &pm8008_irqs[i].type;
0186 
0187         type->type_reg_offset     = pm8008_irqs[i].reg_offset;
0188         type->type_rising_val     = pm8008_irqs[i].mask;
0189         type->type_falling_val    = pm8008_irqs[i].mask;
0190         type->type_level_high_val = 0;
0191         type->type_level_low_val  = 0;
0192 
0193         if (type->type_reg_offset == PM8008_MISC)
0194             type->types_supported = IRQ_TYPE_EDGE_RISING;
0195         else
0196             type->types_supported = (IRQ_TYPE_EDGE_BOTH |
0197                 IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW);
0198     }
0199 
0200     rc = devm_regmap_add_irq_chip(dev, regmap, client_irq,
0201             IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data);
0202     if (rc) {
0203         dev_err(dev, "Failed to add IRQ chip: %d\n", rc);
0204         return rc;
0205     }
0206 
0207     return 0;
0208 }
0209 
0210 static int pm8008_probe(struct i2c_client *client)
0211 {
0212     int rc;
0213     struct device *dev;
0214     struct regmap *regmap;
0215 
0216     dev = &client->dev;
0217     regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg);
0218     if (!regmap)
0219         return -ENODEV;
0220 
0221     i2c_set_clientdata(client, regmap);
0222 
0223     if (of_property_read_bool(dev->of_node, "interrupt-controller")) {
0224         rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq);
0225         if (rc)
0226             dev_err(dev, "Failed to probe irq periphs: %d\n", rc);
0227     }
0228 
0229     return devm_of_platform_populate(dev);
0230 }
0231 
0232 static const struct of_device_id pm8008_match[] = {
0233     { .compatible = "qcom,pm8008", },
0234     { },
0235 };
0236 
0237 static struct i2c_driver pm8008_mfd_driver = {
0238     .driver = {
0239         .name = "pm8008",
0240         .of_match_table = pm8008_match,
0241     },
0242     .probe_new = pm8008_probe,
0243 };
0244 module_i2c_driver(pm8008_mfd_driver);
0245 
0246 MODULE_LICENSE("GPL v2");
0247 MODULE_ALIAS("i2c:qcom-pm8008");