1277 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Base driver for Marvell 88PM86074 *5 * Copyright (C) 2009 Marvell International Ltd.6 *7 * Author: Haojian Zhuang <haojian.zhuang@marvell.com>8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/err.h>13#include <linux/i2c.h>14#include <linux/irq.h>15#include <linux/interrupt.h>16#include <linux/irqdomain.h>17#include <linux/of.h>18#include <linux/of_platform.h>19#include <linux/platform_device.h>20#include <linux/regmap.h>21#include <linux/slab.h>22#include <linux/mfd/core.h>23#include <linux/mfd/88pm860x.h>24#include <linux/regulator/machine.h>25#include <linux/power/charger-manager.h>26 27#define INT_STATUS_NUM 328 29static const struct resource bk0_resources[] = {30 {2, 2, "duty cycle", IORESOURCE_REG, },31 {3, 3, "always on", IORESOURCE_REG, },32 {3, 3, "current", IORESOURCE_REG, },33};34static const struct resource bk1_resources[] = {35 {4, 4, "duty cycle", IORESOURCE_REG, },36 {5, 5, "always on", IORESOURCE_REG, },37 {5, 5, "current", IORESOURCE_REG, },38};39static const struct resource bk2_resources[] = {40 {6, 6, "duty cycle", IORESOURCE_REG, },41 {7, 7, "always on", IORESOURCE_REG, },42 {5, 5, "current", IORESOURCE_REG, },43};44 45static const struct resource led0_resources[] = {46 /* RGB1 Red LED */47 {0xd, 0xd, "control", IORESOURCE_REG, },48 {0xc, 0xc, "blink", IORESOURCE_REG, },49};50static const struct resource led1_resources[] = {51 /* RGB1 Green LED */52 {0xe, 0xe, "control", IORESOURCE_REG, },53 {0xc, 0xc, "blink", IORESOURCE_REG, },54};55static const struct resource led2_resources[] = {56 /* RGB1 Blue LED */57 {0xf, 0xf, "control", IORESOURCE_REG, },58 {0xc, 0xc, "blink", IORESOURCE_REG, },59};60static const struct resource led3_resources[] = {61 /* RGB2 Red LED */62 {0x9, 0x9, "control", IORESOURCE_REG, },63 {0x8, 0x8, "blink", IORESOURCE_REG, },64};65static const struct resource led4_resources[] = {66 /* RGB2 Green LED */67 {0xa, 0xa, "control", IORESOURCE_REG, },68 {0x8, 0x8, "blink", IORESOURCE_REG, },69};70static const struct resource led5_resources[] = {71 /* RGB2 Blue LED */72 {0xb, 0xb, "control", IORESOURCE_REG, },73 {0x8, 0x8, "blink", IORESOURCE_REG, },74};75 76static const struct resource buck1_resources[] = {77 {0x24, 0x24, "buck set", IORESOURCE_REG, },78};79static const struct resource buck2_resources[] = {80 {0x25, 0x25, "buck set", IORESOURCE_REG, },81};82static const struct resource buck3_resources[] = {83 {0x26, 0x26, "buck set", IORESOURCE_REG, },84};85static const struct resource ldo1_resources[] = {86 {0x10, 0x10, "ldo set", IORESOURCE_REG, },87};88static const struct resource ldo2_resources[] = {89 {0x11, 0x11, "ldo set", IORESOURCE_REG, },90};91static const struct resource ldo3_resources[] = {92 {0x12, 0x12, "ldo set", IORESOURCE_REG, },93};94static const struct resource ldo4_resources[] = {95 {0x13, 0x13, "ldo set", IORESOURCE_REG, },96};97static const struct resource ldo5_resources[] = {98 {0x14, 0x14, "ldo set", IORESOURCE_REG, },99};100static const struct resource ldo6_resources[] = {101 {0x15, 0x15, "ldo set", IORESOURCE_REG, },102};103static const struct resource ldo7_resources[] = {104 {0x16, 0x16, "ldo set", IORESOURCE_REG, },105};106static const struct resource ldo8_resources[] = {107 {0x17, 0x17, "ldo set", IORESOURCE_REG, },108};109static const struct resource ldo9_resources[] = {110 {0x18, 0x18, "ldo set", IORESOURCE_REG, },111};112static const struct resource ldo10_resources[] = {113 {0x19, 0x19, "ldo set", IORESOURCE_REG, },114};115static const struct resource ldo12_resources[] = {116 {0x1a, 0x1a, "ldo set", IORESOURCE_REG, },117};118static const struct resource ldo_vibrator_resources[] = {119 {0x28, 0x28, "ldo set", IORESOURCE_REG, },120};121static const struct resource ldo14_resources[] = {122 {0x1b, 0x1b, "ldo set", IORESOURCE_REG, },123};124 125static struct resource touch_resources[] = {126 {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},127};128 129static struct resource onkey_resources[] = {130 {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},131};132 133static struct resource codec_resources[] = {134 /* Headset microphone insertion or removal */135 {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},136 /* Hook-switch press or release */137 {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,},138 /* Headset insertion or removal */139 {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},140 /* Audio short */141 {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short",142 IORESOURCE_IRQ,},143};144 145static struct resource battery_resources[] = {146 {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},147 {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},148};149 150static struct resource charger_resources[] = {151 {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},152 {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done",153 IORESOURCE_IRQ,},154 {PM8607_IRQ_CHG_FAIL, PM8607_IRQ_CHG_FAIL, "charging timeout",155 IORESOURCE_IRQ,},156 {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging fault",157 IORESOURCE_IRQ,},158 {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature",159 IORESOURCE_IRQ,},160 {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},161 {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},162};163 164static struct resource rtc_resources[] = {165 {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},166};167 168static struct mfd_cell bk_devs[] = {169 {170 .name = "88pm860x-backlight",171 .id = 0,172 .num_resources = ARRAY_SIZE(bk0_resources),173 .resources = bk0_resources,174 }, {175 .name = "88pm860x-backlight",176 .id = 1,177 .num_resources = ARRAY_SIZE(bk1_resources),178 .resources = bk1_resources,179 }, {180 .name = "88pm860x-backlight",181 .id = 2,182 .num_resources = ARRAY_SIZE(bk2_resources),183 .resources = bk2_resources,184 },185};186 187static struct mfd_cell led_devs[] = {188 {189 .name = "88pm860x-led",190 .id = 0,191 .num_resources = ARRAY_SIZE(led0_resources),192 .resources = led0_resources,193 }, {194 .name = "88pm860x-led",195 .id = 1,196 .num_resources = ARRAY_SIZE(led1_resources),197 .resources = led1_resources,198 }, {199 .name = "88pm860x-led",200 .id = 2,201 .num_resources = ARRAY_SIZE(led2_resources),202 .resources = led2_resources,203 }, {204 .name = "88pm860x-led",205 .id = 3,206 .num_resources = ARRAY_SIZE(led3_resources),207 .resources = led3_resources,208 }, {209 .name = "88pm860x-led",210 .id = 4,211 .num_resources = ARRAY_SIZE(led4_resources),212 .resources = led4_resources,213 }, {214 .name = "88pm860x-led",215 .id = 5,216 .num_resources = ARRAY_SIZE(led5_resources),217 .resources = led5_resources,218 },219};220 221static struct mfd_cell reg_devs[] = {222 {223 .name = "88pm860x-regulator",224 .id = 0,225 .num_resources = ARRAY_SIZE(buck1_resources),226 .resources = buck1_resources,227 }, {228 .name = "88pm860x-regulator",229 .id = 1,230 .num_resources = ARRAY_SIZE(buck2_resources),231 .resources = buck2_resources,232 }, {233 .name = "88pm860x-regulator",234 .id = 2,235 .num_resources = ARRAY_SIZE(buck3_resources),236 .resources = buck3_resources,237 }, {238 .name = "88pm860x-regulator",239 .id = 3,240 .num_resources = ARRAY_SIZE(ldo1_resources),241 .resources = ldo1_resources,242 }, {243 .name = "88pm860x-regulator",244 .id = 4,245 .num_resources = ARRAY_SIZE(ldo2_resources),246 .resources = ldo2_resources,247 }, {248 .name = "88pm860x-regulator",249 .id = 5,250 .num_resources = ARRAY_SIZE(ldo3_resources),251 .resources = ldo3_resources,252 }, {253 .name = "88pm860x-regulator",254 .id = 6,255 .num_resources = ARRAY_SIZE(ldo4_resources),256 .resources = ldo4_resources,257 }, {258 .name = "88pm860x-regulator",259 .id = 7,260 .num_resources = ARRAY_SIZE(ldo5_resources),261 .resources = ldo5_resources,262 }, {263 .name = "88pm860x-regulator",264 .id = 8,265 .num_resources = ARRAY_SIZE(ldo6_resources),266 .resources = ldo6_resources,267 }, {268 .name = "88pm860x-regulator",269 .id = 9,270 .num_resources = ARRAY_SIZE(ldo7_resources),271 .resources = ldo7_resources,272 }, {273 .name = "88pm860x-regulator",274 .id = 10,275 .num_resources = ARRAY_SIZE(ldo8_resources),276 .resources = ldo8_resources,277 }, {278 .name = "88pm860x-regulator",279 .id = 11,280 .num_resources = ARRAY_SIZE(ldo9_resources),281 .resources = ldo9_resources,282 }, {283 .name = "88pm860x-regulator",284 .id = 12,285 .num_resources = ARRAY_SIZE(ldo10_resources),286 .resources = ldo10_resources,287 }, {288 .name = "88pm860x-regulator",289 .id = 13,290 .num_resources = ARRAY_SIZE(ldo12_resources),291 .resources = ldo12_resources,292 }, {293 .name = "88pm860x-regulator",294 .id = 14,295 .num_resources = ARRAY_SIZE(ldo_vibrator_resources),296 .resources = ldo_vibrator_resources,297 }, {298 .name = "88pm860x-regulator",299 .id = 15,300 .num_resources = ARRAY_SIZE(ldo14_resources),301 .resources = ldo14_resources,302 },303};304 305static struct mfd_cell touch_devs[] = {306 {"88pm860x-touch", -1,},307};308 309static struct mfd_cell onkey_devs[] = {310 {"88pm860x-onkey", -1,},311};312 313static struct mfd_cell codec_devs[] = {314 {"88pm860x-codec", -1,},315};316 317static struct regulator_consumer_supply preg_supply[] = {318 REGULATOR_SUPPLY("preg", "charger-manager"),319};320 321static struct regulator_init_data preg_init_data = {322 .num_consumer_supplies = ARRAY_SIZE(preg_supply),323 .consumer_supplies = &preg_supply[0],324};325 326static struct charger_regulator chg_desc_regulator_data[] = {327 { .regulator_name = "preg", },328};329 330static struct mfd_cell power_devs[] = {331 {"88pm860x-battery", -1,},332 {"88pm860x-charger", -1,},333 {"88pm860x-preg", -1,},334 {"charger-manager", -1,},335};336 337static struct mfd_cell rtc_devs[] = {338 {"88pm860x-rtc", -1,},339};340 341 342struct pm860x_irq_data {343 int reg;344 int mask_reg;345 int enable; /* enable or not */346 int offs; /* bit offset in mask register */347};348 349static struct pm860x_irq_data pm860x_irqs[] = {350 [PM8607_IRQ_ONKEY] = {351 .reg = PM8607_INT_STATUS1,352 .mask_reg = PM8607_INT_MASK_1,353 .offs = 1 << 0,354 },355 [PM8607_IRQ_EXTON] = {356 .reg = PM8607_INT_STATUS1,357 .mask_reg = PM8607_INT_MASK_1,358 .offs = 1 << 1,359 },360 [PM8607_IRQ_CHG] = {361 .reg = PM8607_INT_STATUS1,362 .mask_reg = PM8607_INT_MASK_1,363 .offs = 1 << 2,364 },365 [PM8607_IRQ_BAT] = {366 .reg = PM8607_INT_STATUS1,367 .mask_reg = PM8607_INT_MASK_1,368 .offs = 1 << 3,369 },370 [PM8607_IRQ_RTC] = {371 .reg = PM8607_INT_STATUS1,372 .mask_reg = PM8607_INT_MASK_1,373 .offs = 1 << 4,374 },375 [PM8607_IRQ_CC] = {376 .reg = PM8607_INT_STATUS1,377 .mask_reg = PM8607_INT_MASK_1,378 .offs = 1 << 5,379 },380 [PM8607_IRQ_VBAT] = {381 .reg = PM8607_INT_STATUS2,382 .mask_reg = PM8607_INT_MASK_2,383 .offs = 1 << 0,384 },385 [PM8607_IRQ_VCHG] = {386 .reg = PM8607_INT_STATUS2,387 .mask_reg = PM8607_INT_MASK_2,388 .offs = 1 << 1,389 },390 [PM8607_IRQ_VSYS] = {391 .reg = PM8607_INT_STATUS2,392 .mask_reg = PM8607_INT_MASK_2,393 .offs = 1 << 2,394 },395 [PM8607_IRQ_TINT] = {396 .reg = PM8607_INT_STATUS2,397 .mask_reg = PM8607_INT_MASK_2,398 .offs = 1 << 3,399 },400 [PM8607_IRQ_GPADC0] = {401 .reg = PM8607_INT_STATUS2,402 .mask_reg = PM8607_INT_MASK_2,403 .offs = 1 << 4,404 },405 [PM8607_IRQ_GPADC1] = {406 .reg = PM8607_INT_STATUS2,407 .mask_reg = PM8607_INT_MASK_2,408 .offs = 1 << 5,409 },410 [PM8607_IRQ_GPADC2] = {411 .reg = PM8607_INT_STATUS2,412 .mask_reg = PM8607_INT_MASK_2,413 .offs = 1 << 6,414 },415 [PM8607_IRQ_GPADC3] = {416 .reg = PM8607_INT_STATUS2,417 .mask_reg = PM8607_INT_MASK_2,418 .offs = 1 << 7,419 },420 [PM8607_IRQ_AUDIO_SHORT] = {421 .reg = PM8607_INT_STATUS3,422 .mask_reg = PM8607_INT_MASK_3,423 .offs = 1 << 0,424 },425 [PM8607_IRQ_PEN] = {426 .reg = PM8607_INT_STATUS3,427 .mask_reg = PM8607_INT_MASK_3,428 .offs = 1 << 1,429 },430 [PM8607_IRQ_HEADSET] = {431 .reg = PM8607_INT_STATUS3,432 .mask_reg = PM8607_INT_MASK_3,433 .offs = 1 << 2,434 },435 [PM8607_IRQ_HOOK] = {436 .reg = PM8607_INT_STATUS3,437 .mask_reg = PM8607_INT_MASK_3,438 .offs = 1 << 3,439 },440 [PM8607_IRQ_MICIN] = {441 .reg = PM8607_INT_STATUS3,442 .mask_reg = PM8607_INT_MASK_3,443 .offs = 1 << 4,444 },445 [PM8607_IRQ_CHG_FAIL] = {446 .reg = PM8607_INT_STATUS3,447 .mask_reg = PM8607_INT_MASK_3,448 .offs = 1 << 5,449 },450 [PM8607_IRQ_CHG_DONE] = {451 .reg = PM8607_INT_STATUS3,452 .mask_reg = PM8607_INT_MASK_3,453 .offs = 1 << 6,454 },455 [PM8607_IRQ_CHG_FAULT] = {456 .reg = PM8607_INT_STATUS3,457 .mask_reg = PM8607_INT_MASK_3,458 .offs = 1 << 7,459 },460};461 462static irqreturn_t pm860x_irq(int irq, void *data)463{464 struct pm860x_chip *chip = data;465 struct pm860x_irq_data *irq_data;466 struct i2c_client *i2c;467 int read_reg = -1, value = 0;468 int i;469 470 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;471 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {472 irq_data = &pm860x_irqs[i];473 if (read_reg != irq_data->reg) {474 read_reg = irq_data->reg;475 value = pm860x_reg_read(i2c, irq_data->reg);476 }477 if (value & irq_data->enable)478 handle_nested_irq(chip->irq_base + i);479 }480 return IRQ_HANDLED;481}482 483static void pm860x_irq_lock(struct irq_data *data)484{485 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);486 487 mutex_lock(&chip->irq_lock);488}489 490static void pm860x_irq_sync_unlock(struct irq_data *data)491{492 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);493 struct pm860x_irq_data *irq_data;494 struct i2c_client *i2c;495 static unsigned char cached[3] = {0x0, 0x0, 0x0};496 unsigned char mask[3];497 int i;498 499 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;500 /* Load cached value. In initial, all IRQs are masked */501 for (i = 0; i < 3; i++)502 mask[i] = cached[i];503 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {504 irq_data = &pm860x_irqs[i];505 switch (irq_data->mask_reg) {506 case PM8607_INT_MASK_1:507 mask[0] &= ~irq_data->offs;508 mask[0] |= irq_data->enable;509 break;510 case PM8607_INT_MASK_2:511 mask[1] &= ~irq_data->offs;512 mask[1] |= irq_data->enable;513 break;514 case PM8607_INT_MASK_3:515 mask[2] &= ~irq_data->offs;516 mask[2] |= irq_data->enable;517 break;518 default:519 dev_err(chip->dev, "wrong IRQ\n");520 break;521 }522 }523 /* update mask into registers */524 for (i = 0; i < 3; i++) {525 if (mask[i] != cached[i]) {526 cached[i] = mask[i];527 pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);528 }529 }530 531 mutex_unlock(&chip->irq_lock);532}533 534static void pm860x_irq_enable(struct irq_data *data)535{536 pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs;537}538 539static void pm860x_irq_disable(struct irq_data *data)540{541 pm860x_irqs[data->hwirq].enable = 0;542}543 544static struct irq_chip pm860x_irq_chip = {545 .name = "88pm860x",546 .irq_bus_lock = pm860x_irq_lock,547 .irq_bus_sync_unlock = pm860x_irq_sync_unlock,548 .irq_enable = pm860x_irq_enable,549 .irq_disable = pm860x_irq_disable,550};551 552static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq,553 irq_hw_number_t hw)554{555 irq_set_chip_data(virq, d->host_data);556 irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq);557 irq_set_nested_thread(virq, 1);558 irq_set_noprobe(virq);559 return 0;560}561 562static const struct irq_domain_ops pm860x_irq_domain_ops = {563 .map = pm860x_irq_domain_map,564 .xlate = irq_domain_xlate_onetwocell,565};566 567static int device_irq_init(struct pm860x_chip *chip,568 struct pm860x_platform_data *pdata)569{570 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ?571 chip->client : chip->companion;572 unsigned char status_buf[INT_STATUS_NUM];573 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;574 int data, mask, ret = -EINVAL;575 int nr_irqs, irq_base = -1;576 struct device_node *node = i2c->dev.of_node;577 578 mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR579 | PM8607_B0_MISC1_INT_MASK;580 data = 0;581 chip->irq_mode = 0;582 if (pdata && pdata->irq_mode) {583 /*584 * irq_mode defines the way of clearing interrupt. If it's 1,585 * clear IRQ by write. Otherwise, clear it by read.586 * This control bit is valid from 88PM8607 B0 steping.587 */588 data |= PM8607_B0_MISC1_INT_CLEAR;589 chip->irq_mode = 1;590 }591 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);592 if (ret < 0)593 goto out;594 595 /* mask all IRQs */596 memset(status_buf, 0, INT_STATUS_NUM);597 ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,598 INT_STATUS_NUM, status_buf);599 if (ret < 0)600 goto out;601 602 if (chip->irq_mode) {603 /* clear interrupt status by write */604 memset(status_buf, 0xFF, INT_STATUS_NUM);605 ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,606 INT_STATUS_NUM, status_buf);607 } else {608 /* clear interrupt status by read */609 ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,610 INT_STATUS_NUM, status_buf);611 }612 if (ret < 0)613 goto out;614 615 mutex_init(&chip->irq_lock);616 617 if (pdata && pdata->irq_base)618 irq_base = pdata->irq_base;619 nr_irqs = ARRAY_SIZE(pm860x_irqs);620 chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0);621 if (chip->irq_base < 0) {622 dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d\n",623 chip->irq_base);624 ret = -EBUSY;625 goto out;626 }627 irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0,628 &pm860x_irq_domain_ops, chip);629 chip->core_irq = i2c->irq;630 if (!chip->core_irq)631 goto out;632 633 ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq,634 flags | IRQF_ONESHOT, "88pm860x", chip);635 if (ret) {636 dev_err(chip->dev, "Failed to request IRQ: %d\n", ret);637 chip->core_irq = 0;638 }639 640 return 0;641out:642 chip->core_irq = 0;643 return ret;644}645 646static void device_irq_exit(struct pm860x_chip *chip)647{648 if (chip->core_irq)649 free_irq(chip->core_irq, chip);650}651 652int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)653{654 int ret = -EIO;655 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?656 chip->client : chip->companion;657 658 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);659 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",660 __func__, chip->osc_vote,661 chip->osc_status);662 663 mutex_lock(&chip->osc_lock);664 /* Update voting status */665 chip->osc_vote |= client;666 /* If reference group is off - turn on*/667 if (chip->osc_status != PM8606_REF_GP_OSC_ON) {668 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;669 /* Enable Reference group Vsys */670 if (pm860x_set_bits(i2c, PM8606_VSYS,671 PM8606_VSYS_EN, PM8606_VSYS_EN))672 goto out;673 674 /*Enable Internal Oscillator */675 if (pm860x_set_bits(i2c, PM8606_MISC,676 PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))677 goto out;678 /* Update status (only if writes succeed) */679 chip->osc_status = PM8606_REF_GP_OSC_ON;680 }681 mutex_unlock(&chip->osc_lock);682 683 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",684 __func__, chip->osc_vote,685 chip->osc_status, ret);686 return 0;687out:688 mutex_unlock(&chip->osc_lock);689 return ret;690}691EXPORT_SYMBOL(pm8606_osc_enable);692 693int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)694{695 int ret = -EIO;696 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?697 chip->client : chip->companion;698 699 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client);700 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n",701 __func__, chip->osc_vote,702 chip->osc_status);703 704 mutex_lock(&chip->osc_lock);705 /* Update voting status */706 chip->osc_vote &= ~(client);707 /*708 * If reference group is off and this is the last client to release709 * - turn off710 */711 if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&712 (chip->osc_vote == REF_GP_NO_CLIENTS)) {713 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;714 /* Disable Reference group Vsys */715 if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))716 goto out;717 /* Disable Internal Oscillator */718 if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))719 goto out;720 chip->osc_status = PM8606_REF_GP_OSC_OFF;721 }722 mutex_unlock(&chip->osc_lock);723 724 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n",725 __func__, chip->osc_vote,726 chip->osc_status, ret);727 return 0;728out:729 mutex_unlock(&chip->osc_lock);730 return ret;731}732EXPORT_SYMBOL(pm8606_osc_disable);733 734static void device_osc_init(struct i2c_client *i2c)735{736 struct pm860x_chip *chip = i2c_get_clientdata(i2c);737 738 mutex_init(&chip->osc_lock);739 /* init portofino reference group voting and status */740 /* Disable Reference group Vsys */741 pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);742 /* Disable Internal Oscillator */743 pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);744 745 chip->osc_vote = REF_GP_NO_CLIENTS;746 chip->osc_status = PM8606_REF_GP_OSC_OFF;747}748 749static void device_bk_init(struct pm860x_chip *chip,750 struct pm860x_platform_data *pdata)751{752 int ret, i;753 754 if (pdata && pdata->backlight) {755 if (pdata->num_backlights > ARRAY_SIZE(bk_devs))756 pdata->num_backlights = ARRAY_SIZE(bk_devs);757 for (i = 0; i < pdata->num_backlights; i++) {758 bk_devs[i].platform_data = &pdata->backlight[i];759 bk_devs[i].pdata_size =760 sizeof(struct pm860x_backlight_pdata);761 }762 }763 ret = mfd_add_devices(chip->dev, 0, bk_devs,764 ARRAY_SIZE(bk_devs), NULL, 0, NULL);765 if (ret < 0)766 dev_err(chip->dev, "Failed to add backlight subdev\n");767}768 769static void device_led_init(struct pm860x_chip *chip,770 struct pm860x_platform_data *pdata)771{772 int ret, i;773 774 if (pdata && pdata->led) {775 if (pdata->num_leds > ARRAY_SIZE(led_devs))776 pdata->num_leds = ARRAY_SIZE(led_devs);777 for (i = 0; i < pdata->num_leds; i++) {778 led_devs[i].platform_data = &pdata->led[i];779 led_devs[i].pdata_size =780 sizeof(struct pm860x_led_pdata);781 }782 }783 ret = mfd_add_devices(chip->dev, 0, led_devs,784 ARRAY_SIZE(led_devs), NULL, 0, NULL);785 if (ret < 0) {786 dev_err(chip->dev, "Failed to add led subdev\n");787 return;788 }789}790 791static void device_regulator_init(struct pm860x_chip *chip,792 struct pm860x_platform_data *pdata)793{794 int ret;795 796 if (pdata == NULL)797 return;798 if (pdata->buck1) {799 reg_devs[0].platform_data = pdata->buck1;800 reg_devs[0].pdata_size = sizeof(struct regulator_init_data);801 }802 if (pdata->buck2) {803 reg_devs[1].platform_data = pdata->buck2;804 reg_devs[1].pdata_size = sizeof(struct regulator_init_data);805 }806 if (pdata->buck3) {807 reg_devs[2].platform_data = pdata->buck3;808 reg_devs[2].pdata_size = sizeof(struct regulator_init_data);809 }810 if (pdata->ldo1) {811 reg_devs[3].platform_data = pdata->ldo1;812 reg_devs[3].pdata_size = sizeof(struct regulator_init_data);813 }814 if (pdata->ldo2) {815 reg_devs[4].platform_data = pdata->ldo2;816 reg_devs[4].pdata_size = sizeof(struct regulator_init_data);817 }818 if (pdata->ldo3) {819 reg_devs[5].platform_data = pdata->ldo3;820 reg_devs[5].pdata_size = sizeof(struct regulator_init_data);821 }822 if (pdata->ldo4) {823 reg_devs[6].platform_data = pdata->ldo4;824 reg_devs[6].pdata_size = sizeof(struct regulator_init_data);825 }826 if (pdata->ldo5) {827 reg_devs[7].platform_data = pdata->ldo5;828 reg_devs[7].pdata_size = sizeof(struct regulator_init_data);829 }830 if (pdata->ldo6) {831 reg_devs[8].platform_data = pdata->ldo6;832 reg_devs[8].pdata_size = sizeof(struct regulator_init_data);833 }834 if (pdata->ldo7) {835 reg_devs[9].platform_data = pdata->ldo7;836 reg_devs[9].pdata_size = sizeof(struct regulator_init_data);837 }838 if (pdata->ldo8) {839 reg_devs[10].platform_data = pdata->ldo8;840 reg_devs[10].pdata_size = sizeof(struct regulator_init_data);841 }842 if (pdata->ldo9) {843 reg_devs[11].platform_data = pdata->ldo9;844 reg_devs[11].pdata_size = sizeof(struct regulator_init_data);845 }846 if (pdata->ldo10) {847 reg_devs[12].platform_data = pdata->ldo10;848 reg_devs[12].pdata_size = sizeof(struct regulator_init_data);849 }850 if (pdata->ldo12) {851 reg_devs[13].platform_data = pdata->ldo12;852 reg_devs[13].pdata_size = sizeof(struct regulator_init_data);853 }854 if (pdata->ldo_vibrator) {855 reg_devs[14].platform_data = pdata->ldo_vibrator;856 reg_devs[14].pdata_size = sizeof(struct regulator_init_data);857 }858 if (pdata->ldo14) {859 reg_devs[15].platform_data = pdata->ldo14;860 reg_devs[15].pdata_size = sizeof(struct regulator_init_data);861 }862 ret = mfd_add_devices(chip->dev, 0, reg_devs,863 ARRAY_SIZE(reg_devs), NULL, 0, NULL);864 if (ret < 0) {865 dev_err(chip->dev, "Failed to add regulator subdev\n");866 return;867 }868}869 870static void device_rtc_init(struct pm860x_chip *chip,871 struct pm860x_platform_data *pdata)872{873 int ret;874 875 if (!pdata)876 return;877 878 rtc_devs[0].platform_data = pdata->rtc;879 rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);880 rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);881 rtc_devs[0].resources = &rtc_resources[0];882 ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],883 ARRAY_SIZE(rtc_devs), &rtc_resources[0],884 chip->irq_base, NULL);885 if (ret < 0)886 dev_err(chip->dev, "Failed to add rtc subdev\n");887}888 889static void device_touch_init(struct pm860x_chip *chip,890 struct pm860x_platform_data *pdata)891{892 int ret;893 894 if (pdata == NULL)895 return;896 897 touch_devs[0].platform_data = pdata->touch;898 touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);899 touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);900 touch_devs[0].resources = &touch_resources[0];901 ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],902 ARRAY_SIZE(touch_devs), &touch_resources[0],903 chip->irq_base, NULL);904 if (ret < 0)905 dev_err(chip->dev, "Failed to add touch subdev\n");906}907 908static void device_power_init(struct pm860x_chip *chip,909 struct pm860x_platform_data *pdata)910{911 int ret;912 913 if (pdata == NULL)914 return;915 916 power_devs[0].platform_data = pdata->power;917 power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);918 power_devs[0].num_resources = ARRAY_SIZE(battery_resources);919 power_devs[0].resources = &battery_resources[0];920 ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,921 &battery_resources[0], chip->irq_base, NULL);922 if (ret < 0)923 dev_err(chip->dev, "Failed to add battery subdev\n");924 925 power_devs[1].platform_data = pdata->power;926 power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);927 power_devs[1].num_resources = ARRAY_SIZE(charger_resources);928 power_devs[1].resources = &charger_resources[0];929 ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,930 &charger_resources[0], chip->irq_base, NULL);931 if (ret < 0)932 dev_err(chip->dev, "Failed to add charger subdev\n");933 934 power_devs[2].platform_data = &preg_init_data;935 power_devs[2].pdata_size = sizeof(struct regulator_init_data);936 ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,937 NULL, chip->irq_base, NULL);938 if (ret < 0)939 dev_err(chip->dev, "Failed to add preg subdev\n");940 941 if (pdata->chg_desc) {942 pdata->chg_desc->charger_regulators =943 &chg_desc_regulator_data[0];944 pdata->chg_desc->num_charger_regulators =945 ARRAY_SIZE(chg_desc_regulator_data);946 power_devs[3].platform_data = pdata->chg_desc;947 power_devs[3].pdata_size = sizeof(*pdata->chg_desc);948 ret = mfd_add_devices(chip->dev, 0, &power_devs[3], 1,949 NULL, chip->irq_base, NULL);950 if (ret < 0)951 dev_err(chip->dev, "Failed to add chg-manager subdev\n");952 }953}954 955static void device_onkey_init(struct pm860x_chip *chip,956 struct pm860x_platform_data *pdata)957{958 int ret;959 960 onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);961 onkey_devs[0].resources = &onkey_resources[0];962 ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],963 ARRAY_SIZE(onkey_devs), &onkey_resources[0],964 chip->irq_base, NULL);965 if (ret < 0)966 dev_err(chip->dev, "Failed to add onkey subdev\n");967}968 969static void device_codec_init(struct pm860x_chip *chip,970 struct pm860x_platform_data *pdata)971{972 int ret;973 974 codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);975 codec_devs[0].resources = &codec_resources[0];976 ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],977 ARRAY_SIZE(codec_devs), &codec_resources[0], 0,978 NULL);979 if (ret < 0)980 dev_err(chip->dev, "Failed to add codec subdev\n");981}982 983static void device_8607_init(struct pm860x_chip *chip,984 struct i2c_client *i2c,985 struct pm860x_platform_data *pdata)986{987 int data, ret;988 989 ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);990 if (ret < 0) {991 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);992 goto out;993 }994 switch (ret & PM8607_VERSION_MASK) {995 case 0x40:996 case 0x50:997 dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n",998 ret);999 break;1000 default:1001 dev_err(chip->dev,1002 "Failed to detect Marvell 88PM8607. Chip ID: %02x\n",1003 ret);1004 goto out;1005 }1006 1007 ret = pm860x_reg_read(i2c, PM8607_BUCK3);1008 if (ret < 0) {1009 dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret);1010 goto out;1011 }1012 if (ret & PM8607_BUCK3_DOUBLE)1013 chip->buck3_double = 1;1014 1015 ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);1016 if (ret < 0) {1017 dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret);1018 goto out;1019 }1020 1021 if (pdata && (pdata->i2c_port == PI2C_PORT))1022 data = PM8607_B0_MISC1_PI2C;1023 else1024 data = 0;1025 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);1026 if (ret < 0) {1027 dev_err(chip->dev, "Failed to access MISC1:%d\n", ret);1028 goto out;1029 }1030 1031 ret = device_irq_init(chip, pdata);1032 if (ret < 0)1033 goto out;1034 1035 device_regulator_init(chip, pdata);1036 device_rtc_init(chip, pdata);1037 device_onkey_init(chip, pdata);1038 device_touch_init(chip, pdata);1039 device_power_init(chip, pdata);1040 device_codec_init(chip, pdata);1041out:1042 return;1043}1044 1045static void device_8606_init(struct pm860x_chip *chip,1046 struct i2c_client *i2c,1047 struct pm860x_platform_data *pdata)1048{1049 device_osc_init(i2c);1050 device_bk_init(chip, pdata);1051 device_led_init(chip, pdata);1052}1053 1054static int pm860x_device_init(struct pm860x_chip *chip,1055 struct pm860x_platform_data *pdata)1056{1057 chip->core_irq = 0;1058 1059 switch (chip->id) {1060 case CHIP_PM8606:1061 device_8606_init(chip, chip->client, pdata);1062 break;1063 case CHIP_PM8607:1064 device_8607_init(chip, chip->client, pdata);1065 break;1066 }1067 1068 if (chip->companion) {1069 switch (chip->id) {1070 case CHIP_PM8607:1071 device_8606_init(chip, chip->companion, pdata);1072 break;1073 case CHIP_PM8606:1074 device_8607_init(chip, chip->companion, pdata);1075 break;1076 }1077 }1078 1079 return 0;1080}1081 1082static void pm860x_device_exit(struct pm860x_chip *chip)1083{1084 device_irq_exit(chip);1085 mfd_remove_devices(chip->dev);1086}1087 1088static int verify_addr(struct i2c_client *i2c)1089{1090 unsigned short addr_8607[] = {0x30, 0x34};1091 unsigned short addr_8606[] = {0x10, 0x11};1092 int size, i;1093 1094 if (i2c == NULL)1095 return 0;1096 size = ARRAY_SIZE(addr_8606);1097 for (i = 0; i < size; i++) {1098 if (i2c->addr == *(addr_8606 + i))1099 return CHIP_PM8606;1100 }1101 size = ARRAY_SIZE(addr_8607);1102 for (i = 0; i < size; i++) {1103 if (i2c->addr == *(addr_8607 + i))1104 return CHIP_PM8607;1105 }1106 return 0;1107}1108 1109static const struct regmap_config pm860x_regmap_config = {1110 .reg_bits = 8,1111 .val_bits = 8,1112};1113 1114static int pm860x_dt_init(struct device_node *np,1115 struct device *dev,1116 struct pm860x_platform_data *pdata)1117{1118 int ret;1119 1120 pdata->irq_mode = of_property_read_bool(np, "marvell,88pm860x-irq-read-clr");1121 ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr",1122 &pdata->companion_addr);1123 if (ret) {1124 dev_err(dev,1125 "Not found \"marvell,88pm860x-slave-addr\" property\n");1126 pdata->companion_addr = 0;1127 }1128 return 0;1129}1130 1131static int pm860x_probe(struct i2c_client *client)1132{1133 struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev);1134 struct device_node *node = client->dev.of_node;1135 struct pm860x_chip *chip;1136 int ret;1137 1138 if (node && !pdata) {1139 /* parse DT to get platform data */1140 pdata = devm_kzalloc(&client->dev,1141 sizeof(struct pm860x_platform_data),1142 GFP_KERNEL);1143 if (!pdata)1144 return -ENOMEM;1145 ret = pm860x_dt_init(node, &client->dev, pdata);1146 if (ret)1147 return ret;1148 } else if (!pdata) {1149 pr_info("No platform data in %s!\n", __func__);1150 return -EINVAL;1151 }1152 1153 chip = devm_kzalloc(&client->dev,1154 sizeof(struct pm860x_chip), GFP_KERNEL);1155 if (chip == NULL)1156 return -ENOMEM;1157 1158 chip->id = verify_addr(client);1159 chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config);1160 if (IS_ERR(chip->regmap)) {1161 ret = PTR_ERR(chip->regmap);1162 dev_err(&client->dev, "Failed to allocate register map: %d\n",1163 ret);1164 return ret;1165 }1166 chip->client = client;1167 i2c_set_clientdata(client, chip);1168 chip->dev = &client->dev;1169 1170 /*1171 * Both client and companion client shares same platform driver.1172 * Driver distinguishes them by pdata->companion_addr.1173 * pdata->companion_addr is only assigned if companion chip exists.1174 * At the same time, the companion_addr shouldn't equal to client1175 * address.1176 */1177 if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {1178 chip->companion_addr = pdata->companion_addr;1179 chip->companion = i2c_new_dummy_device(chip->client->adapter,1180 chip->companion_addr);1181 if (IS_ERR(chip->companion)) {1182 dev_err(&client->dev,1183 "Failed to allocate I2C companion device\n");1184 return PTR_ERR(chip->companion);1185 }1186 chip->regmap_companion = regmap_init_i2c(chip->companion,1187 &pm860x_regmap_config);1188 if (IS_ERR(chip->regmap_companion)) {1189 ret = PTR_ERR(chip->regmap_companion);1190 dev_err(&chip->companion->dev,1191 "Failed to allocate register map: %d\n", ret);1192 i2c_unregister_device(chip->companion);1193 return ret;1194 }1195 i2c_set_clientdata(chip->companion, chip);1196 }1197 1198 pm860x_device_init(chip, pdata);1199 return 0;1200}1201 1202static void pm860x_remove(struct i2c_client *client)1203{1204 struct pm860x_chip *chip = i2c_get_clientdata(client);1205 1206 pm860x_device_exit(chip);1207 if (chip->companion) {1208 regmap_exit(chip->regmap_companion);1209 i2c_unregister_device(chip->companion);1210 }1211}1212 1213static int pm860x_suspend(struct device *dev)1214{1215 struct i2c_client *client = to_i2c_client(dev);1216 struct pm860x_chip *chip = i2c_get_clientdata(client);1217 1218 if (device_may_wakeup(dev) && chip->wakeup_flag)1219 enable_irq_wake(chip->core_irq);1220 return 0;1221}1222 1223static int pm860x_resume(struct device *dev)1224{1225 struct i2c_client *client = to_i2c_client(dev);1226 struct pm860x_chip *chip = i2c_get_clientdata(client);1227 1228 if (device_may_wakeup(dev) && chip->wakeup_flag)1229 disable_irq_wake(chip->core_irq);1230 return 0;1231}1232 1233static DEFINE_SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);1234 1235static const struct i2c_device_id pm860x_id_table[] = {1236 { "88PM860x" },1237 {}1238};1239MODULE_DEVICE_TABLE(i2c, pm860x_id_table);1240 1241static const struct of_device_id pm860x_dt_ids[] = {1242 { .compatible = "marvell,88pm860x", },1243 {},1244};1245MODULE_DEVICE_TABLE(of, pm860x_dt_ids);1246 1247static struct i2c_driver pm860x_driver = {1248 .driver = {1249 .name = "88PM860x",1250 .pm = pm_sleep_ptr(&pm860x_pm_ops),1251 .of_match_table = pm860x_dt_ids,1252 },1253 .probe = pm860x_probe,1254 .remove = pm860x_remove,1255 .id_table = pm860x_id_table,1256};1257 1258static int __init pm860x_i2c_init(void)1259{1260 int ret;1261 1262 ret = i2c_add_driver(&pm860x_driver);1263 if (ret != 0)1264 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);1265 return ret;1266}1267subsys_initcall(pm860x_i2c_init);1268 1269static void __exit pm860x_i2c_exit(void)1270{1271 i2c_del_driver(&pm860x_driver);1272}1273module_exit(pm860x_i2c_exit);1274 1275MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");1276MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");1277