1/* 2 * axp20x.c - MFD core driver for the X-Powers' Power Management ICs 3 * 4 * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC 5 * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature 6 * as well as configurable GPIOs. 7 * 8 * Author: Carlo Caione <carlo@caione.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 15#include <linux/err.h> 16#include <linux/i2c.h> 17#include <linux/interrupt.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/pm_runtime.h> 21#include <linux/regmap.h> 22#include <linux/slab.h> 23#include <linux/regulator/consumer.h> 24#include <linux/mfd/axp20x.h> 25#include <linux/mfd/core.h> 26#include <linux/of_device.h> 27#include <linux/of_irq.h> 28#include <linux/acpi.h> 29 30#define AXP20X_OFF 0x80 31 32static const char * const axp20x_model_names[] = { 33 "AXP202", 34 "AXP209", 35 "AXP288", 36}; 37 38static const struct regmap_range axp20x_writeable_ranges[] = { 39 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), 40 regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES), 41}; 42 43static const struct regmap_range axp20x_volatile_ranges[] = { 44 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), 45}; 46 47static const struct regmap_access_table axp20x_writeable_table = { 48 .yes_ranges = axp20x_writeable_ranges, 49 .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges), 50}; 51 52static const struct regmap_access_table axp20x_volatile_table = { 53 .yes_ranges = axp20x_volatile_ranges, 54 .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), 55}; 56 57static const struct regmap_range axp288_writeable_ranges[] = { 58 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), 59 regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), 60}; 61 62static const struct regmap_range axp288_volatile_ranges[] = { 63 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L), 64}; 65 66static const struct regmap_access_table axp288_writeable_table = { 67 .yes_ranges = axp288_writeable_ranges, 68 .n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges), 69}; 70 71static const struct regmap_access_table axp288_volatile_table = { 72 .yes_ranges = axp288_volatile_ranges, 73 .n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges), 74}; 75 76static struct resource axp20x_pek_resources[] = { 77 { 78 .name = "PEK_DBR", 79 .start = AXP20X_IRQ_PEK_RIS_EDGE, 80 .end = AXP20X_IRQ_PEK_RIS_EDGE, 81 .flags = IORESOURCE_IRQ, 82 }, { 83 .name = "PEK_DBF", 84 .start = AXP20X_IRQ_PEK_FAL_EDGE, 85 .end = AXP20X_IRQ_PEK_FAL_EDGE, 86 .flags = IORESOURCE_IRQ, 87 }, 88}; 89 90static struct resource axp288_fuel_gauge_resources[] = { 91 { 92 .start = AXP288_IRQ_QWBTU, 93 .end = AXP288_IRQ_QWBTU, 94 .flags = IORESOURCE_IRQ, 95 }, 96 { 97 .start = AXP288_IRQ_WBTU, 98 .end = AXP288_IRQ_WBTU, 99 .flags = IORESOURCE_IRQ, 100 }, 101 { 102 .start = AXP288_IRQ_QWBTO, 103 .end = AXP288_IRQ_QWBTO, 104 .flags = IORESOURCE_IRQ, 105 }, 106 { 107 .start = AXP288_IRQ_WBTO, 108 .end = AXP288_IRQ_WBTO, 109 .flags = IORESOURCE_IRQ, 110 }, 111 { 112 .start = AXP288_IRQ_WL2, 113 .end = AXP288_IRQ_WL2, 114 .flags = IORESOURCE_IRQ, 115 }, 116 { 117 .start = AXP288_IRQ_WL1, 118 .end = AXP288_IRQ_WL1, 119 .flags = IORESOURCE_IRQ, 120 }, 121}; 122 123static const struct regmap_config axp20x_regmap_config = { 124 .reg_bits = 8, 125 .val_bits = 8, 126 .wr_table = &axp20x_writeable_table, 127 .volatile_table = &axp20x_volatile_table, 128 .max_register = AXP20X_FG_RES, 129 .cache_type = REGCACHE_RBTREE, 130}; 131 132static const struct regmap_config axp288_regmap_config = { 133 .reg_bits = 8, 134 .val_bits = 8, 135 .wr_table = &axp288_writeable_table, 136 .volatile_table = &axp288_volatile_table, 137 .max_register = AXP288_FG_TUNE5, 138 .cache_type = REGCACHE_RBTREE, 139}; 140 141#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \ 142 [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } 143 144static const struct regmap_irq axp20x_regmap_irqs[] = { 145 INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7), 146 INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6), 147 INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5), 148 INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4), 149 INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3), 150 INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2), 151 INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1), 152 INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7), 153 INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6), 154 INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5), 155 INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4), 156 INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3), 157 INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2), 158 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1), 159 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0), 160 INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7), 161 INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6), 162 INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5), 163 INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4), 164 INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3), 165 INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1), 166 INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0), 167 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7), 168 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6), 169 INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5), 170 INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4), 171 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3), 172 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2), 173 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1), 174 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0), 175 INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7), 176 INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6), 177 INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5), 178 INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3), 179 INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2), 180 INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1), 181 INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0), 182}; 183 184/* some IRQs are compatible with axp20x models */ 185static const struct regmap_irq axp288_regmap_irqs[] = { 186 INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2), 187 INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3), 188 INIT_REGMAP_IRQ(AXP288, OV, 0, 4), 189 190 INIT_REGMAP_IRQ(AXP288, DONE, 1, 2), 191 INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3), 192 INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4), 193 INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5), 194 INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6), 195 INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7), 196 197 INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0), 198 INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1), 199 INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2), 200 INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3), 201 INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4), 202 INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5), 203 INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6), 204 INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7), 205 206 INIT_REGMAP_IRQ(AXP288, WL2, 3, 0), 207 INIT_REGMAP_IRQ(AXP288, WL1, 3, 1), 208 INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2), 209 INIT_REGMAP_IRQ(AXP288, OT, 3, 7), 210 211 INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0), 212 INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1), 213 INIT_REGMAP_IRQ(AXP288, POKO, 4, 2), 214 INIT_REGMAP_IRQ(AXP288, POKL, 4, 3), 215 INIT_REGMAP_IRQ(AXP288, POKS, 4, 4), 216 INIT_REGMAP_IRQ(AXP288, POKN, 4, 5), 217 INIT_REGMAP_IRQ(AXP288, POKP, 4, 6), 218 INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7), 219 220 INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0), 221 INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1), 222}; 223 224static const struct of_device_id axp20x_of_match[] = { 225 { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, 226 { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, 227 { }, 228}; 229MODULE_DEVICE_TABLE(of, axp20x_of_match); 230 231/* 232 * This is useless for OF-enabled devices, but it is needed by I2C subsystem 233 */ 234static const struct i2c_device_id axp20x_i2c_id[] = { 235 { }, 236}; 237MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); 238 239static const struct acpi_device_id axp20x_acpi_match[] = { 240 { 241 .id = "INT33F4", 242 .driver_data = AXP288_ID, 243 }, 244 { }, 245}; 246MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match); 247 248static const struct regmap_irq_chip axp20x_regmap_irq_chip = { 249 .name = "axp20x_irq_chip", 250 .status_base = AXP20X_IRQ1_STATE, 251 .ack_base = AXP20X_IRQ1_STATE, 252 .mask_base = AXP20X_IRQ1_EN, 253 .mask_invert = true, 254 .init_ack_masked = true, 255 .irqs = axp20x_regmap_irqs, 256 .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), 257 .num_regs = 5, 258 259}; 260 261static const struct regmap_irq_chip axp288_regmap_irq_chip = { 262 .name = "axp288_irq_chip", 263 .status_base = AXP20X_IRQ1_STATE, 264 .ack_base = AXP20X_IRQ1_STATE, 265 .mask_base = AXP20X_IRQ1_EN, 266 .mask_invert = true, 267 .init_ack_masked = true, 268 .irqs = axp288_regmap_irqs, 269 .num_irqs = ARRAY_SIZE(axp288_regmap_irqs), 270 .num_regs = 6, 271 272}; 273 274static struct mfd_cell axp20x_cells[] = { 275 { 276 .name = "axp20x-pek", 277 .num_resources = ARRAY_SIZE(axp20x_pek_resources), 278 .resources = axp20x_pek_resources, 279 }, { 280 .name = "axp20x-regulator", 281 }, 282}; 283 284static struct resource axp288_adc_resources[] = { 285 { 286 .name = "GPADC", 287 .start = AXP288_IRQ_GPADC, 288 .end = AXP288_IRQ_GPADC, 289 .flags = IORESOURCE_IRQ, 290 }, 291}; 292 293static struct resource axp288_extcon_resources[] = { 294 { 295 .start = AXP288_IRQ_VBUS_FALL, 296 .end = AXP288_IRQ_VBUS_FALL, 297 .flags = IORESOURCE_IRQ, 298 }, 299 { 300 .start = AXP288_IRQ_VBUS_RISE, 301 .end = AXP288_IRQ_VBUS_RISE, 302 .flags = IORESOURCE_IRQ, 303 }, 304 { 305 .start = AXP288_IRQ_MV_CHNG, 306 .end = AXP288_IRQ_MV_CHNG, 307 .flags = IORESOURCE_IRQ, 308 }, 309 { 310 .start = AXP288_IRQ_BC_USB_CHNG, 311 .end = AXP288_IRQ_BC_USB_CHNG, 312 .flags = IORESOURCE_IRQ, 313 }, 314}; 315 316static struct resource axp288_charger_resources[] = { 317 { 318 .start = AXP288_IRQ_OV, 319 .end = AXP288_IRQ_OV, 320 .flags = IORESOURCE_IRQ, 321 }, 322 { 323 .start = AXP288_IRQ_DONE, 324 .end = AXP288_IRQ_DONE, 325 .flags = IORESOURCE_IRQ, 326 }, 327 { 328 .start = AXP288_IRQ_CHARGING, 329 .end = AXP288_IRQ_CHARGING, 330 .flags = IORESOURCE_IRQ, 331 }, 332 { 333 .start = AXP288_IRQ_SAFE_QUIT, 334 .end = AXP288_IRQ_SAFE_QUIT, 335 .flags = IORESOURCE_IRQ, 336 }, 337 { 338 .start = AXP288_IRQ_SAFE_ENTER, 339 .end = AXP288_IRQ_SAFE_ENTER, 340 .flags = IORESOURCE_IRQ, 341 }, 342 { 343 .start = AXP288_IRQ_QCBTU, 344 .end = AXP288_IRQ_QCBTU, 345 .flags = IORESOURCE_IRQ, 346 }, 347 { 348 .start = AXP288_IRQ_CBTU, 349 .end = AXP288_IRQ_CBTU, 350 .flags = IORESOURCE_IRQ, 351 }, 352 { 353 .start = AXP288_IRQ_QCBTO, 354 .end = AXP288_IRQ_QCBTO, 355 .flags = IORESOURCE_IRQ, 356 }, 357 { 358 .start = AXP288_IRQ_CBTO, 359 .end = AXP288_IRQ_CBTO, 360 .flags = IORESOURCE_IRQ, 361 }, 362}; 363 364static struct mfd_cell axp288_cells[] = { 365 { 366 .name = "axp288_adc", 367 .num_resources = ARRAY_SIZE(axp288_adc_resources), 368 .resources = axp288_adc_resources, 369 }, 370 { 371 .name = "axp288_extcon", 372 .num_resources = ARRAY_SIZE(axp288_extcon_resources), 373 .resources = axp288_extcon_resources, 374 }, 375 { 376 .name = "axp288_charger", 377 .num_resources = ARRAY_SIZE(axp288_charger_resources), 378 .resources = axp288_charger_resources, 379 }, 380 { 381 .name = "axp288_fuel_gauge", 382 .num_resources = ARRAY_SIZE(axp288_fuel_gauge_resources), 383 .resources = axp288_fuel_gauge_resources, 384 }, 385 { 386 .name = "axp288_pmic_acpi", 387 }, 388}; 389 390static struct axp20x_dev *axp20x_pm_power_off; 391static void axp20x_power_off(void) 392{ 393 if (axp20x_pm_power_off->variant == AXP288_ID) 394 return; 395 396 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, 397 AXP20X_OFF); 398} 399 400static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev) 401{ 402 const struct acpi_device_id *acpi_id; 403 const struct of_device_id *of_id; 404 405 if (dev->of_node) { 406 of_id = of_match_device(axp20x_of_match, dev); 407 if (!of_id) { 408 dev_err(dev, "Unable to match OF ID\n"); 409 return -ENODEV; 410 } 411 axp20x->variant = (long) of_id->data; 412 } else { 413 acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); 414 if (!acpi_id || !acpi_id->driver_data) { 415 dev_err(dev, "Unable to match ACPI ID and data\n"); 416 return -ENODEV; 417 } 418 axp20x->variant = (long) acpi_id->driver_data; 419 } 420 421 switch (axp20x->variant) { 422 case AXP202_ID: 423 case AXP209_ID: 424 axp20x->nr_cells = ARRAY_SIZE(axp20x_cells); 425 axp20x->cells = axp20x_cells; 426 axp20x->regmap_cfg = &axp20x_regmap_config; 427 axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip; 428 break; 429 case AXP288_ID: 430 axp20x->cells = axp288_cells; 431 axp20x->nr_cells = ARRAY_SIZE(axp288_cells); 432 axp20x->regmap_cfg = &axp288_regmap_config; 433 axp20x->regmap_irq_chip = &axp288_regmap_irq_chip; 434 break; 435 default: 436 dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); 437 return -EINVAL; 438 } 439 dev_info(dev, "AXP20x variant %s found\n", 440 axp20x_model_names[axp20x->variant]); 441 442 return 0; 443} 444 445static int axp20x_i2c_probe(struct i2c_client *i2c, 446 const struct i2c_device_id *id) 447{ 448 struct axp20x_dev *axp20x; 449 int ret; 450 451 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); 452 if (!axp20x) 453 return -ENOMEM; 454 455 ret = axp20x_match_device(axp20x, &i2c->dev); 456 if (ret) 457 return ret; 458 459 axp20x->i2c_client = i2c; 460 axp20x->dev = &i2c->dev; 461 dev_set_drvdata(axp20x->dev, axp20x); 462 463 axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg); 464 if (IS_ERR(axp20x->regmap)) { 465 ret = PTR_ERR(axp20x->regmap); 466 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 467 return ret; 468 } 469 470 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, 471 IRQF_ONESHOT | IRQF_SHARED, -1, 472 axp20x->regmap_irq_chip, 473 &axp20x->regmap_irqc); 474 if (ret) { 475 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); 476 return ret; 477 } 478 479 ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells, 480 axp20x->nr_cells, NULL, 0, NULL); 481 482 if (ret) { 483 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); 484 regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc); 485 return ret; 486 } 487 488 if (!pm_power_off) { 489 axp20x_pm_power_off = axp20x; 490 pm_power_off = axp20x_power_off; 491 } 492 493 dev_info(&i2c->dev, "AXP20X driver loaded\n"); 494 495 return 0; 496} 497 498static int axp20x_i2c_remove(struct i2c_client *i2c) 499{ 500 struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); 501 502 if (axp20x == axp20x_pm_power_off) { 503 axp20x_pm_power_off = NULL; 504 pm_power_off = NULL; 505 } 506 507 mfd_remove_devices(axp20x->dev); 508 regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc); 509 510 return 0; 511} 512 513static struct i2c_driver axp20x_i2c_driver = { 514 .driver = { 515 .name = "axp20x", 516 .owner = THIS_MODULE, 517 .of_match_table = of_match_ptr(axp20x_of_match), 518 .acpi_match_table = ACPI_PTR(axp20x_acpi_match), 519 }, 520 .probe = axp20x_i2c_probe, 521 .remove = axp20x_i2c_remove, 522 .id_table = axp20x_i2c_id, 523}; 524 525module_i2c_driver(axp20x_i2c_driver); 526 527MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X"); 528MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); 529MODULE_LICENSE("GPL"); 530