mfd: Initial max8925 support
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / mfd / max8925-i2c.c
CommitLineData
d50f8f33
HZ
1/*
2 * I2C driver for Maxim MAX8925
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/max8925.h>
16
17static inline int max8925_read_device(struct i2c_client *i2c,
18 int reg, int bytes, void *dest)
19{
20 unsigned char data;
21 unsigned char *buf;
22 int ret;
23
24 buf = kzalloc(bytes + 1, GFP_KERNEL);
25 if (!buf)
26 return -ENOMEM;
27
28 data = (unsigned char)reg;
29 ret = i2c_master_send(i2c, &data, 1);
30 if (ret < 0)
31 return ret;
32
33 ret = i2c_master_recv(i2c, buf, bytes + 1);
34 if (ret < 0)
35 return ret;
36 memcpy(dest, buf, bytes);
37 return 0;
38}
39
40static inline int max8925_write_device(struct i2c_client *i2c,
41 int reg, int bytes, void *src)
42{
43 unsigned char buf[bytes + 1];
44 int ret;
45
46 buf[0] = (unsigned char)reg;
47 memcpy(&buf[1], src, bytes);
48
49 ret = i2c_master_send(i2c, buf, bytes + 1);
50 if (ret < 0)
51 return ret;
52 return 0;
53}
54
55int max8925_reg_read(struct i2c_client *i2c, int reg)
56{
57 struct max8925_chip *chip = i2c_get_clientdata(i2c);
58 unsigned char data;
59 int ret;
60
61 mutex_lock(&chip->io_lock);
62 ret = max8925_read_device(i2c, reg, 1, &data);
63 mutex_unlock(&chip->io_lock);
64
65 if (ret < 0)
66 return ret;
67 else
68 return (int)data;
69}
70EXPORT_SYMBOL(max8925_reg_read);
71
72int max8925_reg_write(struct i2c_client *i2c, int reg,
73 unsigned char data)
74{
75 struct max8925_chip *chip = i2c_get_clientdata(i2c);
76 int ret;
77
78 mutex_lock(&chip->io_lock);
79 ret = max8925_write_device(i2c, reg, 1, &data);
80 mutex_unlock(&chip->io_lock);
81
82 return ret;
83}
84EXPORT_SYMBOL(max8925_reg_write);
85
86int max8925_bulk_read(struct i2c_client *i2c, int reg,
87 int count, unsigned char *buf)
88{
89 struct max8925_chip *chip = i2c_get_clientdata(i2c);
90 int ret;
91
92 mutex_lock(&chip->io_lock);
93 ret = max8925_read_device(i2c, reg, count, buf);
94 mutex_unlock(&chip->io_lock);
95
96 return ret;
97}
98EXPORT_SYMBOL(max8925_bulk_read);
99
100int max8925_bulk_write(struct i2c_client *i2c, int reg,
101 int count, unsigned char *buf)
102{
103 struct max8925_chip *chip = i2c_get_clientdata(i2c);
104 int ret;
105
106 mutex_lock(&chip->io_lock);
107 ret = max8925_write_device(i2c, reg, count, buf);
108 mutex_unlock(&chip->io_lock);
109
110 return ret;
111}
112EXPORT_SYMBOL(max8925_bulk_write);
113
114int max8925_set_bits(struct i2c_client *i2c, int reg,
115 unsigned char mask, unsigned char data)
116{
117 struct max8925_chip *chip = i2c_get_clientdata(i2c);
118 unsigned char value;
119 int ret;
120
121 mutex_lock(&chip->io_lock);
122 ret = max8925_read_device(i2c, reg, 1, &value);
123 if (ret < 0)
124 goto out;
125 value &= ~mask;
126 value |= data;
127 ret = max8925_write_device(i2c, reg, 1, &value);
128out:
129 mutex_unlock(&chip->io_lock);
130 return ret;
131}
132EXPORT_SYMBOL(max8925_set_bits);
133
134
135static const struct i2c_device_id max8925_id_table[] = {
136 { "max8925", 0 },
137 {}
138};
139MODULE_DEVICE_TABLE(i2c, max8925_id_table);
140
141static int __devinit max8925_probe(struct i2c_client *client,
142 const struct i2c_device_id *id)
143{
144 struct max8925_platform_data *pdata = client->dev.platform_data;
145 struct max8925_chip *chip;
146
147 if (!pdata) {
148 pr_info("%s: platform data is missing\n", __func__);
149 return -EINVAL;
150 }
151 if ((pdata->chip_id <= MAX8925_INVALID)
152 || (pdata->chip_id >= MAX8925_MAX)) {
153 pr_info("#%s: wrong chip identification\n", __func__);
154 return -EINVAL;
155 }
156
157 chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
158 if (chip == NULL)
159 return -ENOMEM;
160 chip->i2c = client;
161 chip->chip_id = pdata->chip_id;
162 i2c_set_clientdata(client, chip);
163 chip->dev = &client->dev;
164 mutex_init(&chip->io_lock);
165 dev_set_drvdata(chip->dev, chip);
166 max8925_device_init(chip, pdata);
167
168 return 0;
169}
170
171static int __devexit max8925_remove(struct i2c_client *client)
172{
173 struct max8925_chip *chip = i2c_get_clientdata(client);
174
175 max8925_device_exit(chip);
176 i2c_set_clientdata(client, NULL);
177 kfree(chip);
178 return 0;
179}
180
181static struct i2c_driver max8925_driver = {
182 .driver = {
183 .name = "max8925",
184 .owner = THIS_MODULE,
185 },
186 .probe = max8925_probe,
187 .remove = __devexit_p(max8925_remove),
188 .id_table = max8925_id_table,
189};
190
191static int __init max8925_i2c_init(void)
192{
193 int ret;
194
195 ret = i2c_add_driver(&max8925_driver);
196 if (ret != 0)
197 pr_err("Failed to register MAX8925 I2C driver: %d\n", ret);
198 return ret;
199}
200subsys_initcall(max8925_i2c_init);
201
202static void __exit max8925_i2c_exit(void)
203{
204 i2c_del_driver(&max8925_driver);
205}
206module_exit(max8925_i2c_exit);
207
208MODULE_DESCRIPTION("I2C Driver for Maxim 8925");
209MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
210MODULE_LICENSE("GPL");