Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: Add lp8788 mfd driver

TI LP8788 PMU provides regulators, battery charger, ADC,
RTC, backlight driver and current sinks.

This MFD patch supports the I2C communication using the regmap,
the interrupt handling using the linear IRQ domain and
configurable platform data structures for each driver module.

(Driver Architecture)

< mfd devices >
LP8788 HW .......... mfd .......... regulator drivers
I2C power supply driver
IRQs iio adc driver
rtc driver
backlight driver
current sink drivers

o regulators : LDOs and BUCKs
o power supply : Battery charger
o iio adc : Battery voltage/temperature
o rtc : RTC and alarm
o backlight
o current sink : LED and vibrator

All MFD device modules are registered by LP8788 MFD core driver.
For sharing information such like the virtual IRQ number,
MFD core driver uses the resource structure.
Then each module can retrieve the specific IRQ number and detect it
in the IRQ thread.

Configurable platform data is handled in each driver module.

Signed-off-by: Milo(Woogyom) Kim <milo.kim@ti.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Milo Kim and committed by
Samuel Ortiz
eea6b7cc 804971ec

+871
+10
drivers/mfd/Kconfig
··· 440 440 individual components like LCD backlight, LEDs, GPIOs and Kepad 441 441 under the corresponding menus. 442 442 443 + config MFD_LP8788 444 + bool "Texas Instruments LP8788 Power Management Unit Driver" 445 + depends on I2C=y 446 + select MFD_CORE 447 + select REGMAP_I2C 448 + select IRQ_DOMAIN 449 + help 450 + TI LP8788 PMU supports regulators, battery charger, RTC, 451 + ADC, backlight driver and current sinks. 452 + 443 453 config MFD_MAX77686 444 454 bool "Maxim Semiconductor MAX77686 PMIC Support" 445 455 depends on I2C=y && GENERIC_HARDIRQS
+2
drivers/mfd/Makefile
··· 89 89 obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o 90 90 obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o 91 91 92 + obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o 93 + 92 94 obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o 93 95 obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o 94 96 obj-$(CONFIG_MFD_MAX8907) += max8907.o
+198
drivers/mfd/lp8788-irq.c
··· 1 + /* 2 + * TI LP8788 MFD - interrupt handler 3 + * 4 + * Copyright 2012 Texas Instruments 5 + * 6 + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + 14 + #include <linux/delay.h> 15 + #include <linux/err.h> 16 + #include <linux/interrupt.h> 17 + #include <linux/irq.h> 18 + #include <linux/irqdomain.h> 19 + #include <linux/device.h> 20 + #include <linux/mfd/lp8788.h> 21 + #include <linux/module.h> 22 + #include <linux/slab.h> 23 + 24 + /* register address */ 25 + #define LP8788_INT_1 0x00 26 + #define LP8788_INTEN_1 0x03 27 + 28 + #define BASE_INTEN_ADDR LP8788_INTEN_1 29 + #define SIZE_REG 8 30 + #define NUM_REGS 3 31 + 32 + /* 33 + * struct lp8788_irq_data 34 + * @lp : used for accessing to lp8788 registers 35 + * @irq_lock : mutex for enabling/disabling the interrupt 36 + * @domain : IRQ domain for handling nested interrupt 37 + * @enabled : status of enabled interrupt 38 + */ 39 + struct lp8788_irq_data { 40 + struct lp8788 *lp; 41 + struct mutex irq_lock; 42 + struct irq_domain *domain; 43 + int enabled[LP8788_INT_MAX]; 44 + }; 45 + 46 + static inline u8 _irq_to_addr(enum lp8788_int_id id) 47 + { 48 + return id / SIZE_REG; 49 + } 50 + 51 + static inline u8 _irq_to_enable_addr(enum lp8788_int_id id) 52 + { 53 + return _irq_to_addr(id) + BASE_INTEN_ADDR; 54 + } 55 + 56 + static inline u8 _irq_to_mask(enum lp8788_int_id id) 57 + { 58 + return 1 << (id % SIZE_REG); 59 + } 60 + 61 + static inline u8 _irq_to_val(enum lp8788_int_id id, int enable) 62 + { 63 + return enable << (id % SIZE_REG); 64 + } 65 + 66 + static void lp8788_irq_enable(struct irq_data *data) 67 + { 68 + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); 69 + irqd->enabled[data->hwirq] = 1; 70 + } 71 + 72 + static void lp8788_irq_disable(struct irq_data *data) 73 + { 74 + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); 75 + irqd->enabled[data->hwirq] = 0; 76 + } 77 + 78 + static void lp8788_irq_bus_lock(struct irq_data *data) 79 + { 80 + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); 81 + 82 + mutex_lock(&irqd->irq_lock); 83 + } 84 + 85 + static void lp8788_irq_bus_sync_unlock(struct irq_data *data) 86 + { 87 + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); 88 + enum lp8788_int_id irq = data->hwirq; 89 + u8 addr, mask, val; 90 + 91 + addr = _irq_to_enable_addr(irq); 92 + mask = _irq_to_mask(irq); 93 + val = _irq_to_val(irq, irqd->enabled[irq]); 94 + 95 + lp8788_update_bits(irqd->lp, addr, mask, val); 96 + 97 + mutex_unlock(&irqd->irq_lock); 98 + } 99 + 100 + static struct irq_chip lp8788_irq_chip = { 101 + .name = "lp8788", 102 + .irq_enable = lp8788_irq_enable, 103 + .irq_disable = lp8788_irq_disable, 104 + .irq_bus_lock = lp8788_irq_bus_lock, 105 + .irq_bus_sync_unlock = lp8788_irq_bus_sync_unlock, 106 + }; 107 + 108 + static irqreturn_t lp8788_irq_handler(int irq, void *ptr) 109 + { 110 + struct lp8788_irq_data *irqd = ptr; 111 + struct lp8788 *lp = irqd->lp; 112 + u8 status[NUM_REGS], addr, mask; 113 + bool handled; 114 + int i; 115 + 116 + if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS)) 117 + return IRQ_NONE; 118 + 119 + for (i = 0 ; i < LP8788_INT_MAX ; i++) { 120 + addr = _irq_to_addr(i); 121 + mask = _irq_to_mask(i); 122 + 123 + /* reporting only if the irq is enabled */ 124 + if (status[addr] & mask) { 125 + handle_nested_irq(irq_find_mapping(irqd->domain, i)); 126 + handled = true; 127 + } 128 + } 129 + 130 + return handled ? IRQ_HANDLED : IRQ_NONE; 131 + } 132 + 133 + static int lp8788_irq_map(struct irq_domain *d, unsigned int virq, 134 + irq_hw_number_t hwirq) 135 + { 136 + struct lp8788_irq_data *irqd = d->host_data; 137 + struct irq_chip *chip = &lp8788_irq_chip; 138 + 139 + irq_set_chip_data(virq, irqd); 140 + irq_set_chip_and_handler(virq, chip, handle_edge_irq); 141 + irq_set_nested_thread(virq, 1); 142 + 143 + #ifdef CONFIG_ARM 144 + set_irq_flags(virq, IRQF_VALID); 145 + #else 146 + irq_set_noprobe(virq); 147 + #endif 148 + 149 + return 0; 150 + } 151 + 152 + static struct irq_domain_ops lp8788_domain_ops = { 153 + .map = lp8788_irq_map, 154 + }; 155 + 156 + int lp8788_irq_init(struct lp8788 *lp, int irq) 157 + { 158 + struct lp8788_irq_data *irqd; 159 + int ret; 160 + 161 + if (irq <= 0) { 162 + dev_warn(lp->dev, "invalid irq number: %d\n", irq); 163 + return 0; 164 + } 165 + 166 + irqd = devm_kzalloc(lp->dev, sizeof(*irqd), GFP_KERNEL); 167 + if (!irqd) 168 + return -ENOMEM; 169 + 170 + irqd->lp = lp; 171 + irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX, 172 + &lp8788_domain_ops, irqd); 173 + if (!irqd->domain) { 174 + dev_err(lp->dev, "failed to add irq domain err\n"); 175 + return -EINVAL; 176 + } 177 + 178 + lp->irqdm = irqd->domain; 179 + mutex_init(&irqd->irq_lock); 180 + 181 + ret = request_threaded_irq(irq, NULL, lp8788_irq_handler, 182 + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 183 + "lp8788-irq", irqd); 184 + if (ret) { 185 + dev_err(lp->dev, "failed to create a thread for IRQ_N\n"); 186 + return ret; 187 + } 188 + 189 + lp->irq = irq; 190 + 191 + return 0; 192 + } 193 + 194 + void lp8788_irq_exit(struct lp8788 *lp) 195 + { 196 + if (lp->irq) 197 + free_irq(lp->irq, lp->irqdm); 198 + }
+245
drivers/mfd/lp8788.c
··· 1 + /* 2 + * TI LP8788 MFD - core interface 3 + * 4 + * Copyright 2012 Texas Instruments 5 + * 6 + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + 14 + #include <linux/err.h> 15 + #include <linux/i2c.h> 16 + #include <linux/mfd/core.h> 17 + #include <linux/mfd/lp8788.h> 18 + #include <linux/module.h> 19 + #include <linux/slab.h> 20 + 21 + #define MAX_LP8788_REGISTERS 0xA2 22 + 23 + #define MFD_DEV_SIMPLE(_name) \ 24 + { \ 25 + .name = LP8788_DEV_##_name, \ 26 + } 27 + 28 + #define MFD_DEV_WITH_ID(_name, _id) \ 29 + { \ 30 + .name = LP8788_DEV_##_name, \ 31 + .id = _id, \ 32 + } 33 + 34 + #define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \ 35 + { \ 36 + .name = LP8788_DEV_##_name, \ 37 + .resources = _resource, \ 38 + .num_resources = num_resource, \ 39 + } 40 + 41 + static struct resource chg_irqs[] = { 42 + /* Charger Interrupts */ 43 + { 44 + .start = LP8788_INT_CHG_INPUT_STATE, 45 + .end = LP8788_INT_PRECHG_TIMEOUT, 46 + .name = LP8788_CHG_IRQ, 47 + .flags = IORESOURCE_IRQ, 48 + }, 49 + /* Power Routing Switch Interrupts */ 50 + { 51 + .start = LP8788_INT_ENTER_SYS_SUPPORT, 52 + .end = LP8788_INT_EXIT_SYS_SUPPORT, 53 + .name = LP8788_PRSW_IRQ, 54 + .flags = IORESOURCE_IRQ, 55 + }, 56 + /* Battery Interrupts */ 57 + { 58 + .start = LP8788_INT_BATT_LOW, 59 + .end = LP8788_INT_NO_BATT, 60 + .name = LP8788_BATT_IRQ, 61 + .flags = IORESOURCE_IRQ, 62 + }, 63 + }; 64 + 65 + static struct resource rtc_irqs[] = { 66 + { 67 + .start = LP8788_INT_RTC_ALARM1, 68 + .end = LP8788_INT_RTC_ALARM2, 69 + .name = LP8788_ALM_IRQ, 70 + .flags = IORESOURCE_IRQ, 71 + }, 72 + }; 73 + 74 + static struct mfd_cell lp8788_devs[] = { 75 + /* 4 bucks */ 76 + MFD_DEV_WITH_ID(BUCK, 1), 77 + MFD_DEV_WITH_ID(BUCK, 2), 78 + MFD_DEV_WITH_ID(BUCK, 3), 79 + MFD_DEV_WITH_ID(BUCK, 4), 80 + 81 + /* 12 digital ldos */ 82 + MFD_DEV_WITH_ID(DLDO, 1), 83 + MFD_DEV_WITH_ID(DLDO, 2), 84 + MFD_DEV_WITH_ID(DLDO, 3), 85 + MFD_DEV_WITH_ID(DLDO, 4), 86 + MFD_DEV_WITH_ID(DLDO, 5), 87 + MFD_DEV_WITH_ID(DLDO, 6), 88 + MFD_DEV_WITH_ID(DLDO, 7), 89 + MFD_DEV_WITH_ID(DLDO, 8), 90 + MFD_DEV_WITH_ID(DLDO, 9), 91 + MFD_DEV_WITH_ID(DLDO, 10), 92 + MFD_DEV_WITH_ID(DLDO, 11), 93 + MFD_DEV_WITH_ID(DLDO, 12), 94 + 95 + /* 10 analog ldos */ 96 + MFD_DEV_WITH_ID(ALDO, 1), 97 + MFD_DEV_WITH_ID(ALDO, 2), 98 + MFD_DEV_WITH_ID(ALDO, 3), 99 + MFD_DEV_WITH_ID(ALDO, 4), 100 + MFD_DEV_WITH_ID(ALDO, 5), 101 + MFD_DEV_WITH_ID(ALDO, 6), 102 + MFD_DEV_WITH_ID(ALDO, 7), 103 + MFD_DEV_WITH_ID(ALDO, 8), 104 + MFD_DEV_WITH_ID(ALDO, 9), 105 + MFD_DEV_WITH_ID(ALDO, 10), 106 + 107 + /* ADC */ 108 + MFD_DEV_SIMPLE(ADC), 109 + 110 + /* battery charger */ 111 + MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)), 112 + 113 + /* rtc */ 114 + MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)), 115 + 116 + /* backlight */ 117 + MFD_DEV_SIMPLE(BACKLIGHT), 118 + 119 + /* current sink for vibrator */ 120 + MFD_DEV_SIMPLE(VIBRATOR), 121 + 122 + /* current sink for keypad LED */ 123 + MFD_DEV_SIMPLE(KEYLED), 124 + }; 125 + 126 + int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data) 127 + { 128 + int ret; 129 + unsigned int val; 130 + 131 + ret = regmap_read(lp->regmap, reg, &val); 132 + if (ret < 0) { 133 + dev_err(lp->dev, "failed to read 0x%.2x\n", reg); 134 + return ret; 135 + } 136 + 137 + *data = (u8)val; 138 + return 0; 139 + } 140 + EXPORT_SYMBOL_GPL(lp8788_read_byte); 141 + 142 + int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count) 143 + { 144 + return regmap_bulk_read(lp->regmap, reg, data, count); 145 + } 146 + EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes); 147 + 148 + int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data) 149 + { 150 + return regmap_write(lp->regmap, reg, data); 151 + } 152 + EXPORT_SYMBOL_GPL(lp8788_write_byte); 153 + 154 + int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data) 155 + { 156 + return regmap_update_bits(lp->regmap, reg, mask, data); 157 + } 158 + EXPORT_SYMBOL_GPL(lp8788_update_bits); 159 + 160 + static int lp8788_platform_init(struct lp8788 *lp) 161 + { 162 + struct lp8788_platform_data *pdata = lp->pdata; 163 + 164 + return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0; 165 + } 166 + 167 + static const struct regmap_config lp8788_regmap_config = { 168 + .reg_bits = 8, 169 + .val_bits = 8, 170 + .max_register = MAX_LP8788_REGISTERS, 171 + }; 172 + 173 + static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) 174 + { 175 + struct lp8788 *lp; 176 + struct lp8788_platform_data *pdata = cl->dev.platform_data; 177 + int ret; 178 + 179 + lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); 180 + if (!lp) 181 + return -ENOMEM; 182 + 183 + lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config); 184 + if (IS_ERR(lp->regmap)) { 185 + ret = PTR_ERR(lp->regmap); 186 + dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); 187 + return ret; 188 + } 189 + 190 + lp->pdata = pdata; 191 + lp->dev = &cl->dev; 192 + i2c_set_clientdata(cl, lp); 193 + 194 + ret = lp8788_platform_init(lp); 195 + if (ret) 196 + return ret; 197 + 198 + ret = lp8788_irq_init(lp, cl->irq); 199 + if (ret) 200 + return ret; 201 + 202 + return mfd_add_devices(lp->dev, -1, lp8788_devs, 203 + ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); 204 + } 205 + 206 + static int __devexit lp8788_remove(struct i2c_client *cl) 207 + { 208 + struct lp8788 *lp = i2c_get_clientdata(cl); 209 + 210 + mfd_remove_devices(lp->dev); 211 + lp8788_irq_exit(lp); 212 + return 0; 213 + } 214 + 215 + static const struct i2c_device_id lp8788_ids[] = { 216 + {"lp8788", 0}, 217 + { } 218 + }; 219 + MODULE_DEVICE_TABLE(i2c, lp8788_ids); 220 + 221 + static struct i2c_driver lp8788_driver = { 222 + .driver = { 223 + .name = "lp8788", 224 + .owner = THIS_MODULE, 225 + }, 226 + .probe = lp8788_probe, 227 + .remove = __devexit_p(lp8788_remove), 228 + .id_table = lp8788_ids, 229 + }; 230 + 231 + static int __init lp8788_init(void) 232 + { 233 + return i2c_add_driver(&lp8788_driver); 234 + } 235 + subsys_initcall(lp8788_init); 236 + 237 + static void __exit lp8788_exit(void) 238 + { 239 + i2c_del_driver(&lp8788_driver); 240 + } 241 + module_exit(lp8788_exit); 242 + 243 + MODULE_DESCRIPTION("TI LP8788 MFD Driver"); 244 + MODULE_AUTHOR("Milo Kim"); 245 + MODULE_LICENSE("GPL");
+52
include/linux/mfd/lp8788-isink.h
··· 1 + /* 2 + * TI LP8788 MFD - common definitions for current sinks 3 + * 4 + * Copyright 2012 Texas Instruments 5 + * 6 + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + 14 + #ifndef __ISINK_LP8788_H__ 15 + #define __ISINK_LP8788_H__ 16 + 17 + /* register address */ 18 + #define LP8788_ISINK_CTRL 0x99 19 + #define LP8788_ISINK12_IOUT 0x9A 20 + #define LP8788_ISINK3_IOUT 0x9B 21 + #define LP8788_ISINK1_PWM 0x9C 22 + #define LP8788_ISINK2_PWM 0x9D 23 + #define LP8788_ISINK3_PWM 0x9E 24 + 25 + /* mask bits */ 26 + #define LP8788_ISINK1_IOUT_M 0x0F /* Addr 9Ah */ 27 + #define LP8788_ISINK2_IOUT_M 0xF0 28 + #define LP8788_ISINK3_IOUT_M 0x0F /* Addr 9Bh */ 29 + 30 + /* 6 bits used for PWM code : Addr 9C ~ 9Eh */ 31 + #define LP8788_ISINK_MAX_PWM 63 32 + #define LP8788_ISINK_SCALE_OFFSET 3 33 + 34 + static const u8 lp8788_iout_addr[] = { 35 + LP8788_ISINK12_IOUT, 36 + LP8788_ISINK12_IOUT, 37 + LP8788_ISINK3_IOUT, 38 + }; 39 + 40 + static const u8 lp8788_iout_mask[] = { 41 + LP8788_ISINK1_IOUT_M, 42 + LP8788_ISINK2_IOUT_M, 43 + LP8788_ISINK3_IOUT_M, 44 + }; 45 + 46 + static const u8 lp8788_pwm_addr[] = { 47 + LP8788_ISINK1_PWM, 48 + LP8788_ISINK2_PWM, 49 + LP8788_ISINK3_PWM, 50 + }; 51 + 52 + #endif
+364
include/linux/mfd/lp8788.h
··· 1 + /* 2 + * TI LP8788 MFD Device 3 + * 4 + * Copyright 2012 Texas Instruments 5 + * 6 + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + 14 + #ifndef __MFD_LP8788_H__ 15 + #define __MFD_LP8788_H__ 16 + 17 + #include <linux/gpio.h> 18 + #include <linux/irqdomain.h> 19 + #include <linux/regmap.h> 20 + 21 + #define LP8788_DEV_BUCK "lp8788-buck" 22 + #define LP8788_DEV_DLDO "lp8788-dldo" 23 + #define LP8788_DEV_ALDO "lp8788-aldo" 24 + #define LP8788_DEV_CHARGER "lp8788-charger" 25 + #define LP8788_DEV_RTC "lp8788-rtc" 26 + #define LP8788_DEV_BACKLIGHT "lp8788-backlight" 27 + #define LP8788_DEV_VIBRATOR "lp8788-vibrator" 28 + #define LP8788_DEV_KEYLED "lp8788-keyled" 29 + #define LP8788_DEV_ADC "lp8788-adc" 30 + 31 + #define LP8788_NUM_BUCKS 4 32 + #define LP8788_NUM_DLDOS 12 33 + #define LP8788_NUM_ALDOS 10 34 + #define LP8788_NUM_BUCK2_DVS 2 35 + 36 + #define LP8788_CHG_IRQ "CHG_IRQ" 37 + #define LP8788_PRSW_IRQ "PRSW_IRQ" 38 + #define LP8788_BATT_IRQ "BATT_IRQ" 39 + #define LP8788_ALM_IRQ "ALARM_IRQ" 40 + 41 + enum lp8788_int_id { 42 + /* interrup register 1 : Addr 00h */ 43 + LP8788_INT_TSDL, 44 + LP8788_INT_TSDH, 45 + LP8788_INT_UVLO, 46 + LP8788_INT_FLAGMON, 47 + LP8788_INT_PWRON_TIME, 48 + LP8788_INT_PWRON, 49 + LP8788_INT_COMP1, 50 + LP8788_INT_COMP2, 51 + 52 + /* interrupt register 2 : Addr 01h */ 53 + LP8788_INT_CHG_INPUT_STATE, 54 + LP8788_INT_CHG_STATE, 55 + LP8788_INT_EOC, 56 + LP8788_INT_CHG_RESTART, 57 + LP8788_INT_RESTART_TIMEOUT, 58 + LP8788_INT_FULLCHG_TIMEOUT, 59 + LP8788_INT_PRECHG_TIMEOUT, 60 + 61 + /* interrupt register 3 : Addr 02h */ 62 + LP8788_INT_RTC_ALARM1 = 17, 63 + LP8788_INT_RTC_ALARM2, 64 + LP8788_INT_ENTER_SYS_SUPPORT, 65 + LP8788_INT_EXIT_SYS_SUPPORT, 66 + LP8788_INT_BATT_LOW, 67 + LP8788_INT_NO_BATT, 68 + 69 + LP8788_INT_MAX = 24, 70 + }; 71 + 72 + enum lp8788_dvs_sel { 73 + DVS_SEL_V0, 74 + DVS_SEL_V1, 75 + DVS_SEL_V2, 76 + DVS_SEL_V3, 77 + }; 78 + 79 + enum lp8788_ext_ldo_en_id { 80 + EN_ALDO1, 81 + EN_ALDO234, 82 + EN_ALDO5, 83 + EN_ALDO7, 84 + EN_DLDO7, 85 + EN_DLDO911, 86 + EN_LDOS_MAX, 87 + }; 88 + 89 + enum lp8788_charger_event { 90 + NO_CHARGER, 91 + CHARGER_DETECTED, 92 + }; 93 + 94 + enum lp8788_bl_ctrl_mode { 95 + LP8788_BL_REGISTER_ONLY, 96 + LP8788_BL_COMB_PWM_BASED, /* PWM + I2C, changed by PWM input */ 97 + LP8788_BL_COMB_REGISTER_BASED, /* PWM + I2C, changed by I2C */ 98 + }; 99 + 100 + enum lp8788_bl_dim_mode { 101 + LP8788_DIM_EXPONENTIAL, 102 + LP8788_DIM_LINEAR, 103 + }; 104 + 105 + enum lp8788_bl_full_scale_current { 106 + LP8788_FULLSCALE_5000uA, 107 + LP8788_FULLSCALE_8500uA, 108 + LP8788_FULLSCALE_1200uA, 109 + LP8788_FULLSCALE_1550uA, 110 + LP8788_FULLSCALE_1900uA, 111 + LP8788_FULLSCALE_2250uA, 112 + LP8788_FULLSCALE_2600uA, 113 + LP8788_FULLSCALE_2950uA, 114 + }; 115 + 116 + enum lp8788_bl_ramp_step { 117 + LP8788_RAMP_8us, 118 + LP8788_RAMP_1024us, 119 + LP8788_RAMP_2048us, 120 + LP8788_RAMP_4096us, 121 + LP8788_RAMP_8192us, 122 + LP8788_RAMP_16384us, 123 + LP8788_RAMP_32768us, 124 + LP8788_RAMP_65538us, 125 + }; 126 + 127 + enum lp8788_bl_pwm_polarity { 128 + LP8788_PWM_ACTIVE_HIGH, 129 + LP8788_PWM_ACTIVE_LOW, 130 + }; 131 + 132 + enum lp8788_isink_scale { 133 + LP8788_ISINK_SCALE_100mA, 134 + LP8788_ISINK_SCALE_120mA, 135 + }; 136 + 137 + enum lp8788_isink_number { 138 + LP8788_ISINK_1, 139 + LP8788_ISINK_2, 140 + LP8788_ISINK_3, 141 + }; 142 + 143 + enum lp8788_alarm_sel { 144 + LP8788_ALARM_1, 145 + LP8788_ALARM_2, 146 + LP8788_ALARM_MAX, 147 + }; 148 + 149 + enum lp8788_adc_id { 150 + LPADC_VBATT_5P5, 151 + LPADC_VIN_CHG, 152 + LPADC_IBATT, 153 + LPADC_IC_TEMP, 154 + LPADC_VBATT_6P0, 155 + LPADC_VBATT_5P0, 156 + LPADC_ADC1, 157 + LPADC_ADC2, 158 + LPADC_VDD, 159 + LPADC_VCOIN, 160 + LPADC_VDD_LDO, 161 + LPADC_ADC3, 162 + LPADC_ADC4, 163 + LPADC_MAX, 164 + }; 165 + 166 + struct lp8788; 167 + 168 + /* 169 + * lp8788_buck1_dvs 170 + * @gpio : gpio pin number for dvs control 171 + * @vsel : dvs selector for buck v1 register 172 + */ 173 + struct lp8788_buck1_dvs { 174 + int gpio; 175 + enum lp8788_dvs_sel vsel; 176 + }; 177 + 178 + /* 179 + * lp8788_buck2_dvs 180 + * @gpio : two gpio pin numbers are used for dvs 181 + * @vsel : dvs selector for buck v2 register 182 + */ 183 + struct lp8788_buck2_dvs { 184 + int gpio[LP8788_NUM_BUCK2_DVS]; 185 + enum lp8788_dvs_sel vsel; 186 + }; 187 + 188 + /* 189 + * struct lp8788_ldo_enable_pin 190 + * 191 + * Basically, all LDOs are enabled through the I2C commands. 192 + * But ALDO 1 ~ 5, 7, DLDO 7, 9, 11 can be enabled by external gpio pins. 193 + * 194 + * @gpio : gpio number which is used for enabling ldos 195 + * @init_state : initial gpio state (ex. GPIOF_OUT_INIT_LOW) 196 + */ 197 + struct lp8788_ldo_enable_pin { 198 + int gpio; 199 + int init_state; 200 + }; 201 + 202 + /* 203 + * struct lp8788_chg_param 204 + * @addr : charging control register address (range : 0x11 ~ 0x1C) 205 + * @val : charging parameter value 206 + */ 207 + struct lp8788_chg_param { 208 + u8 addr; 209 + u8 val; 210 + }; 211 + 212 + /* 213 + * struct lp8788_charger_platform_data 214 + * @vbatt_adc : adc selection id for battery voltage 215 + * @batt_temp_adc : adc selection id for battery temperature 216 + * @max_vbatt_mv : used for calculating battery capacity 217 + * @chg_params : initial charging parameters 218 + * @num_chg_params : numbers of charging parameters 219 + * @charger_event : the charger event can be reported to the platform side 220 + */ 221 + struct lp8788_charger_platform_data { 222 + enum lp8788_adc_id vbatt_adc; 223 + enum lp8788_adc_id batt_temp_adc; 224 + unsigned int max_vbatt_mv; 225 + struct lp8788_chg_param *chg_params; 226 + int num_chg_params; 227 + void (*charger_event) (struct lp8788 *lp, 228 + enum lp8788_charger_event event); 229 + }; 230 + 231 + /* 232 + * struct lp8788_bl_pwm_data 233 + * @pwm_set_intensity : set duty of pwm 234 + * @pwm_get_intensity : get current duty of pwm 235 + */ 236 + struct lp8788_bl_pwm_data { 237 + void (*pwm_set_intensity) (int brightness, int max_brightness); 238 + int (*pwm_get_intensity) (int max_brightness); 239 + }; 240 + 241 + /* 242 + * struct lp8788_backlight_platform_data 243 + * @name : backlight driver name. (default: "lcd-backlight") 244 + * @initial_brightness : initial value of backlight brightness 245 + * @bl_mode : brightness control by pwm or lp8788 register 246 + * @dim_mode : dimming mode selection 247 + * @full_scale : full scale current setting 248 + * @rise_time : brightness ramp up step time 249 + * @fall_time : brightness ramp down step time 250 + * @pwm_pol : pwm polarity setting when bl_mode is pwm based 251 + * @pwm_data : platform specific pwm generation functions 252 + * only valid when bl_mode is pwm based 253 + */ 254 + struct lp8788_backlight_platform_data { 255 + char *name; 256 + int initial_brightness; 257 + enum lp8788_bl_ctrl_mode bl_mode; 258 + enum lp8788_bl_dim_mode dim_mode; 259 + enum lp8788_bl_full_scale_current full_scale; 260 + enum lp8788_bl_ramp_step rise_time; 261 + enum lp8788_bl_ramp_step fall_time; 262 + enum lp8788_bl_pwm_polarity pwm_pol; 263 + struct lp8788_bl_pwm_data pwm_data; 264 + }; 265 + 266 + /* 267 + * struct lp8788_led_platform_data 268 + * @name : led driver name. (default: "keyboard-backlight") 269 + * @scale : current scale 270 + * @num : current sink number 271 + * @iout_code : current output value (Addr 9Ah ~ 9Bh) 272 + */ 273 + struct lp8788_led_platform_data { 274 + char *name; 275 + enum lp8788_isink_scale scale; 276 + enum lp8788_isink_number num; 277 + int iout_code; 278 + }; 279 + 280 + /* 281 + * struct lp8788_vib_platform_data 282 + * @name : vibrator driver name 283 + * @scale : current scale 284 + * @num : current sink number 285 + * @iout_code : current output value (Addr 9Ah ~ 9Bh) 286 + * @pwm_code : PWM code value (Addr 9Ch ~ 9Eh) 287 + */ 288 + struct lp8788_vib_platform_data { 289 + char *name; 290 + enum lp8788_isink_scale scale; 291 + enum lp8788_isink_number num; 292 + int iout_code; 293 + int pwm_code; 294 + }; 295 + 296 + /* 297 + * struct lp8788_platform_data 298 + * @init_func : used for initializing registers 299 + * before mfd driver is registered 300 + * @buck_data : regulator initial data for buck 301 + * @dldo_data : regulator initial data for digital ldo 302 + * @aldo_data : regulator initial data for analog ldo 303 + * @buck1_dvs : gpio configurations for buck1 dvs 304 + * @buck2_dvs : gpio configurations for buck2 dvs 305 + * @ldo_pin : gpio configurations for enabling LDOs 306 + * @chg_pdata : platform data for charger driver 307 + * @alarm_sel : rtc alarm selection (1 or 2) 308 + * @bl_pdata : configurable data for backlight driver 309 + * @led_pdata : configurable data for led driver 310 + * @vib_pdata : configurable data for vibrator driver 311 + * @adc_pdata : iio map data for adc driver 312 + */ 313 + struct lp8788_platform_data { 314 + /* general system information */ 315 + int (*init_func) (struct lp8788 *lp); 316 + 317 + /* regulators */ 318 + struct regulator_init_data *buck_data[LP8788_NUM_BUCKS]; 319 + struct regulator_init_data *dldo_data[LP8788_NUM_DLDOS]; 320 + struct regulator_init_data *aldo_data[LP8788_NUM_ALDOS]; 321 + struct lp8788_buck1_dvs *buck1_dvs; 322 + struct lp8788_buck2_dvs *buck2_dvs; 323 + struct lp8788_ldo_enable_pin *ldo_pin[EN_LDOS_MAX]; 324 + 325 + /* charger */ 326 + struct lp8788_charger_platform_data *chg_pdata; 327 + 328 + /* rtc alarm */ 329 + enum lp8788_alarm_sel alarm_sel; 330 + 331 + /* backlight */ 332 + struct lp8788_backlight_platform_data *bl_pdata; 333 + 334 + /* current sinks */ 335 + struct lp8788_led_platform_data *led_pdata; 336 + struct lp8788_vib_platform_data *vib_pdata; 337 + 338 + /* adc iio map data */ 339 + struct iio_map *adc_pdata; 340 + }; 341 + 342 + /* 343 + * struct lp8788 344 + * @dev : parent device pointer 345 + * @regmap : used for i2c communcation on accessing registers 346 + * @irqdm : interrupt domain for handling nested interrupt 347 + * @irq : pin number of IRQ_N 348 + * @pdata : lp8788 platform specific data 349 + */ 350 + struct lp8788 { 351 + struct device *dev; 352 + struct regmap *regmap; 353 + struct irq_domain *irqdm; 354 + int irq; 355 + struct lp8788_platform_data *pdata; 356 + }; 357 + 358 + int lp8788_irq_init(struct lp8788 *lp, int chip_irq); 359 + void lp8788_irq_exit(struct lp8788 *lp); 360 + int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data); 361 + int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count); 362 + int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data); 363 + int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data); 364 + #endif