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