1 // SPDX-License-Identifier: GPL-2.0-only
3 * TI LP8788 MFD - core interface
5 * Copyright 2012 Texas Instruments
7 * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
10 #include <linux/err.h>
11 #include <linux/i2c.h>
12 #include <linux/mfd/core.h>
13 #include <linux/mfd/lp8788.h>
14 #include <linux/module.h>
15 #include <linux/slab.h>
17 #define MAX_LP8788_REGISTERS 0xA2
19 #define MFD_DEV_SIMPLE(_name) \
21 .name = LP8788_DEV_##_name, \
24 #define MFD_DEV_WITH_ID(_name, _id) \
26 .name = LP8788_DEV_##_name, \
30 #define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \
32 .name = LP8788_DEV_##_name, \
33 .resources = _resource, \
34 .num_resources = num_resource, \
37 static const struct resource chg_irqs
[] = {
38 /* Charger Interrupts */
40 .start
= LP8788_INT_CHG_INPUT_STATE
,
41 .end
= LP8788_INT_PRECHG_TIMEOUT
,
42 .name
= LP8788_CHG_IRQ
,
43 .flags
= IORESOURCE_IRQ
,
45 /* Power Routing Switch Interrupts */
47 .start
= LP8788_INT_ENTER_SYS_SUPPORT
,
48 .end
= LP8788_INT_EXIT_SYS_SUPPORT
,
49 .name
= LP8788_PRSW_IRQ
,
50 .flags
= IORESOURCE_IRQ
,
52 /* Battery Interrupts */
54 .start
= LP8788_INT_BATT_LOW
,
55 .end
= LP8788_INT_NO_BATT
,
56 .name
= LP8788_BATT_IRQ
,
57 .flags
= IORESOURCE_IRQ
,
61 static const struct resource rtc_irqs
[] = {
63 .start
= LP8788_INT_RTC_ALARM1
,
64 .end
= LP8788_INT_RTC_ALARM2
,
65 .name
= LP8788_ALM_IRQ
,
66 .flags
= IORESOURCE_IRQ
,
70 static const struct mfd_cell lp8788_devs
[] = {
72 MFD_DEV_WITH_ID(BUCK
, 1),
73 MFD_DEV_WITH_ID(BUCK
, 2),
74 MFD_DEV_WITH_ID(BUCK
, 3),
75 MFD_DEV_WITH_ID(BUCK
, 4),
78 MFD_DEV_WITH_ID(DLDO
, 1),
79 MFD_DEV_WITH_ID(DLDO
, 2),
80 MFD_DEV_WITH_ID(DLDO
, 3),
81 MFD_DEV_WITH_ID(DLDO
, 4),
82 MFD_DEV_WITH_ID(DLDO
, 5),
83 MFD_DEV_WITH_ID(DLDO
, 6),
84 MFD_DEV_WITH_ID(DLDO
, 7),
85 MFD_DEV_WITH_ID(DLDO
, 8),
86 MFD_DEV_WITH_ID(DLDO
, 9),
87 MFD_DEV_WITH_ID(DLDO
, 10),
88 MFD_DEV_WITH_ID(DLDO
, 11),
89 MFD_DEV_WITH_ID(DLDO
, 12),
92 MFD_DEV_WITH_ID(ALDO
, 1),
93 MFD_DEV_WITH_ID(ALDO
, 2),
94 MFD_DEV_WITH_ID(ALDO
, 3),
95 MFD_DEV_WITH_ID(ALDO
, 4),
96 MFD_DEV_WITH_ID(ALDO
, 5),
97 MFD_DEV_WITH_ID(ALDO
, 6),
98 MFD_DEV_WITH_ID(ALDO
, 7),
99 MFD_DEV_WITH_ID(ALDO
, 8),
100 MFD_DEV_WITH_ID(ALDO
, 9),
101 MFD_DEV_WITH_ID(ALDO
, 10),
106 /* battery charger */
107 MFD_DEV_WITH_RESOURCE(CHARGER
, chg_irqs
, ARRAY_SIZE(chg_irqs
)),
110 MFD_DEV_WITH_RESOURCE(RTC
, rtc_irqs
, ARRAY_SIZE(rtc_irqs
)),
113 MFD_DEV_SIMPLE(BACKLIGHT
),
115 /* current sink for vibrator */
116 MFD_DEV_SIMPLE(VIBRATOR
),
118 /* current sink for keypad LED */
119 MFD_DEV_SIMPLE(KEYLED
),
122 int lp8788_read_byte(struct lp8788
*lp
, u8 reg
, u8
*data
)
127 ret
= regmap_read(lp
->regmap
, reg
, &val
);
129 dev_err(lp
->dev
, "failed to read 0x%.2x\n", reg
);
136 EXPORT_SYMBOL_GPL(lp8788_read_byte
);
138 int lp8788_read_multi_bytes(struct lp8788
*lp
, u8 reg
, u8
*data
, size_t count
)
140 return regmap_bulk_read(lp
->regmap
, reg
, data
, count
);
142 EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes
);
144 int lp8788_write_byte(struct lp8788
*lp
, u8 reg
, u8 data
)
146 return regmap_write(lp
->regmap
, reg
, data
);
148 EXPORT_SYMBOL_GPL(lp8788_write_byte
);
150 int lp8788_update_bits(struct lp8788
*lp
, u8 reg
, u8 mask
, u8 data
)
152 return regmap_update_bits(lp
->regmap
, reg
, mask
, data
);
154 EXPORT_SYMBOL_GPL(lp8788_update_bits
);
156 static int lp8788_platform_init(struct lp8788
*lp
)
158 struct lp8788_platform_data
*pdata
= lp
->pdata
;
160 return (pdata
&& pdata
->init_func
) ? pdata
->init_func(lp
) : 0;
163 static const struct regmap_config lp8788_regmap_config
= {
166 .max_register
= MAX_LP8788_REGISTERS
,
169 static int lp8788_probe(struct i2c_client
*cl
)
172 struct lp8788_platform_data
*pdata
= dev_get_platdata(&cl
->dev
);
175 lp
= devm_kzalloc(&cl
->dev
, sizeof(struct lp8788
), GFP_KERNEL
);
179 lp
->regmap
= devm_regmap_init_i2c(cl
, &lp8788_regmap_config
);
180 if (IS_ERR(lp
->regmap
)) {
181 ret
= PTR_ERR(lp
->regmap
);
182 dev_err(&cl
->dev
, "regmap init i2c err: %d\n", ret
);
188 i2c_set_clientdata(cl
, lp
);
190 ret
= lp8788_platform_init(lp
);
194 ret
= lp8788_irq_init(lp
, cl
->irq
);
198 ret
= mfd_add_devices(lp
->dev
, -1, lp8788_devs
,
199 ARRAY_SIZE(lp8788_devs
), NULL
, 0, NULL
);
210 static void lp8788_remove(struct i2c_client
*cl
)
212 struct lp8788
*lp
= i2c_get_clientdata(cl
);
214 mfd_remove_devices(lp
->dev
);
218 static const struct i2c_device_id lp8788_ids
[] = {
222 MODULE_DEVICE_TABLE(i2c
, lp8788_ids
);
224 static struct i2c_driver lp8788_driver
= {
228 .probe
= lp8788_probe
,
229 .remove
= lp8788_remove
,
230 .id_table
= lp8788_ids
,
233 static int __init
lp8788_init(void)
235 return i2c_add_driver(&lp8788_driver
);
237 subsys_initcall(lp8788_init
);
239 static void __exit
lp8788_exit(void)
241 i2c_del_driver(&lp8788_driver
);
243 module_exit(lp8788_exit
);
245 MODULE_DESCRIPTION("TI LP8788 MFD Driver");
246 MODULE_AUTHOR("Milo Kim");