1 /* 2 * Base driver for Marvell 88PM8607 3 * 4 * Copyright (C) 2009 Marvell International Ltd. 5 * Haojian Zhuang <haojian.zhuang@marvell.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/i2c.h> 15 #include <linux/irq.h> 16 #include <linux/interrupt.h> 17 #include <linux/platform_device.h> 18 #include <linux/mfd/core.h> 19 #include <linux/mfd/88pm860x.h> 20 #include <linux/regulator/machine.h> 21 22 #define INT_STATUS_NUM 3 23 24 static struct resource io_parent = { 25 .start = 0, 26 .end = 0xffffffff, 27 .flags = IORESOURCE_IO, 28 }; 29 30 static struct resource bk_resources[] __devinitdata = { 31 {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO, 32 &io_parent,}, 33 {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO, 34 &io_parent,}, 35 {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO, 36 &io_parent,}, 37 }; 38 39 static struct resource led_resources[] __devinitdata = { 40 {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO, 41 &io_parent,}, 42 {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO, 43 &io_parent,}, 44 {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO, 45 &io_parent,}, 46 {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO, 47 &io_parent,}, 48 {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO, 49 &io_parent,}, 50 {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO, 51 &io_parent,}, 52 }; 53 54 static struct resource regulator_resources[] __devinitdata = { 55 {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO, 56 &io_parent,}, 57 {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO, 58 &io_parent,}, 59 {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO, 60 &io_parent,}, 61 {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO, 62 &io_parent,}, 63 {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO, 64 &io_parent,}, 65 {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO, 66 &io_parent,}, 67 {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO, 68 &io_parent,}, 69 {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO, 70 &io_parent,}, 71 {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO, 72 &io_parent,}, 73 {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO, 74 &io_parent,}, 75 {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO, 76 &io_parent,}, 77 {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO, 78 &io_parent,}, 79 {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO, 80 &io_parent,}, 81 {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO, 82 &io_parent,}, 83 {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO, 84 &io_parent,}, 85 {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO, 86 &io_parent,}, 87 {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO, 88 &io_parent,}, 89 {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO, 90 &io_parent,}, 91 }; 92 93 static struct resource touch_resources[] __devinitdata = { 94 {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, 95 }; 96 97 static struct resource onkey_resources[] __devinitdata = { 98 {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, 99 }; 100 101 static struct resource codec_resources[] __devinitdata = { 102 /* Headset microphone insertion or removal */ 103 {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, 104 /* Hook-switch press or release */ 105 {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,}, 106 /* Headset insertion or removal */ 107 {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,}, 108 /* Audio short */ 109 {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, 110 }; 111 112 static struct resource battery_resources[] __devinitdata = { 113 {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,}, 114 {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,}, 115 }; 116 117 static struct resource charger_resources[] __devinitdata = { 118 {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,}, 119 {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,}, 120 {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,}, 121 {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,}, 122 {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,}, 123 {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, 124 }; 125 126 static struct resource preg_resources[] __devinitdata = { 127 {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO, 128 &io_parent,}, 129 }; 130 131 static struct resource rtc_resources[] __devinitdata = { 132 {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ, &io_parent,}, 133 }; 134 135 static struct mfd_cell bk_devs[] = { 136 {"88pm860x-backlight", 0,}, 137 {"88pm860x-backlight", 1,}, 138 {"88pm860x-backlight", 2,}, 139 }; 140 141 static struct mfd_cell led_devs[] = { 142 {"88pm860x-led", 0,}, 143 {"88pm860x-led", 1,}, 144 {"88pm860x-led", 2,}, 145 {"88pm860x-led", 3,}, 146 {"88pm860x-led", 4,}, 147 {"88pm860x-led", 5,}, 148 }; 149 150 static struct mfd_cell regulator_devs[] = { 151 {"88pm860x-regulator", 0,}, 152 {"88pm860x-regulator", 1,}, 153 {"88pm860x-regulator", 2,}, 154 {"88pm860x-regulator", 3,}, 155 {"88pm860x-regulator", 4,}, 156 {"88pm860x-regulator", 5,}, 157 {"88pm860x-regulator", 6,}, 158 {"88pm860x-regulator", 7,}, 159 {"88pm860x-regulator", 8,}, 160 {"88pm860x-regulator", 9,}, 161 {"88pm860x-regulator", 10,}, 162 {"88pm860x-regulator", 11,}, 163 {"88pm860x-regulator", 12,}, 164 {"88pm860x-regulator", 13,}, 165 {"88pm860x-regulator", 14,}, 166 {"88pm860x-regulator", 15,}, 167 {"88pm860x-regulator", 16,}, 168 {"88pm860x-regulator", 17,}, 169 }; 170 171 static struct mfd_cell touch_devs[] = { 172 {"88pm860x-touch", -1,}, 173 }; 174 175 static struct mfd_cell onkey_devs[] = { 176 {"88pm860x-onkey", -1,}, 177 }; 178 179 static struct mfd_cell codec_devs[] = { 180 {"88pm860x-codec", -1,}, 181 }; 182 183 static struct regulator_consumer_supply preg_supply[] = { 184 REGULATOR_SUPPLY("preg", "charger-manager"), 185 }; 186 187 static struct regulator_init_data preg_init_data = { 188 .num_consumer_supplies = ARRAY_SIZE(preg_supply), 189 .consumer_supplies = &preg_supply[0], 190 }; 191 192 static struct mfd_cell power_devs[] = { 193 {"88pm860x-battery", -1,}, 194 {"88pm860x-charger", -1,}, 195 {"88pm860x-preg", -1,}, 196 }; 197 198 static struct mfd_cell rtc_devs[] = { 199 {"88pm860x-rtc", -1,}, 200 }; 201 202 203 struct pm860x_irq_data { 204 int reg; 205 int mask_reg; 206 int enable; /* enable or not */ 207 int offs; /* bit offset in mask register */ 208 }; 209 210 static struct pm860x_irq_data pm860x_irqs[] = { 211 [PM8607_IRQ_ONKEY] = { 212 .reg = PM8607_INT_STATUS1, 213 .mask_reg = PM8607_INT_MASK_1, 214 .offs = 1 << 0, 215 }, 216 [PM8607_IRQ_EXTON] = { 217 .reg = PM8607_INT_STATUS1, 218 .mask_reg = PM8607_INT_MASK_1, 219 .offs = 1 << 1, 220 }, 221 [PM8607_IRQ_CHG] = { 222 .reg = PM8607_INT_STATUS1, 223 .mask_reg = PM8607_INT_MASK_1, 224 .offs = 1 << 2, 225 }, 226 [PM8607_IRQ_BAT] = { 227 .reg = PM8607_INT_STATUS1, 228 .mask_reg = PM8607_INT_MASK_1, 229 .offs = 1 << 3, 230 }, 231 [PM8607_IRQ_RTC] = { 232 .reg = PM8607_INT_STATUS1, 233 .mask_reg = PM8607_INT_MASK_1, 234 .offs = 1 << 4, 235 }, 236 [PM8607_IRQ_CC] = { 237 .reg = PM8607_INT_STATUS1, 238 .mask_reg = PM8607_INT_MASK_1, 239 .offs = 1 << 5, 240 }, 241 [PM8607_IRQ_VBAT] = { 242 .reg = PM8607_INT_STATUS2, 243 .mask_reg = PM8607_INT_MASK_2, 244 .offs = 1 << 0, 245 }, 246 [PM8607_IRQ_VCHG] = { 247 .reg = PM8607_INT_STATUS2, 248 .mask_reg = PM8607_INT_MASK_2, 249 .offs = 1 << 1, 250 }, 251 [PM8607_IRQ_VSYS] = { 252 .reg = PM8607_INT_STATUS2, 253 .mask_reg = PM8607_INT_MASK_2, 254 .offs = 1 << 2, 255 }, 256 [PM8607_IRQ_TINT] = { 257 .reg = PM8607_INT_STATUS2, 258 .mask_reg = PM8607_INT_MASK_2, 259 .offs = 1 << 3, 260 }, 261 [PM8607_IRQ_GPADC0] = { 262 .reg = PM8607_INT_STATUS2, 263 .mask_reg = PM8607_INT_MASK_2, 264 .offs = 1 << 4, 265 }, 266 [PM8607_IRQ_GPADC1] = { 267 .reg = PM8607_INT_STATUS2, 268 .mask_reg = PM8607_INT_MASK_2, 269 .offs = 1 << 5, 270 }, 271 [PM8607_IRQ_GPADC2] = { 272 .reg = PM8607_INT_STATUS2, 273 .mask_reg = PM8607_INT_MASK_2, 274 .offs = 1 << 6, 275 }, 276 [PM8607_IRQ_GPADC3] = { 277 .reg = PM8607_INT_STATUS2, 278 .mask_reg = PM8607_INT_MASK_2, 279 .offs = 1 << 7, 280 }, 281 [PM8607_IRQ_AUDIO_SHORT] = { 282 .reg = PM8607_INT_STATUS3, 283 .mask_reg = PM8607_INT_MASK_3, 284 .offs = 1 << 0, 285 }, 286 [PM8607_IRQ_PEN] = { 287 .reg = PM8607_INT_STATUS3, 288 .mask_reg = PM8607_INT_MASK_3, 289 .offs = 1 << 1, 290 }, 291 [PM8607_IRQ_HEADSET] = { 292 .reg = PM8607_INT_STATUS3, 293 .mask_reg = PM8607_INT_MASK_3, 294 .offs = 1 << 2, 295 }, 296 [PM8607_IRQ_HOOK] = { 297 .reg = PM8607_INT_STATUS3, 298 .mask_reg = PM8607_INT_MASK_3, 299 .offs = 1 << 3, 300 }, 301 [PM8607_IRQ_MICIN] = { 302 .reg = PM8607_INT_STATUS3, 303 .mask_reg = PM8607_INT_MASK_3, 304 .offs = 1 << 4, 305 }, 306 [PM8607_IRQ_CHG_FAIL] = { 307 .reg = PM8607_INT_STATUS3, 308 .mask_reg = PM8607_INT_MASK_3, 309 .offs = 1 << 5, 310 }, 311 [PM8607_IRQ_CHG_DONE] = { 312 .reg = PM8607_INT_STATUS3, 313 .mask_reg = PM8607_INT_MASK_3, 314 .offs = 1 << 6, 315 }, 316 [PM8607_IRQ_CHG_FAULT] = { 317 .reg = PM8607_INT_STATUS3, 318 .mask_reg = PM8607_INT_MASK_3, 319 .offs = 1 << 7, 320 }, 321 }; 322 323 static irqreturn_t pm860x_irq(int irq, void *data) 324 { 325 struct pm860x_chip *chip = data; 326 struct pm860x_irq_data *irq_data; 327 struct i2c_client *i2c; 328 int read_reg = -1, value = 0; 329 int i; 330 331 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 332 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 333 irq_data = &pm860x_irqs[i]; 334 if (read_reg != irq_data->reg) { 335 read_reg = irq_data->reg; 336 value = pm860x_reg_read(i2c, irq_data->reg); 337 } 338 if (value & irq_data->enable) 339 handle_nested_irq(chip->irq_base + i); 340 } 341 return IRQ_HANDLED; 342 } 343 344 static void pm860x_irq_lock(struct irq_data *data) 345 { 346 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); 347 348 mutex_lock(&chip->irq_lock); 349 } 350 351 static void pm860x_irq_sync_unlock(struct irq_data *data) 352 { 353 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); 354 struct pm860x_irq_data *irq_data; 355 struct i2c_client *i2c; 356 static unsigned char cached[3] = {0x0, 0x0, 0x0}; 357 unsigned char mask[3]; 358 int i; 359 360 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 361 /* Load cached value. In initial, all IRQs are masked */ 362 for (i = 0; i < 3; i++) 363 mask[i] = cached[i]; 364 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 365 irq_data = &pm860x_irqs[i]; 366 switch (irq_data->mask_reg) { 367 case PM8607_INT_MASK_1: 368 mask[0] &= ~irq_data->offs; 369 mask[0] |= irq_data->enable; 370 break; 371 case PM8607_INT_MASK_2: 372 mask[1] &= ~irq_data->offs; 373 mask[1] |= irq_data->enable; 374 break; 375 case PM8607_INT_MASK_3: 376 mask[2] &= ~irq_data->offs; 377 mask[2] |= irq_data->enable; 378 break; 379 default: 380 dev_err(chip->dev, "wrong IRQ\n"); 381 break; 382 } 383 } 384 /* update mask into registers */ 385 for (i = 0; i < 3; i++) { 386 if (mask[i] != cached[i]) { 387 cached[i] = mask[i]; 388 pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]); 389 } 390 } 391 392 mutex_unlock(&chip->irq_lock); 393 } 394 395 static void pm860x_irq_enable(struct irq_data *data) 396 { 397 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); 398 pm860x_irqs[data->irq - chip->irq_base].enable 399 = pm860x_irqs[data->irq - chip->irq_base].offs; 400 } 401 402 static void pm860x_irq_disable(struct irq_data *data) 403 { 404 struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); 405 pm860x_irqs[data->irq - chip->irq_base].enable = 0; 406 } 407 408 static struct irq_chip pm860x_irq_chip = { 409 .name = "88pm860x", 410 .irq_bus_lock = pm860x_irq_lock, 411 .irq_bus_sync_unlock = pm860x_irq_sync_unlock, 412 .irq_enable = pm860x_irq_enable, 413 .irq_disable = pm860x_irq_disable, 414 }; 415 416 static int __devinit device_gpadc_init(struct pm860x_chip *chip, 417 struct pm860x_platform_data *pdata) 418 { 419 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ 420 : chip->companion; 421 int data; 422 int ret; 423 424 /* initialize GPADC without activating it */ 425 426 if (!pdata || !pdata->touch) 427 return -EINVAL; 428 429 /* set GPADC MISC1 register */ 430 data = 0; 431 data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK; 432 data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; 433 data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK; 434 data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK; 435 if (data) { 436 ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); 437 if (ret < 0) 438 goto out; 439 } 440 /* set tsi prebias time */ 441 if (pdata->touch->tsi_prebias) { 442 data = pdata->touch->tsi_prebias; 443 ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); 444 if (ret < 0) 445 goto out; 446 } 447 /* set prebias & prechg time of pen detect */ 448 data = 0; 449 data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; 450 data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK; 451 if (data) { 452 ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); 453 if (ret < 0) 454 goto out; 455 } 456 457 ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, 458 PM8607_GPADC_EN, PM8607_GPADC_EN); 459 out: 460 return ret; 461 } 462 463 static int __devinit device_irq_init(struct pm860x_chip *chip, 464 struct pm860x_platform_data *pdata) 465 { 466 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ 467 : chip->companion; 468 unsigned char status_buf[INT_STATUS_NUM]; 469 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; 470 int i, data, mask, ret = -EINVAL; 471 int __irq; 472 473 if (!pdata || !pdata->irq_base) { 474 dev_warn(chip->dev, "No interrupt support on IRQ base\n"); 475 return -EINVAL; 476 } 477 478 mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR 479 | PM8607_B0_MISC1_INT_MASK; 480 data = 0; 481 chip->irq_mode = 0; 482 if (pdata && pdata->irq_mode) { 483 /* 484 * irq_mode defines the way of clearing interrupt. If it's 1, 485 * clear IRQ by write. Otherwise, clear it by read. 486 * This control bit is valid from 88PM8607 B0 steping. 487 */ 488 data |= PM8607_B0_MISC1_INT_CLEAR; 489 chip->irq_mode = 1; 490 } 491 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data); 492 if (ret < 0) 493 goto out; 494 495 /* mask all IRQs */ 496 memset(status_buf, 0, INT_STATUS_NUM); 497 ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1, 498 INT_STATUS_NUM, status_buf); 499 if (ret < 0) 500 goto out; 501 502 if (chip->irq_mode) { 503 /* clear interrupt status by write */ 504 memset(status_buf, 0xFF, INT_STATUS_NUM); 505 ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1, 506 INT_STATUS_NUM, status_buf); 507 } else { 508 /* clear interrupt status by read */ 509 ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1, 510 INT_STATUS_NUM, status_buf); 511 } 512 if (ret < 0) 513 goto out; 514 515 mutex_init(&chip->irq_lock); 516 chip->irq_base = pdata->irq_base; 517 chip->core_irq = i2c->irq; 518 if (!chip->core_irq) 519 goto out; 520 521 /* register IRQ by genirq */ 522 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 523 __irq = i + chip->irq_base; 524 irq_set_chip_data(__irq, chip); 525 irq_set_chip_and_handler(__irq, &pm860x_irq_chip, 526 handle_edge_irq); 527 irq_set_nested_thread(__irq, 1); 528 #ifdef CONFIG_ARM 529 set_irq_flags(__irq, IRQF_VALID); 530 #else 531 irq_set_noprobe(__irq); 532 #endif 533 } 534 535 ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, 536 "88pm860x", chip); 537 if (ret) { 538 dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); 539 chip->core_irq = 0; 540 } 541 542 return 0; 543 out: 544 chip->core_irq = 0; 545 return ret; 546 } 547 548 static void device_irq_exit(struct pm860x_chip *chip) 549 { 550 if (chip->core_irq) 551 free_irq(chip->core_irq, chip); 552 } 553 554 int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client) 555 { 556 int ret = -EIO; 557 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? 558 chip->client : chip->companion; 559 560 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); 561 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", 562 __func__, chip->osc_vote, 563 chip->osc_status); 564 565 mutex_lock(&chip->osc_lock); 566 /* Update voting status */ 567 chip->osc_vote |= client; 568 /* If reference group is off - turn on*/ 569 if (chip->osc_status != PM8606_REF_GP_OSC_ON) { 570 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; 571 /* Enable Reference group Vsys */ 572 if (pm860x_set_bits(i2c, PM8606_VSYS, 573 PM8606_VSYS_EN, PM8606_VSYS_EN)) 574 goto out; 575 576 /*Enable Internal Oscillator */ 577 if (pm860x_set_bits(i2c, PM8606_MISC, 578 PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN)) 579 goto out; 580 /* Update status (only if writes succeed) */ 581 chip->osc_status = PM8606_REF_GP_OSC_ON; 582 } 583 mutex_unlock(&chip->osc_lock); 584 585 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", 586 __func__, chip->osc_vote, 587 chip->osc_status, ret); 588 return 0; 589 out: 590 mutex_unlock(&chip->osc_lock); 591 return ret; 592 } 593 EXPORT_SYMBOL(pm8606_osc_enable); 594 595 int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client) 596 { 597 int ret = -EIO; 598 struct i2c_client *i2c = (chip->id == CHIP_PM8606) ? 599 chip->client : chip->companion; 600 601 dev_dbg(chip->dev, "%s(B): client=0x%x\n", __func__, client); 602 dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d\n", 603 __func__, chip->osc_vote, 604 chip->osc_status); 605 606 mutex_lock(&chip->osc_lock); 607 /*Update voting status */ 608 chip->osc_vote &= ~(client); 609 /* If reference group is off and this is the last client to release 610 * - turn off */ 611 if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) && 612 (chip->osc_vote == REF_GP_NO_CLIENTS)) { 613 chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN; 614 /* Disable Reference group Vsys */ 615 if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0)) 616 goto out; 617 /* Disable Internal Oscillator */ 618 if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0)) 619 goto out; 620 chip->osc_status = PM8606_REF_GP_OSC_OFF; 621 } 622 mutex_unlock(&chip->osc_lock); 623 624 dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d\n", 625 __func__, chip->osc_vote, 626 chip->osc_status, ret); 627 return 0; 628 out: 629 mutex_unlock(&chip->osc_lock); 630 return ret; 631 } 632 EXPORT_SYMBOL(pm8606_osc_disable); 633 634 static void __devinit device_osc_init(struct i2c_client *i2c) 635 { 636 struct pm860x_chip *chip = i2c_get_clientdata(i2c); 637 638 mutex_init(&chip->osc_lock); 639 /* init portofino reference group voting and status */ 640 /* Disable Reference group Vsys */ 641 pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0); 642 /* Disable Internal Oscillator */ 643 pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0); 644 645 chip->osc_vote = REF_GP_NO_CLIENTS; 646 chip->osc_status = PM8606_REF_GP_OSC_OFF; 647 } 648 649 static void __devinit device_bk_init(struct pm860x_chip *chip, 650 struct pm860x_platform_data *pdata) 651 { 652 int ret; 653 int i, j, id; 654 655 if ((pdata == NULL) || (pdata->backlight == NULL)) 656 return; 657 658 if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) 659 pdata->num_backlights = ARRAY_SIZE(bk_devs); 660 661 for (i = 0; i < pdata->num_backlights; i++) { 662 bk_devs[i].platform_data = &pdata->backlight[i]; 663 bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); 664 665 for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { 666 id = bk_resources[j].start; 667 if (pdata->backlight[i].flags != id) 668 continue; 669 670 bk_devs[i].num_resources = 1; 671 bk_devs[i].resources = &bk_resources[j]; 672 ret = mfd_add_devices(chip->dev, 0, 673 &bk_devs[i], 1, 674 &bk_resources[j], 0); 675 if (ret < 0) { 676 dev_err(chip->dev, "Failed to add " 677 "backlight subdev\n"); 678 return; 679 } 680 } 681 } 682 } 683 684 static void __devinit device_led_init(struct pm860x_chip *chip, 685 struct pm860x_platform_data *pdata) 686 { 687 int ret; 688 int i, j, id; 689 690 if ((pdata == NULL) || (pdata->led == NULL)) 691 return; 692 693 if (pdata->num_leds > ARRAY_SIZE(led_devs)) 694 pdata->num_leds = ARRAY_SIZE(led_devs); 695 696 for (i = 0; i < pdata->num_leds; i++) { 697 led_devs[i].platform_data = &pdata->led[i]; 698 led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); 699 700 for (j = 0; j < ARRAY_SIZE(led_devs); j++) { 701 id = led_resources[j].start; 702 if (pdata->led[i].flags != id) 703 continue; 704 705 led_devs[i].num_resources = 1; 706 led_devs[i].resources = &led_resources[j], 707 ret = mfd_add_devices(chip->dev, 0, 708 &led_devs[i], 1, 709 &led_resources[j], 0); 710 if (ret < 0) { 711 dev_err(chip->dev, "Failed to add " 712 "led subdev\n"); 713 return; 714 } 715 } 716 } 717 } 718 719 static void __devinit device_regulator_init(struct pm860x_chip *chip, 720 struct pm860x_platform_data *pdata) 721 { 722 struct regulator_init_data *initdata; 723 int ret; 724 int i, seq; 725 726 if ((pdata == NULL) || (pdata->regulator == NULL)) 727 return; 728 729 if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) 730 pdata->num_regulators = ARRAY_SIZE(regulator_devs); 731 732 for (i = 0, seq = -1; i < pdata->num_regulators; i++) { 733 initdata = &pdata->regulator[i]; 734 seq = *(unsigned int *)initdata->driver_data; 735 if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { 736 dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", 737 seq, initdata->constraints.name); 738 goto out; 739 } 740 regulator_devs[i].platform_data = &pdata->regulator[i]; 741 regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); 742 regulator_devs[i].num_resources = 1; 743 regulator_devs[i].resources = ®ulator_resources[seq]; 744 745 ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, 746 ®ulator_resources[seq], 0); 747 if (ret < 0) { 748 dev_err(chip->dev, "Failed to add regulator subdev\n"); 749 goto out; 750 } 751 } 752 out: 753 return; 754 } 755 756 static void __devinit device_rtc_init(struct pm860x_chip *chip, 757 struct pm860x_platform_data *pdata) 758 { 759 int ret; 760 761 if ((pdata == NULL)) 762 return; 763 764 rtc_devs[0].platform_data = pdata->rtc; 765 rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata); 766 rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources); 767 rtc_devs[0].resources = &rtc_resources[0]; 768 ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], 769 ARRAY_SIZE(rtc_devs), &rtc_resources[0], 770 chip->irq_base); 771 if (ret < 0) 772 dev_err(chip->dev, "Failed to add rtc subdev\n"); 773 } 774 775 static void __devinit device_touch_init(struct pm860x_chip *chip, 776 struct pm860x_platform_data *pdata) 777 { 778 int ret; 779 780 if (pdata == NULL) 781 return; 782 783 touch_devs[0].platform_data = pdata->touch; 784 touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata); 785 touch_devs[0].num_resources = ARRAY_SIZE(touch_resources); 786 touch_devs[0].resources = &touch_resources[0]; 787 ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], 788 ARRAY_SIZE(touch_devs), &touch_resources[0], 789 chip->irq_base); 790 if (ret < 0) 791 dev_err(chip->dev, "Failed to add touch subdev\n"); 792 } 793 794 static void __devinit device_power_init(struct pm860x_chip *chip, 795 struct pm860x_platform_data *pdata) 796 { 797 int ret; 798 799 if (pdata == NULL) 800 return; 801 802 power_devs[0].platform_data = pdata->power; 803 power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata); 804 power_devs[0].num_resources = ARRAY_SIZE(battery_resources); 805 power_devs[0].resources = &battery_resources[0], 806 ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, 807 &battery_resources[0], chip->irq_base); 808 if (ret < 0) 809 dev_err(chip->dev, "Failed to add battery subdev\n"); 810 811 power_devs[1].platform_data = pdata->power; 812 power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata); 813 power_devs[1].num_resources = ARRAY_SIZE(charger_resources); 814 power_devs[1].resources = &charger_resources[0], 815 ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, 816 &charger_resources[0], chip->irq_base); 817 if (ret < 0) 818 dev_err(chip->dev, "Failed to add charger subdev\n"); 819 820 power_devs[2].platform_data = &preg_init_data; 821 power_devs[2].pdata_size = sizeof(struct regulator_init_data); 822 power_devs[2].num_resources = ARRAY_SIZE(preg_resources); 823 power_devs[2].resources = &preg_resources[0], 824 ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, 825 &preg_resources[0], chip->irq_base); 826 if (ret < 0) 827 dev_err(chip->dev, "Failed to add preg subdev\n"); 828 } 829 830 static void __devinit device_onkey_init(struct pm860x_chip *chip, 831 struct pm860x_platform_data *pdata) 832 { 833 int ret; 834 835 onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources); 836 onkey_devs[0].resources = &onkey_resources[0], 837 ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], 838 ARRAY_SIZE(onkey_devs), &onkey_resources[0], 839 chip->irq_base); 840 if (ret < 0) 841 dev_err(chip->dev, "Failed to add onkey subdev\n"); 842 } 843 844 static void __devinit device_codec_init(struct pm860x_chip *chip, 845 struct pm860x_platform_data *pdata) 846 { 847 int ret; 848 849 codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); 850 codec_devs[0].resources = &codec_resources[0], 851 ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], 852 ARRAY_SIZE(codec_devs), &codec_resources[0], 0); 853 if (ret < 0) 854 dev_err(chip->dev, "Failed to add codec subdev\n"); 855 } 856 857 static void __devinit device_8607_init(struct pm860x_chip *chip, 858 struct i2c_client *i2c, 859 struct pm860x_platform_data *pdata) 860 { 861 int data, ret; 862 863 ret = pm860x_reg_read(i2c, PM8607_CHIP_ID); 864 if (ret < 0) { 865 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); 866 goto out; 867 } 868 switch (ret & PM8607_VERSION_MASK) { 869 case 0x40: 870 case 0x50: 871 dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", 872 ret); 873 break; 874 default: 875 dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " 876 "Chip ID: %02x\n", ret); 877 goto out; 878 } 879 880 ret = pm860x_reg_read(i2c, PM8607_BUCK3); 881 if (ret < 0) { 882 dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); 883 goto out; 884 } 885 if (ret & PM8607_BUCK3_DOUBLE) 886 chip->buck3_double = 1; 887 888 ret = pm860x_reg_read(i2c, PM8607_B0_MISC1); 889 if (ret < 0) { 890 dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); 891 goto out; 892 } 893 894 if (pdata && (pdata->i2c_port == PI2C_PORT)) 895 data = PM8607_B0_MISC1_PI2C; 896 else 897 data = 0; 898 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data); 899 if (ret < 0) { 900 dev_err(chip->dev, "Failed to access MISC1:%d\n", ret); 901 goto out; 902 } 903 904 ret = device_gpadc_init(chip, pdata); 905 if (ret < 0) 906 goto out; 907 908 ret = device_irq_init(chip, pdata); 909 if (ret < 0) 910 goto out; 911 912 device_regulator_init(chip, pdata); 913 device_rtc_init(chip, pdata); 914 device_onkey_init(chip, pdata); 915 device_touch_init(chip, pdata); 916 device_power_init(chip, pdata); 917 device_codec_init(chip, pdata); 918 out: 919 return; 920 } 921 922 static void __devinit device_8606_init(struct pm860x_chip *chip, 923 struct i2c_client *i2c, 924 struct pm860x_platform_data *pdata) 925 { 926 device_osc_init(i2c); 927 device_bk_init(chip, pdata); 928 device_led_init(chip, pdata); 929 } 930 931 int __devinit pm860x_device_init(struct pm860x_chip *chip, 932 struct pm860x_platform_data *pdata) 933 { 934 chip->core_irq = 0; 935 936 switch (chip->id) { 937 case CHIP_PM8606: 938 device_8606_init(chip, chip->client, pdata); 939 break; 940 case CHIP_PM8607: 941 device_8607_init(chip, chip->client, pdata); 942 break; 943 } 944 945 if (chip->companion) { 946 switch (chip->id) { 947 case CHIP_PM8607: 948 device_8606_init(chip, chip->companion, pdata); 949 break; 950 case CHIP_PM8606: 951 device_8607_init(chip, chip->companion, pdata); 952 break; 953 } 954 } 955 956 return 0; 957 } 958 959 void __devexit pm860x_device_exit(struct pm860x_chip *chip) 960 { 961 device_irq_exit(chip); 962 mfd_remove_devices(chip->dev); 963 } 964 965 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); 966 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 967 MODULE_LICENSE("GPL"); 968