Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lp8788.c
Go to the documentation of this file.
1 /*
2  * TI LP8788 MFD - core interface
3  *
4  * Copyright 2012 Texas Instruments
5  *
6  * Author: Milo(Woogyom) Kim <[email protected]>
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  {
46  .name = LP8788_CHG_IRQ,
47  .flags = IORESOURCE_IRQ,
48  },
49  /* Power Routing Switch Interrupts */
50  {
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 */
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 
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 }
141 
143 {
144  return regmap_bulk_read(lp->regmap, reg, data, count);
145 }
147 
149 {
150  return regmap_write(lp->regmap, reg, data);
151 }
153 
155 {
156  return regmap_update_bits(lp->regmap, reg, mask, data);
157 }
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");