1d50f8f33SHaojian Zhuang /* 2d50f8f33SHaojian Zhuang * Base driver for Maxim MAX8925 3d50f8f33SHaojian Zhuang * 4d50f8f33SHaojian Zhuang * Copyright (C) 2009 Marvell International Ltd. 5d50f8f33SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@marvell.com> 6d50f8f33SHaojian Zhuang * 7d50f8f33SHaojian Zhuang * This program is free software; you can redistribute it and/or modify 8d50f8f33SHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 9d50f8f33SHaojian Zhuang * published by the Free Software Foundation. 10d50f8f33SHaojian Zhuang */ 11d50f8f33SHaojian Zhuang 12d50f8f33SHaojian Zhuang #include <linux/kernel.h> 13d50f8f33SHaojian Zhuang #include <linux/module.h> 14d50f8f33SHaojian Zhuang #include <linux/i2c.h> 15d50f8f33SHaojian Zhuang #include <linux/interrupt.h> 16d50f8f33SHaojian Zhuang #include <linux/platform_device.h> 17d50f8f33SHaojian Zhuang #include <linux/mfd/core.h> 18d50f8f33SHaojian Zhuang #include <linux/mfd/max8925.h> 19d50f8f33SHaojian Zhuang 20d50f8f33SHaojian Zhuang #define IRQ_MODE_STATUS 0 21d50f8f33SHaojian Zhuang #define IRQ_MODE_MASK 1 22d50f8f33SHaojian Zhuang 231ad99893SHaojian Zhuang static struct resource backlight_resources[] = { 241ad99893SHaojian Zhuang { 251ad99893SHaojian Zhuang .name = "max8925-backlight", 261ad99893SHaojian Zhuang .start = MAX8925_WLED_MODE_CNTL, 271ad99893SHaojian Zhuang .end = MAX8925_WLED_CNTL, 281ad99893SHaojian Zhuang .flags = IORESOURCE_IO, 291ad99893SHaojian Zhuang }, 301ad99893SHaojian Zhuang }; 311ad99893SHaojian Zhuang 321ad99893SHaojian Zhuang static struct mfd_cell backlight_devs[] = { 331ad99893SHaojian Zhuang { 341ad99893SHaojian Zhuang .name = "max8925-backlight", 351ad99893SHaojian Zhuang .num_resources = 1, 361ad99893SHaojian Zhuang .resources = &backlight_resources[0], 371ad99893SHaojian Zhuang .id = -1, 381ad99893SHaojian Zhuang }, 391ad99893SHaojian Zhuang }; 401ad99893SHaojian Zhuang 411ad99893SHaojian Zhuang static struct resource touch_resources[] = { 421ad99893SHaojian Zhuang { 431ad99893SHaojian Zhuang .name = "max8925-tsc", 441ad99893SHaojian Zhuang .start = MAX8925_TSC_IRQ, 451ad99893SHaojian Zhuang .end = MAX8925_ADC_RES_END, 461ad99893SHaojian Zhuang .flags = IORESOURCE_IO, 471ad99893SHaojian Zhuang }, 481ad99893SHaojian Zhuang }; 491ad99893SHaojian Zhuang 501ad99893SHaojian Zhuang static struct mfd_cell touch_devs[] = { 511ad99893SHaojian Zhuang { 521ad99893SHaojian Zhuang .name = "max8925-touch", 531ad99893SHaojian Zhuang .num_resources = 1, 541ad99893SHaojian Zhuang .resources = &touch_resources[0], 551ad99893SHaojian Zhuang .id = -1, 561ad99893SHaojian Zhuang }, 571ad99893SHaojian Zhuang }; 581ad99893SHaojian Zhuang 591ad99893SHaojian Zhuang #define MAX8925_REG_RESOURCE(_start, _end) \ 601ad99893SHaojian Zhuang { \ 611ad99893SHaojian Zhuang .start = MAX8925_##_start, \ 621ad99893SHaojian Zhuang .end = MAX8925_##_end, \ 631ad99893SHaojian Zhuang .flags = IORESOURCE_IO, \ 641ad99893SHaojian Zhuang } 651ad99893SHaojian Zhuang 661ad99893SHaojian Zhuang static struct resource regulator_resources[] = { 671ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(SDCTL1, SDCTL1), 681ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(SDCTL2, SDCTL2), 691ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(SDCTL3, SDCTL3), 701ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1), 711ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2), 721ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3), 731ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4), 741ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5), 751ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6), 761ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7), 771ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8), 781ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9), 791ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10), 801ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11), 811ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12), 821ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13), 831ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14), 841ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15), 851ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16), 861ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17), 871ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18), 881ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19), 891ad99893SHaojian Zhuang MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20), 901ad99893SHaojian Zhuang }; 911ad99893SHaojian Zhuang 921ad99893SHaojian Zhuang #define MAX8925_REG_DEVS(_id) \ 931ad99893SHaojian Zhuang { \ 941ad99893SHaojian Zhuang .name = "max8925-regulator", \ 951ad99893SHaojian Zhuang .num_resources = 1, \ 961ad99893SHaojian Zhuang .resources = ®ulator_resources[MAX8925_ID_##_id], \ 971ad99893SHaojian Zhuang .id = MAX8925_ID_##_id, \ 981ad99893SHaojian Zhuang } 991ad99893SHaojian Zhuang 1001ad99893SHaojian Zhuang static struct mfd_cell regulator_devs[] = { 1011ad99893SHaojian Zhuang MAX8925_REG_DEVS(SD1), 1021ad99893SHaojian Zhuang MAX8925_REG_DEVS(SD2), 1031ad99893SHaojian Zhuang MAX8925_REG_DEVS(SD3), 1041ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO1), 1051ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO2), 1061ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO3), 1071ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO4), 1081ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO5), 1091ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO6), 1101ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO7), 1111ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO8), 1121ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO9), 1131ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO10), 1141ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO11), 1151ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO12), 1161ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO13), 1171ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO14), 1181ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO15), 1191ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO16), 1201ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO17), 1211ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO18), 1221ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO19), 1231ad99893SHaojian Zhuang MAX8925_REG_DEVS(LDO20), 1241ad99893SHaojian Zhuang }; 1251ad99893SHaojian Zhuang 126d50f8f33SHaojian Zhuang static int __get_irq_offset(struct max8925_chip *chip, int irq, int mode, 127d50f8f33SHaojian Zhuang int *offset, int *bit) 128d50f8f33SHaojian Zhuang { 129d50f8f33SHaojian Zhuang if (!offset || !bit) 130d50f8f33SHaojian Zhuang return -EINVAL; 131d50f8f33SHaojian Zhuang 132d50f8f33SHaojian Zhuang switch (chip->chip_id) { 133d50f8f33SHaojian Zhuang case MAX8925_GPM: 134d50f8f33SHaojian Zhuang *bit = irq % BITS_PER_BYTE; 135d50f8f33SHaojian Zhuang if (irq < (BITS_PER_BYTE << 1)) { /* irq = [0,15] */ 136d50f8f33SHaojian Zhuang *offset = (mode) ? MAX8925_CHG_IRQ1_MASK 137d50f8f33SHaojian Zhuang : MAX8925_CHG_IRQ1; 138d50f8f33SHaojian Zhuang if (irq >= BITS_PER_BYTE) 139d50f8f33SHaojian Zhuang (*offset)++; 140d50f8f33SHaojian Zhuang } else { /* irq = [16,31] */ 141d50f8f33SHaojian Zhuang *offset = (mode) ? MAX8925_ON_OFF_IRQ1_MASK 142d50f8f33SHaojian Zhuang : MAX8925_ON_OFF_IRQ1; 143d50f8f33SHaojian Zhuang if (irq >= (BITS_PER_BYTE * 3)) 144d50f8f33SHaojian Zhuang (*offset)++; 145d50f8f33SHaojian Zhuang } 146d50f8f33SHaojian Zhuang break; 147d50f8f33SHaojian Zhuang case MAX8925_ADC: 148d50f8f33SHaojian Zhuang *bit = irq % BITS_PER_BYTE; 149d50f8f33SHaojian Zhuang *offset = (mode) ? MAX8925_TSC_IRQ_MASK : MAX8925_TSC_IRQ; 150d50f8f33SHaojian Zhuang break; 151d50f8f33SHaojian Zhuang default: 152d50f8f33SHaojian Zhuang goto out; 153d50f8f33SHaojian Zhuang } 154d50f8f33SHaojian Zhuang return 0; 155d50f8f33SHaojian Zhuang out: 156d50f8f33SHaojian Zhuang dev_err(chip->dev, "Wrong irq #%d is assigned\n", irq); 157d50f8f33SHaojian Zhuang return -EINVAL; 158d50f8f33SHaojian Zhuang } 159d50f8f33SHaojian Zhuang 160d50f8f33SHaojian Zhuang static int __check_irq(int irq) 161d50f8f33SHaojian Zhuang { 162d50f8f33SHaojian Zhuang if ((irq < 0) || (irq >= MAX8925_NUM_IRQ)) 163d50f8f33SHaojian Zhuang return -EINVAL; 164d50f8f33SHaojian Zhuang return 0; 165d50f8f33SHaojian Zhuang } 166d50f8f33SHaojian Zhuang 167d50f8f33SHaojian Zhuang int max8925_mask_irq(struct max8925_chip *chip, int irq) 168d50f8f33SHaojian Zhuang { 169d50f8f33SHaojian Zhuang int offset, bit, ret; 170d50f8f33SHaojian Zhuang 171d50f8f33SHaojian Zhuang ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); 172d50f8f33SHaojian Zhuang if (ret < 0) 173d50f8f33SHaojian Zhuang return ret; 174d50f8f33SHaojian Zhuang ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 1 << bit); 175d50f8f33SHaojian Zhuang return ret; 176d50f8f33SHaojian Zhuang } 177d50f8f33SHaojian Zhuang 178d50f8f33SHaojian Zhuang int max8925_unmask_irq(struct max8925_chip *chip, int irq) 179d50f8f33SHaojian Zhuang { 180d50f8f33SHaojian Zhuang int offset, bit, ret; 181d50f8f33SHaojian Zhuang 182d50f8f33SHaojian Zhuang ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit); 183d50f8f33SHaojian Zhuang if (ret < 0) 184d50f8f33SHaojian Zhuang return ret; 185d50f8f33SHaojian Zhuang ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 0); 186d50f8f33SHaojian Zhuang return ret; 187d50f8f33SHaojian Zhuang } 188d50f8f33SHaojian Zhuang 189d50f8f33SHaojian Zhuang #define INT_STATUS_NUM (MAX8925_NUM_IRQ / BITS_PER_BYTE) 190d50f8f33SHaojian Zhuang 191d50f8f33SHaojian Zhuang static irqreturn_t max8925_irq_thread(int irq, void *data) 192d50f8f33SHaojian Zhuang { 193d50f8f33SHaojian Zhuang struct max8925_chip *chip = data; 194d50f8f33SHaojian Zhuang unsigned long irq_status[INT_STATUS_NUM]; 195d50f8f33SHaojian Zhuang unsigned char status_buf[INT_STATUS_NUM << 1]; 196d50f8f33SHaojian Zhuang int i, ret; 197d50f8f33SHaojian Zhuang 198d50f8f33SHaojian Zhuang memset(irq_status, 0, sizeof(unsigned long) * INT_STATUS_NUM); 199d50f8f33SHaojian Zhuang 200d50f8f33SHaojian Zhuang /* all these interrupt status registers are read-only */ 201d50f8f33SHaojian Zhuang switch (chip->chip_id) { 202d50f8f33SHaojian Zhuang case MAX8925_GPM: 203d50f8f33SHaojian Zhuang ret = max8925_bulk_read(chip->i2c, MAX8925_CHG_IRQ1, 204d50f8f33SHaojian Zhuang 4, status_buf); 205d50f8f33SHaojian Zhuang if (ret < 0) 206d50f8f33SHaojian Zhuang goto out; 207d50f8f33SHaojian Zhuang ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ1, 208d50f8f33SHaojian Zhuang 2, &status_buf[4]); 209d50f8f33SHaojian Zhuang if (ret < 0) 210d50f8f33SHaojian Zhuang goto out; 211d50f8f33SHaojian Zhuang ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ2, 212d50f8f33SHaojian Zhuang 2, &status_buf[6]); 213d50f8f33SHaojian Zhuang if (ret < 0) 214d50f8f33SHaojian Zhuang goto out; 215d50f8f33SHaojian Zhuang /* clear masked interrupt status */ 216d50f8f33SHaojian Zhuang status_buf[0] &= (~status_buf[2] & CHG_IRQ1_MASK); 217d50f8f33SHaojian Zhuang irq_status[0] |= status_buf[0]; 218d50f8f33SHaojian Zhuang status_buf[1] &= (~status_buf[3] & CHG_IRQ2_MASK); 219d50f8f33SHaojian Zhuang irq_status[0] |= (status_buf[1] << BITS_PER_BYTE); 220d50f8f33SHaojian Zhuang status_buf[4] &= (~status_buf[5] & ON_OFF_IRQ1_MASK); 221d50f8f33SHaojian Zhuang irq_status[0] |= (status_buf[4] << (BITS_PER_BYTE * 2)); 222d50f8f33SHaojian Zhuang status_buf[6] &= (~status_buf[7] & ON_OFF_IRQ2_MASK); 223d50f8f33SHaojian Zhuang irq_status[0] |= (status_buf[6] << (BITS_PER_BYTE * 3)); 224d50f8f33SHaojian Zhuang break; 225d50f8f33SHaojian Zhuang case MAX8925_ADC: 226d50f8f33SHaojian Zhuang ret = max8925_bulk_read(chip->i2c, MAX8925_TSC_IRQ, 227d50f8f33SHaojian Zhuang 2, status_buf); 228d50f8f33SHaojian Zhuang if (ret < 0) 229d50f8f33SHaojian Zhuang goto out; 230d50f8f33SHaojian Zhuang /* clear masked interrupt status */ 231d50f8f33SHaojian Zhuang status_buf[0] &= (~status_buf[1] & TSC_IRQ_MASK); 232d50f8f33SHaojian Zhuang irq_status[0] |= status_buf[0]; 233d50f8f33SHaojian Zhuang break; 234d50f8f33SHaojian Zhuang default: 235d50f8f33SHaojian Zhuang goto out; 236d50f8f33SHaojian Zhuang } 237d50f8f33SHaojian Zhuang 238d50f8f33SHaojian Zhuang for_each_bit(i, &irq_status[0], MAX8925_NUM_IRQ) { 239d50f8f33SHaojian Zhuang clear_bit(i, irq_status); 240d50f8f33SHaojian Zhuang dev_dbg(chip->dev, "Servicing IRQ #%d in %s\n", i, chip->name); 241d50f8f33SHaojian Zhuang 242d50f8f33SHaojian Zhuang mutex_lock(&chip->irq_lock); 243d50f8f33SHaojian Zhuang if (chip->irq[i].handler) 244d50f8f33SHaojian Zhuang chip->irq[i].handler(i, chip->irq[i].data); 245d50f8f33SHaojian Zhuang else { 246d50f8f33SHaojian Zhuang max8925_mask_irq(chip, i); 247d50f8f33SHaojian Zhuang dev_err(chip->dev, "Noboday cares IRQ #%d in %s. " 248d50f8f33SHaojian Zhuang "Now mask it.\n", i, chip->name); 249d50f8f33SHaojian Zhuang } 250d50f8f33SHaojian Zhuang mutex_unlock(&chip->irq_lock); 251d50f8f33SHaojian Zhuang } 252d50f8f33SHaojian Zhuang out: 253d50f8f33SHaojian Zhuang return IRQ_HANDLED; 254d50f8f33SHaojian Zhuang } 255d50f8f33SHaojian Zhuang 256d50f8f33SHaojian Zhuang int max8925_request_irq(struct max8925_chip *chip, int irq, 257d50f8f33SHaojian Zhuang irq_handler_t handler, void *data) 258d50f8f33SHaojian Zhuang { 259d50f8f33SHaojian Zhuang if ((__check_irq(irq) < 0) || !handler) 260d50f8f33SHaojian Zhuang return -EINVAL; 261d50f8f33SHaojian Zhuang 262d50f8f33SHaojian Zhuang mutex_lock(&chip->irq_lock); 263d50f8f33SHaojian Zhuang chip->irq[irq].handler = handler; 264d50f8f33SHaojian Zhuang chip->irq[irq].data = data; 265d50f8f33SHaojian Zhuang mutex_unlock(&chip->irq_lock); 266d50f8f33SHaojian Zhuang return 0; 267d50f8f33SHaojian Zhuang } 268d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_request_irq); 269d50f8f33SHaojian Zhuang 270d50f8f33SHaojian Zhuang int max8925_free_irq(struct max8925_chip *chip, int irq) 271d50f8f33SHaojian Zhuang { 272d50f8f33SHaojian Zhuang if (__check_irq(irq) < 0) 273d50f8f33SHaojian Zhuang return -EINVAL; 274d50f8f33SHaojian Zhuang 275d50f8f33SHaojian Zhuang mutex_lock(&chip->irq_lock); 276d50f8f33SHaojian Zhuang chip->irq[irq].handler = NULL; 277d50f8f33SHaojian Zhuang chip->irq[irq].data = NULL; 278d50f8f33SHaojian Zhuang mutex_unlock(&chip->irq_lock); 279d50f8f33SHaojian Zhuang return 0; 280d50f8f33SHaojian Zhuang } 281d50f8f33SHaojian Zhuang EXPORT_SYMBOL(max8925_free_irq); 282d50f8f33SHaojian Zhuang 283d50f8f33SHaojian Zhuang static int __devinit device_gpm_init(struct max8925_chip *chip, 284d50f8f33SHaojian Zhuang struct i2c_client *i2c, 285d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata) 286d50f8f33SHaojian Zhuang { 287d50f8f33SHaojian Zhuang int ret; 288d50f8f33SHaojian Zhuang 289d50f8f33SHaojian Zhuang /* mask all IRQs */ 290d50f8f33SHaojian Zhuang ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ1_MASK, 0x7, 0x7); 291d50f8f33SHaojian Zhuang if (ret < 0) 292d50f8f33SHaojian Zhuang goto out; 293d50f8f33SHaojian Zhuang ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ2_MASK, 0xff, 0xff); 294d50f8f33SHaojian Zhuang if (ret < 0) 295d50f8f33SHaojian Zhuang goto out; 296d50f8f33SHaojian Zhuang ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff, 0xff); 297d50f8f33SHaojian Zhuang if (ret < 0) 298d50f8f33SHaojian Zhuang goto out; 299d50f8f33SHaojian Zhuang ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ2_MASK, 0x3, 0x3); 300d50f8f33SHaojian Zhuang if (ret < 0) 301d50f8f33SHaojian Zhuang goto out; 302d50f8f33SHaojian Zhuang 303d50f8f33SHaojian Zhuang chip->name = "GPM"; 304d50f8f33SHaojian Zhuang memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); 305d50f8f33SHaojian Zhuang ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, 306d50f8f33SHaojian Zhuang IRQF_ONESHOT | IRQF_TRIGGER_LOW, 307d50f8f33SHaojian Zhuang "max8925-gpm", chip); 308d50f8f33SHaojian Zhuang if (ret < 0) { 309d50f8f33SHaojian Zhuang dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); 310d50f8f33SHaojian Zhuang goto out; 311d50f8f33SHaojian Zhuang } 312d50f8f33SHaojian Zhuang chip->chip_irq = i2c->irq; 313d50f8f33SHaojian Zhuang 314d50f8f33SHaojian Zhuang /* enable hard-reset for ONKEY power-off */ 315d50f8f33SHaojian Zhuang max8925_set_bits(i2c, MAX8925_SYSENSEL, 0x80, 0x80); 3161ad99893SHaojian Zhuang 3171ad99893SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], 3181ad99893SHaojian Zhuang ARRAY_SIZE(regulator_devs), 3191ad99893SHaojian Zhuang ®ulator_resources[0], 0); 3201ad99893SHaojian Zhuang if (ret < 0) { 3211ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add regulator subdev\n"); 3221ad99893SHaojian Zhuang goto out_irq; 3231ad99893SHaojian Zhuang } 3241ad99893SHaojian Zhuang 3251ad99893SHaojian Zhuang if (pdata && pdata->backlight) { 3261ad99893SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], 3271ad99893SHaojian Zhuang ARRAY_SIZE(backlight_devs), 3281ad99893SHaojian Zhuang &backlight_resources[0], 0); 3291ad99893SHaojian Zhuang if (ret < 0) { 3301ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add backlight subdev\n"); 3311ad99893SHaojian Zhuang goto out_dev; 3321ad99893SHaojian Zhuang } 3331ad99893SHaojian Zhuang } 3341ad99893SHaojian Zhuang return 0; 3351ad99893SHaojian Zhuang out_dev: 3361ad99893SHaojian Zhuang mfd_remove_devices(chip->dev); 3371ad99893SHaojian Zhuang out_irq: 3381ad99893SHaojian Zhuang if (chip->chip_irq) 3391ad99893SHaojian Zhuang free_irq(chip->chip_irq, chip); 340d50f8f33SHaojian Zhuang out: 341d50f8f33SHaojian Zhuang return ret; 342d50f8f33SHaojian Zhuang } 343d50f8f33SHaojian Zhuang 344d50f8f33SHaojian Zhuang static int __devinit device_adc_init(struct max8925_chip *chip, 345d50f8f33SHaojian Zhuang struct i2c_client *i2c, 346d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata) 347d50f8f33SHaojian Zhuang { 348d50f8f33SHaojian Zhuang int ret; 349d50f8f33SHaojian Zhuang 350d50f8f33SHaojian Zhuang /* mask all IRQs */ 351d50f8f33SHaojian Zhuang ret = max8925_set_bits(i2c, MAX8925_TSC_IRQ_MASK, 3, 3); 352d50f8f33SHaojian Zhuang 353d50f8f33SHaojian Zhuang chip->name = "ADC"; 354d50f8f33SHaojian Zhuang memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ); 355d50f8f33SHaojian Zhuang ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread, 356d50f8f33SHaojian Zhuang IRQF_ONESHOT | IRQF_TRIGGER_LOW, 357d50f8f33SHaojian Zhuang "max8925-adc", chip); 358d50f8f33SHaojian Zhuang if (ret < 0) { 359d50f8f33SHaojian Zhuang dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq); 360d50f8f33SHaojian Zhuang goto out; 361d50f8f33SHaojian Zhuang } 362d50f8f33SHaojian Zhuang chip->chip_irq = i2c->irq; 3631ad99893SHaojian Zhuang 3641ad99893SHaojian Zhuang if (pdata && pdata->touch) { 3651ad99893SHaojian Zhuang ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], 3661ad99893SHaojian Zhuang ARRAY_SIZE(touch_devs), 3671ad99893SHaojian Zhuang &touch_resources[0], 0); 3681ad99893SHaojian Zhuang if (ret < 0) { 3691ad99893SHaojian Zhuang dev_err(chip->dev, "Failed to add touch subdev\n"); 3701ad99893SHaojian Zhuang goto out_irq; 3711ad99893SHaojian Zhuang } 3721ad99893SHaojian Zhuang } 3731ad99893SHaojian Zhuang return 0; 3741ad99893SHaojian Zhuang out_irq: 3751ad99893SHaojian Zhuang if (chip->chip_irq) 3761ad99893SHaojian Zhuang free_irq(chip->chip_irq, chip); 377d50f8f33SHaojian Zhuang out: 378d50f8f33SHaojian Zhuang return ret; 379d50f8f33SHaojian Zhuang } 380d50f8f33SHaojian Zhuang 381d50f8f33SHaojian Zhuang int __devinit max8925_device_init(struct max8925_chip *chip, 382d50f8f33SHaojian Zhuang struct max8925_platform_data *pdata) 383d50f8f33SHaojian Zhuang { 384d50f8f33SHaojian Zhuang switch (chip->chip_id) { 385d50f8f33SHaojian Zhuang case MAX8925_GPM: 386d50f8f33SHaojian Zhuang device_gpm_init(chip, chip->i2c, pdata); 387d50f8f33SHaojian Zhuang break; 388d50f8f33SHaojian Zhuang case MAX8925_ADC: 389d50f8f33SHaojian Zhuang device_adc_init(chip, chip->i2c, pdata); 390d50f8f33SHaojian Zhuang break; 391d50f8f33SHaojian Zhuang } 392d50f8f33SHaojian Zhuang return 0; 393d50f8f33SHaojian Zhuang } 394d50f8f33SHaojian Zhuang 395d50f8f33SHaojian Zhuang void max8925_device_exit(struct max8925_chip *chip) 396d50f8f33SHaojian Zhuang { 397d50f8f33SHaojian Zhuang if (chip->chip_irq >= 0) 398d50f8f33SHaojian Zhuang free_irq(chip->chip_irq, chip); 3991ad99893SHaojian Zhuang mfd_remove_devices(chip->dev); 400d50f8f33SHaojian Zhuang } 401d50f8f33SHaojian Zhuang 402d50f8f33SHaojian Zhuang MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925"); 403d50f8f33SHaojian Zhuang MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com"); 404d50f8f33SHaojian Zhuang MODULE_LICENSE("GPL"); 405