27e219f1ec894f9651b50bab7a24e87cc3676148
[cascardo/linux.git] / drivers / mfd / s5m-core.c
1 /*
2  * s5m87xx.c
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd
5  *              http://www.samsung.com
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  */
13
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/init.h>
17 #include <linux/err.h>
18 #include <linux/slab.h>
19 #include <linux/i2c.h>
20 #include <linux/interrupt.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/mutex.h>
23 #include <linux/mfd/core.h>
24 #include <linux/mfd/s5m87xx/s5m-core.h>
25 #include <linux/mfd/s5m87xx/s5m-pmic.h>
26 #include <linux/mfd/s5m87xx/s5m-rtc.h>
27 #include <linux/regmap.h>
28
29 #ifdef CONFIG_OF
30 static struct of_device_id __devinitdata s5m87xx_pmic_dt_match[] = {
31         {.compatible = "samsung,s5m8767-pmic"},
32         {},
33 };
34 #endif
35
36 static struct mfd_cell s5m8751_devs[] = {
37         {
38                 .name = "s5m8751-pmic",
39         }, {
40                 .name = "s5m-charger",
41         }, {
42                 .name = "s5m8751-codec",
43         },
44 };
45
46 static struct mfd_cell s5m8763_devs[] = {
47         {
48                 .name = "s5m8763-pmic",
49         }, {
50                 .name = "s5m-rtc",
51         }, {
52                 .name = "s5m-charger",
53         },
54 };
55
56 static struct mfd_cell s5m8767_devs[] = {
57         {
58                 .name = "s5m8767-pmic",
59         }, {
60                 .name = "s5m-rtc",
61         },
62 };
63
64 int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
65 {
66         return regmap_read(s5m87xx->regmap, reg, dest);
67 }
68 EXPORT_SYMBOL_GPL(s5m_reg_read);
69
70 int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
71 {
72         return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);
73 }
74 EXPORT_SYMBOL_GPL(s5m_bulk_read);
75
76 int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
77 {
78         return regmap_write(s5m87xx->regmap, reg, value);
79 }
80 EXPORT_SYMBOL_GPL(s5m_reg_write);
81
82 int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
83 {
84         return regmap_raw_write(s5m87xx->regmap, reg, buf, count);
85 }
86 EXPORT_SYMBOL_GPL(s5m_bulk_write);
87
88 int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
89 {
90         return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
91 }
92 EXPORT_SYMBOL_GPL(s5m_reg_update);
93
94 static struct regmap_config s5m_regmap_config = {
95         .reg_bits = 8,
96         .val_bits = 8,
97 };
98
99 static inline int s5m87xx_i2c_get_driver_data(struct i2c_client *i2c,
100                                                const struct i2c_device_id *id)
101 {
102 #ifdef CONFIG_OF
103         if (i2c->dev.of_node) {
104                 const struct of_device_id *match;
105                 match = of_match_node(s5m87xx_pmic_dt_match, i2c->dev.of_node);
106                 return (int)match->data;
107         }
108 #endif
109         return (int)id->driver_data;
110 }
111
112 #ifdef CONFIG_OF
113 static struct s5m_platform_data *s5m87xx_i2c_parse_dt_pdata(struct device *dev)
114 {
115         struct s5m_platform_data *pd;
116
117         pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
118         if (!pd) {
119                 dev_err(dev, "could not allocate memory for pdata\n");
120                 return ERR_PTR(-ENOMEM);
121         }
122
123         if (of_property_read_u32(dev->of_node, "s5m-core,device_type",
124                                  &pd->device_type)) {
125                 dev_warn(dev, "no OF device_type property");
126         }
127         dev_dbg(dev, "OF device_type property = %u", pd->device_type);
128
129         if (of_get_property(dev->of_node, "s5m-core,enable-low-jitter", NULL)) {
130                 if (!(pd->device_type == S5M8767X))
131                         dev_warn(dev, "no low-jitter for this PMIC type\n");
132                 else
133                         pd->low_jitter = true;
134         }
135         dev_dbg(dev, "OF low-jitter property: %u\n", pd->low_jitter);
136
137         return pd;
138 }
139 #else
140 static struct s5m_platform_data *s5m87xx_i2c_parse_dt_pdata(struct device *dev)
141 {
142         return 0;
143 }
144 #endif
145
146 static int s5m87xx_set_low_jitter(struct s5m87xx_dev *s5m87xx)
147 {
148         if (!s5m87xx->pdata->low_jitter)
149                 return 0;
150
151         return s5m_reg_update(s5m87xx, S5M8767_REG_CTRL1,
152                               S5M8767_LOW_JITTER_MASK,
153                               S5M8767_LOW_JITTER_MASK);
154 }
155
156 static int __devinit s5m87xx_i2c_probe(struct i2c_client *i2c,
157                                        const struct i2c_device_id *id)
158 {
159         struct s5m_platform_data *pdata = i2c->dev.platform_data;
160         struct s5m87xx_dev *s5m87xx;
161         int ret;
162
163         s5m87xx = devm_kzalloc(&i2c->dev, sizeof(struct s5m87xx_dev),
164                                 GFP_KERNEL);
165         if (s5m87xx == NULL)
166                 return -ENOMEM;
167
168         i2c_set_clientdata(i2c, s5m87xx);
169         s5m87xx->dev = &i2c->dev;
170         s5m87xx->i2c = i2c;
171         s5m87xx->irq = i2c->irq;
172         s5m87xx->type = s5m87xx_i2c_get_driver_data(i2c, id);
173
174         if (s5m87xx->dev->of_node) {
175                 pdata = s5m87xx_i2c_parse_dt_pdata(s5m87xx->dev);
176                 if (IS_ERR(pdata)) {
177                         ret = PTR_ERR(pdata);
178                         goto err;
179                 }
180         }
181         s5m87xx->pdata = pdata;
182
183         if (!pdata) {
184                 ret = -ENODEV;
185                 dev_warn(s5m87xx->dev, "No platform data found\n");
186                 goto err;
187         }
188
189         s5m87xx->device_type = pdata->device_type;
190         /* TODO(tbroch): address whether we want this addtional interrupt node
191            and add it to DT parsing if yes.
192         */
193         s5m87xx->ono = pdata->ono;
194         /* TODO(tbroch): remove hack below and parse irq_base via DT */
195         s5m87xx->irq_base = pdata->irq_base = MAX77686_IRQ_BASE;
196 #ifdef OF_CONFIG
197         s5m87xx->wakeup = i2c->flags & I2C_CLIENT_WAKE;
198 #else
199         s5m87xx->wakeup = pdata->wakeup;
200 #endif
201
202         s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
203         if (IS_ERR(s5m87xx->regmap)) {
204                 ret = PTR_ERR(s5m87xx->regmap);
205                 dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
206                         ret);
207                 goto err;
208         }
209
210         s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
211         i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
212
213         if (pdata && pdata->cfg_pmic_irq)
214                 pdata->cfg_pmic_irq();
215
216         s5m_irq_init(s5m87xx);
217
218         pm_runtime_set_active(s5m87xx->dev);
219
220         switch (s5m87xx->device_type) {
221         case S5M8751X:
222                 ret = mfd_add_devices(s5m87xx->dev, -1, s5m8751_devs,
223                                       ARRAY_SIZE(s5m8751_devs), NULL, 0);
224                 break;
225         case S5M8763X:
226                 ret = mfd_add_devices(s5m87xx->dev, -1, s5m8763_devs,
227                                       ARRAY_SIZE(s5m8763_devs), NULL, 0);
228                 break;
229         case S5M8767X:
230                 ret = mfd_add_devices(s5m87xx->dev, -1, s5m8767_devs,
231                                       ARRAY_SIZE(s5m8767_devs), NULL, 0);
232                 break;
233         default:
234                 /* If this happens the probe function is problem */
235                 BUG();
236         }
237
238         if (ret < 0)
239                 goto err;
240
241         if (s5m87xx_set_low_jitter(s5m87xx) < 0) {
242                 dev_err(s5m87xx->dev, "failed to configure low-jitter\n");
243                 ret = -EIO;
244                 goto err;
245         }
246
247         return ret;
248
249 err:
250         mfd_remove_devices(s5m87xx->dev);
251         s5m_irq_exit(s5m87xx);
252         i2c_unregister_device(s5m87xx->rtc);
253         regmap_exit(s5m87xx->regmap);
254         return ret;
255 }
256
257 static int s5m87xx_i2c_remove(struct i2c_client *i2c)
258 {
259         struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
260
261         mfd_remove_devices(s5m87xx->dev);
262         s5m_irq_exit(s5m87xx);
263         i2c_unregister_device(s5m87xx->rtc);
264         regmap_exit(s5m87xx->regmap);
265         return 0;
266 }
267
268 static const struct i2c_device_id s5m87xx_i2c_id[] = {
269         { "s5m87xx", 0 },
270         { }
271 };
272 MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
273
274 static struct i2c_driver s5m87xx_i2c_driver = {
275         .driver = {
276                    .name = "s5m87xx",
277                    .owner = THIS_MODULE,
278                    .of_match_table = of_match_ptr(s5m87xx_pmic_dt_match),
279         },
280         .probe = s5m87xx_i2c_probe,
281         .remove = s5m87xx_i2c_remove,
282         .id_table = s5m87xx_i2c_id,
283 };
284
285 static int __init s5m87xx_i2c_init(void)
286 {
287         return i2c_add_driver(&s5m87xx_i2c_driver);
288 }
289
290 subsys_initcall(s5m87xx_i2c_init);
291
292 static void __exit s5m87xx_i2c_exit(void)
293 {
294         i2c_del_driver(&s5m87xx_i2c_driver);
295 }
296 module_exit(s5m87xx_i2c_exit);
297
298 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
299 MODULE_DESCRIPTION("Core support for the S5M MFD");
300 MODULE_LICENSE("GPL");