aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/max8907c.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/mfd/max8907c.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/mfd/max8907c.c')
-rw-r--r--drivers/mfd/max8907c.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c
new file mode 100644
index 00000000000..d03dbced21e
--- /dev/null
+++ b/drivers/mfd/max8907c.c
@@ -0,0 +1,376 @@
1/*
2 * max8907c.c - mfd driver for MAX8907c
3 *
4 * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/init.h>
13#include <linux/slab.h>
14#include <linux/i2c.h>
15#include <linux/mfd/core.h>
16#include <linux/mfd/max8907c.h>
17
18static struct mfd_cell cells[] = {
19 {.name = "max8907-regulator",},
20 {.name = "max8907c-rtc",},
21};
22
23static int max8907c_i2c_read(struct i2c_client *i2c, u8 reg, u8 count, u8 *dest)
24{
25 struct i2c_msg xfer[2];
26 int ret = 0;
27
28 xfer[0].addr = i2c->addr;
29 xfer[0].flags = I2C_M_NOSTART;
30 xfer[0].len = 1;
31 xfer[0].buf = &reg;
32
33 xfer[1].addr = i2c->addr;
34 xfer[1].flags = I2C_M_RD;
35 xfer[1].len = count;
36 xfer[1].buf = dest;
37
38 ret = i2c_transfer(i2c->adapter, xfer, 2);
39 if (ret < 0)
40 return ret;
41 if (ret != 2)
42 return -EIO;
43
44 return 0;
45}
46
47static int max8907c_i2c_write(struct i2c_client *i2c, u8 reg, u8 count, const u8 *src)
48{
49 u8 msg[0x100 + 1];
50 int ret = 0;
51
52 msg[0] = reg;
53 memcpy(&msg[1], src, count);
54
55 ret = i2c_master_send(i2c, msg, count + 1);
56 if (ret < 0)
57 return ret;
58 if (ret != count + 1)
59 return -EIO;
60
61 return 0;
62}
63
64int max8907c_reg_read(struct i2c_client *i2c, u8 reg)
65{
66 int ret;
67 u8 val;
68
69 ret = max8907c_i2c_read(i2c, reg, 1, &val);
70
71 pr_debug("max8907c: reg read reg=%x, val=%x\n",
72 (unsigned int)reg, (unsigned int)val);
73
74 if (ret != 0)
75 pr_err("Failed to read max8907c I2C driver: %d\n", ret);
76 return val;
77}
78EXPORT_SYMBOL_GPL(max8907c_reg_read);
79
80int max8907c_reg_bulk_read(struct i2c_client *i2c, u8 reg, u8 count, u8 *val)
81{
82 int ret;
83
84 ret = max8907c_i2c_read(i2c, reg, count, val);
85
86 pr_debug("max8907c: reg read reg=%x, val=%x\n",
87 (unsigned int)reg, (unsigned int)*val);
88
89 if (ret != 0)
90 pr_err("Failed to read max8907c I2C driver: %d\n", ret);
91 return ret;
92}
93EXPORT_SYMBOL_GPL(max8907c_reg_bulk_read);
94
95int max8907c_reg_write(struct i2c_client *i2c, u8 reg, u8 val)
96{
97 struct max8907c *max8907c = i2c_get_clientdata(i2c);
98 int ret;
99
100 pr_debug("max8907c: reg write reg=%x, val=%x\n",
101 (unsigned int)reg, (unsigned int)val);
102
103 mutex_lock(&max8907c->io_lock);
104 ret = max8907c_i2c_write(i2c, reg, 1, &val);
105 mutex_unlock(&max8907c->io_lock);
106
107 if (ret != 0)
108 pr_err("Failed to write max8907c I2C driver: %d\n", ret);
109 return ret;
110}
111EXPORT_SYMBOL_GPL(max8907c_reg_write);
112
113int max8907c_reg_bulk_write(struct i2c_client *i2c, u8 reg, u8 count, u8 *val)
114{
115 struct max8907c *max8907c = i2c_get_clientdata(i2c);
116 int ret;
117
118 pr_debug("max8907c: reg write reg=%x, val=%x\n",
119 (unsigned int)reg, (unsigned int)*val);
120
121 mutex_lock(&max8907c->io_lock);
122 ret = max8907c_i2c_write(i2c, reg, count, val);
123 mutex_unlock(&max8907c->io_lock);
124
125 if (ret != 0)
126 pr_err("Failed to write max8907c I2C driver: %d\n", ret);
127 return ret;
128}
129EXPORT_SYMBOL_GPL(max8907c_reg_bulk_write);
130
131int max8907c_set_bits(struct i2c_client *i2c, u8 reg, u8 mask, u8 val)
132{
133 struct max8907c *max8907c = i2c_get_clientdata(i2c);
134 u8 tmp;
135 int ret;
136
137 pr_debug("max8907c: reg write reg=%02X, val=%02X, mask=%02X\n",
138 (unsigned int)reg, (unsigned int)val, (unsigned int)mask);
139
140 mutex_lock(&max8907c->io_lock);
141 ret = max8907c_i2c_read(i2c, reg, 1, &tmp);
142 if (ret == 0) {
143 val = (tmp & ~mask) | (val & mask);
144 ret = max8907c_i2c_write(i2c, reg, 1, &val);
145 }
146 mutex_unlock(&max8907c->io_lock);
147
148 if (ret != 0)
149 pr_err("Failed to write max8907c I2C driver: %d\n", ret);
150 return ret;
151}
152EXPORT_SYMBOL_GPL(max8907c_set_bits);
153
154static struct i2c_client *max8907c_client = NULL;
155static void max8907c_power_off(void)
156{
157 if (!max8907c_client)
158 return;
159
160 max8907c_set_bits(max8907c_client, MAX8907C_REG_RESET_CNFG,
161 MAX8907C_MASK_POWER_OFF, 0x40);
162}
163
164void max8907c_deep_sleep(int enter)
165{
166 if (!max8907c_client)
167 return;
168
169 if (enter) {
170 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1,
171 MAX8907C_POWER_UP_DELAY_CNT12);
172 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT2,
173 MAX8907C_DELAY_CNT0);
174 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDCTL2,
175 MAX8907C_SD_SEQ2);
176 } else {
177 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1,
178 MAX8907C_DELAY_CNT0);
179 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDCTL2,
180 MAX8907C_SD_SEQ1);
181 max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT2,
182 MAX8907C_POWER_UP_DELAY_CNT1 | MAX8907C_POWER_DOWN_DELAY_CNT12);
183 }
184}
185
186static int max8907c_remove_subdev(struct device *dev, void *unused)
187{
188 platform_device_unregister(to_platform_device(dev));
189 return 0;
190}
191
192static int max8907c_remove_subdevs(struct max8907c *max8907c)
193{
194 return device_for_each_child(max8907c->dev, NULL,
195 max8907c_remove_subdev);
196}
197
198static int max8097c_add_subdevs(struct max8907c *max8907c,
199 struct max8907c_platform_data *pdata)
200{
201 struct platform_device *pdev;
202 int ret;
203 int i;
204
205 for (i = 0; i < pdata->num_subdevs; i++) {
206 pdev = platform_device_alloc(pdata->subdevs[i]->name,
207 pdata->subdevs[i]->id);
208
209 pdev->dev.parent = max8907c->dev;
210 pdev->dev.platform_data = pdata->subdevs[i]->dev.platform_data;
211
212 ret = platform_device_add(pdev);
213 if (ret)
214 goto error;
215 }
216 return 0;
217
218error:
219 max8907c_remove_subdevs(max8907c);
220 return ret;
221}
222
223int max8907c_pwr_en_config(void)
224{
225 int ret;
226 u8 data;
227
228 if (!max8907c_client)
229 return -EINVAL;
230
231 /*
232 * Enable/disable PWREN h/w control mechanism (PWREN signal must be
233 * inactive = high at this time)
234 */
235 ret = max8907c_set_bits(max8907c_client, MAX8907C_REG_RESET_CNFG,
236 MAX8907C_MASK_PWR_EN, MAX8907C_PWR_EN);
237 if (ret != 0)
238 return ret;
239
240 /*
241 * When enabled, connect PWREN to SEQ2 by clearing SEQ2 configuration
242 * settings for silicon revision that requires s/w WAR. On other
243 * MAX8907B revisions PWREN is always connected to SEQ2.
244 */
245 data = max8907c_reg_read(max8907c_client, MAX8907C_REG_II2RR);
246
247 if (data == MAX8907B_II2RR_PWREN_WAR) {
248 data = 0x00;
249 ret = max8907c_reg_write(max8907c_client, MAX8907C_REG_SEQ2CNFG, data);
250 }
251 return ret;
252}
253
254int max8907c_pwr_en_attach(void)
255{
256 int ret;
257
258 if (!max8907c_client)
259 return -EINVAL;
260
261 /* No sequencer delay for CPU rail when it is attached */
262 ret = max8907c_reg_write(max8907c_client, MAX8907C_REG_SDSEQCNT1,
263 MAX8907C_DELAY_CNT0);
264 if (ret != 0)
265 return ret;
266
267 return max8907c_set_bits(max8907c_client, MAX8907C_REG_SDCTL1,
268 MAX8907C_MASK_CTL_SEQ, MAX8907C_CTL_SEQ);
269}
270
271static int max8907c_i2c_probe(struct i2c_client *i2c,
272 const struct i2c_device_id *id)
273{
274 struct max8907c *max8907c;
275 struct max8907c_platform_data *pdata = i2c->dev.platform_data;
276 int ret;
277 int i;
278
279 max8907c = kzalloc(sizeof(struct max8907c), GFP_KERNEL);
280 if (max8907c == NULL)
281 return -ENOMEM;
282
283 max8907c->dev = &i2c->dev;
284 dev_set_drvdata(max8907c->dev, max8907c);
285
286 max8907c->i2c_power = i2c;
287 i2c_set_clientdata(i2c, max8907c);
288
289 max8907c->i2c_rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
290 i2c_set_clientdata(max8907c->i2c_rtc, max8907c);
291
292 mutex_init(&max8907c->io_lock);
293
294 for (i = 0; i < ARRAY_SIZE(cells); i++) {
295 cells[i].platform_data = max8907c;
296 cells[i].pdata_size = sizeof(*max8907c);
297 }
298 ret = mfd_add_devices(max8907c->dev, -1, cells, ARRAY_SIZE(cells),
299 NULL, 0);
300 if (ret != 0) {
301 i2c_unregister_device(max8907c->i2c_rtc);
302 kfree(max8907c);
303 pr_debug("max8907c: failed to add MFD devices %X\n", ret);
304 return ret;
305 }
306
307 max8907c_client = i2c;
308
309 max8907c_irq_init(max8907c, i2c->irq, pdata->irq_base);
310
311 ret = max8097c_add_subdevs(max8907c, pdata);
312
313 if (pdata->use_power_off && !pm_power_off)
314 pm_power_off = max8907c_power_off;
315
316 if (pdata->max8907c_setup)
317 return pdata->max8907c_setup();
318
319 return ret;
320}
321
322static int max8907c_i2c_remove(struct i2c_client *i2c)
323{
324 struct max8907c *max8907c = i2c_get_clientdata(i2c);
325
326 max8907c_remove_subdevs(max8907c);
327 i2c_unregister_device(max8907c->i2c_rtc);
328 mfd_remove_devices(max8907c->dev);
329 max8907c_irq_free(max8907c);
330 kfree(max8907c);
331
332 return 0;
333}
334
335static const struct i2c_device_id max8907c_i2c_id[] = {
336 {"max8907c", 0},
337 {}
338};
339
340MODULE_DEVICE_TABLE(i2c, max8907c_i2c_id);
341
342static struct i2c_driver max8907c_i2c_driver = {
343 .driver = {
344 .name = "max8907c",
345 .owner = THIS_MODULE,
346 },
347 .probe = max8907c_i2c_probe,
348 .remove = max8907c_i2c_remove,
349 .suspend = max8907c_suspend,
350 .resume = max8907c_resume,
351 .id_table = max8907c_i2c_id,
352};
353
354static int __init max8907c_i2c_init(void)
355{
356 int ret = -ENODEV;
357
358 ret = i2c_add_driver(&max8907c_i2c_driver);
359 if (ret != 0)
360 pr_err("Failed to register I2C driver: %d\n", ret);
361
362 return ret;
363}
364
365subsys_initcall(max8907c_i2c_init);
366
367static void __exit max8907c_i2c_exit(void)
368{
369 i2c_del_driver(&max8907c_i2c_driver);
370}
371
372module_exit(max8907c_i2c_exit);
373
374MODULE_DESCRIPTION("MAX8907C multi-function core driver");
375MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
376MODULE_LICENSE("GPL");