mfd: Split 88pm8607 driver
[safe/jmp/linux-2.6] / drivers / mfd / 88pm860x-i2c.c
1 /*
2  * I2C driver for Marvell 88PM8607
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  *      Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/i2c.h>
15 #include <linux/mfd/88pm8607.h>
16
17 static inline int pm8607_read_device(struct pm8607_chip *chip,
18                                      int reg, int bytes, void *dest)
19 {
20         struct i2c_client *i2c = chip->client;
21         unsigned char data;
22         int ret;
23
24         data = (unsigned char)reg;
25         ret = i2c_master_send(i2c, &data, 1);
26         if (ret < 0)
27                 return ret;
28
29         ret = i2c_master_recv(i2c, dest, bytes);
30         if (ret < 0)
31                 return ret;
32         return 0;
33 }
34
35 static inline int pm8607_write_device(struct pm8607_chip *chip,
36                                       int reg, int bytes, void *src)
37 {
38         struct i2c_client *i2c = chip->client;
39         unsigned char buf[bytes + 1];
40         int ret;
41
42         buf[0] = (unsigned char)reg;
43         memcpy(&buf[1], src, bytes);
44
45         ret = i2c_master_send(i2c, buf, bytes + 1);
46         if (ret < 0)
47                 return ret;
48         return 0;
49 }
50
51 int pm8607_reg_read(struct pm8607_chip *chip, int reg)
52 {
53         unsigned char data;
54         int ret;
55
56         mutex_lock(&chip->io_lock);
57         ret = chip->read(chip, reg, 1, &data);
58         mutex_unlock(&chip->io_lock);
59
60         if (ret < 0)
61                 return ret;
62         else
63                 return (int)data;
64 }
65 EXPORT_SYMBOL(pm8607_reg_read);
66
67 int pm8607_reg_write(struct pm8607_chip *chip, int reg,
68                      unsigned char data)
69 {
70         int ret;
71
72         mutex_lock(&chip->io_lock);
73         ret = chip->write(chip, reg, 1, &data);
74         mutex_unlock(&chip->io_lock);
75
76         return ret;
77 }
78 EXPORT_SYMBOL(pm8607_reg_write);
79
80 int pm8607_bulk_read(struct pm8607_chip *chip, int reg,
81                      int count, unsigned char *buf)
82 {
83         int ret;
84
85         mutex_lock(&chip->io_lock);
86         ret = chip->read(chip, reg, count, buf);
87         mutex_unlock(&chip->io_lock);
88
89         return ret;
90 }
91 EXPORT_SYMBOL(pm8607_bulk_read);
92
93 int pm8607_bulk_write(struct pm8607_chip *chip, int reg,
94                       int count, unsigned char *buf)
95 {
96         int ret;
97
98         mutex_lock(&chip->io_lock);
99         ret = chip->write(chip, reg, count, buf);
100         mutex_unlock(&chip->io_lock);
101
102         return ret;
103 }
104 EXPORT_SYMBOL(pm8607_bulk_write);
105
106 int pm8607_set_bits(struct pm8607_chip *chip, int reg,
107                     unsigned char mask, unsigned char data)
108 {
109         unsigned char value;
110         int ret;
111
112         mutex_lock(&chip->io_lock);
113         ret = chip->read(chip, reg, 1, &value);
114         if (ret < 0)
115                 goto out;
116         value &= ~mask;
117         value |= data;
118         ret = chip->write(chip, reg, 1, &value);
119 out:
120         mutex_unlock(&chip->io_lock);
121         return ret;
122 }
123 EXPORT_SYMBOL(pm8607_set_bits);
124
125
126 static const struct i2c_device_id pm860x_id_table[] = {
127         { "88PM8607", 0 },
128         {}
129 };
130 MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
131
132 static int __devinit pm860x_probe(struct i2c_client *client,
133                                   const struct i2c_device_id *id)
134 {
135         struct pm8607_platform_data *pdata = client->dev.platform_data;
136         struct pm8607_chip *chip;
137         int ret;
138
139         chip = kzalloc(sizeof(struct pm8607_chip), GFP_KERNEL);
140         if (chip == NULL)
141                 return -ENOMEM;
142
143         chip->client = client;
144         chip->dev = &client->dev;
145         chip->read = pm8607_read_device;
146         chip->write = pm8607_write_device;
147         memcpy(&chip->id, id, sizeof(struct i2c_device_id));
148         i2c_set_clientdata(client, chip);
149
150         mutex_init(&chip->io_lock);
151         dev_set_drvdata(chip->dev, chip);
152
153         ret = pm860x_device_init(chip, pdata);
154         if (ret < 0)
155                 goto out;
156
157
158         return 0;
159
160 out:
161         i2c_set_clientdata(client, NULL);
162         kfree(chip);
163         return ret;
164 }
165
166 static int __devexit pm860x_remove(struct i2c_client *client)
167 {
168         struct pm8607_chip *chip = i2c_get_clientdata(client);
169
170         kfree(chip);
171         return 0;
172 }
173
174 static struct i2c_driver pm860x_driver = {
175         .driver = {
176                 .name   = "88PM860x",
177                 .owner  = THIS_MODULE,
178         },
179         .probe          = pm860x_probe,
180         .remove         = __devexit_p(pm860x_remove),
181         .id_table       = pm860x_id_table,
182 };
183
184 static int __init pm860x_i2c_init(void)
185 {
186         int ret;
187         ret = i2c_add_driver(&pm860x_driver);
188         if (ret != 0)
189                 pr_err("Failed to register 88PM860x I2C driver: %d\n", ret);
190         return ret;
191 }
192 subsys_initcall(pm860x_i2c_init);
193
194 static void __exit pm860x_i2c_exit(void)
195 {
196         i2c_del_driver(&pm860x_driver);
197 }
198 module_exit(pm860x_i2c_exit);
199
200 MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x");
201 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
202 MODULE_LICENSE("GPL");