| 1 | |
| 2 | |
| 3 | * Core driver for the PF1550
|
| 4 | *
|
| 5 | * Copyright (C) 2016 Freescale Semiconductor, Inc.
|
| 6 | * Robin Gong <[email protected]>
|
| 7 | *
|
| 8 | * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
|
| 9 | * Samuel Kayode <[email protected]>
|
| 10 |
|
| 11 |
|
| 12 | #include <linux/err.h>
|
| 13 | #include <linux/i2c.h>
|
| 14 | #include <linux/interrupt.h>
|
| 15 | #include <linux/mfd/core.h>
|
| 16 | #include <linux/mfd/pf1550.h>
|
| 17 | #include <linux/module.h>
|
| 18 | #include <linux/of.h>
|
| 19 | #include <linux/regmap.h>
|
| 20 |
|
| 21 | static const struct regmap_config pf1550_regmap_config = {
|
| 22 | .reg_bits = 8,
|
| 23 | .val_bits = 8,
|
| 24 | .max_register = PF1550_PMIC_REG_END,
|
| 25 | };
|
| 26 |
|
| 27 | static const struct regmap_irq pf1550_irqs[] = {
|
| 28 | REGMAP_IRQ_REG(PF1550_IRQ_CHG, 0, IRQ_CHG),
|
| 29 | REGMAP_IRQ_REG(PF1550_IRQ_REGULATOR, 0, IRQ_REGULATOR),
|
| 30 | REGMAP_IRQ_REG(PF1550_IRQ_ONKEY, 0, IRQ_ONKEY),
|
| 31 | };
|
| 32 |
|
| 33 | static const struct regmap_irq_chip pf1550_irq_chip = {
|
| 34 | .name = "pf1550",
|
| 35 | .status_base = PF1550_PMIC_REG_INT_CATEGORY,
|
| 36 | .init_ack_masked = 1,
|
| 37 | .num_regs = 1,
|
| 38 | .irqs = pf1550_irqs,
|
| 39 | .num_irqs = ARRAY_SIZE(pf1550_irqs),
|
| 40 | };
|
| 41 |
|
| 42 | static const struct regmap_irq pf1550_regulator_irqs[] = {
|
| 43 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_LS, 0, PMIC_IRQ_SW1_LS),
|
| 44 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_LS, 0, PMIC_IRQ_SW2_LS),
|
| 45 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_LS, 0, PMIC_IRQ_SW3_LS),
|
| 46 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_HS, 3, PMIC_IRQ_SW1_HS),
|
| 47 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_HS, 3, PMIC_IRQ_SW2_HS),
|
| 48 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_HS, 3, PMIC_IRQ_SW3_HS),
|
| 49 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO1_FAULT, 16, PMIC_IRQ_LDO1_FAULT),
|
| 50 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO2_FAULT, 16, PMIC_IRQ_LDO2_FAULT),
|
| 51 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO3_FAULT, 16, PMIC_IRQ_LDO3_FAULT),
|
| 52 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_110, 24, PMIC_IRQ_TEMP_110),
|
| 53 | REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_125, 24, PMIC_IRQ_TEMP_125),
|
| 54 | };
|
| 55 |
|
| 56 | static const struct regmap_irq_chip pf1550_regulator_irq_chip = {
|
| 57 | .name = "pf1550-regulator",
|
| 58 | .status_base = PF1550_PMIC_REG_SW_INT_STAT0,
|
| 59 | .ack_base = PF1550_PMIC_REG_SW_INT_STAT0,
|
| 60 | .mask_base = PF1550_PMIC_REG_SW_INT_MASK0,
|
| 61 | .use_ack = 1,
|
| 62 | .init_ack_masked = 1,
|
| 63 | .num_regs = 25,
|
| 64 | .irqs = pf1550_regulator_irqs,
|
| 65 | .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs),
|
| 66 | };
|
| 67 |
|
| 68 | static const struct resource regulator_resources[] = {
|
| 69 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_LS),
|
| 70 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_LS),
|
| 71 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_LS),
|
| 72 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_HS),
|
| 73 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_HS),
|
| 74 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_HS),
|
| 75 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO1_FAULT),
|
| 76 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO2_FAULT),
|
| 77 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO3_FAULT),
|
| 78 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_110),
|
| 79 | DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_125),
|
| 80 | };
|
| 81 |
|
| 82 | static const struct regmap_irq pf1550_onkey_irqs[] = {
|
| 83 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_PUSHI, 0, ONKEY_IRQ_PUSHI),
|
| 84 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_1SI, 0, ONKEY_IRQ_1SI),
|
| 85 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_2SI, 0, ONKEY_IRQ_2SI),
|
| 86 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_3SI, 0, ONKEY_IRQ_3SI),
|
| 87 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_4SI, 0, ONKEY_IRQ_4SI),
|
| 88 | REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_8SI, 0, ONKEY_IRQ_8SI),
|
| 89 | };
|
| 90 |
|
| 91 | static const struct regmap_irq_chip pf1550_onkey_irq_chip = {
|
| 92 | .name = "pf1550-onkey",
|
| 93 | .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
|
| 94 | .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
|
| 95 | .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0,
|
| 96 | .use_ack = 1,
|
| 97 | .init_ack_masked = 1,
|
| 98 | .num_regs = 1,
|
| 99 | .irqs = pf1550_onkey_irqs,
|
| 100 | .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs),
|
| 101 | };
|
| 102 |
|
| 103 | static const struct resource onkey_resources[] = {
|
| 104 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_PUSHI),
|
| 105 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_1SI),
|
| 106 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_2SI),
|
| 107 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_3SI),
|
| 108 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_4SI),
|
| 109 | DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_8SI),
|
| 110 | };
|
| 111 |
|
| 112 | static const struct regmap_irq pf1550_charger_irqs[] = {
|
| 113 | REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BAT2SOCI, 0, CHARG_IRQ_BAT2SOCI),
|
| 114 | REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BATI, 0, CHARG_IRQ_BATI),
|
| 115 | REGMAP_IRQ_REG(PF1550_CHARG_IRQ_CHGI, 0, CHARG_IRQ_CHGI),
|
| 116 | REGMAP_IRQ_REG(PF1550_CHARG_IRQ_VBUSI, 0, CHARG_IRQ_VBUSI),
|
| 117 | REGMAP_IRQ_REG(PF1550_CHARG_IRQ_THMI, 0, CHARG_IRQ_THMI),
|
| 118 | };
|
| 119 |
|
| 120 | static const struct regmap_irq_chip pf1550_charger_irq_chip = {
|
| 121 | .name = "pf1550-charger",
|
| 122 | .status_base = PF1550_CHARG_REG_CHG_INT,
|
| 123 | .ack_base = PF1550_CHARG_REG_CHG_INT,
|
| 124 | .mask_base = PF1550_CHARG_REG_CHG_INT_MASK,
|
| 125 | .use_ack = 1,
|
| 126 | .init_ack_masked = 1,
|
| 127 | .num_regs = 1,
|
| 128 | .irqs = pf1550_charger_irqs,
|
| 129 | .num_irqs = ARRAY_SIZE(pf1550_charger_irqs),
|
| 130 | };
|
| 131 |
|
| 132 | static const struct resource charger_resources[] = {
|
| 133 | DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BAT2SOCI),
|
| 134 | DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BATI),
|
| 135 | DEFINE_RES_IRQ(PF1550_CHARG_IRQ_CHGI),
|
| 136 | DEFINE_RES_IRQ(PF1550_CHARG_IRQ_VBUSI),
|
| 137 | DEFINE_RES_IRQ(PF1550_CHARG_IRQ_THMI),
|
| 138 | };
|
| 139 |
|
| 140 | static const struct mfd_cell pf1550_regulator_cell = {
|
| 141 | .name = "pf1550-regulator",
|
| 142 | .num_resources = ARRAY_SIZE(regulator_resources),
|
| 143 | .resources = regulator_resources,
|
| 144 | };
|
| 145 |
|
| 146 | static const struct mfd_cell pf1550_onkey_cell = {
|
| 147 | .name = "pf1550-onkey",
|
| 148 | .num_resources = ARRAY_SIZE(onkey_resources),
|
| 149 | .resources = onkey_resources,
|
| 150 | };
|
| 151 |
|
| 152 | static const struct mfd_cell pf1550_charger_cell = {
|
| 153 | .name = "pf1550-charger",
|
| 154 | .num_resources = ARRAY_SIZE(charger_resources),
|
| 155 | .resources = charger_resources,
|
| 156 | };
|
| 157 |
|
| 158 | |
| 159 | * The PF1550 is shipped in variants of A0, A1,...A9. Each variant defines a
|
| 160 | * configuration of the PMIC in a One-Time Programmable (OTP) memory.
|
| 161 | * This memory is accessed indirectly by writing valid keys to specific
|
| 162 | * registers of the PMIC. To read the OTP memory after writing the valid keys,
|
| 163 | * the OTP register address to be read is written to pf1550 register 0xc4 and
|
| 164 | * its value read from pf1550 register 0xc5.
|
| 165 |
|
| 166 | static int pf1550_read_otp(const struct pf1550_ddata *pf1550, unsigned int index,
|
| 167 | unsigned int *val)
|
| 168 | {
|
| 169 | int ret = 0;
|
| 170 |
|
| 171 | ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, PF1550_OTP_PMIC_KEY);
|
| 172 | if (ret)
|
| 173 | goto read_err;
|
| 174 |
|
| 175 | ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, PF1550_OTP_CHGR_KEY);
|
| 176 | if (ret)
|
| 177 | goto read_err;
|
| 178 |
|
| 179 | ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, PF1550_OTP_TEST_KEY);
|
| 180 | if (ret)
|
| 181 | goto read_err;
|
| 182 |
|
| 183 | ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index);
|
| 184 | if (ret)
|
| 185 | goto read_err;
|
| 186 |
|
| 187 | ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val);
|
| 188 | if (ret)
|
| 189 | goto read_err;
|
| 190 |
|
| 191 | return 0;
|
| 192 |
|
| 193 | read_err:
|
| 194 | return dev_err_probe(pf1550->dev, ret, "OTP reg %x not found!\n", index);
|
| 195 | }
|
| 196 |
|
| 197 | static int pf1550_i2c_probe(struct i2c_client *i2c)
|
| 198 | {
|
| 199 | const struct mfd_cell *regulator = &pf1550_regulator_cell;
|
| 200 | const struct mfd_cell *charger = &pf1550_charger_cell;
|
| 201 | const struct mfd_cell *onkey = &pf1550_onkey_cell;
|
| 202 | unsigned int reg_data = 0, otp_data = 0;
|
| 203 | struct pf1550_ddata *pf1550;
|
| 204 | struct irq_domain *domain;
|
| 205 | int irq, ret = 0;
|
| 206 |
|
| 207 | pf1550 = devm_kzalloc(&i2c->dev, sizeof(*pf1550), GFP_KERNEL);
|
| 208 | if (!pf1550)
|
| 209 | return -ENOMEM;
|
| 210 |
|
| 211 | i2c_set_clientdata(i2c, pf1550);
|
| 212 | pf1550->dev = &i2c->dev;
|
| 213 | pf1550->irq = i2c->irq;
|
| 214 |
|
| 215 | pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config);
|
| 216 | if (IS_ERR(pf1550->regmap))
|
| 217 | return dev_err_probe(pf1550->dev, PTR_ERR(pf1550->regmap),
|
| 218 | "failed to allocate register map\n");
|
| 219 |
|
| 220 | ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, ®_data);
|
| 221 | if (ret < 0)
|
| 222 | return dev_err_probe(pf1550->dev, ret, "cannot read chip ID\n");
|
| 223 | if (reg_data != PF1550_DEVICE_ID)
|
| 224 | return dev_err_probe(pf1550->dev, -ENODEV, "invalid device ID: 0x%02x\n", reg_data);
|
| 225 |
|
| 226 |
|
| 227 | ret = pf1550_read_otp(pf1550, PF1550_OTP_SW2_SW3, &otp_data);
|
| 228 | if (ret)
|
| 229 | return ret;
|
| 230 |
|
| 231 |
|
| 232 | if (!(otp_data & OTP_SW2_DVS_ENB))
|
| 233 | pf1550->dvs2_enable = true;
|
| 234 |
|
| 235 |
|
| 236 | ret = pf1550_read_otp(pf1550, PF1550_OTP_SW1_SW2, &otp_data);
|
| 237 | if (ret)
|
| 238 | return ret;
|
| 239 |
|
| 240 | if (!(otp_data & OTP_SW1_DVS_ENB))
|
| 241 | pf1550->dvs1_enable = true;
|
| 242 |
|
| 243 |
|
| 244 | ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, pf1550->irq,
|
| 245 | IRQF_ONESHOT | IRQF_SHARED |
|
| 246 | IRQF_TRIGGER_FALLING,
|
| 247 | 0, &pf1550_irq_chip,
|
| 248 | &pf1550->irq_data);
|
| 249 | if (ret)
|
| 250 | return ret;
|
| 251 |
|
| 252 |
|
| 253 | irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_REGULATOR);
|
| 254 | if (irq < 0)
|
| 255 | return dev_err_probe(pf1550->dev, irq,
|
| 256 | "Failed to get parent vIRQ(%d) for chip %s\n",
|
| 257 | PF1550_IRQ_REGULATOR, pf1550_irq_chip.name);
|
| 258 |
|
| 259 | ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
|
| 260 | IRQF_ONESHOT | IRQF_SHARED |
|
| 261 | IRQF_TRIGGER_FALLING, 0,
|
| 262 | &pf1550_regulator_irq_chip,
|
| 263 | &pf1550->irq_data_regulator);
|
| 264 | if (ret)
|
| 265 | return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
|
| 266 | pf1550_regulator_irq_chip.name);
|
| 267 |
|
| 268 | domain = regmap_irq_get_domain(pf1550->irq_data_regulator);
|
| 269 |
|
| 270 | ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, regulator, 1, NULL, 0, domain);
|
| 271 | if (ret)
|
| 272 | return ret;
|
| 273 |
|
| 274 |
|
| 275 | irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_ONKEY);
|
| 276 | if (irq < 0)
|
| 277 | return dev_err_probe(pf1550->dev, irq,
|
| 278 | "Failed to get parent vIRQ(%d) for chip %s\n",
|
| 279 | PF1550_IRQ_ONKEY, pf1550_irq_chip.name);
|
| 280 |
|
| 281 | ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
|
| 282 | IRQF_ONESHOT | IRQF_SHARED |
|
| 283 | IRQF_TRIGGER_FALLING, 0,
|
| 284 | &pf1550_onkey_irq_chip,
|
| 285 | &pf1550->irq_data_onkey);
|
| 286 | if (ret)
|
| 287 | return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
|
| 288 | pf1550_onkey_irq_chip.name);
|
| 289 |
|
| 290 | domain = regmap_irq_get_domain(pf1550->irq_data_onkey);
|
| 291 |
|
| 292 | ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, onkey, 1, NULL, 0, domain);
|
| 293 | if (ret)
|
| 294 | return ret;
|
| 295 |
|
| 296 |
|
| 297 | irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_CHG);
|
| 298 | if (irq < 0)
|
| 299 | return dev_err_probe(pf1550->dev, irq,
|
| 300 | "Failed to get parent vIRQ(%d) for chip %s\n",
|
| 301 | PF1550_IRQ_CHG, pf1550_irq_chip.name);
|
| 302 |
|
| 303 | ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
|
| 304 | IRQF_ONESHOT | IRQF_SHARED |
|
| 305 | IRQF_TRIGGER_FALLING, 0,
|
| 306 | &pf1550_charger_irq_chip,
|
| 307 | &pf1550->irq_data_charger);
|
| 308 | if (ret)
|
| 309 | return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
|
| 310 | pf1550_charger_irq_chip.name);
|
| 311 |
|
| 312 | domain = regmap_irq_get_domain(pf1550->irq_data_charger);
|
| 313 |
|
| 314 | return devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, charger, 1, NULL, 0, domain);
|
| 315 | }
|
| 316 |
|
| 317 | static int pf1550_suspend(struct device *dev)
|
| 318 | {
|
| 319 | struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
|
| 320 |
|
| 321 | if (device_may_wakeup(dev)) {
|
| 322 | enable_irq_wake(pf1550->irq);
|
| 323 | disable_irq(pf1550->irq);
|
| 324 | }
|
| 325 |
|
| 326 | return 0;
|
| 327 | }
|
| 328 |
|
| 329 | static int pf1550_resume(struct device *dev)
|
| 330 | {
|
| 331 | struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
|
| 332 |
|
| 333 | if (device_may_wakeup(dev)) {
|
| 334 | disable_irq_wake(pf1550->irq);
|
| 335 | enable_irq(pf1550->irq);
|
| 336 | }
|
| 337 |
|
| 338 | return 0;
|
| 339 | }
|
| 340 | static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_pm, pf1550_suspend, pf1550_resume);
|
| 341 |
|
| 342 | static const struct i2c_device_id pf1550_i2c_id[] = {
|
| 343 | { "pf1550" },
|
| 344 | { }
|
| 345 | };
|
| 346 | MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id);
|
| 347 |
|
| 348 | static const struct of_device_id pf1550_dt_match[] = {
|
| 349 | { .compatible = "nxp,pf1550" },
|
| 350 | { }
|
| 351 | };
|
| 352 | MODULE_DEVICE_TABLE(of, pf1550_dt_match);
|
| 353 |
|
| 354 | static struct i2c_driver pf1550_i2c_driver = {
|
| 355 | .driver = {
|
| 356 | .name = "pf1550",
|
| 357 | .pm = pm_sleep_ptr(&pf1550_pm),
|
| 358 | .of_match_table = pf1550_dt_match,
|
| 359 | },
|
| 360 | .probe = pf1550_i2c_probe,
|
| 361 | .id_table = pf1550_i2c_id,
|
| 362 | };
|
| 363 | module_i2c_driver(pf1550_i2c_driver);
|
| 364 |
|
| 365 | MODULE_DESCRIPTION("NXP PF1550 core driver");
|
| 366 | MODULE_AUTHOR("Robin Gong <[email protected]>");
|
| 367 | MODULE_LICENSE("GPL");
|