Commit | Line | Data |
---|---|---|
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 | ||
17 | static 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 | ||
40 | static 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 | ||
55 | int 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 | } | |
70 | EXPORT_SYMBOL(max8925_reg_read); | |
71 | ||
72 | int 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 | } | |
84 | EXPORT_SYMBOL(max8925_reg_write); | |
85 | ||
86 | int 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 | } | |
98 | EXPORT_SYMBOL(max8925_bulk_read); | |
99 | ||
100 | int 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 | } | |
112 | EXPORT_SYMBOL(max8925_bulk_write); | |
113 | ||
114 | int 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); | |
128 | out: | |
129 | mutex_unlock(&chip->io_lock); | |
130 | return ret; | |
131 | } | |
132 | EXPORT_SYMBOL(max8925_set_bits); | |
133 | ||
134 | ||
135 | static const struct i2c_device_id max8925_id_table[] = { | |
136 | { "max8925", 0 }, | |
137 | {} | |
138 | }; | |
139 | MODULE_DEVICE_TABLE(i2c, max8925_id_table); | |
140 | ||
141 | static 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 | ||
171 | static 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 | ||
181 | static 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 | ||
191 | static 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 | } | |
200 | subsys_initcall(max8925_i2c_init); | |
201 | ||
202 | static void __exit max8925_i2c_exit(void) | |
203 | { | |
204 | i2c_del_driver(&max8925_driver); | |
205 | } | |
206 | module_exit(max8925_i2c_exit); | |
207 | ||
208 | MODULE_DESCRIPTION("I2C Driver for Maxim 8925"); | |
209 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | |
210 | MODULE_LICENSE("GPL"); |