OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * A hwmon driver for the Gateworks System Controller |
||
3 | * Copyright (C) 2009 Gateworks Corporation |
||
4 | * |
||
5 | * Author: Chris Lang <clang@gateworks.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, |
||
9 | * as published by the Free Software Foundation - version 2. |
||
10 | */ |
||
11 | |||
12 | #include <linux/module.h> |
||
13 | #include <linux/i2c.h> |
||
14 | #include <linux/hwmon.h> |
||
15 | #include <linux/hwmon-sysfs.h> |
||
16 | #include <linux/err.h> |
||
17 | #include <linux/slab.h> |
||
18 | |||
19 | #define DRV_VERSION "0.2" |
||
20 | |||
21 | enum chips { gsp }; |
||
22 | |||
23 | /* AD7418 registers */ |
||
24 | #define GSP_REG_TEMP_IN 0x00 |
||
25 | #define GSP_REG_VIN 0x02 |
||
26 | #define GSP_REG_3P3 0x05 |
||
27 | #define GSP_REG_BAT 0x08 |
||
28 | #define GSP_REG_5P0 0x0b |
||
29 | #define GSP_REG_CORE 0x0e |
||
30 | #define GSP_REG_CPU1 0x11 |
||
31 | #define GSP_REG_CPU2 0x14 |
||
32 | #define GSP_REG_DRAM 0x17 |
||
33 | #define GSP_REG_EXT_BAT 0x1a |
||
34 | #define GSP_REG_IO1 0x1d |
||
35 | #define GSP_REG_IO2 0x20 |
||
36 | #define GSP_REG_PCIE 0x23 |
||
37 | #define GSP_REG_CURRENT 0x26 |
||
38 | #define GSP_FAN_0 0x2C |
||
39 | #define GSP_FAN_1 0x2E |
||
40 | #define GSP_FAN_2 0x30 |
||
41 | #define GSP_FAN_3 0x32 |
||
42 | #define GSP_FAN_4 0x34 |
||
43 | #define GSP_FAN_5 0x36 |
||
44 | |||
45 | struct gsp_sensor_info { |
||
46 | const char* name; |
||
47 | int reg; |
||
48 | }; |
||
49 | |||
50 | static const struct gsp_sensor_info gsp_sensors[] = { |
||
51 | {"temp", GSP_REG_TEMP_IN}, |
||
52 | {"vin", GSP_REG_VIN}, |
||
53 | {"3p3", GSP_REG_3P3}, |
||
54 | {"bat", GSP_REG_BAT}, |
||
55 | {"5p0", GSP_REG_5P0}, |
||
56 | {"core", GSP_REG_CORE}, |
||
57 | {"cpu1", GSP_REG_CPU1}, |
||
58 | {"cpu2", GSP_REG_CPU2}, |
||
59 | {"dram", GSP_REG_DRAM}, |
||
60 | {"ext_bat", GSP_REG_EXT_BAT}, |
||
61 | {"io1", GSP_REG_IO1}, |
||
62 | {"io2", GSP_REG_IO2}, |
||
63 | {"pci2", GSP_REG_PCIE}, |
||
64 | {"current", GSP_REG_CURRENT}, |
||
65 | {"fan_point0", GSP_FAN_0}, |
||
66 | {"fan_point1", GSP_FAN_1}, |
||
67 | {"fan_point2", GSP_FAN_2}, |
||
68 | {"fan_point3", GSP_FAN_3}, |
||
69 | {"fan_point4", GSP_FAN_4}, |
||
70 | {"fan_point5", GSP_FAN_5}, |
||
71 | }; |
||
72 | |||
73 | struct gsp_data { |
||
74 | struct device *hwmon_dev; |
||
75 | struct attribute_group attrs; |
||
76 | enum chips type; |
||
77 | }; |
||
78 | |||
79 | static int gsp_probe(struct i2c_client *client, |
||
80 | const struct i2c_device_id *id); |
||
81 | static int gsp_remove(struct i2c_client *client); |
||
82 | |||
83 | static const struct i2c_device_id gsp_id[] = { |
||
84 | { "gsp", 0 }, |
||
85 | { } |
||
86 | }; |
||
87 | MODULE_DEVICE_TABLE(i2c, gsp_id); |
||
88 | |||
89 | static struct i2c_driver gsp_driver = { |
||
90 | .driver = { |
||
91 | .name = "gsp", |
||
92 | }, |
||
93 | .probe = gsp_probe, |
||
94 | .remove = gsp_remove, |
||
95 | .id_table = gsp_id, |
||
96 | }; |
||
97 | |||
98 | /* All registers are word-sized, except for the configuration registers. |
||
99 | * AD7418 uses a high-byte first convention. Do NOT use those functions to |
||
100 | * access the configuration registers CONF and CONF2, as they are byte-sized. |
||
101 | */ |
||
102 | static inline int gsp_read(struct i2c_client *client, u8 reg) |
||
103 | { |
||
104 | unsigned int adc = 0; |
||
105 | if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT) |
||
106 | { |
||
107 | adc |= i2c_smbus_read_byte_data(client, reg); |
||
108 | adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; |
||
109 | return adc; |
||
110 | } |
||
111 | else |
||
112 | { |
||
113 | adc |= i2c_smbus_read_byte_data(client, reg); |
||
114 | adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8; |
||
115 | adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16; |
||
116 | return adc; |
||
117 | } |
||
118 | } |
||
119 | |||
120 | static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value) |
||
121 | { |
||
122 | i2c_smbus_write_byte_data(client, reg, value & 0xff); |
||
123 | i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff)); |
||
124 | return 1; |
||
125 | } |
||
126 | |||
127 | static ssize_t show_adc(struct device *dev, struct device_attribute *devattr, |
||
128 | char *buf) |
||
129 | { |
||
130 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
||
131 | struct i2c_client *client = to_i2c_client(dev); |
||
132 | return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg)); |
||
133 | } |
||
134 | |||
135 | static ssize_t show_label(struct device *dev, |
||
136 | struct device_attribute *devattr, char *buf) |
||
137 | { |
||
138 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
||
139 | |||
140 | return sprintf(buf, "%s\n", gsp_sensors[attr->index].name); |
||
141 | } |
||
142 | |||
143 | static ssize_t store_fan(struct device *dev, |
||
144 | struct device_attribute *devattr, const char *buf, size_t count) |
||
145 | { |
||
146 | u16 val; |
||
147 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); |
||
148 | struct i2c_client *client = to_i2c_client(dev); |
||
149 | val = simple_strtoul(buf, NULL, 10); |
||
150 | gsp_write(client, gsp_sensors[attr->index].reg, val); |
||
151 | return count; |
||
152 | } |
||
153 | |||
154 | static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0); |
||
155 | static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0); |
||
156 | |||
157 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1); |
||
158 | static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1); |
||
159 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2); |
||
160 | static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2); |
||
161 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3); |
||
162 | static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3); |
||
163 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4); |
||
164 | static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4); |
||
165 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5); |
||
166 | static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5); |
||
167 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6); |
||
168 | static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6); |
||
169 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7); |
||
170 | static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7); |
||
171 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8); |
||
172 | static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8); |
||
173 | static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9); |
||
174 | static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9); |
||
175 | static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10); |
||
176 | static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10); |
||
177 | static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11); |
||
178 | static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11); |
||
179 | static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12); |
||
180 | static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12); |
||
181 | static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13); |
||
182 | static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13); |
||
183 | |||
184 | static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14); |
||
185 | static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15); |
||
186 | static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16); |
||
187 | static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17); |
||
188 | static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18); |
||
189 | static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19); |
||
190 | |||
191 | static struct attribute *gsp_attributes[] = { |
||
192 | &sensor_dev_attr_temp0_input.dev_attr.attr, |
||
193 | &sensor_dev_attr_in0_input.dev_attr.attr, |
||
194 | &sensor_dev_attr_in1_input.dev_attr.attr, |
||
195 | &sensor_dev_attr_in2_input.dev_attr.attr, |
||
196 | &sensor_dev_attr_in3_input.dev_attr.attr, |
||
197 | &sensor_dev_attr_in4_input.dev_attr.attr, |
||
198 | &sensor_dev_attr_in5_input.dev_attr.attr, |
||
199 | &sensor_dev_attr_in6_input.dev_attr.attr, |
||
200 | &sensor_dev_attr_in7_input.dev_attr.attr, |
||
201 | &sensor_dev_attr_in8_input.dev_attr.attr, |
||
202 | &sensor_dev_attr_in9_input.dev_attr.attr, |
||
203 | &sensor_dev_attr_in10_input.dev_attr.attr, |
||
204 | &sensor_dev_attr_in11_input.dev_attr.attr, |
||
205 | &sensor_dev_attr_in12_input.dev_attr.attr, |
||
206 | |||
207 | &sensor_dev_attr_temp0_label.dev_attr.attr, |
||
208 | &sensor_dev_attr_in0_label.dev_attr.attr, |
||
209 | &sensor_dev_attr_in1_label.dev_attr.attr, |
||
210 | &sensor_dev_attr_in2_label.dev_attr.attr, |
||
211 | &sensor_dev_attr_in3_label.dev_attr.attr, |
||
212 | &sensor_dev_attr_in4_label.dev_attr.attr, |
||
213 | &sensor_dev_attr_in5_label.dev_attr.attr, |
||
214 | &sensor_dev_attr_in6_label.dev_attr.attr, |
||
215 | &sensor_dev_attr_in7_label.dev_attr.attr, |
||
216 | &sensor_dev_attr_in8_label.dev_attr.attr, |
||
217 | &sensor_dev_attr_in9_label.dev_attr.attr, |
||
218 | &sensor_dev_attr_in10_label.dev_attr.attr, |
||
219 | &sensor_dev_attr_in11_label.dev_attr.attr, |
||
220 | &sensor_dev_attr_in12_label.dev_attr.attr, |
||
221 | |||
222 | &sensor_dev_attr_fan0_point0.dev_attr.attr, |
||
223 | &sensor_dev_attr_fan0_point1.dev_attr.attr, |
||
224 | &sensor_dev_attr_fan0_point2.dev_attr.attr, |
||
225 | &sensor_dev_attr_fan0_point3.dev_attr.attr, |
||
226 | &sensor_dev_attr_fan0_point4.dev_attr.attr, |
||
227 | &sensor_dev_attr_fan0_point5.dev_attr.attr, |
||
228 | NULL |
||
229 | }; |
||
230 | |||
231 | |||
232 | static int gsp_probe(struct i2c_client *client, |
||
233 | const struct i2c_device_id *id) |
||
234 | { |
||
235 | struct i2c_adapter *adapter = client->adapter; |
||
236 | struct gsp_data *data; |
||
237 | int err; |
||
238 | |||
239 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | |
||
240 | I2C_FUNC_SMBUS_WORD_DATA)) { |
||
241 | err = -EOPNOTSUPP; |
||
242 | goto exit; |
||
243 | } |
||
244 | |||
245 | if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) { |
||
246 | err = -ENOMEM; |
||
247 | goto exit; |
||
248 | } |
||
249 | |||
250 | i2c_set_clientdata(client, data); |
||
251 | |||
252 | data->type = id->driver_data; |
||
253 | |||
254 | switch (data->type) { |
||
255 | case 0: |
||
256 | data->attrs.attrs = gsp_attributes; |
||
257 | break; |
||
258 | } |
||
259 | |||
260 | dev_info(&client->dev, "%s chip found\n", client->name); |
||
261 | |||
262 | /* Register sysfs hooks */ |
||
263 | if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) |
||
264 | goto exit_free; |
||
265 | |||
266 | data->hwmon_dev = hwmon_device_register(&client->dev); |
||
267 | if (IS_ERR(data->hwmon_dev)) { |
||
268 | err = PTR_ERR(data->hwmon_dev); |
||
269 | goto exit_remove; |
||
270 | } |
||
271 | |||
272 | return 0; |
||
273 | |||
274 | exit_remove: |
||
275 | sysfs_remove_group(&client->dev.kobj, &data->attrs); |
||
276 | exit_free: |
||
277 | kfree(data); |
||
278 | exit: |
||
279 | return err; |
||
280 | } |
||
281 | |||
282 | static int gsp_remove(struct i2c_client *client) |
||
283 | { |
||
284 | struct gsp_data *data = i2c_get_clientdata(client); |
||
285 | hwmon_device_unregister(data->hwmon_dev); |
||
286 | sysfs_remove_group(&client->dev.kobj, &data->attrs); |
||
287 | kfree(data); |
||
288 | return 0; |
||
289 | } |
||
290 | |||
291 | static int __init gsp_init(void) |
||
292 | { |
||
293 | return i2c_add_driver(&gsp_driver); |
||
294 | } |
||
295 | |||
296 | static void __exit gsp_exit(void) |
||
297 | { |
||
298 | i2c_del_driver(&gsp_driver); |
||
299 | } |
||
300 | |||
301 | module_init(gsp_init); |
||
302 | module_exit(gsp_exit); |
||
303 | |||
304 | MODULE_AUTHOR("Chris Lang <clang@gateworks.com>"); |
||
305 | MODULE_DESCRIPTION("GSC HWMON driver"); |
||
306 | MODULE_LICENSE("GPL"); |
||
307 | MODULE_VERSION(DRV_VERSION); |
||
308 |