diff options
author | Wolfram Sang <w.sang@pengutronix.de> | 2009-06-15 12:01:49 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-06-15 12:01:49 -0400 |
commit | 4b364f230a5ef984818837ec7c2be0884eac191c (patch) | |
tree | 678d5847dc658b5d3f175be2491bd129c00a0179 /drivers/misc | |
parent | c52cf01f5b35d77b2a918c319e22567de5c3c15f (diff) |
i2c/chips: Move max6875 to drivers/misc/eeprom
This driver only reads the user EEPROM of that chip, so we can move it
to the eeprom-directory in order to further clean up (and later remove)
drivers/i2c/chips.
The Kconfig text was updated to match the current functionality,
dropping the meanwhile obsoleted parts.
Defconfigs have been adapted.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Ben Gardner <gardner.ben@gmail.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/eeprom/Kconfig | 14 | ||||
-rw-r--r-- | drivers/misc/eeprom/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/eeprom/max6875.c | 246 |
3 files changed, 261 insertions, 0 deletions
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec052f3b4..9118613af321 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig | |||
@@ -48,6 +48,20 @@ config EEPROM_LEGACY | |||
48 | This driver can also be built as a module. If so, the module | 48 | This driver can also be built as a module. If so, the module |
49 | will be called eeprom. | 49 | will be called eeprom. |
50 | 50 | ||
51 | config EEPROM_MAX6875 | ||
52 | tristate "Maxim MAX6874/5 power supply supervisor" | ||
53 | depends on I2C && EXPERIMENTAL | ||
54 | help | ||
55 | If you say yes here you get read-only support for the user EEPROM of | ||
56 | the Maxim MAX6874/5 EEPROM-programmable, quad power-supply | ||
57 | sequencer/supervisor. | ||
58 | |||
59 | All other features of this chip should be accessed via i2c-dev. | ||
60 | |||
61 | This driver can also be built as a module. If so, the module | ||
62 | will be called max6875. | ||
63 | |||
64 | |||
51 | config EEPROM_93CX6 | 65 | config EEPROM_93CX6 |
52 | tristate "EEPROM 93CX6 support" | 66 | tristate "EEPROM 93CX6 support" |
53 | help | 67 | help |
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f88128..df3d68ffa9d1 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_EEPROM_AT24) += at24.o | 1 | obj-$(CONFIG_EEPROM_AT24) += at24.o |
2 | obj-$(CONFIG_EEPROM_AT25) += at25.o | 2 | obj-$(CONFIG_EEPROM_AT25) += at25.o |
3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o | 3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o |
4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o | ||
4 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c new file mode 100644 index 000000000000..3c0c58eed347 --- /dev/null +++ b/drivers/misc/eeprom/max6875.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | max6875.c - driver for MAX6874/MAX6875 | ||
3 | |||
4 | Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> | ||
5 | |||
6 | Based on eeprom.c | ||
7 | |||
8 | The MAX6875 has a bank of registers and two banks of EEPROM. | ||
9 | Address ranges are defined as follows: | ||
10 | * 0x0000 - 0x0046 = configuration registers | ||
11 | * 0x8000 - 0x8046 = configuration EEPROM | ||
12 | * 0x8100 - 0x82FF = user EEPROM | ||
13 | |||
14 | This driver makes the user EEPROM available for read. | ||
15 | |||
16 | The registers & config EEPROM should be accessed via i2c-dev. | ||
17 | |||
18 | The MAX6875 ignores the lowest address bit, so each chip responds to | ||
19 | two addresses - 0x50/0x51 and 0x52/0x53. | ||
20 | |||
21 | Note that the MAX6875 uses i2c_smbus_write_byte_data() to set the read | ||
22 | address, so this driver is destructive if loaded for the wrong EEPROM chip. | ||
23 | |||
24 | This program is free software; you can redistribute it and/or modify | ||
25 | it under the terms of the GNU General Public License as published by | ||
26 | the Free Software Foundation; version 2 of the License. | ||
27 | */ | ||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <linux/mutex.h> | ||
35 | |||
36 | /* Do not scan - the MAX6875 access method will write to some EEPROM chips */ | ||
37 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
38 | |||
39 | /* Insmod parameters */ | ||
40 | I2C_CLIENT_INSMOD_1(max6875); | ||
41 | |||
42 | /* The MAX6875 can only read/write 16 bytes at a time */ | ||
43 | #define SLICE_SIZE 16 | ||
44 | #define SLICE_BITS 4 | ||
45 | |||
46 | /* USER EEPROM is at addresses 0x8100 - 0x82FF */ | ||
47 | #define USER_EEPROM_BASE 0x8100 | ||
48 | #define USER_EEPROM_SIZE 0x0200 | ||
49 | #define USER_EEPROM_SLICES 32 | ||
50 | |||
51 | /* MAX6875 commands */ | ||
52 | #define MAX6875_CMD_BLK_READ 0x84 | ||
53 | |||
54 | /* Each client has this additional data */ | ||
55 | struct max6875_data { | ||
56 | struct i2c_client *fake_client; | ||
57 | struct mutex update_lock; | ||
58 | |||
59 | u32 valid; | ||
60 | u8 data[USER_EEPROM_SIZE]; | ||
61 | unsigned long last_updated[USER_EEPROM_SLICES]; | ||
62 | }; | ||
63 | |||
64 | static void max6875_update_slice(struct i2c_client *client, int slice) | ||
65 | { | ||
66 | struct max6875_data *data = i2c_get_clientdata(client); | ||
67 | int i, j, addr; | ||
68 | u8 *buf; | ||
69 | |||
70 | if (slice >= USER_EEPROM_SLICES) | ||
71 | return; | ||
72 | |||
73 | mutex_lock(&data->update_lock); | ||
74 | |||
75 | buf = &data->data[slice << SLICE_BITS]; | ||
76 | |||
77 | if (!(data->valid & (1 << slice)) || | ||
78 | time_after(jiffies, data->last_updated[slice])) { | ||
79 | |||
80 | dev_dbg(&client->dev, "Starting update of slice %u\n", slice); | ||
81 | |||
82 | data->valid &= ~(1 << slice); | ||
83 | |||
84 | addr = USER_EEPROM_BASE + (slice << SLICE_BITS); | ||
85 | |||
86 | /* select the eeprom address */ | ||
87 | if (i2c_smbus_write_byte_data(client, addr >> 8, addr & 0xFF)) { | ||
88 | dev_err(&client->dev, "address set failed\n"); | ||
89 | goto exit_up; | ||
90 | } | ||
91 | |||
92 | if (i2c_check_functionality(client->adapter, | ||
93 | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { | ||
94 | if (i2c_smbus_read_i2c_block_data(client, | ||
95 | MAX6875_CMD_BLK_READ, | ||
96 | SLICE_SIZE, | ||
97 | buf) != SLICE_SIZE) { | ||
98 | goto exit_up; | ||
99 | } | ||
100 | } else { | ||
101 | for (i = 0; i < SLICE_SIZE; i++) { | ||
102 | j = i2c_smbus_read_byte(client); | ||
103 | if (j < 0) { | ||
104 | goto exit_up; | ||
105 | } | ||
106 | buf[i] = j; | ||
107 | } | ||
108 | } | ||
109 | data->last_updated[slice] = jiffies; | ||
110 | data->valid |= (1 << slice); | ||
111 | } | ||
112 | exit_up: | ||
113 | mutex_unlock(&data->update_lock); | ||
114 | } | ||
115 | |||
116 | static ssize_t max6875_read(struct kobject *kobj, | ||
117 | struct bin_attribute *bin_attr, | ||
118 | char *buf, loff_t off, size_t count) | ||
119 | { | ||
120 | struct i2c_client *client = kobj_to_i2c_client(kobj); | ||
121 | struct max6875_data *data = i2c_get_clientdata(client); | ||
122 | int slice, max_slice; | ||
123 | |||
124 | if (off > USER_EEPROM_SIZE) | ||
125 | return 0; | ||
126 | |||
127 | if (off + count > USER_EEPROM_SIZE) | ||
128 | count = USER_EEPROM_SIZE - off; | ||
129 | |||
130 | /* refresh slices which contain requested bytes */ | ||
131 | max_slice = (off + count - 1) >> SLICE_BITS; | ||
132 | for (slice = (off >> SLICE_BITS); slice <= max_slice; slice++) | ||
133 | max6875_update_slice(client, slice); | ||
134 | |||
135 | memcpy(buf, &data->data[off], count); | ||
136 | |||
137 | return count; | ||
138 | } | ||
139 | |||
140 | static struct bin_attribute user_eeprom_attr = { | ||
141 | .attr = { | ||
142 | .name = "eeprom", | ||
143 | .mode = S_IRUGO, | ||
144 | }, | ||
145 | .size = USER_EEPROM_SIZE, | ||
146 | .read = max6875_read, | ||
147 | }; | ||
148 | |||
149 | /* Return 0 if detection is successful, -ENODEV otherwise */ | ||
150 | static int max6875_detect(struct i2c_client *client, int kind, | ||
151 | struct i2c_board_info *info) | ||
152 | { | ||
153 | struct i2c_adapter *adapter = client->adapter; | ||
154 | |||
155 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | ||
156 | | I2C_FUNC_SMBUS_READ_BYTE)) | ||
157 | return -ENODEV; | ||
158 | |||
159 | /* Only check even addresses */ | ||
160 | if (client->addr & 1) | ||
161 | return -ENODEV; | ||
162 | |||
163 | strlcpy(info->type, "max6875", I2C_NAME_SIZE); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int max6875_probe(struct i2c_client *client, | ||
169 | const struct i2c_device_id *id) | ||
170 | { | ||
171 | struct max6875_data *data; | ||
172 | int err; | ||
173 | |||
174 | if (!(data = kzalloc(sizeof(struct max6875_data), GFP_KERNEL))) | ||
175 | return -ENOMEM; | ||
176 | |||
177 | /* A fake client is created on the odd address */ | ||
178 | data->fake_client = i2c_new_dummy(client->adapter, client->addr + 1); | ||
179 | if (!data->fake_client) { | ||
180 | err = -ENOMEM; | ||
181 | goto exit_kfree; | ||
182 | } | ||
183 | |||
184 | /* Init real i2c_client */ | ||
185 | i2c_set_clientdata(client, data); | ||
186 | mutex_init(&data->update_lock); | ||
187 | |||
188 | err = sysfs_create_bin_file(&client->dev.kobj, &user_eeprom_attr); | ||
189 | if (err) | ||
190 | goto exit_remove_fake; | ||
191 | |||
192 | return 0; | ||
193 | |||
194 | exit_remove_fake: | ||
195 | i2c_unregister_device(data->fake_client); | ||
196 | exit_kfree: | ||
197 | kfree(data); | ||
198 | return err; | ||
199 | } | ||
200 | |||
201 | static int max6875_remove(struct i2c_client *client) | ||
202 | { | ||
203 | struct max6875_data *data = i2c_get_clientdata(client); | ||
204 | |||
205 | i2c_unregister_device(data->fake_client); | ||
206 | |||
207 | sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr); | ||
208 | kfree(data); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static const struct i2c_device_id max6875_id[] = { | ||
214 | { "max6875", 0 }, | ||
215 | { } | ||
216 | }; | ||
217 | |||
218 | static struct i2c_driver max6875_driver = { | ||
219 | .driver = { | ||
220 | .name = "max6875", | ||
221 | }, | ||
222 | .probe = max6875_probe, | ||
223 | .remove = max6875_remove, | ||
224 | .id_table = max6875_id, | ||
225 | |||
226 | .detect = max6875_detect, | ||
227 | .address_data = &addr_data, | ||
228 | }; | ||
229 | |||
230 | static int __init max6875_init(void) | ||
231 | { | ||
232 | return i2c_add_driver(&max6875_driver); | ||
233 | } | ||
234 | |||
235 | static void __exit max6875_exit(void) | ||
236 | { | ||
237 | i2c_del_driver(&max6875_driver); | ||
238 | } | ||
239 | |||
240 | |||
241 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | ||
242 | MODULE_DESCRIPTION("MAX6875 driver"); | ||
243 | MODULE_LICENSE("GPL"); | ||
244 | |||
245 | module_init(max6875_init); | ||
246 | module_exit(max6875_exit); | ||