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 32 static const char * const axp20x_model_names[] = { 33 "AXP152", 34 "AXP202", 35 "AXP209", 36 "AXP221", 37 "AXP288", 38 }; 39 40 static const struct regmap_range axp152_writeable_ranges[] = { 41 regmap_reg_range(AXP152_LDO3456_DC1234_CTRL, AXP152_IRQ3_STATE), 42 regmap_reg_range(AXP152_DCDC_MODE, AXP152_PWM1_DUTY_CYCLE), 43 }; 44 45 static const struct regmap_range axp152_volatile_ranges[] = { 46 regmap_reg_range(AXP152_PWR_OP_MODE, AXP152_PWR_OP_MODE), 47 regmap_reg_range(AXP152_IRQ1_EN, AXP152_IRQ3_STATE), 48 regmap_reg_range(AXP152_GPIO_INPUT, AXP152_GPIO_INPUT), 49 }; 50 51 static const struct regmap_access_table axp152_writeable_table = { 52 .yes_ranges = axp152_writeable_ranges, 53 .n_yes_ranges = ARRAY_SIZE(axp152_writeable_ranges), 54 }; 55 56 static const struct regmap_access_table axp152_volatile_table = { 57 .yes_ranges = axp152_volatile_ranges, 58 .n_yes_ranges = ARRAY_SIZE(axp152_volatile_ranges), 59 }; 60 61 static const struct regmap_range axp20x_writeable_ranges[] = { 62 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), 63 regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES), 64 regmap_reg_range(AXP20X_RDC_H, AXP20X_OCV(AXP20X_OCV_MAX)), 65 }; 66 67 static const struct regmap_range axp20x_volatile_ranges[] = { 68 regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_USB_OTG_STATUS), 69 regmap_reg_range(AXP20X_CHRG_CTRL1, AXP20X_CHRG_CTRL2), 70 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), 71 regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L), 72 regmap_reg_range(AXP20X_GPIO20_SS, AXP20X_GPIO3_CTRL), 73 regmap_reg_range(AXP20X_FG_RES, AXP20X_RDC_L), 74 }; 75 76 static const struct regmap_access_table axp20x_writeable_table = { 77 .yes_ranges = axp20x_writeable_ranges, 78 .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges), 79 }; 80 81 static const struct regmap_access_table axp20x_volatile_table = { 82 .yes_ranges = axp20x_volatile_ranges, 83 .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), 84 }; 85 86 static const struct regmap_range axp22x_writeable_ranges[] = { 87 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), 88 regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1), 89 }; 90 91 static const struct regmap_range axp22x_volatile_ranges[] = { 92 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), 93 }; 94 95 static const struct regmap_access_table axp22x_writeable_table = { 96 .yes_ranges = axp22x_writeable_ranges, 97 .n_yes_ranges = ARRAY_SIZE(axp22x_writeable_ranges), 98 }; 99 100 static const struct regmap_access_table axp22x_volatile_table = { 101 .yes_ranges = axp22x_volatile_ranges, 102 .n_yes_ranges = ARRAY_SIZE(axp22x_volatile_ranges), 103 }; 104 105 static const struct regmap_range axp288_writeable_ranges[] = { 106 regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE), 107 regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5), 108 }; 109 110 static const struct regmap_range axp288_volatile_ranges[] = { 111 regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L), 112 }; 113 114 static const struct regmap_access_table axp288_writeable_table = { 115 .yes_ranges = axp288_writeable_ranges, 116 .n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges), 117 }; 118 119 static const struct regmap_access_table axp288_volatile_table = { 120 .yes_ranges = axp288_volatile_ranges, 121 .n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges), 122 }; 123 124 static struct resource axp152_pek_resources[] = { 125 DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"), 126 DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"), 127 }; 128 129 static struct resource axp20x_pek_resources[] = { 130 { 131 .name = "PEK_DBR", 132 .start = AXP20X_IRQ_PEK_RIS_EDGE, 133 .end = AXP20X_IRQ_PEK_RIS_EDGE, 134 .flags = IORESOURCE_IRQ, 135 }, { 136 .name = "PEK_DBF", 137 .start = AXP20X_IRQ_PEK_FAL_EDGE, 138 .end = AXP20X_IRQ_PEK_FAL_EDGE, 139 .flags = IORESOURCE_IRQ, 140 }, 141 }; 142 143 static struct resource axp20x_usb_power_supply_resources[] = { 144 DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), 145 DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), 146 DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_VALID, "VBUS_VALID"), 147 DEFINE_RES_IRQ_NAMED(AXP20X_IRQ_VBUS_NOT_VALID, "VBUS_NOT_VALID"), 148 }; 149 150 static struct resource axp22x_pek_resources[] = { 151 { 152 .name = "PEK_DBR", 153 .start = AXP22X_IRQ_PEK_RIS_EDGE, 154 .end = AXP22X_IRQ_PEK_RIS_EDGE, 155 .flags = IORESOURCE_IRQ, 156 }, { 157 .name = "PEK_DBF", 158 .start = AXP22X_IRQ_PEK_FAL_EDGE, 159 .end = AXP22X_IRQ_PEK_FAL_EDGE, 160 .flags = IORESOURCE_IRQ, 161 }, 162 }; 163 164 static struct resource axp288_fuel_gauge_resources[] = { 165 { 166 .start = AXP288_IRQ_QWBTU, 167 .end = AXP288_IRQ_QWBTU, 168 .flags = IORESOURCE_IRQ, 169 }, 170 { 171 .start = AXP288_IRQ_WBTU, 172 .end = AXP288_IRQ_WBTU, 173 .flags = IORESOURCE_IRQ, 174 }, 175 { 176 .start = AXP288_IRQ_QWBTO, 177 .end = AXP288_IRQ_QWBTO, 178 .flags = IORESOURCE_IRQ, 179 }, 180 { 181 .start = AXP288_IRQ_WBTO, 182 .end = AXP288_IRQ_WBTO, 183 .flags = IORESOURCE_IRQ, 184 }, 185 { 186 .start = AXP288_IRQ_WL2, 187 .end = AXP288_IRQ_WL2, 188 .flags = IORESOURCE_IRQ, 189 }, 190 { 191 .start = AXP288_IRQ_WL1, 192 .end = AXP288_IRQ_WL1, 193 .flags = IORESOURCE_IRQ, 194 }, 195 }; 196 197 static const struct regmap_config axp152_regmap_config = { 198 .reg_bits = 8, 199 .val_bits = 8, 200 .wr_table = &axp152_writeable_table, 201 .volatile_table = &axp152_volatile_table, 202 .max_register = AXP152_PWM1_DUTY_CYCLE, 203 .cache_type = REGCACHE_RBTREE, 204 }; 205 206 static const struct regmap_config axp20x_regmap_config = { 207 .reg_bits = 8, 208 .val_bits = 8, 209 .wr_table = &axp20x_writeable_table, 210 .volatile_table = &axp20x_volatile_table, 211 .max_register = AXP20X_OCV(AXP20X_OCV_MAX), 212 .cache_type = REGCACHE_RBTREE, 213 }; 214 215 static const struct regmap_config axp22x_regmap_config = { 216 .reg_bits = 8, 217 .val_bits = 8, 218 .wr_table = &axp22x_writeable_table, 219 .volatile_table = &axp22x_volatile_table, 220 .max_register = AXP22X_BATLOW_THRES1, 221 .cache_type = REGCACHE_RBTREE, 222 }; 223 224 static const struct regmap_config axp288_regmap_config = { 225 .reg_bits = 8, 226 .val_bits = 8, 227 .wr_table = &axp288_writeable_table, 228 .volatile_table = &axp288_volatile_table, 229 .max_register = AXP288_FG_TUNE5, 230 .cache_type = REGCACHE_RBTREE, 231 }; 232 233 #define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \ 234 [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } 235 236 static const struct regmap_irq axp152_regmap_irqs[] = { 237 INIT_REGMAP_IRQ(AXP152, LDO0IN_CONNECT, 0, 6), 238 INIT_REGMAP_IRQ(AXP152, LDO0IN_REMOVAL, 0, 5), 239 INIT_REGMAP_IRQ(AXP152, ALDO0IN_CONNECT, 0, 3), 240 INIT_REGMAP_IRQ(AXP152, ALDO0IN_REMOVAL, 0, 2), 241 INIT_REGMAP_IRQ(AXP152, DCDC1_V_LOW, 1, 5), 242 INIT_REGMAP_IRQ(AXP152, DCDC2_V_LOW, 1, 4), 243 INIT_REGMAP_IRQ(AXP152, DCDC3_V_LOW, 1, 3), 244 INIT_REGMAP_IRQ(AXP152, DCDC4_V_LOW, 1, 2), 245 INIT_REGMAP_IRQ(AXP152, PEK_SHORT, 1, 1), 246 INIT_REGMAP_IRQ(AXP152, PEK_LONG, 1, 0), 247 INIT_REGMAP_IRQ(AXP152, TIMER, 2, 7), 248 INIT_REGMAP_IRQ(AXP152, PEK_RIS_EDGE, 2, 6), 249 INIT_REGMAP_IRQ(AXP152, PEK_FAL_EDGE, 2, 5), 250 INIT_REGMAP_IRQ(AXP152, GPIO3_INPUT, 2, 3), 251 INIT_REGMAP_IRQ(AXP152, GPIO2_INPUT, 2, 2), 252 INIT_REGMAP_IRQ(AXP152, GPIO1_INPUT, 2, 1), 253 INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0), 254 }; 255 256 static const struct regmap_irq axp20x_regmap_irqs[] = { 257 INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7), 258 INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6), 259 INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5), 260 INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4), 261 INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3), 262 INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2), 263 INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1), 264 INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7), 265 INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6), 266 INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5), 267 INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4), 268 INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3), 269 INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2), 270 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1), 271 INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0), 272 INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7), 273 INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6), 274 INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5), 275 INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4), 276 INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3), 277 INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1), 278 INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0), 279 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7), 280 INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6), 281 INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5), 282 INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4), 283 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3), 284 INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2), 285 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1), 286 INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0), 287 INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7), 288 INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6), 289 INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5), 290 INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3), 291 INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2), 292 INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1), 293 INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0), 294 }; 295 296 static const struct regmap_irq axp22x_regmap_irqs[] = { 297 INIT_REGMAP_IRQ(AXP22X, ACIN_OVER_V, 0, 7), 298 INIT_REGMAP_IRQ(AXP22X, ACIN_PLUGIN, 0, 6), 299 INIT_REGMAP_IRQ(AXP22X, ACIN_REMOVAL, 0, 5), 300 INIT_REGMAP_IRQ(AXP22X, VBUS_OVER_V, 0, 4), 301 INIT_REGMAP_IRQ(AXP22X, VBUS_PLUGIN, 0, 3), 302 INIT_REGMAP_IRQ(AXP22X, VBUS_REMOVAL, 0, 2), 303 INIT_REGMAP_IRQ(AXP22X, VBUS_V_LOW, 0, 1), 304 INIT_REGMAP_IRQ(AXP22X, BATT_PLUGIN, 1, 7), 305 INIT_REGMAP_IRQ(AXP22X, BATT_REMOVAL, 1, 6), 306 INIT_REGMAP_IRQ(AXP22X, BATT_ENT_ACT_MODE, 1, 5), 307 INIT_REGMAP_IRQ(AXP22X, BATT_EXIT_ACT_MODE, 1, 4), 308 INIT_REGMAP_IRQ(AXP22X, CHARG, 1, 3), 309 INIT_REGMAP_IRQ(AXP22X, CHARG_DONE, 1, 2), 310 INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_HIGH, 1, 1), 311 INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_LOW, 1, 0), 312 INIT_REGMAP_IRQ(AXP22X, DIE_TEMP_HIGH, 2, 7), 313 INIT_REGMAP_IRQ(AXP22X, PEK_SHORT, 2, 1), 314 INIT_REGMAP_IRQ(AXP22X, PEK_LONG, 2, 0), 315 INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL1, 3, 1), 316 INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL2, 3, 0), 317 INIT_REGMAP_IRQ(AXP22X, TIMER, 4, 7), 318 INIT_REGMAP_IRQ(AXP22X, PEK_RIS_EDGE, 4, 6), 319 INIT_REGMAP_IRQ(AXP22X, PEK_FAL_EDGE, 4, 5), 320 INIT_REGMAP_IRQ(AXP22X, GPIO1_INPUT, 4, 1), 321 INIT_REGMAP_IRQ(AXP22X, GPIO0_INPUT, 4, 0), 322 }; 323 324 /* some IRQs are compatible with axp20x models */ 325 static const struct regmap_irq axp288_regmap_irqs[] = { 326 INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2), 327 INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3), 328 INIT_REGMAP_IRQ(AXP288, OV, 0, 4), 329 330 INIT_REGMAP_IRQ(AXP288, DONE, 1, 2), 331 INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3), 332 INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4), 333 INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5), 334 INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6), 335 INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7), 336 337 INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0), 338 INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1), 339 INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2), 340 INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3), 341 INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4), 342 INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5), 343 INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6), 344 INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7), 345 346 INIT_REGMAP_IRQ(AXP288, WL2, 3, 0), 347 INIT_REGMAP_IRQ(AXP288, WL1, 3, 1), 348 INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2), 349 INIT_REGMAP_IRQ(AXP288, OT, 3, 7), 350 351 INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0), 352 INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1), 353 INIT_REGMAP_IRQ(AXP288, POKO, 4, 2), 354 INIT_REGMAP_IRQ(AXP288, POKL, 4, 3), 355 INIT_REGMAP_IRQ(AXP288, POKS, 4, 4), 356 INIT_REGMAP_IRQ(AXP288, POKN, 4, 5), 357 INIT_REGMAP_IRQ(AXP288, POKP, 4, 6), 358 INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7), 359 360 INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0), 361 INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1), 362 }; 363 364 static const struct of_device_id axp20x_of_match[] = { 365 { .compatible = "x-powers,axp152", .data = (void *) AXP152_ID }, 366 { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, 367 { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, 368 { .compatible = "x-powers,axp221", .data = (void *) AXP221_ID }, 369 { }, 370 }; 371 MODULE_DEVICE_TABLE(of, axp20x_of_match); 372 373 /* 374 * This is useless for OF-enabled devices, but it is needed by I2C subsystem 375 */ 376 static const struct i2c_device_id axp20x_i2c_id[] = { 377 { }, 378 }; 379 MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); 380 381 static const struct acpi_device_id axp20x_acpi_match[] = { 382 { 383 .id = "INT33F4", 384 .driver_data = AXP288_ID, 385 }, 386 { }, 387 }; 388 MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match); 389 390 static const struct regmap_irq_chip axp152_regmap_irq_chip = { 391 .name = "axp152_irq_chip", 392 .status_base = AXP152_IRQ1_STATE, 393 .ack_base = AXP152_IRQ1_STATE, 394 .mask_base = AXP152_IRQ1_EN, 395 .mask_invert = true, 396 .init_ack_masked = true, 397 .irqs = axp152_regmap_irqs, 398 .num_irqs = ARRAY_SIZE(axp152_regmap_irqs), 399 .num_regs = 3, 400 }; 401 402 static const struct regmap_irq_chip axp20x_regmap_irq_chip = { 403 .name = "axp20x_irq_chip", 404 .status_base = AXP20X_IRQ1_STATE, 405 .ack_base = AXP20X_IRQ1_STATE, 406 .mask_base = AXP20X_IRQ1_EN, 407 .mask_invert = true, 408 .init_ack_masked = true, 409 .irqs = axp20x_regmap_irqs, 410 .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), 411 .num_regs = 5, 412 413 }; 414 415 static const struct regmap_irq_chip axp22x_regmap_irq_chip = { 416 .name = "axp22x_irq_chip", 417 .status_base = AXP20X_IRQ1_STATE, 418 .ack_base = AXP20X_IRQ1_STATE, 419 .mask_base = AXP20X_IRQ1_EN, 420 .mask_invert = true, 421 .init_ack_masked = true, 422 .irqs = axp22x_regmap_irqs, 423 .num_irqs = ARRAY_SIZE(axp22x_regmap_irqs), 424 .num_regs = 5, 425 }; 426 427 static const struct regmap_irq_chip axp288_regmap_irq_chip = { 428 .name = "axp288_irq_chip", 429 .status_base = AXP20X_IRQ1_STATE, 430 .ack_base = AXP20X_IRQ1_STATE, 431 .mask_base = AXP20X_IRQ1_EN, 432 .mask_invert = true, 433 .init_ack_masked = true, 434 .irqs = axp288_regmap_irqs, 435 .num_irqs = ARRAY_SIZE(axp288_regmap_irqs), 436 .num_regs = 6, 437 438 }; 439 440 static struct mfd_cell axp20x_cells[] = { 441 { 442 .name = "axp20x-pek", 443 .num_resources = ARRAY_SIZE(axp20x_pek_resources), 444 .resources = axp20x_pek_resources, 445 }, { 446 .name = "axp20x-regulator", 447 }, { 448 .name = "axp20x-usb-power-supply", 449 .of_compatible = "x-powers,axp202-usb-power-supply", 450 .num_resources = ARRAY_SIZE(axp20x_usb_power_supply_resources), 451 .resources = axp20x_usb_power_supply_resources, 452 }, 453 }; 454 455 static struct mfd_cell axp22x_cells[] = { 456 { 457 .name = "axp20x-pek", 458 .num_resources = ARRAY_SIZE(axp22x_pek_resources), 459 .resources = axp22x_pek_resources, 460 }, { 461 .name = "axp20x-regulator", 462 }, 463 }; 464 465 static struct mfd_cell axp152_cells[] = { 466 { 467 .name = "axp20x-pek", 468 .num_resources = ARRAY_SIZE(axp152_pek_resources), 469 .resources = axp152_pek_resources, 470 }, 471 }; 472 473 static struct resource axp288_adc_resources[] = { 474 { 475 .name = "GPADC", 476 .start = AXP288_IRQ_GPADC, 477 .end = AXP288_IRQ_GPADC, 478 .flags = IORESOURCE_IRQ, 479 }, 480 }; 481 482 static struct resource axp288_extcon_resources[] = { 483 { 484 .start = AXP288_IRQ_VBUS_FALL, 485 .end = AXP288_IRQ_VBUS_FALL, 486 .flags = IORESOURCE_IRQ, 487 }, 488 { 489 .start = AXP288_IRQ_VBUS_RISE, 490 .end = AXP288_IRQ_VBUS_RISE, 491 .flags = IORESOURCE_IRQ, 492 }, 493 { 494 .start = AXP288_IRQ_MV_CHNG, 495 .end = AXP288_IRQ_MV_CHNG, 496 .flags = IORESOURCE_IRQ, 497 }, 498 { 499 .start = AXP288_IRQ_BC_USB_CHNG, 500 .end = AXP288_IRQ_BC_USB_CHNG, 501 .flags = IORESOURCE_IRQ, 502 }, 503 }; 504 505 static struct resource axp288_charger_resources[] = { 506 { 507 .start = AXP288_IRQ_OV, 508 .end = AXP288_IRQ_OV, 509 .flags = IORESOURCE_IRQ, 510 }, 511 { 512 .start = AXP288_IRQ_DONE, 513 .end = AXP288_IRQ_DONE, 514 .flags = IORESOURCE_IRQ, 515 }, 516 { 517 .start = AXP288_IRQ_CHARGING, 518 .end = AXP288_IRQ_CHARGING, 519 .flags = IORESOURCE_IRQ, 520 }, 521 { 522 .start = AXP288_IRQ_SAFE_QUIT, 523 .end = AXP288_IRQ_SAFE_QUIT, 524 .flags = IORESOURCE_IRQ, 525 }, 526 { 527 .start = AXP288_IRQ_SAFE_ENTER, 528 .end = AXP288_IRQ_SAFE_ENTER, 529 .flags = IORESOURCE_IRQ, 530 }, 531 { 532 .start = AXP288_IRQ_QCBTU, 533 .end = AXP288_IRQ_QCBTU, 534 .flags = IORESOURCE_IRQ, 535 }, 536 { 537 .start = AXP288_IRQ_CBTU, 538 .end = AXP288_IRQ_CBTU, 539 .flags = IORESOURCE_IRQ, 540 }, 541 { 542 .start = AXP288_IRQ_QCBTO, 543 .end = AXP288_IRQ_QCBTO, 544 .flags = IORESOURCE_IRQ, 545 }, 546 { 547 .start = AXP288_IRQ_CBTO, 548 .end = AXP288_IRQ_CBTO, 549 .flags = IORESOURCE_IRQ, 550 }, 551 }; 552 553 static struct mfd_cell axp288_cells[] = { 554 { 555 .name = "axp288_adc", 556 .num_resources = ARRAY_SIZE(axp288_adc_resources), 557 .resources = axp288_adc_resources, 558 }, 559 { 560 .name = "axp288_extcon", 561 .num_resources = ARRAY_SIZE(axp288_extcon_resources), 562 .resources = axp288_extcon_resources, 563 }, 564 { 565 .name = "axp288_charger", 566 .num_resources = ARRAY_SIZE(axp288_charger_resources), 567 .resources = axp288_charger_resources, 568 }, 569 { 570 .name = "axp288_fuel_gauge", 571 .num_resources = ARRAY_SIZE(axp288_fuel_gauge_resources), 572 .resources = axp288_fuel_gauge_resources, 573 }, 574 { 575 .name = "axp288_pmic_acpi", 576 }, 577 }; 578 579 static struct axp20x_dev *axp20x_pm_power_off; 580 static void axp20x_power_off(void) 581 { 582 if (axp20x_pm_power_off->variant == AXP288_ID) 583 return; 584 585 regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, 586 AXP20X_OFF); 587 } 588 589 static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev) 590 { 591 const struct acpi_device_id *acpi_id; 592 const struct of_device_id *of_id; 593 594 if (dev->of_node) { 595 of_id = of_match_device(axp20x_of_match, dev); 596 if (!of_id) { 597 dev_err(dev, "Unable to match OF ID\n"); 598 return -ENODEV; 599 } 600 axp20x->variant = (long) of_id->data; 601 } else { 602 acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); 603 if (!acpi_id || !acpi_id->driver_data) { 604 dev_err(dev, "Unable to match ACPI ID and data\n"); 605 return -ENODEV; 606 } 607 axp20x->variant = (long) acpi_id->driver_data; 608 } 609 610 switch (axp20x->variant) { 611 case AXP152_ID: 612 axp20x->nr_cells = ARRAY_SIZE(axp152_cells); 613 axp20x->cells = axp152_cells; 614 axp20x->regmap_cfg = &axp152_regmap_config; 615 axp20x->regmap_irq_chip = &axp152_regmap_irq_chip; 616 break; 617 case AXP202_ID: 618 case AXP209_ID: 619 axp20x->nr_cells = ARRAY_SIZE(axp20x_cells); 620 axp20x->cells = axp20x_cells; 621 axp20x->regmap_cfg = &axp20x_regmap_config; 622 axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip; 623 break; 624 case AXP221_ID: 625 axp20x->nr_cells = ARRAY_SIZE(axp22x_cells); 626 axp20x->cells = axp22x_cells; 627 axp20x->regmap_cfg = &axp22x_regmap_config; 628 axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip; 629 break; 630 case AXP288_ID: 631 axp20x->cells = axp288_cells; 632 axp20x->nr_cells = ARRAY_SIZE(axp288_cells); 633 axp20x->regmap_cfg = &axp288_regmap_config; 634 axp20x->regmap_irq_chip = &axp288_regmap_irq_chip; 635 break; 636 default: 637 dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); 638 return -EINVAL; 639 } 640 dev_info(dev, "AXP20x variant %s found\n", 641 axp20x_model_names[axp20x->variant]); 642 643 return 0; 644 } 645 646 static int axp20x_i2c_probe(struct i2c_client *i2c, 647 const struct i2c_device_id *id) 648 { 649 struct axp20x_dev *axp20x; 650 int ret; 651 652 axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); 653 if (!axp20x) 654 return -ENOMEM; 655 656 ret = axp20x_match_device(axp20x, &i2c->dev); 657 if (ret) 658 return ret; 659 660 axp20x->i2c_client = i2c; 661 axp20x->dev = &i2c->dev; 662 dev_set_drvdata(axp20x->dev, axp20x); 663 664 axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg); 665 if (IS_ERR(axp20x->regmap)) { 666 ret = PTR_ERR(axp20x->regmap); 667 dev_err(&i2c->dev, "regmap init failed: %d\n", ret); 668 return ret; 669 } 670 671 ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, 672 IRQF_ONESHOT | IRQF_SHARED, -1, 673 axp20x->regmap_irq_chip, 674 &axp20x->regmap_irqc); 675 if (ret) { 676 dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); 677 return ret; 678 } 679 680 ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells, 681 axp20x->nr_cells, NULL, 0, NULL); 682 683 if (ret) { 684 dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); 685 regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc); 686 return ret; 687 } 688 689 if (!pm_power_off) { 690 axp20x_pm_power_off = axp20x; 691 pm_power_off = axp20x_power_off; 692 } 693 694 dev_info(&i2c->dev, "AXP20X driver loaded\n"); 695 696 return 0; 697 } 698 699 static int axp20x_i2c_remove(struct i2c_client *i2c) 700 { 701 struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); 702 703 if (axp20x == axp20x_pm_power_off) { 704 axp20x_pm_power_off = NULL; 705 pm_power_off = NULL; 706 } 707 708 mfd_remove_devices(axp20x->dev); 709 regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc); 710 711 return 0; 712 } 713 714 static struct i2c_driver axp20x_i2c_driver = { 715 .driver = { 716 .name = "axp20x", 717 .of_match_table = of_match_ptr(axp20x_of_match), 718 .acpi_match_table = ACPI_PTR(axp20x_acpi_match), 719 }, 720 .probe = axp20x_i2c_probe, 721 .remove = axp20x_i2c_remove, 722 .id_table = axp20x_i2c_id, 723 }; 724 725 module_i2c_driver(axp20x_i2c_driver); 726 727 MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X"); 728 MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); 729 MODULE_LICENSE("GPL"); 730