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 21 #define INT_STATUS_NUM 3 22 23 char pm860x_backlight_name[][MFD_NAME_SIZE] = { 24 "backlight-0", 25 "backlight-1", 26 "backlight-2", 27 }; 28 EXPORT_SYMBOL(pm860x_backlight_name); 29 30 char pm860x_led_name[][MFD_NAME_SIZE] = { 31 "led0-red", 32 "led0-green", 33 "led0-blue", 34 "led1-red", 35 "led1-green", 36 "led1-blue", 37 }; 38 EXPORT_SYMBOL(pm860x_led_name); 39 40 #define PM8606_BACKLIGHT_RESOURCE(_i, _x) \ 41 { \ 42 .name = pm860x_backlight_name[_i], \ 43 .start = PM8606_##_x, \ 44 .end = PM8606_##_x, \ 45 .flags = IORESOURCE_IO, \ 46 } 47 48 static struct resource backlight_resources[] = { 49 PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A), 50 PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A), 51 PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A), 52 }; 53 54 #define PM8606_BACKLIGHT_DEVS(_i) \ 55 { \ 56 .name = "88pm860x-backlight", \ 57 .num_resources = 1, \ 58 .resources = &backlight_resources[_i], \ 59 .id = _i, \ 60 } 61 62 static struct mfd_cell backlight_devs[] = { 63 PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1), 64 PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2), 65 PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3), 66 }; 67 68 #define PM8606_LED_RESOURCE(_i, _x) \ 69 { \ 70 .name = pm860x_led_name[_i], \ 71 .start = PM8606_##_x, \ 72 .end = PM8606_##_x, \ 73 .flags = IORESOURCE_IO, \ 74 } 75 76 static struct resource led_resources[] = { 77 PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB2B), 78 PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB2C), 79 PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB2D), 80 PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB1B), 81 PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB1C), 82 PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB1D), 83 }; 84 85 #define PM8606_LED_DEVS(_i) \ 86 { \ 87 .name = "88pm860x-led", \ 88 .num_resources = 1, \ 89 .resources = &led_resources[_i], \ 90 .id = _i, \ 91 } 92 93 static struct mfd_cell led_devs[] = { 94 PM8606_LED_DEVS(PM8606_LED1_RED), 95 PM8606_LED_DEVS(PM8606_LED1_GREEN), 96 PM8606_LED_DEVS(PM8606_LED1_BLUE), 97 PM8606_LED_DEVS(PM8606_LED2_RED), 98 PM8606_LED_DEVS(PM8606_LED2_GREEN), 99 PM8606_LED_DEVS(PM8606_LED2_BLUE), 100 }; 101 102 static struct resource touch_resources[] = { 103 { 104 .start = PM8607_IRQ_PEN, 105 .end = PM8607_IRQ_PEN, 106 .flags = IORESOURCE_IRQ, 107 }, 108 }; 109 110 static struct mfd_cell touch_devs[] = { 111 { 112 .name = "88pm860x-touch", 113 .num_resources = 1, 114 .resources = &touch_resources[0], 115 }, 116 }; 117 118 #define PM8607_REG_RESOURCE(_start, _end) \ 119 { \ 120 .start = PM8607_##_start, \ 121 .end = PM8607_##_end, \ 122 .flags = IORESOURCE_IO, \ 123 } 124 125 static struct resource power_supply_resources[] = { 126 { 127 .name = "88pm860x-power", 128 .start = PM8607_IRQ_CHG, 129 .end = PM8607_IRQ_CHG, 130 .flags = IORESOURCE_IRQ, 131 }, 132 }; 133 134 static struct mfd_cell power_devs[] = { 135 { 136 .name = "88pm860x-power", 137 .num_resources = 1, 138 .resources = &power_supply_resources[0], 139 .id = -1, 140 }, 141 }; 142 143 static struct resource onkey_resources[] = { 144 { 145 .name = "88pm860x-onkey", 146 .start = PM8607_IRQ_ONKEY, 147 .end = PM8607_IRQ_ONKEY, 148 .flags = IORESOURCE_IRQ, 149 }, 150 }; 151 152 static struct mfd_cell onkey_devs[] = { 153 { 154 .name = "88pm860x-onkey", 155 .num_resources = 1, 156 .resources = &onkey_resources[0], 157 .id = -1, 158 }, 159 }; 160 161 static struct resource regulator_resources[] = { 162 PM8607_REG_RESOURCE(BUCK1, BUCK1), 163 PM8607_REG_RESOURCE(BUCK2, BUCK2), 164 PM8607_REG_RESOURCE(BUCK3, BUCK3), 165 PM8607_REG_RESOURCE(LDO1, LDO1), 166 PM8607_REG_RESOURCE(LDO2, LDO2), 167 PM8607_REG_RESOURCE(LDO3, LDO3), 168 PM8607_REG_RESOURCE(LDO4, LDO4), 169 PM8607_REG_RESOURCE(LDO5, LDO5), 170 PM8607_REG_RESOURCE(LDO6, LDO6), 171 PM8607_REG_RESOURCE(LDO7, LDO7), 172 PM8607_REG_RESOURCE(LDO8, LDO8), 173 PM8607_REG_RESOURCE(LDO9, LDO9), 174 PM8607_REG_RESOURCE(LDO10, LDO10), 175 PM8607_REG_RESOURCE(LDO12, LDO12), 176 PM8607_REG_RESOURCE(LDO14, LDO14), 177 }; 178 179 #define PM8607_REG_DEVS(_id) \ 180 { \ 181 .name = "88pm860x-regulator", \ 182 .num_resources = 1, \ 183 .resources = ®ulator_resources[PM8607_ID_##_id], \ 184 .id = PM8607_ID_##_id, \ 185 } 186 187 static struct mfd_cell regulator_devs[] = { 188 PM8607_REG_DEVS(BUCK1), 189 PM8607_REG_DEVS(BUCK2), 190 PM8607_REG_DEVS(BUCK3), 191 PM8607_REG_DEVS(LDO1), 192 PM8607_REG_DEVS(LDO2), 193 PM8607_REG_DEVS(LDO3), 194 PM8607_REG_DEVS(LDO4), 195 PM8607_REG_DEVS(LDO5), 196 PM8607_REG_DEVS(LDO6), 197 PM8607_REG_DEVS(LDO7), 198 PM8607_REG_DEVS(LDO8), 199 PM8607_REG_DEVS(LDO9), 200 PM8607_REG_DEVS(LDO10), 201 PM8607_REG_DEVS(LDO12), 202 PM8607_REG_DEVS(LDO14), 203 }; 204 205 struct pm860x_irq_data { 206 int reg; 207 int mask_reg; 208 int enable; /* enable or not */ 209 int offs; /* bit offset in mask register */ 210 }; 211 212 static struct pm860x_irq_data pm860x_irqs[] = { 213 [PM8607_IRQ_ONKEY] = { 214 .reg = PM8607_INT_STATUS1, 215 .mask_reg = PM8607_INT_MASK_1, 216 .offs = 1 << 0, 217 }, 218 [PM8607_IRQ_EXTON] = { 219 .reg = PM8607_INT_STATUS1, 220 .mask_reg = PM8607_INT_MASK_1, 221 .offs = 1 << 1, 222 }, 223 [PM8607_IRQ_CHG] = { 224 .reg = PM8607_INT_STATUS1, 225 .mask_reg = PM8607_INT_MASK_1, 226 .offs = 1 << 2, 227 }, 228 [PM8607_IRQ_BAT] = { 229 .reg = PM8607_INT_STATUS1, 230 .mask_reg = PM8607_INT_MASK_1, 231 .offs = 1 << 3, 232 }, 233 [PM8607_IRQ_RTC] = { 234 .reg = PM8607_INT_STATUS1, 235 .mask_reg = PM8607_INT_MASK_1, 236 .offs = 1 << 4, 237 }, 238 [PM8607_IRQ_CC] = { 239 .reg = PM8607_INT_STATUS1, 240 .mask_reg = PM8607_INT_MASK_1, 241 .offs = 1 << 5, 242 }, 243 [PM8607_IRQ_VBAT] = { 244 .reg = PM8607_INT_STATUS2, 245 .mask_reg = PM8607_INT_MASK_2, 246 .offs = 1 << 0, 247 }, 248 [PM8607_IRQ_VCHG] = { 249 .reg = PM8607_INT_STATUS2, 250 .mask_reg = PM8607_INT_MASK_2, 251 .offs = 1 << 1, 252 }, 253 [PM8607_IRQ_VSYS] = { 254 .reg = PM8607_INT_STATUS2, 255 .mask_reg = PM8607_INT_MASK_2, 256 .offs = 1 << 2, 257 }, 258 [PM8607_IRQ_TINT] = { 259 .reg = PM8607_INT_STATUS2, 260 .mask_reg = PM8607_INT_MASK_2, 261 .offs = 1 << 3, 262 }, 263 [PM8607_IRQ_GPADC0] = { 264 .reg = PM8607_INT_STATUS2, 265 .mask_reg = PM8607_INT_MASK_2, 266 .offs = 1 << 4, 267 }, 268 [PM8607_IRQ_GPADC1] = { 269 .reg = PM8607_INT_STATUS2, 270 .mask_reg = PM8607_INT_MASK_2, 271 .offs = 1 << 5, 272 }, 273 [PM8607_IRQ_GPADC2] = { 274 .reg = PM8607_INT_STATUS2, 275 .mask_reg = PM8607_INT_MASK_2, 276 .offs = 1 << 6, 277 }, 278 [PM8607_IRQ_GPADC3] = { 279 .reg = PM8607_INT_STATUS2, 280 .mask_reg = PM8607_INT_MASK_2, 281 .offs = 1 << 7, 282 }, 283 [PM8607_IRQ_AUDIO_SHORT] = { 284 .reg = PM8607_INT_STATUS3, 285 .mask_reg = PM8607_INT_MASK_3, 286 .offs = 1 << 0, 287 }, 288 [PM8607_IRQ_PEN] = { 289 .reg = PM8607_INT_STATUS3, 290 .mask_reg = PM8607_INT_MASK_3, 291 .offs = 1 << 1, 292 }, 293 [PM8607_IRQ_HEADSET] = { 294 .reg = PM8607_INT_STATUS3, 295 .mask_reg = PM8607_INT_MASK_3, 296 .offs = 1 << 2, 297 }, 298 [PM8607_IRQ_HOOK] = { 299 .reg = PM8607_INT_STATUS3, 300 .mask_reg = PM8607_INT_MASK_3, 301 .offs = 1 << 3, 302 }, 303 [PM8607_IRQ_MICIN] = { 304 .reg = PM8607_INT_STATUS3, 305 .mask_reg = PM8607_INT_MASK_3, 306 .offs = 1 << 4, 307 }, 308 [PM8607_IRQ_CHG_FAIL] = { 309 .reg = PM8607_INT_STATUS3, 310 .mask_reg = PM8607_INT_MASK_3, 311 .offs = 1 << 5, 312 }, 313 [PM8607_IRQ_CHG_DONE] = { 314 .reg = PM8607_INT_STATUS3, 315 .mask_reg = PM8607_INT_MASK_3, 316 .offs = 1 << 6, 317 }, 318 [PM8607_IRQ_CHG_FAULT] = { 319 .reg = PM8607_INT_STATUS3, 320 .mask_reg = PM8607_INT_MASK_3, 321 .offs = 1 << 7, 322 }, 323 }; 324 325 static inline struct pm860x_irq_data *irq_to_pm860x(struct pm860x_chip *chip, 326 int irq) 327 { 328 return &pm860x_irqs[irq - chip->irq_base]; 329 } 330 331 static irqreturn_t pm860x_irq(int irq, void *data) 332 { 333 struct pm860x_chip *chip = data; 334 struct pm860x_irq_data *irq_data; 335 struct i2c_client *i2c; 336 int read_reg = -1, value = 0; 337 int i; 338 339 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 340 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 341 irq_data = &pm860x_irqs[i]; 342 if (read_reg != irq_data->reg) { 343 read_reg = irq_data->reg; 344 value = pm860x_reg_read(i2c, irq_data->reg); 345 } 346 if (value & irq_data->enable) 347 handle_nested_irq(chip->irq_base + i); 348 } 349 return IRQ_HANDLED; 350 } 351 352 static void pm860x_irq_lock(unsigned int irq) 353 { 354 struct pm860x_chip *chip = get_irq_chip_data(irq); 355 356 mutex_lock(&chip->irq_lock); 357 } 358 359 static void pm860x_irq_sync_unlock(unsigned int irq) 360 { 361 struct pm860x_chip *chip = get_irq_chip_data(irq); 362 struct pm860x_irq_data *irq_data; 363 struct i2c_client *i2c; 364 static unsigned char cached[3] = {0x0, 0x0, 0x0}; 365 unsigned char mask[3]; 366 int i; 367 368 i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; 369 /* Load cached value. In initial, all IRQs are masked */ 370 for (i = 0; i < 3; i++) 371 mask[i] = cached[i]; 372 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 373 irq_data = &pm860x_irqs[i]; 374 switch (irq_data->mask_reg) { 375 case PM8607_INT_MASK_1: 376 mask[0] &= ~irq_data->offs; 377 mask[0] |= irq_data->enable; 378 break; 379 case PM8607_INT_MASK_2: 380 mask[1] &= ~irq_data->offs; 381 mask[1] |= irq_data->enable; 382 break; 383 case PM8607_INT_MASK_3: 384 mask[2] &= ~irq_data->offs; 385 mask[2] |= irq_data->enable; 386 break; 387 default: 388 dev_err(chip->dev, "wrong IRQ\n"); 389 break; 390 } 391 } 392 /* update mask into registers */ 393 for (i = 0; i < 3; i++) { 394 if (mask[i] != cached[i]) { 395 cached[i] = mask[i]; 396 pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]); 397 } 398 } 399 400 mutex_unlock(&chip->irq_lock); 401 } 402 403 static void pm860x_irq_enable(unsigned int irq) 404 { 405 struct pm860x_chip *chip = get_irq_chip_data(irq); 406 pm860x_irqs[irq - chip->irq_base].enable 407 = pm860x_irqs[irq - chip->irq_base].offs; 408 } 409 410 static void pm860x_irq_disable(unsigned int irq) 411 { 412 struct pm860x_chip *chip = get_irq_chip_data(irq); 413 pm860x_irqs[irq - chip->irq_base].enable = 0; 414 } 415 416 static struct irq_chip pm860x_irq_chip = { 417 .name = "88pm860x", 418 .bus_lock = pm860x_irq_lock, 419 .bus_sync_unlock = pm860x_irq_sync_unlock, 420 .enable = pm860x_irq_enable, 421 .disable = pm860x_irq_disable, 422 }; 423 424 static int __devinit device_gpadc_init(struct pm860x_chip *chip, 425 struct pm860x_platform_data *pdata) 426 { 427 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ 428 : chip->companion; 429 int use_gpadc = 0, data, ret; 430 431 /* initialize GPADC without activating it */ 432 433 if (pdata && pdata->touch) { 434 /* set GPADC MISC1 register */ 435 data = 0; 436 data |= (pdata->touch->gpadc_prebias << 1) 437 & PM8607_GPADC_PREBIAS_MASK; 438 data |= (pdata->touch->slot_cycle << 3) 439 & PM8607_GPADC_SLOT_CYCLE_MASK; 440 data |= (pdata->touch->off_scale << 5) 441 & PM8607_GPADC_OFF_SCALE_MASK; 442 data |= (pdata->touch->sw_cal << 7) 443 & PM8607_GPADC_SW_CAL_MASK; 444 if (data) { 445 ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); 446 if (ret < 0) 447 goto out; 448 } 449 /* set tsi prebias time */ 450 if (pdata->touch->tsi_prebias) { 451 data = pdata->touch->tsi_prebias; 452 ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); 453 if (ret < 0) 454 goto out; 455 } 456 /* set prebias & prechg time of pen detect */ 457 data = 0; 458 data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; 459 data |= (pdata->touch->pen_prechg << 5) 460 & PM8607_PD_PRECHG_MASK; 461 if (data) { 462 ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); 463 if (ret < 0) 464 goto out; 465 } 466 467 use_gpadc = 1; 468 } 469 470 /* turn on GPADC */ 471 if (use_gpadc) { 472 ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, 473 PM8607_GPADC_EN, PM8607_GPADC_EN); 474 } 475 out: 476 return ret; 477 } 478 479 static int __devinit device_irq_init(struct pm860x_chip *chip, 480 struct pm860x_platform_data *pdata) 481 { 482 struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ 483 : chip->companion; 484 unsigned char status_buf[INT_STATUS_NUM]; 485 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; 486 struct irq_desc *desc; 487 int i, data, mask, ret = -EINVAL; 488 int __irq; 489 490 if (!pdata || !pdata->irq_base) { 491 dev_warn(chip->dev, "No interrupt support on IRQ base\n"); 492 return -EINVAL; 493 } 494 495 mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR 496 | PM8607_B0_MISC1_INT_MASK; 497 data = 0; 498 chip->irq_mode = 0; 499 if (pdata && pdata->irq_mode) { 500 /* 501 * irq_mode defines the way of clearing interrupt. If it's 1, 502 * clear IRQ by write. Otherwise, clear it by read. 503 * This control bit is valid from 88PM8607 B0 steping. 504 */ 505 data |= PM8607_B0_MISC1_INT_CLEAR; 506 chip->irq_mode = 1; 507 } 508 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data); 509 if (ret < 0) 510 goto out; 511 512 /* mask all IRQs */ 513 memset(status_buf, 0, INT_STATUS_NUM); 514 ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1, 515 INT_STATUS_NUM, status_buf); 516 if (ret < 0) 517 goto out; 518 519 if (chip->irq_mode) { 520 /* clear interrupt status by write */ 521 memset(status_buf, 0xFF, INT_STATUS_NUM); 522 ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1, 523 INT_STATUS_NUM, status_buf); 524 } else { 525 /* clear interrupt status by read */ 526 ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1, 527 INT_STATUS_NUM, status_buf); 528 } 529 if (ret < 0) 530 goto out; 531 532 mutex_init(&chip->irq_lock); 533 chip->irq_base = pdata->irq_base; 534 chip->core_irq = i2c->irq; 535 if (!chip->core_irq) 536 goto out; 537 538 desc = irq_to_desc(chip->core_irq); 539 540 /* register IRQ by genirq */ 541 for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { 542 __irq = i + chip->irq_base; 543 set_irq_chip_data(__irq, chip); 544 set_irq_chip_and_handler(__irq, &pm860x_irq_chip, 545 handle_edge_irq); 546 set_irq_nested_thread(__irq, 1); 547 #ifdef CONFIG_ARM 548 set_irq_flags(__irq, IRQF_VALID); 549 #else 550 set_irq_noprobe(__irq); 551 #endif 552 } 553 554 ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, 555 "88pm860x", chip); 556 if (ret) { 557 dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); 558 chip->core_irq = 0; 559 } 560 561 return 0; 562 out: 563 chip->core_irq = 0; 564 return ret; 565 } 566 567 static void __devexit device_irq_exit(struct pm860x_chip *chip) 568 { 569 if (chip->core_irq) 570 free_irq(chip->core_irq, chip); 571 } 572 573 static void __devinit device_8606_init(struct pm860x_chip *chip, 574 struct i2c_client *i2c, 575 struct pm860x_platform_data *pdata) 576 { 577 int ret; 578 579 if (pdata && pdata->backlight) { 580 ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], 581 ARRAY_SIZE(backlight_devs), 582 &backlight_resources[0], 0); 583 if (ret < 0) { 584 dev_err(chip->dev, "Failed to add backlight " 585 "subdev\n"); 586 goto out_dev; 587 } 588 } 589 590 if (pdata && pdata->led) { 591 ret = mfd_add_devices(chip->dev, 0, &led_devs[0], 592 ARRAY_SIZE(led_devs), 593 &led_resources[0], 0); 594 if (ret < 0) { 595 dev_err(chip->dev, "Failed to add led " 596 "subdev\n"); 597 goto out_dev; 598 } 599 } 600 return; 601 out_dev: 602 mfd_remove_devices(chip->dev); 603 device_irq_exit(chip); 604 } 605 606 static void __devinit device_8607_init(struct pm860x_chip *chip, 607 struct i2c_client *i2c, 608 struct pm860x_platform_data *pdata) 609 { 610 int data, ret; 611 612 ret = pm860x_reg_read(i2c, PM8607_CHIP_ID); 613 if (ret < 0) { 614 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret); 615 goto out; 616 } 617 if ((ret & PM8607_VERSION_MASK) == PM8607_VERSION) 618 dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected\n", 619 ret); 620 else { 621 dev_err(chip->dev, "Failed to detect Marvell 88PM8607. " 622 "Chip ID: %02x\n", ret); 623 goto out; 624 } 625 626 ret = pm860x_reg_read(i2c, PM8607_BUCK3); 627 if (ret < 0) { 628 dev_err(chip->dev, "Failed to read BUCK3 register: %d\n", ret); 629 goto out; 630 } 631 if (ret & PM8607_BUCK3_DOUBLE) 632 chip->buck3_double = 1; 633 634 ret = pm860x_reg_read(i2c, PM8607_B0_MISC1); 635 if (ret < 0) { 636 dev_err(chip->dev, "Failed to read MISC1 register: %d\n", ret); 637 goto out; 638 } 639 640 if (pdata && (pdata->i2c_port == PI2C_PORT)) 641 data = PM8607_B0_MISC1_PI2C; 642 else 643 data = 0; 644 ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data); 645 if (ret < 0) { 646 dev_err(chip->dev, "Failed to access MISC1:%d\n", ret); 647 goto out; 648 } 649 650 ret = device_gpadc_init(chip, pdata); 651 if (ret < 0) 652 goto out; 653 654 ret = device_irq_init(chip, pdata); 655 if (ret < 0) 656 goto out; 657 658 ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], 659 ARRAY_SIZE(regulator_devs), 660 ®ulator_resources[0], 0); 661 if (ret < 0) { 662 dev_err(chip->dev, "Failed to add regulator subdev\n"); 663 goto out_dev; 664 } 665 666 if (pdata && pdata->touch) { 667 ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], 668 ARRAY_SIZE(touch_devs), 669 &touch_resources[0], 0); 670 if (ret < 0) { 671 dev_err(chip->dev, "Failed to add touch " 672 "subdev\n"); 673 goto out_dev; 674 } 675 } 676 677 if (pdata && pdata->power) { 678 ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 679 ARRAY_SIZE(power_devs), 680 &power_supply_resources[0], 0); 681 if (ret < 0) { 682 dev_err(chip->dev, "Failed to add power supply " 683 "subdev\n"); 684 goto out_dev; 685 } 686 } 687 688 ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], 689 ARRAY_SIZE(onkey_devs), 690 &onkey_resources[0], 0); 691 if (ret < 0) { 692 dev_err(chip->dev, "Failed to add onkey subdev\n"); 693 goto out_dev; 694 } 695 696 return; 697 out_dev: 698 mfd_remove_devices(chip->dev); 699 device_irq_exit(chip); 700 out: 701 return; 702 } 703 704 int pm860x_device_init(struct pm860x_chip *chip, 705 struct pm860x_platform_data *pdata) 706 { 707 chip->core_irq = 0; 708 709 switch (chip->id) { 710 case CHIP_PM8606: 711 device_8606_init(chip, chip->client, pdata); 712 break; 713 case CHIP_PM8607: 714 device_8607_init(chip, chip->client, pdata); 715 break; 716 } 717 718 if (chip->companion) { 719 switch (chip->id) { 720 case CHIP_PM8607: 721 device_8606_init(chip, chip->companion, pdata); 722 break; 723 case CHIP_PM8606: 724 device_8607_init(chip, chip->companion, pdata); 725 break; 726 } 727 } 728 729 return 0; 730 } 731 732 void pm860x_device_exit(struct pm860x_chip *chip) 733 { 734 device_irq_exit(chip); 735 mfd_remove_devices(chip->dev); 736 } 737 738 MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); 739 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); 740 MODULE_LICENSE("GPL"); 741