0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/err.h>
0011 #include <linux/i2c.h>
0012 #include <linux/mfd/core.h>
0013 #include <linux/mfd/lp8788.h>
0014 #include <linux/module.h>
0015 #include <linux/slab.h>
0016
0017 #define MAX_LP8788_REGISTERS 0xA2
0018
0019 #define MFD_DEV_SIMPLE(_name) \
0020 { \
0021 .name = LP8788_DEV_##_name, \
0022 }
0023
0024 #define MFD_DEV_WITH_ID(_name, _id) \
0025 { \
0026 .name = LP8788_DEV_##_name, \
0027 .id = _id, \
0028 }
0029
0030 #define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \
0031 { \
0032 .name = LP8788_DEV_##_name, \
0033 .resources = _resource, \
0034 .num_resources = num_resource, \
0035 }
0036
0037 static const struct resource chg_irqs[] = {
0038
0039 {
0040 .start = LP8788_INT_CHG_INPUT_STATE,
0041 .end = LP8788_INT_PRECHG_TIMEOUT,
0042 .name = LP8788_CHG_IRQ,
0043 .flags = IORESOURCE_IRQ,
0044 },
0045
0046 {
0047 .start = LP8788_INT_ENTER_SYS_SUPPORT,
0048 .end = LP8788_INT_EXIT_SYS_SUPPORT,
0049 .name = LP8788_PRSW_IRQ,
0050 .flags = IORESOURCE_IRQ,
0051 },
0052
0053 {
0054 .start = LP8788_INT_BATT_LOW,
0055 .end = LP8788_INT_NO_BATT,
0056 .name = LP8788_BATT_IRQ,
0057 .flags = IORESOURCE_IRQ,
0058 },
0059 };
0060
0061 static const struct resource rtc_irqs[] = {
0062 {
0063 .start = LP8788_INT_RTC_ALARM1,
0064 .end = LP8788_INT_RTC_ALARM2,
0065 .name = LP8788_ALM_IRQ,
0066 .flags = IORESOURCE_IRQ,
0067 },
0068 };
0069
0070 static const struct mfd_cell lp8788_devs[] = {
0071
0072 MFD_DEV_WITH_ID(BUCK, 1),
0073 MFD_DEV_WITH_ID(BUCK, 2),
0074 MFD_DEV_WITH_ID(BUCK, 3),
0075 MFD_DEV_WITH_ID(BUCK, 4),
0076
0077
0078 MFD_DEV_WITH_ID(DLDO, 1),
0079 MFD_DEV_WITH_ID(DLDO, 2),
0080 MFD_DEV_WITH_ID(DLDO, 3),
0081 MFD_DEV_WITH_ID(DLDO, 4),
0082 MFD_DEV_WITH_ID(DLDO, 5),
0083 MFD_DEV_WITH_ID(DLDO, 6),
0084 MFD_DEV_WITH_ID(DLDO, 7),
0085 MFD_DEV_WITH_ID(DLDO, 8),
0086 MFD_DEV_WITH_ID(DLDO, 9),
0087 MFD_DEV_WITH_ID(DLDO, 10),
0088 MFD_DEV_WITH_ID(DLDO, 11),
0089 MFD_DEV_WITH_ID(DLDO, 12),
0090
0091
0092 MFD_DEV_WITH_ID(ALDO, 1),
0093 MFD_DEV_WITH_ID(ALDO, 2),
0094 MFD_DEV_WITH_ID(ALDO, 3),
0095 MFD_DEV_WITH_ID(ALDO, 4),
0096 MFD_DEV_WITH_ID(ALDO, 5),
0097 MFD_DEV_WITH_ID(ALDO, 6),
0098 MFD_DEV_WITH_ID(ALDO, 7),
0099 MFD_DEV_WITH_ID(ALDO, 8),
0100 MFD_DEV_WITH_ID(ALDO, 9),
0101 MFD_DEV_WITH_ID(ALDO, 10),
0102
0103
0104 MFD_DEV_SIMPLE(ADC),
0105
0106
0107 MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)),
0108
0109
0110 MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)),
0111
0112
0113 MFD_DEV_SIMPLE(BACKLIGHT),
0114
0115
0116 MFD_DEV_SIMPLE(VIBRATOR),
0117
0118
0119 MFD_DEV_SIMPLE(KEYLED),
0120 };
0121
0122 int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data)
0123 {
0124 int ret;
0125 unsigned int val;
0126
0127 ret = regmap_read(lp->regmap, reg, &val);
0128 if (ret < 0) {
0129 dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
0130 return ret;
0131 }
0132
0133 *data = (u8)val;
0134 return 0;
0135 }
0136 EXPORT_SYMBOL_GPL(lp8788_read_byte);
0137
0138 int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count)
0139 {
0140 return regmap_bulk_read(lp->regmap, reg, data, count);
0141 }
0142 EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes);
0143
0144 int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data)
0145 {
0146 return regmap_write(lp->regmap, reg, data);
0147 }
0148 EXPORT_SYMBOL_GPL(lp8788_write_byte);
0149
0150 int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data)
0151 {
0152 return regmap_update_bits(lp->regmap, reg, mask, data);
0153 }
0154 EXPORT_SYMBOL_GPL(lp8788_update_bits);
0155
0156 static int lp8788_platform_init(struct lp8788 *lp)
0157 {
0158 struct lp8788_platform_data *pdata = lp->pdata;
0159
0160 return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0;
0161 }
0162
0163 static const struct regmap_config lp8788_regmap_config = {
0164 .reg_bits = 8,
0165 .val_bits = 8,
0166 .max_register = MAX_LP8788_REGISTERS,
0167 };
0168
0169 static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
0170 {
0171 struct lp8788 *lp;
0172 struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev);
0173 int ret;
0174
0175 lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL);
0176 if (!lp)
0177 return -ENOMEM;
0178
0179 lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config);
0180 if (IS_ERR(lp->regmap)) {
0181 ret = PTR_ERR(lp->regmap);
0182 dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
0183 return ret;
0184 }
0185
0186 lp->pdata = pdata;
0187 lp->dev = &cl->dev;
0188 i2c_set_clientdata(cl, lp);
0189
0190 ret = lp8788_platform_init(lp);
0191 if (ret)
0192 return ret;
0193
0194 ret = lp8788_irq_init(lp, cl->irq);
0195 if (ret)
0196 return ret;
0197
0198 return mfd_add_devices(lp->dev, -1, lp8788_devs,
0199 ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
0200 }
0201
0202 static int lp8788_remove(struct i2c_client *cl)
0203 {
0204 struct lp8788 *lp = i2c_get_clientdata(cl);
0205
0206 mfd_remove_devices(lp->dev);
0207 lp8788_irq_exit(lp);
0208 return 0;
0209 }
0210
0211 static const struct i2c_device_id lp8788_ids[] = {
0212 {"lp8788", 0},
0213 { }
0214 };
0215 MODULE_DEVICE_TABLE(i2c, lp8788_ids);
0216
0217 static struct i2c_driver lp8788_driver = {
0218 .driver = {
0219 .name = "lp8788",
0220 },
0221 .probe = lp8788_probe,
0222 .remove = lp8788_remove,
0223 .id_table = lp8788_ids,
0224 };
0225
0226 static int __init lp8788_init(void)
0227 {
0228 return i2c_add_driver(&lp8788_driver);
0229 }
0230 subsys_initcall(lp8788_init);
0231
0232 static void __exit lp8788_exit(void)
0233 {
0234 i2c_del_driver(&lp8788_driver);
0235 }
0236 module_exit(lp8788_exit);
0237
0238 MODULE_DESCRIPTION("TI LP8788 MFD Driver");
0239 MODULE_AUTHOR("Milo Kim");
0240 MODULE_LICENSE("GPL");