Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/mfd/pcf50633-core.c
15111 views
1
/* NXP PCF50633 Power Management Unit (PMU) driver
2
*
3
* (C) 2006-2008 by Openmoko, Inc.
4
* Author: Harald Welte <[email protected]>
5
* Balaji Rao <[email protected]>
6
* All rights reserved.
7
*
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms of the GNU General Public License as published by the
10
* Free Software Foundation; either version 2 of the License, or (at your
11
* option) any later version.
12
*
13
*/
14
15
#include <linux/kernel.h>
16
#include <linux/device.h>
17
#include <linux/sysfs.h>
18
#include <linux/module.h>
19
#include <linux/types.h>
20
#include <linux/interrupt.h>
21
#include <linux/workqueue.h>
22
#include <linux/platform_device.h>
23
#include <linux/i2c.h>
24
#include <linux/pm.h>
25
#include <linux/slab.h>
26
27
#include <linux/mfd/pcf50633/core.h>
28
29
static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
30
{
31
int ret;
32
33
ret = i2c_smbus_read_i2c_block_data(pcf->i2c_client, reg,
34
num, data);
35
if (ret < 0)
36
dev_err(pcf->dev, "Error reading %d regs at %d\n", num, reg);
37
38
return ret;
39
}
40
41
static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data)
42
{
43
int ret;
44
45
ret = i2c_smbus_write_i2c_block_data(pcf->i2c_client, reg,
46
num, data);
47
if (ret < 0)
48
dev_err(pcf->dev, "Error writing %d regs at %d\n", num, reg);
49
50
return ret;
51
52
}
53
54
/* Read a block of up to 32 regs */
55
int pcf50633_read_block(struct pcf50633 *pcf, u8 reg,
56
int nr_regs, u8 *data)
57
{
58
int ret;
59
60
mutex_lock(&pcf->lock);
61
ret = __pcf50633_read(pcf, reg, nr_regs, data);
62
mutex_unlock(&pcf->lock);
63
64
return ret;
65
}
66
EXPORT_SYMBOL_GPL(pcf50633_read_block);
67
68
/* Write a block of up to 32 regs */
69
int pcf50633_write_block(struct pcf50633 *pcf , u8 reg,
70
int nr_regs, u8 *data)
71
{
72
int ret;
73
74
mutex_lock(&pcf->lock);
75
ret = __pcf50633_write(pcf, reg, nr_regs, data);
76
mutex_unlock(&pcf->lock);
77
78
return ret;
79
}
80
EXPORT_SYMBOL_GPL(pcf50633_write_block);
81
82
u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg)
83
{
84
u8 val;
85
86
mutex_lock(&pcf->lock);
87
__pcf50633_read(pcf, reg, 1, &val);
88
mutex_unlock(&pcf->lock);
89
90
return val;
91
}
92
EXPORT_SYMBOL_GPL(pcf50633_reg_read);
93
94
int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val)
95
{
96
int ret;
97
98
mutex_lock(&pcf->lock);
99
ret = __pcf50633_write(pcf, reg, 1, &val);
100
mutex_unlock(&pcf->lock);
101
102
return ret;
103
}
104
EXPORT_SYMBOL_GPL(pcf50633_reg_write);
105
106
int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val)
107
{
108
int ret;
109
u8 tmp;
110
111
val &= mask;
112
113
mutex_lock(&pcf->lock);
114
ret = __pcf50633_read(pcf, reg, 1, &tmp);
115
if (ret < 0)
116
goto out;
117
118
tmp &= ~mask;
119
tmp |= val;
120
ret = __pcf50633_write(pcf, reg, 1, &tmp);
121
122
out:
123
mutex_unlock(&pcf->lock);
124
125
return ret;
126
}
127
EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask);
128
129
int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val)
130
{
131
int ret;
132
u8 tmp;
133
134
mutex_lock(&pcf->lock);
135
ret = __pcf50633_read(pcf, reg, 1, &tmp);
136
if (ret < 0)
137
goto out;
138
139
tmp &= ~val;
140
ret = __pcf50633_write(pcf, reg, 1, &tmp);
141
142
out:
143
mutex_unlock(&pcf->lock);
144
145
return ret;
146
}
147
EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits);
148
149
/* sysfs attributes */
150
static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr,
151
char *buf)
152
{
153
struct pcf50633 *pcf = dev_get_drvdata(dev);
154
u8 dump[16];
155
int n, n1, idx = 0;
156
char *buf1 = buf;
157
static u8 address_no_read[] = { /* must be ascending */
158
PCF50633_REG_INT1,
159
PCF50633_REG_INT2,
160
PCF50633_REG_INT3,
161
PCF50633_REG_INT4,
162
PCF50633_REG_INT5,
163
0 /* terminator */
164
};
165
166
for (n = 0; n < 256; n += sizeof(dump)) {
167
for (n1 = 0; n1 < sizeof(dump); n1++)
168
if (n == address_no_read[idx]) {
169
idx++;
170
dump[n1] = 0x00;
171
} else
172
dump[n1] = pcf50633_reg_read(pcf, n + n1);
173
174
hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0);
175
buf1 += strlen(buf1);
176
*buf1++ = '\n';
177
*buf1 = '\0';
178
}
179
180
return buf1 - buf;
181
}
182
static DEVICE_ATTR(dump_regs, 0400, show_dump_regs, NULL);
183
184
static ssize_t show_resume_reason(struct device *dev,
185
struct device_attribute *attr, char *buf)
186
{
187
struct pcf50633 *pcf = dev_get_drvdata(dev);
188
int n;
189
190
n = sprintf(buf, "%02x%02x%02x%02x%02x\n",
191
pcf->resume_reason[0],
192
pcf->resume_reason[1],
193
pcf->resume_reason[2],
194
pcf->resume_reason[3],
195
pcf->resume_reason[4]);
196
197
return n;
198
}
199
static DEVICE_ATTR(resume_reason, 0400, show_resume_reason, NULL);
200
201
static struct attribute *pcf_sysfs_entries[] = {
202
&dev_attr_dump_regs.attr,
203
&dev_attr_resume_reason.attr,
204
NULL,
205
};
206
207
static struct attribute_group pcf_attr_group = {
208
.name = NULL, /* put in device directory */
209
.attrs = pcf_sysfs_entries,
210
};
211
212
static void
213
pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name,
214
struct platform_device **pdev)
215
{
216
int ret;
217
218
*pdev = platform_device_alloc(name, -1);
219
if (!*pdev) {
220
dev_err(pcf->dev, "Falied to allocate %s\n", name);
221
return;
222
}
223
224
(*pdev)->dev.parent = pcf->dev;
225
226
ret = platform_device_add(*pdev);
227
if (ret) {
228
dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret);
229
platform_device_put(*pdev);
230
*pdev = NULL;
231
}
232
}
233
234
#ifdef CONFIG_PM_SLEEP
235
static int pcf50633_suspend(struct device *dev)
236
{
237
struct i2c_client *client = to_i2c_client(dev);
238
struct pcf50633 *pcf = i2c_get_clientdata(client);
239
240
return pcf50633_irq_suspend(pcf);
241
}
242
243
static int pcf50633_resume(struct device *dev)
244
{
245
struct i2c_client *client = to_i2c_client(dev);
246
struct pcf50633 *pcf = i2c_get_clientdata(client);
247
248
return pcf50633_irq_resume(pcf);
249
}
250
#endif
251
252
static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
253
254
static int __devinit pcf50633_probe(struct i2c_client *client,
255
const struct i2c_device_id *ids)
256
{
257
struct pcf50633 *pcf;
258
struct pcf50633_platform_data *pdata = client->dev.platform_data;
259
int i, ret;
260
int version, variant;
261
262
if (!client->irq) {
263
dev_err(&client->dev, "Missing IRQ\n");
264
return -ENOENT;
265
}
266
267
pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
268
if (!pcf)
269
return -ENOMEM;
270
271
pcf->pdata = pdata;
272
273
mutex_init(&pcf->lock);
274
275
i2c_set_clientdata(client, pcf);
276
pcf->dev = &client->dev;
277
pcf->i2c_client = client;
278
279
version = pcf50633_reg_read(pcf, 0);
280
variant = pcf50633_reg_read(pcf, 1);
281
if (version < 0 || variant < 0) {
282
dev_err(pcf->dev, "Unable to probe pcf50633\n");
283
ret = -ENODEV;
284
goto err_free;
285
}
286
287
dev_info(pcf->dev, "Probed device version %d variant %d\n",
288
version, variant);
289
290
pcf50633_irq_init(pcf, client->irq);
291
292
/* Create sub devices */
293
pcf50633_client_dev_register(pcf, "pcf50633-input",
294
&pcf->input_pdev);
295
pcf50633_client_dev_register(pcf, "pcf50633-rtc",
296
&pcf->rtc_pdev);
297
pcf50633_client_dev_register(pcf, "pcf50633-mbc",
298
&pcf->mbc_pdev);
299
pcf50633_client_dev_register(pcf, "pcf50633-adc",
300
&pcf->adc_pdev);
301
pcf50633_client_dev_register(pcf, "pcf50633-backlight",
302
&pcf->bl_pdev);
303
304
305
for (i = 0; i < PCF50633_NUM_REGULATORS; i++) {
306
struct platform_device *pdev;
307
308
pdev = platform_device_alloc("pcf50633-regltr", i);
309
if (!pdev) {
310
dev_err(pcf->dev, "Cannot create regulator %d\n", i);
311
continue;
312
}
313
314
pdev->dev.parent = pcf->dev;
315
platform_device_add_data(pdev, &pdata->reg_init_data[i],
316
sizeof(pdata->reg_init_data[i]));
317
pcf->regulator_pdev[i] = pdev;
318
319
platform_device_add(pdev);
320
}
321
322
ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group);
323
if (ret)
324
dev_err(pcf->dev, "error creating sysfs entries\n");
325
326
if (pdata->probe_done)
327
pdata->probe_done(pcf);
328
329
return 0;
330
331
err_free:
332
kfree(pcf);
333
334
return ret;
335
}
336
337
static int __devexit pcf50633_remove(struct i2c_client *client)
338
{
339
struct pcf50633 *pcf = i2c_get_clientdata(client);
340
int i;
341
342
sysfs_remove_group(&client->dev.kobj, &pcf_attr_group);
343
pcf50633_irq_free(pcf);
344
345
platform_device_unregister(pcf->input_pdev);
346
platform_device_unregister(pcf->rtc_pdev);
347
platform_device_unregister(pcf->mbc_pdev);
348
platform_device_unregister(pcf->adc_pdev);
349
platform_device_unregister(pcf->bl_pdev);
350
351
for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
352
platform_device_unregister(pcf->regulator_pdev[i]);
353
354
kfree(pcf);
355
356
return 0;
357
}
358
359
static const struct i2c_device_id pcf50633_id_table[] = {
360
{"pcf50633", 0x73},
361
{/* end of list */}
362
};
363
MODULE_DEVICE_TABLE(i2c, pcf50633_id_table);
364
365
static struct i2c_driver pcf50633_driver = {
366
.driver = {
367
.name = "pcf50633",
368
.pm = &pcf50633_pm,
369
},
370
.id_table = pcf50633_id_table,
371
.probe = pcf50633_probe,
372
.remove = __devexit_p(pcf50633_remove),
373
};
374
375
static int __init pcf50633_init(void)
376
{
377
return i2c_add_driver(&pcf50633_driver);
378
}
379
380
static void __exit pcf50633_exit(void)
381
{
382
i2c_del_driver(&pcf50633_driver);
383
}
384
385
MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU");
386
MODULE_AUTHOR("Harald Welte <[email protected]>");
387
MODULE_LICENSE("GPL");
388
389
subsys_initcall(pcf50633_init);
390
module_exit(pcf50633_exit);
391
392