123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /*
- * TI LP8788 MFD - core interface
- *
- * Copyright 2012 Texas Instruments
- *
- * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
- #include <linux/err.h>
- #include <linux/i2c.h>
- #include <linux/mfd/core.h>
- #include <linux/mfd/lp8788.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #define MAX_LP8788_REGISTERS 0xA2
- #define MFD_DEV_SIMPLE(_name) \
- { \
- .name = LP8788_DEV_##_name, \
- }
- #define MFD_DEV_WITH_ID(_name, _id) \
- { \
- .name = LP8788_DEV_##_name, \
- .id = _id, \
- }
- #define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \
- { \
- .name = LP8788_DEV_##_name, \
- .resources = _resource, \
- .num_resources = num_resource, \
- }
- static struct resource chg_irqs[] = {
- /* Charger Interrupts */
- {
- .start = LP8788_INT_CHG_INPUT_STATE,
- .end = LP8788_INT_PRECHG_TIMEOUT,
- .name = LP8788_CHG_IRQ,
- .flags = IORESOURCE_IRQ,
- },
- /* Power Routing Switch Interrupts */
- {
- .start = LP8788_INT_ENTER_SYS_SUPPORT,
- .end = LP8788_INT_EXIT_SYS_SUPPORT,
- .name = LP8788_PRSW_IRQ,
- .flags = IORESOURCE_IRQ,
- },
- /* Battery Interrupts */
- {
- .start = LP8788_INT_BATT_LOW,
- .end = LP8788_INT_NO_BATT,
- .name = LP8788_BATT_IRQ,
- .flags = IORESOURCE_IRQ,
- },
- };
- static struct resource rtc_irqs[] = {
- {
- .start = LP8788_INT_RTC_ALARM1,
- .end = LP8788_INT_RTC_ALARM2,
- .name = LP8788_ALM_IRQ,
- .flags = IORESOURCE_IRQ,
- },
- };
- static const struct mfd_cell lp8788_devs[] = {
- /* 4 bucks */
- MFD_DEV_WITH_ID(BUCK, 1),
- MFD_DEV_WITH_ID(BUCK, 2),
- MFD_DEV_WITH_ID(BUCK, 3),
- MFD_DEV_WITH_ID(BUCK, 4),
- /* 12 digital ldos */
- MFD_DEV_WITH_ID(DLDO, 1),
- MFD_DEV_WITH_ID(DLDO, 2),
- MFD_DEV_WITH_ID(DLDO, 3),
- MFD_DEV_WITH_ID(DLDO, 4),
- MFD_DEV_WITH_ID(DLDO, 5),
- MFD_DEV_WITH_ID(DLDO, 6),
- MFD_DEV_WITH_ID(DLDO, 7),
- MFD_DEV_WITH_ID(DLDO, 8),
- MFD_DEV_WITH_ID(DLDO, 9),
- MFD_DEV_WITH_ID(DLDO, 10),
- MFD_DEV_WITH_ID(DLDO, 11),
- MFD_DEV_WITH_ID(DLDO, 12),
- /* 10 analog ldos */
- MFD_DEV_WITH_ID(ALDO, 1),
- MFD_DEV_WITH_ID(ALDO, 2),
- MFD_DEV_WITH_ID(ALDO, 3),
- MFD_DEV_WITH_ID(ALDO, 4),
- MFD_DEV_WITH_ID(ALDO, 5),
- MFD_DEV_WITH_ID(ALDO, 6),
- MFD_DEV_WITH_ID(ALDO, 7),
- MFD_DEV_WITH_ID(ALDO, 8),
- MFD_DEV_WITH_ID(ALDO, 9),
- MFD_DEV_WITH_ID(ALDO, 10),
- /* ADC */
- MFD_DEV_SIMPLE(ADC),
- /* battery charger */
- MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)),
- /* rtc */
- MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)),
- /* backlight */
- MFD_DEV_SIMPLE(BACKLIGHT),
- /* current sink for vibrator */
- MFD_DEV_SIMPLE(VIBRATOR),
- /* current sink for keypad LED */
- MFD_DEV_SIMPLE(KEYLED),
- };
- int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data)
- {
- int ret;
- unsigned int val;
- ret = regmap_read(lp->regmap, reg, &val);
- if (ret < 0) {
- dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
- return ret;
- }
- *data = (u8)val;
- return 0;
- }
- EXPORT_SYMBOL_GPL(lp8788_read_byte);
- int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count)
- {
- return regmap_bulk_read(lp->regmap, reg, data, count);
- }
- EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes);
- int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data)
- {
- return regmap_write(lp->regmap, reg, data);
- }
- EXPORT_SYMBOL_GPL(lp8788_write_byte);
- int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data)
- {
- return regmap_update_bits(lp->regmap, reg, mask, data);
- }
- EXPORT_SYMBOL_GPL(lp8788_update_bits);
- static int lp8788_platform_init(struct lp8788 *lp)
- {
- struct lp8788_platform_data *pdata = lp->pdata;
- return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0;
- }
- static const struct regmap_config lp8788_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = MAX_LP8788_REGISTERS,
- };
- static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
- {
- struct lp8788 *lp;
- struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev);
- int ret;
- lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL);
- if (!lp)
- return -ENOMEM;
- lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config);
- if (IS_ERR(lp->regmap)) {
- ret = PTR_ERR(lp->regmap);
- dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
- return ret;
- }
- lp->pdata = pdata;
- lp->dev = &cl->dev;
- i2c_set_clientdata(cl, lp);
- ret = lp8788_platform_init(lp);
- if (ret)
- return ret;
- ret = lp8788_irq_init(lp, cl->irq);
- if (ret)
- return ret;
- return mfd_add_devices(lp->dev, -1, lp8788_devs,
- ARRAY_SIZE(lp8788_devs), NULL, 0, NULL);
- }
- static int lp8788_remove(struct i2c_client *cl)
- {
- struct lp8788 *lp = i2c_get_clientdata(cl);
- mfd_remove_devices(lp->dev);
- lp8788_irq_exit(lp);
- return 0;
- }
- static const struct i2c_device_id lp8788_ids[] = {
- {"lp8788", 0},
- { }
- };
- MODULE_DEVICE_TABLE(i2c, lp8788_ids);
- static struct i2c_driver lp8788_driver = {
- .driver = {
- .name = "lp8788",
- },
- .probe = lp8788_probe,
- .remove = lp8788_remove,
- .id_table = lp8788_ids,
- };
- static int __init lp8788_init(void)
- {
- return i2c_add_driver(&lp8788_driver);
- }
- subsys_initcall(lp8788_init);
- static void __exit lp8788_exit(void)
- {
- i2c_del_driver(&lp8788_driver);
- }
- module_exit(lp8788_exit);
- MODULE_DESCRIPTION("TI LP8788 MFD Driver");
- MODULE_AUTHOR("Milo Kim");
- MODULE_LICENSE("GPL");
|