diff options
author | Saul Wold <Saul.Wold@intel.com> | 2010-09-24 15:36:24 -0700 |
---|---|---|
committer | Saul Wold <Saul.Wold@intel.com> | 2010-09-24 16:43:21 -0700 |
commit | 239a368d5715d8f5b7733f9400339c2350c49369 (patch) | |
tree | 2953f12b45e590d9e14b6f72f8e4ee7188e41508 /meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch | |
parent | c5b9525263dac6844d152e40acf8cee4d27b60bc (diff) | |
download | poky-239a368d5715d8f5b7733f9400339c2350c49369.tar.gz |
netbook: Correct netbook build by moving netbook configuration from moblin to meta
Signed-off-by: Saul Wold <Saul.Wold@intel.com>
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch | 1836 |
1 files changed, 1836 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch new file mode 100644 index 0000000000..fce4524518 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch | |||
@@ -0,0 +1,1836 @@ | |||
1 | From cffaf6b15ff40cfbeafd0d4728ba3a5a5fb6155f Mon Sep 17 00:00:00 2001 | ||
2 | From: Alan Olsen <alan.r.olsen@intel.com> | ||
3 | Date: Thu, 15 Oct 2009 14:26:47 -0700 | ||
4 | Subject: [PATCH 062/104] Moorestown Sensor drivers v1.1 consolidated patch | ||
5 | |||
6 | This patch contains the following patches: | ||
7 | |||
8 | Alpha2-1.1-1-5-mrst-Sensors-ALS-Driver-for-Moorestown.patch | ||
9 | |||
10 | [PATCH] ALS Driver for Moorestown Sensors | ||
11 | |||
12 | This patch single patch for Alpha2:2.0. ALS driver will read | ||
13 | the latest Lux measurement based on the light brightness and | ||
14 | will report the LUX output through sysfs interface. | ||
15 | |||
16 | Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com> | ||
17 | |||
18 | Alpha2-1.1-2-5-mrst-Sensors-Compass-Driver-for-Moorestown.patch | ||
19 | |||
20 | [PATCH] Compass Driver for Moorestown Sensors | ||
21 | This patch single patch for Alpha2:2.0.This driver will report | ||
22 | the heading values in degrees to the sysfs interface.The vlaues | ||
23 | returned are head . e.g. 245.6 | ||
24 | |||
25 | Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com> | ||
26 | |||
27 | Alpha2-1.1-3-5-mrst-Sensors-Accelerometer-Driver-for-Moorestown.patch | ||
28 | |||
29 | [PATCH] Accelerometer Driver for Moorestown Sensors | ||
30 | |||
31 | This patch single patch for Alpha2:2.0.Accelerometer driver will | ||
32 | read the x,y,z coordinate registers and provide the information to | ||
33 | user through sysfs interface. | ||
34 | |||
35 | Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com> | ||
36 | |||
37 | Alpha2-1.1-4-5-mrst-Sensors-Vibrator-Driver-for-Moorestown.patch | ||
38 | |||
39 | [PATCH] Vibrator Driver for Moorestown Sensors | ||
40 | |||
41 | This patch single patch for Alpha2:2.0.Vibrator can be switched | ||
42 | on/off using sysfs interface. | ||
43 | |||
44 | Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com> | ||
45 | |||
46 | Alpha2-1.1-5-5-mrst-Sensors-Thermal-Driver-for-Moorestown.patch | ||
47 | |||
48 | [PATCH] Thermal Driver for Moorestown Sensors | ||
49 | |||
50 | Moorestown Platform has EMC1403 chip which support three thermal | ||
51 | devices, one thermal zone is used by the EMC1403 chip itself and | ||
52 | second is used by processor and third one is used for platform | ||
53 | (skin temperature).Driver support poll and interrupt | ||
54 | mode,min/max/crit configuration can be done using sysfs interface. | ||
55 | |||
56 | The driver also support interrupt mode when the temperature crosses the | ||
57 | threshold configured value the min/max/crit. ALERT/THERM interrupt will | ||
58 | be triggered and driver register its callback with GPE driver, and send | ||
59 | the events to OSPM power management to take action. OSPM will take | ||
60 | action and set the new threshold values till it doesnot get ALERT/THERM | ||
61 | events.temp1 is used for configuring internal EMC1403 chip diode, temp2 | ||
62 | is used to configure processor diode and temp3 is used to configure the | ||
63 | platform diode. | ||
64 | |||
65 | The interrupt mode code has dependency MRST PMIC_GPIO/MAX7315/OSPM.Flag | ||
66 | is added to differentiate the generic functionality of the driver with | ||
67 | moorestown specific. | ||
68 | |||
69 | Signed-off-by: Kalhan Trisal <kalhan.trisal at intel.com> | ||
70 | |||
71 | Signed-off-by: Alan Olsen <alan.r.olsen@intel.com> | ||
72 | --- | ||
73 | drivers/hwmon/Kconfig | 35 ++ | ||
74 | drivers/hwmon/Makefile | 4 | ||
75 | drivers/hwmon/emc1403.c | 731 +++++++++++++++++++++++++++++++++++++++++++++++ | ||
76 | drivers/hwmon/hmc6352.c | 250 ++++++++++++++++ | ||
77 | drivers/hwmon/isl29020.c | 248 +++++++++++++++ | ||
78 | drivers/hwmon/lis331dl.c | 322 ++++++++++++++++++++ | ||
79 | drivers/misc/Kconfig | 7 | ||
80 | drivers/misc/Makefile | 1 | ||
81 | drivers/misc/mrst_vib.c | 99 ++++++ | ||
82 | 9 files changed, 1697 insertions(+) | ||
83 | create mode 100644 drivers/hwmon/emc1403.c | ||
84 | create mode 100644 drivers/hwmon/hmc6352.c | ||
85 | create mode 100644 drivers/hwmon/isl29020.c | ||
86 | create mode 100644 drivers/hwmon/lis331dl.c | ||
87 | create mode 100644 drivers/misc/mrst_vib.c | ||
88 | |||
89 | --- a/drivers/hwmon/Kconfig | ||
90 | +++ b/drivers/hwmon/Kconfig | ||
91 | @@ -28,6 +28,41 @@ config HWMON_VID | ||
92 | tristate | ||
93 | default n | ||
94 | |||
95 | +config SENSORS_ISL29020 | ||
96 | + tristate "Intersil ISL29020 ALS" | ||
97 | + depends on I2C_MRST | ||
98 | + help | ||
99 | + If you say yes here you get support for the ALS Devices | ||
100 | + Ambient Light Sensor monitoring chip. | ||
101 | + Range values can be configured using sysfs. | ||
102 | + Lux Data are accessible via sysfs. | ||
103 | + | ||
104 | +config SENSORS_HMC6352 | ||
105 | + tristate "Honeywell HMC6352 compass" | ||
106 | + depends on I2C_MRST | ||
107 | + help | ||
108 | + If you say yes here you get support for the Compass Devices | ||
109 | + Device can be configured using sysfs. | ||
110 | + heading data can be accessible via sysfs. | ||
111 | + | ||
112 | +config SENSORS_LIS331DL | ||
113 | + tristate "STMicroeletronics LIS331DL three-axis digital accelerometer" | ||
114 | + depends on I2C_MRST | ||
115 | + help | ||
116 | + If you say yes here you get support for the Accelerometer Devices | ||
117 | + Device can be configured using sysfs. | ||
118 | + x y Z data can be accessible via sysfs. | ||
119 | + | ||
120 | +config SENSORS_EMC1403 | ||
121 | + tristate "SMSC EMC1403 Thermal" | ||
122 | + depends on I2C_MRST && GPE && GPIO_MAX7315 && MSTWN_POWER_MGMT | ||
123 | + help | ||
124 | + If you say yes here you get support for the SMSC Devices | ||
125 | + EMC1403 temperature monitoring chip. | ||
126 | + | ||
127 | + Threshold values can be configured using sysfs. | ||
128 | + Data from the different diode are accessible via sysfs. | ||
129 | + | ||
130 | config HWMON_DEBUG_CHIP | ||
131 | bool "Hardware Monitoring Chip debugging messages" | ||
132 | default n | ||
133 | --- a/drivers/hwmon/Makefile | ||
134 | +++ b/drivers/hwmon/Makefile | ||
135 | @@ -99,6 +99,10 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7 | ||
136 | obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o | ||
137 | obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o | ||
138 | obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o | ||
139 | +obj-$(CONFIG_SENSORS_ISL29020) += isl29020.o | ||
140 | +obj-$(CONFIG_SENSORS_HMC6352) += hmc6352.o | ||
141 | +obj-$(CONFIG_SENSORS_LIS331DL) += lis331dl.o | ||
142 | +obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o | ||
143 | |||
144 | ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) | ||
145 | EXTRA_CFLAGS += -DDEBUG | ||
146 | --- /dev/null | ||
147 | +++ b/drivers/hwmon/emc1403.c | ||
148 | @@ -0,0 +1,731 @@ | ||
149 | +/* | ||
150 | + * emc1403.c - SMSC Thermal Driver | ||
151 | + * | ||
152 | + * Copyright (C) 2008 Intel Corp | ||
153 | + * | ||
154 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
155 | + * | ||
156 | + * This program is free software; you can redistribute it and/or modify | ||
157 | + * it under the terms of the GNU General Public License as published by | ||
158 | + * the Free Software Foundation; version 2 of the License. | ||
159 | + * | ||
160 | + * This program is distributed in the hope that it will be useful, but | ||
161 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
162 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
163 | + * General Public License for more details. | ||
164 | + * | ||
165 | + * You should have received a copy of the GNU General Public License along | ||
166 | + * with this program; if not, write to the Free Software Foundation, Inc., | ||
167 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
168 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
169 | + */ | ||
170 | + | ||
171 | +#include <linux/module.h> | ||
172 | +#include <linux/init.h> | ||
173 | +#include <linux/slab.h> | ||
174 | +#include <linux/i2c.h> | ||
175 | +#include <linux/hwmon.h> | ||
176 | +#include <linux/hwmon-sysfs.h> | ||
177 | +#include <linux/hwmon-vid.h> | ||
178 | +#include <linux/interrupt.h> | ||
179 | +#include <linux/workqueue.h> | ||
180 | +#include <linux/err.h> | ||
181 | +#include <linux/delay.h> | ||
182 | +#include <linux/mutex.h> | ||
183 | +#include <linux/sysfs.h> | ||
184 | +#include <linux/gpe.h> | ||
185 | +#include <linux/intel_mid.h> | ||
186 | + | ||
187 | + | ||
188 | +MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); | ||
189 | +MODULE_DESCRIPTION("emc1403 Thermal Driver"); | ||
190 | +MODULE_LICENSE("GPL v2"); | ||
191 | + | ||
192 | +/* To support the interrupt mechanism for moorestown interrupt flag is added | ||
193 | + * If the flag is not enabled it support generic emc1403 chip */ | ||
194 | + | ||
195 | +#if defined(CONFIG_GPIO_LNWPMIC) && defined(CONFIG_GPIO_MAX7315) \ | ||
196 | + && defined(CONFIG_MSTWN_POWER_MGMT) | ||
197 | +#define MOORESTOWN_INTERRUPT_ENABLE | ||
198 | +#endif | ||
199 | + | ||
200 | +/* Limit status reg Therm/High/Low/Fault*/ | ||
201 | +static const u8 THM_STAT_REG_TEMP[] = { 0x37, 0x35, 0x36, 0x1B, 0x02}; | ||
202 | + | ||
203 | +/* Channel diode temp set */ | ||
204 | +static const u8 THM_CHAN_TEMP[] = { 0x10, 0x08, 0x04, 0x02, 0x01 }; | ||
205 | + | ||
206 | +/* Therm Limit reg store values */ | ||
207 | +static const u8 THM_LIMIT_REG_TEMP[] = { 0x05, 0x06, 0x07, 0x08, 0x15, 0x16, | ||
208 | + 0x19, 0x1A, 0x20, 0x21 }; | ||
209 | + | ||
210 | +/* DATA REGISTERS */ | ||
211 | +static const u8 THM_REG_CURR_TEMP[] = { 0x00, 0x01, 0x23 }; | ||
212 | + | ||
213 | +#define THERMAL_PID_REG 0xfd | ||
214 | +#define THERMAL_SMSC_ID_REG 0xfe | ||
215 | +#define THERMAL_REVISION_REG 0xff | ||
216 | +#define THERMAL_ADC_UPDATE_BUSY 0x80 | ||
217 | +#define I2C_THERMAL_SLAVE_ADDR 0x4C | ||
218 | +#define TEMP1 1 | ||
219 | +#define TEMP2 2 | ||
220 | +#define TEMP3 4 | ||
221 | +#define IRQ_TYPE_MASK (1 << 15) | ||
222 | +#define HIGH_EVENT 1 | ||
223 | +#define LOW_EVENT 2 | ||
224 | +#define THERM_EVENT 3 | ||
225 | +#define FAULT_EVENT 4 | ||
226 | +#define ALERT_EVENT 1 | ||
227 | +#define POWER_STA_ENABLE 0 | ||
228 | +#define POWER_STA_DISABLE 1 | ||
229 | +#define INTERRUPT_MODE_ENABLE 0 | ||
230 | +#define INTERRUPT_MODE_DISABLE 1 | ||
231 | + | ||
232 | +struct thermal_data { | ||
233 | + struct i2c_client *client; | ||
234 | + struct device *hwmon_dev; | ||
235 | + int therm_irq; | ||
236 | + int alert_irq; | ||
237 | + struct work_struct therm_handler; | ||
238 | + struct work_struct alert_handler; | ||
239 | +}; | ||
240 | + | ||
241 | +static unsigned int i2c_read_current_data(struct i2c_client *client, u8 reg) | ||
242 | +{ | ||
243 | + unsigned int ret_val; | ||
244 | + | ||
245 | + ret_val = i2c_smbus_read_byte_data(client, reg); | ||
246 | + return ret_val; | ||
247 | +} | ||
248 | + | ||
249 | +static unsigned int i2c_write_current_data(struct i2c_client *client, | ||
250 | + unsigned int reg, unsigned int value) | ||
251 | +{ | ||
252 | + int ret_val; | ||
253 | + | ||
254 | + ret_val = i2c_smbus_write_byte_data(client, reg, value); | ||
255 | + return ret_val; | ||
256 | +} | ||
257 | + | ||
258 | +static int calculate_offset(int type, int temp_ofs) | ||
259 | +{ | ||
260 | + int offset = 0; | ||
261 | + | ||
262 | + switch (type) { | ||
263 | + case TEMP1: | ||
264 | + if (temp_ofs == 0) | ||
265 | + offset = 1; | ||
266 | + else if (temp_ofs == 1) | ||
267 | + offset = 0; | ||
268 | + else if (temp_ofs == 2) | ||
269 | + offset = 8; | ||
270 | + break; | ||
271 | + case TEMP2: | ||
272 | + if (temp_ofs == 0) | ||
273 | + offset = 3; | ||
274 | + else if (temp_ofs == 1) | ||
275 | + offset = 2; | ||
276 | + else if (temp_ofs == 2) | ||
277 | + offset = 6; | ||
278 | + break; | ||
279 | + case TEMP3: | ||
280 | + if (temp_ofs == 0) | ||
281 | + offset = 5; | ||
282 | + else if (temp_ofs == 1) | ||
283 | + offset = 4; | ||
284 | + else if (temp_ofs == 2) | ||
285 | + offset = 7; | ||
286 | + break; | ||
287 | + default: | ||
288 | + offset = -1; | ||
289 | + printk(KERN_WARNING "emc1403: Invalid arg \n"); | ||
290 | + break; | ||
291 | + } | ||
292 | + return offset; | ||
293 | + | ||
294 | +} | ||
295 | + | ||
296 | +#ifdef MOORESTOWN_INTERRUPT_ENABLE | ||
297 | +static void status_reg_read(struct i2c_client *client) | ||
298 | +{ | ||
299 | + i2c_read_current_data(client, 0x36); | ||
300 | + i2c_read_current_data(client, 0x35); | ||
301 | + i2c_read_current_data(client, 0x1B); | ||
302 | +} | ||
303 | + | ||
304 | +/* when the thermal governor takes action we unmask the bit | ||
305 | + * if the temp is lower tham threshold values then no new event will | ||
306 | + * be raised else if the current temperature is still high the interrupt | ||
307 | + * will be sent again */ | ||
308 | + | ||
309 | +static void reg_unmask_intr(struct i2c_client *client, int offset, | ||
310 | + int value) | ||
311 | +{ | ||
312 | + u8 ret_val, set_mask, ret = 0, alert = 0; | ||
313 | + | ||
314 | + ret_val = i2c_read_current_data(client, 0x1F); | ||
315 | + if (offset == 6 || offset == 7 || offset == 8) { | ||
316 | + ret = i2c_read_current_data(client, 0x37); /* Themal status */ | ||
317 | + } else if (offset == 2 || offset == 3) { | ||
318 | + if (((ret_val >> 1) & 1)) { | ||
319 | + set_mask = (ret_val & 0x05); | ||
320 | + alert = 1; | ||
321 | + } | ||
322 | + } else if (offset == 4 || offset == 5) { | ||
323 | + if (((ret_val >> 2) & 1)) { | ||
324 | + set_mask = (ret_val & 0x03); | ||
325 | + alert = 1; | ||
326 | + } | ||
327 | + } else if (offset == 0 || offset == 1) { | ||
328 | + if (ret_val & 1) { | ||
329 | + set_mask = (ret_val & 0x06); | ||
330 | + alert = 1; | ||
331 | + } | ||
332 | + } | ||
333 | + /* only rest set the mask for alert events */ | ||
334 | + if (alert == 1) { | ||
335 | + status_reg_read(client); | ||
336 | + i2c_write_current_data(client, 0x1F, set_mask); | ||
337 | + } | ||
338 | +} | ||
339 | +#endif | ||
340 | + | ||
341 | +static ssize_t show_temp_auto_offset(struct device *dev, | ||
342 | + struct device_attribute *attr, char *buf) | ||
343 | +{ | ||
344 | + struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr); | ||
345 | + int temp_index = s_attr->index; | ||
346 | + int temp_ofs = s_attr->nr; | ||
347 | + struct i2c_client *client = to_i2c_client(dev); | ||
348 | + int ret_val = 0; | ||
349 | + int ret_offset = 0; | ||
350 | + | ||
351 | + ret_offset = calculate_offset(temp_index, temp_ofs); | ||
352 | + if (ret_offset != -1) { | ||
353 | + ret_val = i2c_read_current_data(client, | ||
354 | + THM_LIMIT_REG_TEMP[ret_offset]); | ||
355 | + return sprintf(buf, "%d\n", ret_val); | ||
356 | + } else { | ||
357 | + return -EINVAL; | ||
358 | + } | ||
359 | +} | ||
360 | + | ||
361 | +static ssize_t store_temp_auto_offset(struct device *dev, | ||
362 | + struct device_attribute *attr, const char *buf, size_t count) | ||
363 | +{ | ||
364 | + struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr); | ||
365 | + int temp_index = s_attr->index; | ||
366 | + int temp_ofs = s_attr->nr; | ||
367 | + struct i2c_client *client = to_i2c_client(dev); | ||
368 | + unsigned long val; | ||
369 | + int ret_offset = 0; | ||
370 | + | ||
371 | + if (strict_strtoul(buf, 10, &val)) | ||
372 | + return -EINVAL; | ||
373 | + ret_offset = calculate_offset(temp_index, temp_ofs); | ||
374 | + if (ret_offset != -1) { | ||
375 | + i2c_write_current_data(client, | ||
376 | + THM_LIMIT_REG_TEMP[ret_offset], val); | ||
377 | +#ifdef MOORESTOWN_INTERRUPT_ENABLE | ||
378 | + reg_unmask_intr(client, ret_offset, val); | ||
379 | +#endif | ||
380 | + return count; | ||
381 | + } else { | ||
382 | + return -EINVAL; | ||
383 | + } | ||
384 | +} | ||
385 | + | ||
386 | +static ssize_t show_temp_hyst(struct device *dev, | ||
387 | + struct device_attribute *attr, char *buf) | ||
388 | +{ | ||
389 | + struct i2c_client *client = to_i2c_client(dev); | ||
390 | + int ret_val; | ||
391 | + | ||
392 | + ret_val = i2c_read_current_data(client, THM_LIMIT_REG_TEMP[9]); | ||
393 | + return sprintf(buf, "%d\n", ret_val); | ||
394 | +} | ||
395 | + | ||
396 | +static ssize_t store_temp_hyst(struct device *dev, | ||
397 | + struct device_attribute *attr, const char *buf, size_t count) | ||
398 | +{ | ||
399 | + struct i2c_client *client = to_i2c_client(dev); | ||
400 | + unsigned long val = 0; | ||
401 | + | ||
402 | + if (strict_strtoul(buf, 10, &val)) | ||
403 | + return -EINVAL; | ||
404 | + i2c_write_current_data(client, THM_LIMIT_REG_TEMP[9], val); | ||
405 | + return count; | ||
406 | +} | ||
407 | + | ||
408 | +static ssize_t show_temp1_curr_temp(struct device *dev, | ||
409 | + struct device_attribute *attr, char *buf) | ||
410 | +{ | ||
411 | + struct i2c_client *client = to_i2c_client(dev); | ||
412 | + int ret_val; | ||
413 | + | ||
414 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[0]); | ||
415 | + return sprintf(buf, "%d\n", ret_val); | ||
416 | +} | ||
417 | + | ||
418 | +static ssize_t show_temp2_curr_temp(struct device *dev, | ||
419 | + struct device_attribute *attr, char *buf) | ||
420 | +{ | ||
421 | + struct i2c_client *client = to_i2c_client(dev); | ||
422 | + int ret_val; | ||
423 | + | ||
424 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[1]); | ||
425 | + return sprintf(buf, "%d\n", ret_val); | ||
426 | +} | ||
427 | + | ||
428 | +static ssize_t show_temp3_curr_temp(struct device *dev, | ||
429 | + struct device_attribute *attr, char *buf) | ||
430 | +{ | ||
431 | + struct i2c_client *client = to_i2c_client(dev); | ||
432 | + int ret_val; | ||
433 | + | ||
434 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[2]); | ||
435 | + return sprintf(buf, "%d\n", ret_val); | ||
436 | +} | ||
437 | + | ||
438 | +static ssize_t show_status_reg(struct device *dev, | ||
439 | + struct device_attribute *attr, char *buf) | ||
440 | +{ | ||
441 | + struct i2c_client *client = to_i2c_client(dev); | ||
442 | + int ret_val1, ret_val2, ret_val3, ret_val4; | ||
443 | + | ||
444 | + ret_val1 = i2c_read_current_data(client, 0x1F); | ||
445 | + ret_val2 = i2c_read_current_data(client, 0x35); | ||
446 | + ret_val3 = i2c_read_current_data(client, 0x36); | ||
447 | + ret_val4 = i2c_read_current_data(client, 0x37); | ||
448 | + return sprintf(buf, "alarm=%x,High=%x,Low=%x,Therm=%x \n", | ||
449 | + ret_val1, ret_val2, ret_val3, ret_val4); | ||
450 | +} | ||
451 | + | ||
452 | +static ssize_t show_power_state(struct device *dev, | ||
453 | + struct device_attribute *attr, char *buf) | ||
454 | +{ | ||
455 | + struct i2c_client *client = to_i2c_client(dev); | ||
456 | + int ret_val; | ||
457 | + | ||
458 | + ret_val = i2c_read_current_data(client, 0x03); | ||
459 | + ret_val = ret_val & 0x40; | ||
460 | + if (ret_val == 0x40) | ||
461 | + ret_val = 1; | ||
462 | + return sprintf(buf, "%x", ret_val); | ||
463 | +} | ||
464 | + | ||
465 | +static ssize_t store_power_state(struct device *dev, | ||
466 | + struct device_attribute *attr, const char *buf, size_t count) | ||
467 | +{ | ||
468 | + struct i2c_client *client = to_i2c_client(dev); | ||
469 | + unsigned long val = 0; | ||
470 | + char curr_val; | ||
471 | + | ||
472 | + if (strict_strtoul(buf, 10, &val)) | ||
473 | + return -EINVAL; | ||
474 | + | ||
475 | + curr_val = i2c_read_current_data(client, 0x03); | ||
476 | + if (val == POWER_STA_ENABLE) | ||
477 | + curr_val = curr_val & 0xBF; | ||
478 | + else if (val == POWER_STA_DISABLE) | ||
479 | + curr_val = curr_val | 0x40; | ||
480 | + else | ||
481 | + return -EINVAL; | ||
482 | + i2c_write_current_data(client, 0x03, curr_val); | ||
483 | + return count; | ||
484 | +} | ||
485 | + | ||
486 | +static ssize_t show_mode(struct device *dev, | ||
487 | + struct device_attribute *attr, char *buf) | ||
488 | +{ | ||
489 | + struct i2c_client *client = to_i2c_client(dev); | ||
490 | + int ret_val; | ||
491 | + | ||
492 | + ret_val = i2c_read_current_data(client, 0x03); | ||
493 | + ret_val = ret_val & 0x80; | ||
494 | + if (ret_val == 0x80) | ||
495 | + ret_val = 1; | ||
496 | + return sprintf(buf, "%x", ret_val); | ||
497 | +} | ||
498 | + | ||
499 | +static ssize_t store_mode(struct device *dev, | ||
500 | + struct device_attribute *attr, const char *buf, size_t count) | ||
501 | +{ | ||
502 | + struct i2c_client *client = to_i2c_client(dev); | ||
503 | + unsigned long val = 0; | ||
504 | + char curr_val; | ||
505 | + | ||
506 | + if (strict_strtoul(buf, 10, &val)) | ||
507 | + return -EINVAL; | ||
508 | + | ||
509 | + curr_val = i2c_read_current_data(client, 0x03); | ||
510 | + if (val == INTERRUPT_MODE_ENABLE) | ||
511 | + curr_val = curr_val & 0x7F; | ||
512 | + else if (val == INTERRUPT_MODE_DISABLE) | ||
513 | + curr_val = curr_val | 0x80; | ||
514 | + else | ||
515 | + return -EINVAL; | ||
516 | + i2c_write_current_data(client, 0x03, curr_val); | ||
517 | + return count; | ||
518 | +} | ||
519 | + | ||
520 | +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, | ||
521 | + show_temp_auto_offset, store_temp_auto_offset, 0, 1); | ||
522 | +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, | ||
523 | + show_temp_auto_offset, store_temp_auto_offset, 1, 1); | ||
524 | +static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, | ||
525 | + show_temp_auto_offset, store_temp_auto_offset, 2, 1); | ||
526 | +static DEVICE_ATTR(temp1_curr, S_IRUGO, show_temp1_curr_temp, NULL); | ||
527 | + | ||
528 | +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, | ||
529 | + show_temp_auto_offset, store_temp_auto_offset, 0, 2); | ||
530 | +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, | ||
531 | + show_temp_auto_offset, store_temp_auto_offset, 1, 2); | ||
532 | +static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, | ||
533 | + show_temp_auto_offset, store_temp_auto_offset, 2, 2); | ||
534 | +static DEVICE_ATTR(temp2_curr, S_IRUGO, show_temp2_curr_temp, NULL); | ||
535 | + | ||
536 | +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, | ||
537 | + show_temp_auto_offset, store_temp_auto_offset, 0, 4); | ||
538 | +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, | ||
539 | + show_temp_auto_offset, store_temp_auto_offset, 1, 4); | ||
540 | +static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, | ||
541 | + show_temp_auto_offset, store_temp_auto_offset, 2, 4); | ||
542 | +static DEVICE_ATTR(temp3_curr, S_IRUGO, show_temp3_curr_temp, NULL); | ||
543 | + | ||
544 | +static DEVICE_ATTR(hyster, S_IRUGO | S_IWUSR, show_temp_hyst, store_temp_hyst); | ||
545 | +static DEVICE_ATTR(status, S_IRUGO, show_status_reg, NULL); | ||
546 | + | ||
547 | +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, | ||
548 | + show_power_state, store_power_state); | ||
549 | +static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode); | ||
550 | + | ||
551 | +static struct attribute *mid_att_thermal[] = { | ||
552 | + &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
553 | + &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
554 | + &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
555 | + &dev_attr_temp1_curr.attr, | ||
556 | + &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
557 | + &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
558 | + &sensor_dev_attr_temp2_crit.dev_attr.attr, | ||
559 | + &dev_attr_temp2_curr.attr, | ||
560 | + &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
561 | + &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
562 | + &sensor_dev_attr_temp3_crit.dev_attr.attr, | ||
563 | + &dev_attr_temp3_curr.attr, | ||
564 | + &dev_attr_hyster.attr, | ||
565 | + &dev_attr_status.attr, | ||
566 | + &dev_attr_power_state.attr, | ||
567 | + &dev_attr_mode.attr, | ||
568 | + NULL | ||
569 | +}; | ||
570 | + | ||
571 | +static struct attribute_group m_thermal_gr = { | ||
572 | + .name = "emc1403", | ||
573 | + .attrs = mid_att_thermal | ||
574 | +}; | ||
575 | + | ||
576 | +static void emc1403_set_default_config(struct i2c_client *client) | ||
577 | +{ | ||
578 | + i2c_smbus_write_byte_data(client, 0x03, 0x00); | ||
579 | + i2c_smbus_write_byte_data(client, 0x04, 0x02); | ||
580 | + i2c_smbus_write_byte_data(client, 0x22, 0x00); | ||
581 | +} | ||
582 | + | ||
583 | +#ifdef MOORESTOWN_INTERRUPT_ENABLE | ||
584 | +static irqreturn_t therm_interrupt_handler(int id, void *dev) | ||
585 | +{ | ||
586 | + struct thermal_data *data = (struct thermal_data *)dev; | ||
587 | + schedule_work(&data->therm_handler); | ||
588 | + | ||
589 | + return IRQ_HANDLED; | ||
590 | +} | ||
591 | + | ||
592 | +static irqreturn_t alert_interrupt_handler(int id, void *dev) | ||
593 | +{ | ||
594 | + struct thermal_data *data = (struct thermal_data *)dev; | ||
595 | + schedule_work(&data->alert_handler); | ||
596 | + | ||
597 | + return IRQ_HANDLED; | ||
598 | +} | ||
599 | + | ||
600 | +/* when the device raise the interrupt we mask the interrupt | ||
601 | + * bit for that device as the status register is R-C | ||
602 | + * so that till thermal governor doesnot take action we need | ||
603 | + * not to send continuous events */ | ||
604 | + | ||
605 | +static int interrupt_status(struct i2c_client *client, u8 diode_reg_val, | ||
606 | + u8 *status, u8 event) | ||
607 | +{ | ||
608 | + u8 crit_st = 0, set_mask = 0; | ||
609 | + | ||
610 | + set_mask = i2c_read_current_data(client, 0x1F); | ||
611 | + if (diode_reg_val & THM_CHAN_TEMP[3]) { | ||
612 | + set_mask = (set_mask | 0x02); | ||
613 | + crit_st = (crit_st | 2); | ||
614 | + } | ||
615 | + if (diode_reg_val & THM_CHAN_TEMP[2]) { | ||
616 | + set_mask = (set_mask | 0x04); | ||
617 | + crit_st = (crit_st | 4); | ||
618 | + } | ||
619 | + if (diode_reg_val & THM_CHAN_TEMP[4]) { | ||
620 | + set_mask = (set_mask | 0x01); | ||
621 | + crit_st = (crit_st | 1); | ||
622 | + } | ||
623 | + if (event == ALERT_EVENT) | ||
624 | + i2c_smbus_write_byte_data(client, 0x1F, set_mask); | ||
625 | + *status = crit_st; | ||
626 | + return 0; | ||
627 | +} | ||
628 | + | ||
629 | +static void ospm_event(int event_id, int sensor_id, int curr_temp) | ||
630 | +{ | ||
631 | + if (event_id == THERM_EVENT) { | ||
632 | + printk(KERN_ALERT "emc1403: Sensor Id = %d crit event \ | ||
633 | + temp = %d \n", sensor_id, curr_temp); | ||
634 | + ospm_generate_netlink_event(sensor_id, | ||
635 | + OSPM_EVENT_THERMAL_CRITICAL); | ||
636 | + } | ||
637 | + if (event_id == HIGH_EVENT) { | ||
638 | + printk(KERN_ALERT "emc1403: Sensor Id = %d AUX1 event \ | ||
639 | + temp = %d \n", sensor_id, curr_temp); | ||
640 | + ospm_generate_netlink_event(sensor_id, | ||
641 | + OSPM_EVENT_THERMAL_AUX1); | ||
642 | + } | ||
643 | + if (event_id == LOW_EVENT) { | ||
644 | + printk(KERN_ALERT "emc1403: Sensor Id = %d AUX0 event \ | ||
645 | + temp = %d \n", sensor_id, curr_temp); | ||
646 | + ospm_generate_netlink_event(sensor_id, | ||
647 | + OSPM_EVENT_THERMAL_AUX0); | ||
648 | + } | ||
649 | + if (event_id == FAULT_EVENT) { | ||
650 | + printk(KERN_ALERT "emc1403: Sensor Id = %d Fault event \ | ||
651 | + temp = %d \n", sensor_id, curr_temp); | ||
652 | + ospm_generate_netlink_event(sensor_id, | ||
653 | + OSPM_EVENT_THERMAL_DEV_FAULT); | ||
654 | + } | ||
655 | +} | ||
656 | + | ||
657 | +static void send_event(struct i2c_client *client, int status, int event_id) | ||
658 | +{ | ||
659 | + int ret_val; | ||
660 | + | ||
661 | + if (status & TEMP1) { | ||
662 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[0]); | ||
663 | + ospm_event(event_id, TEMP_DEV_ID1, ret_val); | ||
664 | + } | ||
665 | + if (status & TEMP2) { | ||
666 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[1]); | ||
667 | + ospm_event(event_id, TEMP_DEV_ID2, ret_val); | ||
668 | + } | ||
669 | + if (status & TEMP3) { | ||
670 | + ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[2]); | ||
671 | + ospm_event(event_id, TEMP_DEV_ID3, ret_val); | ||
672 | + } | ||
673 | +} | ||
674 | + | ||
675 | +static void therm_handle_intrpt(struct work_struct *work) | ||
676 | +{ | ||
677 | + u8 status, reg_val; | ||
678 | + struct thermal_data *data = container_of(work, | ||
679 | + struct thermal_data, therm_handler); | ||
680 | + | ||
681 | + /* check if therm_module_info is initialized */ | ||
682 | + if (!data) | ||
683 | + return; | ||
684 | + /* Which DIODE has raised the interrupt 0x1B | ||
685 | + internal/External1/External2 */ | ||
686 | + reg_val = i2c_smbus_read_byte_data(data->client, | ||
687 | + THM_STAT_REG_TEMP[0]); | ||
688 | + interrupt_status(data->client, reg_val, &status, THERM_EVENT); | ||
689 | + send_event(data->client, status, THERM_EVENT); | ||
690 | +} | ||
691 | + | ||
692 | +static void alert_handle_intrpt(struct work_struct *work) | ||
693 | +{ | ||
694 | + int sta_reg_val, reg_val; | ||
695 | + u8 status; | ||
696 | + struct thermal_data *data = container_of(work, | ||
697 | + struct thermal_data, alert_handler); | ||
698 | + if (!data) | ||
699 | + return; | ||
700 | + /* HIGH/ LOW / FAULT Alert has occured for */ | ||
701 | + reg_val = i2c_smbus_read_byte_data(data->client, THM_STAT_REG_TEMP[4]); | ||
702 | + /* High status bit is set */ | ||
703 | + if (reg_val & THM_CHAN_TEMP[0]) { | ||
704 | + /* Which DIODE has raised the interrupt 0x1B | ||
705 | + internal/External1/External2 */ | ||
706 | + sta_reg_val = i2c_smbus_read_byte_data(data->client, | ||
707 | + THM_STAT_REG_TEMP[1]); | ||
708 | + interrupt_status(data->client, sta_reg_val, &status, | ||
709 | + ALERT_EVENT); | ||
710 | + send_event(data->client, status, HIGH_EVENT); | ||
711 | + } | ||
712 | + /* Low status bit is set */ | ||
713 | + if (reg_val & THM_CHAN_TEMP[1]) { | ||
714 | + sta_reg_val = i2c_smbus_read_byte_data(data->client, | ||
715 | + THM_STAT_REG_TEMP[2]); | ||
716 | + interrupt_status(data->client, sta_reg_val, &status, | ||
717 | + ALERT_EVENT); | ||
718 | + send_event(data->client, status, LOW_EVENT); | ||
719 | + } | ||
720 | + /* Fault status bit is set */ | ||
721 | + if (reg_val & THM_CHAN_TEMP[2]) { | ||
722 | + sta_reg_val = i2c_smbus_read_byte_data(data->client, | ||
723 | + THM_STAT_REG_TEMP[3]); | ||
724 | + interrupt_status(data->client, sta_reg_val, &status, | ||
725 | + ALERT_EVENT); | ||
726 | + send_event(data->client, status, FAULT_EVENT); | ||
727 | + } | ||
728 | +} | ||
729 | +#endif | ||
730 | + | ||
731 | +static int emc1403_probe(struct i2c_client *new_client, | ||
732 | + const struct i2c_device_id *id) | ||
733 | +{ | ||
734 | + int res = 0; | ||
735 | + struct thermal_data *data; | ||
736 | + u16 pid, smsc_id, revision; | ||
737 | + | ||
738 | +#ifdef MOORESTOWN_INTERRUPT_ENABLE | ||
739 | + u16 t_irq, a_irq; | ||
740 | +#endif | ||
741 | + data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL); | ||
742 | + | ||
743 | + if (data == NULL) { | ||
744 | + printk(KERN_WARNING "emc1403: Memory allocation failed"); | ||
745 | + return -ENOMEM; | ||
746 | + } | ||
747 | + data->client = new_client; | ||
748 | + i2c_set_clientdata(new_client, data); | ||
749 | + | ||
750 | + /* Check if thermal chip is SMSC and EMC1403 */ | ||
751 | + smsc_id = i2c_read_current_data(new_client, | ||
752 | + THERMAL_SMSC_ID_REG); | ||
753 | + if (smsc_id != 0x5d) { | ||
754 | + printk(KERN_WARNING "emc1403: vendor id mismatch \n"); | ||
755 | + goto thermal_error1; | ||
756 | + } | ||
757 | + pid = i2c_read_current_data(new_client, THERMAL_PID_REG); | ||
758 | + if (pid != 0x21) { | ||
759 | + printk(KERN_WARNING "emc1403: Prod id mismatch \n"); | ||
760 | + goto thermal_error1; | ||
761 | + } | ||
762 | + revision = i2c_read_current_data(new_client, | ||
763 | + THERMAL_REVISION_REG); | ||
764 | + if (revision != 0x01) { | ||
765 | + printk(KERN_WARNING "emc1403: Rev id mismatch is \n"); | ||
766 | + goto thermal_error1; | ||
767 | + } | ||
768 | + res = sysfs_create_group(&new_client->dev.kobj, &m_thermal_gr); | ||
769 | + if (res) { | ||
770 | + printk(KERN_WARNING "emc1403: create group failed! \n"); | ||
771 | + hwmon_device_unregister(data->hwmon_dev); | ||
772 | + goto thermal_error1; | ||
773 | + } | ||
774 | + data->hwmon_dev = hwmon_device_register(&new_client->dev); | ||
775 | + if (IS_ERR(data->hwmon_dev)) { | ||
776 | + res = PTR_ERR(data->hwmon_dev); | ||
777 | + data->hwmon_dev = NULL; | ||
778 | + printk(KERN_WARNING "emc1403:Register hwmon dev Failed\n"); | ||
779 | + goto thermal_error1; | ||
780 | + } | ||
781 | +#ifdef MOORESTOWN_INTERRUPT_ENABLE | ||
782 | + INIT_WORK(&data->therm_handler, (void *)therm_handle_intrpt); | ||
783 | + INIT_WORK(&data->alert_handler, (void *)alert_handle_intrpt); | ||
784 | + t_irq = new_client->irq; | ||
785 | + a_irq = *(short *)new_client->dev.platform_data; | ||
786 | + data->therm_irq = t_irq & ~IRQ_TYPE_MASK; | ||
787 | + data->alert_irq = a_irq & ~IRQ_TYPE_MASK; | ||
788 | + /* interpret irq field */ | ||
789 | + if (data->therm_irq == 0x113) { | ||
790 | + if (t_irq & IRQ_TYPE_MASK) { | ||
791 | + /* irq -> GPE_ID */ | ||
792 | + res = request_gpe(data->therm_irq, | ||
793 | + (gpio_function_t)therm_interrupt_handler, | ||
794 | + data, DETECT_LEVEL_LOW); | ||
795 | + if (res) | ||
796 | + dev_crit(&new_client->dev, "%s(): cannot \ | ||
797 | + register therm gpe \n", __func__); | ||
798 | + } else { | ||
799 | + res = request_irq(data->therm_irq, | ||
800 | + therm_interrupt_handler, | ||
801 | + DETECT_LEVEL_LOW, "emc1403", data); | ||
802 | + if (res) | ||
803 | + dev_crit(&new_client->dev, "%s(): \ | ||
804 | + cannot get therm IRQ\n", __func__); | ||
805 | + } | ||
806 | + } else { | ||
807 | + printk(KERN_WARNING"emc1403: IRQ mismatch \ | ||
808 | + sent for therm registration"); | ||
809 | + } | ||
810 | + if (data->alert_irq == 0x114) { | ||
811 | + if (a_irq & IRQ_TYPE_MASK) { | ||
812 | + /* irq -> GPE_ID */ | ||
813 | + res = request_gpe(data->alert_irq, | ||
814 | + (gpio_function_t)alert_interrupt_handler, | ||
815 | + data, DETECT_LEVEL_LOW); | ||
816 | + if (res) | ||
817 | + dev_crit(&new_client->dev, "%s(): \ | ||
818 | + cannot register alert gpe \n", __func__); | ||
819 | + } else { | ||
820 | + res = request_irq(data->alert_irq, | ||
821 | + alert_interrupt_handler, DETECT_LEVEL_LOW, | ||
822 | + "emc1403", data); | ||
823 | + if (res) | ||
824 | + dev_crit(&new_client->dev, "%s(): cannot \ | ||
825 | + get alert IRQ\n", __func__); | ||
826 | + } | ||
827 | + } else { | ||
828 | + printk(KERN_WARNING"emc1403: IRQ mismatch \ | ||
829 | + sent for alert registration"); | ||
830 | + } | ||
831 | +#endif | ||
832 | + emc1403_set_default_config(new_client); | ||
833 | + dev_info(&new_client->dev, "%s EMC1403 Thermal chip found \n", | ||
834 | + new_client->name); | ||
835 | + return res; | ||
836 | +thermal_error1: | ||
837 | + i2c_set_clientdata(new_client, NULL); | ||
838 | + kfree(data); | ||
839 | + return res; | ||
840 | +} | ||
841 | + | ||
842 | +static int emc1403_remove(struct i2c_client *client) | ||
843 | +{ | ||
844 | + struct thermal_data *data = i2c_get_clientdata(client); | ||
845 | + | ||
846 | + hwmon_device_unregister(data->hwmon_dev); | ||
847 | + sysfs_remove_group(&client->dev.kobj, &m_thermal_gr); | ||
848 | + kfree(data); | ||
849 | + return 0; | ||
850 | +} | ||
851 | + | ||
852 | +static struct i2c_device_id emc1403_idtable[] = { | ||
853 | + { "i2c_thermal", 0 }, | ||
854 | + { } | ||
855 | +}; | ||
856 | + | ||
857 | +MODULE_DEVICE_TABLE(i2c, emc1403_idtable); | ||
858 | + | ||
859 | +static struct i2c_driver sensor_emc1403 = { | ||
860 | + .driver = { | ||
861 | + .name = "emc1403", | ||
862 | + }, | ||
863 | + .probe = emc1403_probe, | ||
864 | + .remove = emc1403_remove, | ||
865 | + .id_table = emc1403_idtable, | ||
866 | +}; | ||
867 | + | ||
868 | +static int __init sensor_emc1403_init(void) | ||
869 | +{ | ||
870 | + return i2c_add_driver(&sensor_emc1403); | ||
871 | +} | ||
872 | + | ||
873 | +static void __exit sensor_emc1403_exit(void) | ||
874 | +{ | ||
875 | + i2c_del_driver(&sensor_emc1403); | ||
876 | +} | ||
877 | + | ||
878 | +module_init(sensor_emc1403_init); | ||
879 | +module_exit(sensor_emc1403_exit); | ||
880 | --- /dev/null | ||
881 | +++ b/drivers/hwmon/hmc6352.c | ||
882 | @@ -0,0 +1,250 @@ | ||
883 | +/* | ||
884 | + * hmc6352.c - Honeywell Compass Driver | ||
885 | + * | ||
886 | + * Copyright (C) 2009 Intel Corp | ||
887 | + * | ||
888 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
889 | + * | ||
890 | + * This program is free software; you can redistribute it and/or modify | ||
891 | + * it under the terms of the GNU General Public License as published by | ||
892 | + * the Free Software Foundation; version 2 of the License. | ||
893 | + * | ||
894 | + * This program is distributed in the hope that it will be useful, but | ||
895 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
896 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
897 | + * General Public License for more details. | ||
898 | + * | ||
899 | + * You should have received a copy of the GNU General Public License along | ||
900 | + * with this program; if not, write to the Free Software Foundation, Inc., | ||
901 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
902 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
903 | + * | ||
904 | + */ | ||
905 | + | ||
906 | +#include <linux/module.h> | ||
907 | +#include <linux/init.h> | ||
908 | +#include <linux/slab.h> | ||
909 | +#include <linux/i2c.h> | ||
910 | +#include <linux/hwmon.h> | ||
911 | +#include <linux/hwmon-sysfs.h> | ||
912 | +#include <linux/hwmon-vid.h> | ||
913 | +#include <linux/err.h> | ||
914 | +#include <linux/delay.h> | ||
915 | +#include <linux/mutex.h> | ||
916 | +#include <linux/sysfs.h> | ||
917 | +#include <asm/ipc_defs.h> | ||
918 | + | ||
919 | + | ||
920 | +MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); | ||
921 | +MODULE_DESCRIPTION("hmc6352 Compass Driver"); | ||
922 | +MODULE_LICENSE("GPL v2"); | ||
923 | + | ||
924 | +/* internal return values */ | ||
925 | +#define COMP_CALIB_START 1 | ||
926 | +#define COMP_CALIB_STOP 2 | ||
927 | +#define COMP_SLEEP_MODE 0 | ||
928 | +#define COMP_ACTIVE_MODE 1 | ||
929 | + | ||
930 | +struct compass_data { | ||
931 | + struct device *hwmon_dev; | ||
932 | +}; | ||
933 | + | ||
934 | +static ssize_t compass_calibration_store(struct device *dev, | ||
935 | + struct device_attribute *attr, const char *buf, size_t count) | ||
936 | +{ | ||
937 | + struct i2c_client *client = to_i2c_client(dev); | ||
938 | + int ret; | ||
939 | + unsigned long val; | ||
940 | + char cmd[] = {0x43}; | ||
941 | + char cmd1[] = {0x45}; | ||
942 | + struct i2c_msg msg[] = { | ||
943 | + { client->addr, 0, 1, cmd }, | ||
944 | + }; | ||
945 | + struct i2c_msg msg1[] = { | ||
946 | + { client->addr, 0, 1, cmd1 }, | ||
947 | + }; | ||
948 | + | ||
949 | + if (strict_strtoul(buf, 10, &val)) | ||
950 | + return -EINVAL; | ||
951 | + if (val == COMP_CALIB_START) { | ||
952 | + client->addr = 0x21; | ||
953 | + ret = i2c_transfer(client->adapter, msg, 1); | ||
954 | + if (ret != 1) { | ||
955 | + printk(KERN_WARNING "hmc6352_comp : i2c callib start \ | ||
956 | + cmd failed \n"); | ||
957 | + return ret; | ||
958 | + } | ||
959 | + } else if (val == COMP_CALIB_STOP) { | ||
960 | + client->addr = 0x21; | ||
961 | + ret = i2c_transfer(client->adapter, msg1, 1); | ||
962 | + if (ret != 1) { | ||
963 | + printk(KERN_WARNING " hmc6352_comp : i2c callib stop \ | ||
964 | + cmd failed \n"); | ||
965 | + return ret; | ||
966 | + } | ||
967 | + } else | ||
968 | + return -EINVAL; | ||
969 | + | ||
970 | + return count; | ||
971 | +} | ||
972 | + | ||
973 | +static ssize_t compass_heading_data_show(struct device *dev, | ||
974 | + struct device_attribute *attr, char *buf) | ||
975 | +{ | ||
976 | + | ||
977 | + struct i2c_client *client = to_i2c_client(dev); | ||
978 | + char cmd[] = {0x41}; | ||
979 | + unsigned char i2c_data[2] = {0, 0}; | ||
980 | + unsigned int ret, ret_val; | ||
981 | + struct i2c_msg msg[] = { | ||
982 | + { client->addr, 0, 1, cmd }, | ||
983 | + }; | ||
984 | + struct i2c_msg msg1[] = { | ||
985 | + { client->addr, I2C_M_RD, 2, i2c_data }, | ||
986 | + }; | ||
987 | + | ||
988 | + client->addr = 0x21; | ||
989 | + ret = i2c_transfer(client->adapter, msg, 1); | ||
990 | + if (ret != 1) { | ||
991 | + printk(KERN_WARNING "hmc6352 : i2c cmd 0x41 failed \n"); | ||
992 | + return ret; | ||
993 | + } | ||
994 | + msleep(10); /* sending 0x41 cmd we need to wait for 7-10 milli second*/ | ||
995 | + ret = i2c_transfer(client->adapter, msg1, 1); | ||
996 | + if (ret != 1) { | ||
997 | + printk(KERN_WARNING "hmc6352 : i2c read data cmd failed \n"); | ||
998 | + return ret; | ||
999 | + } | ||
1000 | + ret_val = i2c_data[0]; | ||
1001 | + ret_val = ((ret_val << 8) | i2c_data[1]); | ||
1002 | + return sprintf(buf, "%d.%d\n", ret_val/10, ret_val%10); | ||
1003 | +} | ||
1004 | + | ||
1005 | +static ssize_t compass_power_mode_store(struct device *dev, | ||
1006 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1007 | +{ | ||
1008 | + | ||
1009 | + struct i2c_client *client = to_i2c_client(dev); | ||
1010 | + unsigned long val; | ||
1011 | + unsigned int ret; | ||
1012 | + char cmd[] = {0x53}; | ||
1013 | + char cmd1[] = {0x57}; | ||
1014 | + struct i2c_msg msg[] = { | ||
1015 | + { client->addr, 0, 1, cmd }, | ||
1016 | + }; | ||
1017 | + struct i2c_msg msg1[] = { | ||
1018 | + { client->addr, 0, 1, cmd1 }, | ||
1019 | + }; | ||
1020 | + | ||
1021 | + if (strict_strtoul(buf, 10, &val)) | ||
1022 | + return -EINVAL; | ||
1023 | + | ||
1024 | + if (val == COMP_SLEEP_MODE) { | ||
1025 | + ret = i2c_transfer(client->adapter, msg, 1); | ||
1026 | + if (ret != 1) | ||
1027 | + printk(KERN_WARNING "hmc6352: i2c cmd sleep mode \ | ||
1028 | + failed \n"); | ||
1029 | + } else if (val == COMP_ACTIVE_MODE) { | ||
1030 | + ret = i2c_transfer(client->adapter, msg1, 1); | ||
1031 | + if (ret != 1) | ||
1032 | + printk(KERN_WARNING "hmc6352: i2c cmd active mode \ | ||
1033 | + failed \n"); | ||
1034 | + } else | ||
1035 | + return -EINVAL; | ||
1036 | + | ||
1037 | + return count; | ||
1038 | +} | ||
1039 | + | ||
1040 | +static DEVICE_ATTR(heading, S_IRUGO, compass_heading_data_show, NULL); | ||
1041 | +static DEVICE_ATTR(calibration, S_IWUSR, NULL, compass_calibration_store); | ||
1042 | +static DEVICE_ATTR(power_state, S_IWUSR, NULL, compass_power_mode_store); | ||
1043 | + | ||
1044 | +static struct attribute *mid_att_compass[] = { | ||
1045 | + &dev_attr_heading.attr, | ||
1046 | + &dev_attr_calibration.attr, | ||
1047 | + &dev_attr_power_state.attr, | ||
1048 | + NULL | ||
1049 | +}; | ||
1050 | + | ||
1051 | +static struct attribute_group m_compass_gr = { | ||
1052 | + .name = "hmc6352", | ||
1053 | + .attrs = mid_att_compass | ||
1054 | +}; | ||
1055 | + | ||
1056 | +static int hmc6352_probe(struct i2c_client *client, | ||
1057 | + const struct i2c_device_id *id) | ||
1058 | +{ | ||
1059 | + int res; | ||
1060 | + struct compass_data *data; | ||
1061 | + | ||
1062 | + data = kzalloc(sizeof(struct compass_data), GFP_KERNEL); | ||
1063 | + if (data == NULL) { | ||
1064 | + printk(KERN_WARNING "hmc6352: Memory initialization failed"); | ||
1065 | + return -ENOMEM; | ||
1066 | + } | ||
1067 | + i2c_set_clientdata(client, data); | ||
1068 | + | ||
1069 | + res = sysfs_create_group(&client->dev.kobj, &m_compass_gr); | ||
1070 | + if (res) { | ||
1071 | + printk(KERN_WARNING "hmc6352: device_create_file failed!!\n"); | ||
1072 | + goto compass_error1; | ||
1073 | + } | ||
1074 | + data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1075 | + if (IS_ERR(data->hwmon_dev)) { | ||
1076 | + res = PTR_ERR(data->hwmon_dev); | ||
1077 | + data->hwmon_dev = NULL; | ||
1078 | + printk(KERN_WARNING "hmc6352: fail to register hwmon device\n"); | ||
1079 | + sysfs_remove_group(&client->dev.kobj, &m_compass_gr); | ||
1080 | + goto compass_error1; | ||
1081 | + } | ||
1082 | + dev_info(&client->dev, "%s HMC6352 compass chip found \n", | ||
1083 | + client->name); | ||
1084 | + return res; | ||
1085 | + | ||
1086 | +compass_error1: | ||
1087 | + i2c_set_clientdata(client, NULL); | ||
1088 | + kfree(data); | ||
1089 | + return res; | ||
1090 | +} | ||
1091 | + | ||
1092 | +static int hmc6352_remove(struct i2c_client *client) | ||
1093 | +{ | ||
1094 | + struct compass_data *data = i2c_get_clientdata(client); | ||
1095 | + | ||
1096 | + hwmon_device_unregister(data->hwmon_dev); | ||
1097 | + sysfs_remove_group(&client->dev.kobj, &m_compass_gr); | ||
1098 | + kfree(data); | ||
1099 | + return 0; | ||
1100 | +} | ||
1101 | + | ||
1102 | +static struct i2c_device_id hmc6352_id[] = { | ||
1103 | + { "i2c_compass", 0 }, | ||
1104 | + { } | ||
1105 | +}; | ||
1106 | + | ||
1107 | +MODULE_DEVICE_TABLE(i2c, hmc6352_id); | ||
1108 | + | ||
1109 | +static struct i2c_driver hmc6352_driver = { | ||
1110 | + .driver = { | ||
1111 | + .name = "hmc6352", | ||
1112 | + }, | ||
1113 | + .probe = hmc6352_probe, | ||
1114 | + .remove = hmc6352_remove, | ||
1115 | + .id_table = hmc6352_id, | ||
1116 | +}; | ||
1117 | + | ||
1118 | +static int __init sensor_hmc6352_init(void) | ||
1119 | +{ | ||
1120 | + int res; | ||
1121 | + | ||
1122 | + res = i2c_add_driver(&hmc6352_driver); | ||
1123 | + return res; | ||
1124 | +} | ||
1125 | + | ||
1126 | +static void __exit sensor_hmc6352_exit(void) | ||
1127 | +{ | ||
1128 | + i2c_del_driver(&hmc6352_driver); | ||
1129 | +} | ||
1130 | + | ||
1131 | +module_init(sensor_hmc6352_init); | ||
1132 | +module_exit(sensor_hmc6352_exit); | ||
1133 | --- /dev/null | ||
1134 | +++ b/drivers/hwmon/isl29020.c | ||
1135 | @@ -0,0 +1,248 @@ | ||
1136 | +/* | ||
1137 | + * isl29020.c - Intersil ALS Driver | ||
1138 | + * | ||
1139 | + * Copyright (C) 2008 Intel Corp | ||
1140 | + * | ||
1141 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1142 | + * | ||
1143 | + * This program is free software; you can redistribute it and/or modify | ||
1144 | + * it under the terms of the GNU General Public License as published by | ||
1145 | + * the Free Software Foundation; version 2 of the License. | ||
1146 | + * | ||
1147 | + * This program is distributed in the hope that it will be useful, but | ||
1148 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1149 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1150 | + * General Public License for more details. | ||
1151 | + * | ||
1152 | + * You should have received a copy of the GNU General Public License along | ||
1153 | + * with this program; if not, write to the Free Software Foundation, Inc., | ||
1154 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
1155 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1156 | + * | ||
1157 | + */ | ||
1158 | + | ||
1159 | +#include <linux/module.h> | ||
1160 | +#include <linux/init.h> | ||
1161 | +#include <linux/slab.h> | ||
1162 | +#include <linux/i2c.h> | ||
1163 | +#include <linux/hwmon.h> | ||
1164 | +#include <linux/hwmon-sysfs.h> | ||
1165 | +#include <linux/hwmon-vid.h> | ||
1166 | +#include <linux/err.h> | ||
1167 | +#include <linux/delay.h> | ||
1168 | +#include <linux/mutex.h> | ||
1169 | +#include <linux/sysfs.h> | ||
1170 | +#include <asm/ipc_defs.h> | ||
1171 | + | ||
1172 | +MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); | ||
1173 | +MODULE_DESCRIPTION("intersil isl29020 ALS Driver"); | ||
1174 | +MODULE_LICENSE("GPL v2"); | ||
1175 | + | ||
1176 | +#define ALS_MIN_RANGE_VAL 0 | ||
1177 | +#define ALS_MAX_RANGE_VAL 5 | ||
1178 | +#define POWER_STA_ENABLE 1 | ||
1179 | +#define POWER_STA_DISABLE 0 | ||
1180 | + | ||
1181 | +struct als_data { | ||
1182 | + struct device *hwmon_dev; | ||
1183 | +}; | ||
1184 | + | ||
1185 | +static unsigned int i2c_write_current_data(struct i2c_client *client, | ||
1186 | + unsigned int reg, unsigned int value) | ||
1187 | +{ | ||
1188 | + int ret_val; | ||
1189 | + | ||
1190 | + ret_val = i2c_smbus_write_byte_data(client, reg, value); | ||
1191 | + return ret_val; | ||
1192 | +} | ||
1193 | + | ||
1194 | +static ssize_t als_sensing_range_show(struct device *dev, | ||
1195 | + struct device_attribute *attr, char *buf) | ||
1196 | +{ | ||
1197 | + struct i2c_client *client = to_i2c_client(dev); | ||
1198 | + int val; | ||
1199 | + | ||
1200 | + val = i2c_smbus_read_byte_data(client, 0x00); | ||
1201 | + return sprintf(buf, "%d000\n", 1 << (2 * (val & 3))); | ||
1202 | + | ||
1203 | +} | ||
1204 | + | ||
1205 | +static ssize_t als_lux_output_data_show(struct device *dev, | ||
1206 | + struct device_attribute *attr, char *buf) | ||
1207 | +{ | ||
1208 | + struct i2c_client *client = to_i2c_client(dev); | ||
1209 | + unsigned int ret_val, val; | ||
1210 | + unsigned long int lux, max_count; | ||
1211 | + int tempv1, tempv2; | ||
1212 | + | ||
1213 | + max_count = 65535; | ||
1214 | + tempv1 = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */ | ||
1215 | + tempv2 = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */ | ||
1216 | + ret_val = tempv1; | ||
1217 | + ret_val = (ret_val << 8 | tempv2); | ||
1218 | + val = i2c_smbus_read_byte_data(client, 0x00); | ||
1219 | + lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / max_count; | ||
1220 | + return sprintf(buf, "%ld\n", lux); | ||
1221 | +} | ||
1222 | + | ||
1223 | +static ssize_t als_sensing_range_store(struct device *dev, | ||
1224 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1225 | +{ | ||
1226 | + struct i2c_client *client = to_i2c_client(dev); | ||
1227 | + unsigned int ret_val, set_val = 0; | ||
1228 | + unsigned long val; | ||
1229 | + | ||
1230 | + if (strict_strtoul(buf, 10, &val)) | ||
1231 | + return -EINVAL; | ||
1232 | + ret_val = i2c_smbus_read_byte_data(client, 0x00); | ||
1233 | + ret_val = ret_val & 0xFC; /*reset the bit before setting them */ | ||
1234 | + if (val == 1) | ||
1235 | + set_val = (ret_val | 0x00); /* setting the 1:0 bit */ | ||
1236 | + else if (val == 2) | ||
1237 | + set_val = (ret_val | 0x01); | ||
1238 | + else if (val == 3) | ||
1239 | + set_val = (ret_val | 0x02); | ||
1240 | + else if (val == 4) | ||
1241 | + set_val = (ret_val | 0x03); | ||
1242 | + else | ||
1243 | + goto invarg; | ||
1244 | + i2c_write_current_data(client, 0x00, set_val); | ||
1245 | + return count; | ||
1246 | +invarg: | ||
1247 | + return -EINVAL; | ||
1248 | +} | ||
1249 | + | ||
1250 | +static ssize_t als_power_status_show(struct device *dev, | ||
1251 | + struct device_attribute *attr, char *buf) | ||
1252 | +{ | ||
1253 | + struct i2c_client *client = to_i2c_client(dev); | ||
1254 | + int ret_val; | ||
1255 | + | ||
1256 | + ret_val = i2c_smbus_read_byte_data(client, 0x00); | ||
1257 | + ret_val = ret_val & 0x80; | ||
1258 | + if (ret_val == 0x80) | ||
1259 | + ret_val = 1; | ||
1260 | + return sprintf(buf, "%x", ret_val); | ||
1261 | +} | ||
1262 | + | ||
1263 | +static ssize_t als_power_status_store(struct device *dev, | ||
1264 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1265 | +{ | ||
1266 | + struct i2c_client *client = to_i2c_client(dev); | ||
1267 | + unsigned long val = 0; | ||
1268 | + char curr_val; | ||
1269 | + | ||
1270 | + if (strict_strtoul(buf, 10, &val)) | ||
1271 | + return -EINVAL; | ||
1272 | + | ||
1273 | + curr_val = i2c_smbus_read_byte_data(client, 0x00); | ||
1274 | + if (val == POWER_STA_ENABLE) | ||
1275 | + curr_val = curr_val | 0x80; | ||
1276 | + else if (val == POWER_STA_DISABLE) | ||
1277 | + curr_val = curr_val & 0x7F; | ||
1278 | + else | ||
1279 | + return -EINVAL; | ||
1280 | + i2c_write_current_data(client, 0x00, curr_val); | ||
1281 | + return count; | ||
1282 | +} | ||
1283 | + | ||
1284 | +static DEVICE_ATTR(sensing_range, S_IRUGO | S_IWUSR, | ||
1285 | + als_sensing_range_show, als_sensing_range_store); | ||
1286 | +static DEVICE_ATTR(lux_output, S_IRUGO, als_lux_output_data_show, NULL); | ||
1287 | +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, | ||
1288 | + als_power_status_show, als_power_status_store); | ||
1289 | + | ||
1290 | +static struct attribute *mid_att_als[] = { | ||
1291 | + &dev_attr_sensing_range.attr, | ||
1292 | + &dev_attr_lux_output.attr, | ||
1293 | + &dev_attr_power_state.attr, | ||
1294 | + NULL | ||
1295 | +}; | ||
1296 | + | ||
1297 | +static struct attribute_group m_als_gr = { | ||
1298 | + .name = "isl29020", | ||
1299 | + .attrs = mid_att_als | ||
1300 | +}; | ||
1301 | + | ||
1302 | +static void als_set_default_config(struct i2c_client *client) | ||
1303 | +{ | ||
1304 | + i2c_write_current_data(client, 0x00, 0xc0); | ||
1305 | +} | ||
1306 | + | ||
1307 | +static int isl29020_probe(struct i2c_client *client, | ||
1308 | + const struct i2c_device_id *id) | ||
1309 | +{ | ||
1310 | + int res; | ||
1311 | + struct als_data *data; | ||
1312 | + | ||
1313 | + data = kzalloc(sizeof(struct als_data), GFP_KERNEL); | ||
1314 | + if (data == NULL) { | ||
1315 | + printk(KERN_WARNING " isl29020: Memory initialization failed"); | ||
1316 | + return -ENOMEM; | ||
1317 | + } | ||
1318 | + i2c_set_clientdata(client, data); | ||
1319 | + | ||
1320 | + res = sysfs_create_group(&client->dev.kobj, &m_als_gr); | ||
1321 | + if (res) { | ||
1322 | + printk(KERN_WARNING "isl29020: device create file failed!!\n"); | ||
1323 | + goto als_error1; | ||
1324 | + } | ||
1325 | + data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1326 | + if (IS_ERR(data->hwmon_dev)) { | ||
1327 | + res = PTR_ERR(data->hwmon_dev); | ||
1328 | + data->hwmon_dev = NULL; | ||
1329 | + sysfs_remove_group(&client->dev.kobj, &m_als_gr); | ||
1330 | + printk(KERN_ALERT "isl29020:unable to register hwmon device\n"); | ||
1331 | + goto als_error1; | ||
1332 | + } | ||
1333 | + dev_info(&client->dev, "%s isl29020: ALS chip found \n", client->name); | ||
1334 | + als_set_default_config(client); | ||
1335 | + return res; | ||
1336 | + | ||
1337 | +als_error1: | ||
1338 | + i2c_set_clientdata(client, NULL); | ||
1339 | + kfree(data); | ||
1340 | + return res; | ||
1341 | +} | ||
1342 | + | ||
1343 | +static int isl29020_remove(struct i2c_client *client) | ||
1344 | +{ | ||
1345 | + struct als_data *data = i2c_get_clientdata(client); | ||
1346 | + | ||
1347 | + hwmon_device_unregister(data->hwmon_dev); | ||
1348 | + sysfs_remove_group(&client->dev.kobj, &m_als_gr); | ||
1349 | + kfree(data); | ||
1350 | + return 0; | ||
1351 | +} | ||
1352 | + | ||
1353 | +static struct i2c_device_id isl29020_id[] = { | ||
1354 | + { "i2c_als", 0 }, | ||
1355 | + { } | ||
1356 | +}; | ||
1357 | + | ||
1358 | +MODULE_DEVICE_TABLE(i2c, isl29020_id); | ||
1359 | + | ||
1360 | +static struct i2c_driver isl29020_driver = { | ||
1361 | + .driver = { | ||
1362 | + .name = "isl29020", | ||
1363 | + }, | ||
1364 | + .probe = isl29020_probe, | ||
1365 | + .remove = isl29020_remove, | ||
1366 | + .id_table = isl29020_id, | ||
1367 | +}; | ||
1368 | + | ||
1369 | +static int __init sensor_isl29020_init(void) | ||
1370 | +{ | ||
1371 | + int res; | ||
1372 | + | ||
1373 | + res = i2c_add_driver(&isl29020_driver); | ||
1374 | + return res; | ||
1375 | +} | ||
1376 | + | ||
1377 | +static void __exit sensor_isl29020_exit(void) | ||
1378 | +{ | ||
1379 | + i2c_del_driver(&isl29020_driver); | ||
1380 | +} | ||
1381 | + | ||
1382 | +module_init(sensor_isl29020_init); | ||
1383 | +module_exit(sensor_isl29020_exit); | ||
1384 | --- /dev/null | ||
1385 | +++ b/drivers/hwmon/lis331dl.c | ||
1386 | @@ -0,0 +1,322 @@ | ||
1387 | +/* | ||
1388 | + * lis331dl.c - ST LIS331DL Accelerometer Driver | ||
1389 | + * | ||
1390 | + * Copyright (C) 2009 Intel Corp | ||
1391 | + * | ||
1392 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1393 | + * | ||
1394 | + * This program is free software; you can redistribute it and/or modify | ||
1395 | + * it under the terms of the GNU General Public License as published by | ||
1396 | + * the Free Software Foundation; version 2 of the License. | ||
1397 | + * | ||
1398 | + * This program is distributed in the hope that it will be useful, but | ||
1399 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1400 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1401 | + * General Public License for more details. | ||
1402 | + * | ||
1403 | + * You should have received a copy of the GNU General Public License along | ||
1404 | + * with this program; if not, write to the Free Software Foundation, Inc., | ||
1405 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
1406 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1407 | + * | ||
1408 | + */ | ||
1409 | + | ||
1410 | +#include <linux/module.h> | ||
1411 | +#include <linux/init.h> | ||
1412 | +#include <linux/slab.h> | ||
1413 | +#include <linux/i2c.h> | ||
1414 | +#include <linux/hwmon.h> | ||
1415 | +#include <linux/hwmon-sysfs.h> | ||
1416 | +#include <linux/hwmon-vid.h> | ||
1417 | +#include <linux/err.h> | ||
1418 | +#include <linux/delay.h> | ||
1419 | +#include <linux/mutex.h> | ||
1420 | +#include <linux/sysfs.h> | ||
1421 | + | ||
1422 | + | ||
1423 | +MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); | ||
1424 | +MODULE_DESCRIPTION("STMacroelectronics LIS331DL Accelerometer Driver"); | ||
1425 | +MODULE_LICENSE("GPL v2"); | ||
1426 | + | ||
1427 | +#define ACCEL_DATA_RATE_100HZ 0 | ||
1428 | +#define ACCEL_DATA_RATE_400HZ 1 | ||
1429 | +#define ACCEL_POWER_MODE_DOWN 0 | ||
1430 | +#define ACCEL_POWER_MODE_ACTIVE 1 | ||
1431 | +#define ACCEL_NORMAL_MODE 0 | ||
1432 | +#define ACCEL_MEMORY_REBOOT 1 | ||
1433 | + | ||
1434 | +/* internal return values */ | ||
1435 | + | ||
1436 | +struct acclero_data { | ||
1437 | + struct device *hwmon_dev; | ||
1438 | + struct mutex update_lock; | ||
1439 | +}; | ||
1440 | + | ||
1441 | +static unsigned int i2c_write_current_data(struct i2c_client *client, | ||
1442 | + unsigned int reg, unsigned int value) | ||
1443 | +{ | ||
1444 | + int ret_val; | ||
1445 | + | ||
1446 | + ret_val = i2c_smbus_write_byte_data(client, reg, value); | ||
1447 | + return ret_val; | ||
1448 | +} | ||
1449 | + | ||
1450 | +static ssize_t data_rate_show(struct device *dev, | ||
1451 | + struct device_attribute *attr, char *buf) | ||
1452 | +{ | ||
1453 | + struct i2c_client *client = to_i2c_client(dev); | ||
1454 | + int ret_val, val; | ||
1455 | + | ||
1456 | + val = i2c_smbus_read_byte_data(client, 0x20); | ||
1457 | + ret_val = (val & 0x80); /* 1= 400HZ 0= 100HZ */ | ||
1458 | + if (ret_val == 0x80) | ||
1459 | + ret_val = 1; | ||
1460 | + return sprintf(buf, "%d\n", ret_val); | ||
1461 | + | ||
1462 | +} | ||
1463 | + | ||
1464 | +static ssize_t power_mode_show(struct device *dev, | ||
1465 | + struct device_attribute *attr, char *buf) | ||
1466 | +{ | ||
1467 | + struct i2c_client *client = to_i2c_client(dev); | ||
1468 | + int ret_val, val; | ||
1469 | + | ||
1470 | + val = i2c_smbus_read_byte_data(client, 0x20); | ||
1471 | + ret_val = (val & 0x40); | ||
1472 | + if (ret_val == 0x40) | ||
1473 | + ret_val = 1; | ||
1474 | + return sprintf(buf, "%d\n", ret_val); | ||
1475 | +} | ||
1476 | + | ||
1477 | +static ssize_t x_pos_show(struct device *dev, | ||
1478 | + struct device_attribute *attr, char *buf) | ||
1479 | +{ | ||
1480 | + struct i2c_client *client = to_i2c_client(dev); | ||
1481 | + int ret_val; | ||
1482 | + | ||
1483 | + ret_val = i2c_smbus_read_byte_data(client, 0x29); | ||
1484 | + return sprintf(buf, "%d\n", ret_val); | ||
1485 | +} | ||
1486 | + | ||
1487 | +static ssize_t y_pos_show(struct device *dev, | ||
1488 | + struct device_attribute *attr, char *buf) | ||
1489 | +{ | ||
1490 | + struct i2c_client *client = to_i2c_client(dev); | ||
1491 | + int ret_val; | ||
1492 | + | ||
1493 | + ret_val = i2c_smbus_read_byte_data(client, 0x2B); | ||
1494 | + return sprintf(buf, "%d\n", ret_val); | ||
1495 | +} | ||
1496 | + | ||
1497 | +static ssize_t z_pos_show(struct device *dev, | ||
1498 | + struct device_attribute *attr, char *buf) | ||
1499 | +{ | ||
1500 | + struct i2c_client *client = to_i2c_client(dev); | ||
1501 | + int ret_val; | ||
1502 | + | ||
1503 | + ret_val = i2c_smbus_read_byte_data(client, 0x2D); | ||
1504 | + return sprintf(buf, "%d\n", ret_val); | ||
1505 | +} | ||
1506 | + | ||
1507 | +static ssize_t xyz_pos_show(struct device *dev, | ||
1508 | + struct device_attribute *attr, char *buf) | ||
1509 | +{ | ||
1510 | + int x, y, z; | ||
1511 | + struct i2c_client *client = to_i2c_client(dev); | ||
1512 | + | ||
1513 | + x = i2c_smbus_read_byte_data(client, 0x29); | ||
1514 | + y = i2c_smbus_read_byte_data(client, 0x2B); | ||
1515 | + z = i2c_smbus_read_byte_data(client, 0x2D); | ||
1516 | + return sprintf(buf, "(%d,%d,%d)\n", x, y, z); | ||
1517 | +} | ||
1518 | + | ||
1519 | +static ssize_t data_rate_store(struct device *dev, | ||
1520 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1521 | +{ | ||
1522 | + struct i2c_client *client = to_i2c_client(dev); | ||
1523 | + struct acclero_data *data = i2c_get_clientdata(client); | ||
1524 | + unsigned int ret_val, set_val; | ||
1525 | + unsigned long val; | ||
1526 | + | ||
1527 | + if (strict_strtoul(buf, 10, &val)) | ||
1528 | + return -EINVAL; | ||
1529 | + ret_val = i2c_smbus_read_byte_data(client, 0x20); | ||
1530 | + | ||
1531 | + mutex_lock(&data->update_lock); | ||
1532 | + if (val == ACCEL_DATA_RATE_100HZ) | ||
1533 | + set_val = (ret_val & 0x7F); /* setting the 8th bit to 0 */ | ||
1534 | + else if (val == ACCEL_DATA_RATE_400HZ) | ||
1535 | + set_val = (ret_val | (1 << 7)); | ||
1536 | + else | ||
1537 | + goto invarg; | ||
1538 | + | ||
1539 | + i2c_write_current_data(client, 0x20, set_val); | ||
1540 | + mutex_unlock(&data->update_lock); | ||
1541 | + return count; | ||
1542 | +invarg: | ||
1543 | + mutex_unlock(&data->update_lock); | ||
1544 | + return -EINVAL; | ||
1545 | +} | ||
1546 | + | ||
1547 | +static ssize_t power_mode_store(struct device *dev, | ||
1548 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1549 | +{ | ||
1550 | + struct i2c_client *client = to_i2c_client(dev); | ||
1551 | + struct acclero_data *data = i2c_get_clientdata(client); | ||
1552 | + unsigned int ret_val, set_val; | ||
1553 | + unsigned long val; | ||
1554 | + | ||
1555 | + if (strict_strtoul(buf, 10, &val)) | ||
1556 | + return -EINVAL; | ||
1557 | + ret_val = i2c_smbus_read_byte_data(client, 0x20); | ||
1558 | + | ||
1559 | + mutex_lock(&data->update_lock); | ||
1560 | + if (val == ACCEL_POWER_MODE_DOWN) | ||
1561 | + set_val = ret_val & 0xBF; /* if value id 0 */ | ||
1562 | + else if (val == ACCEL_POWER_MODE_ACTIVE) | ||
1563 | + set_val = (ret_val | (1<<6)); /* if value is 1 */ | ||
1564 | + else | ||
1565 | + goto invarg; | ||
1566 | + | ||
1567 | + i2c_write_current_data(client, 0x20, set_val); | ||
1568 | + mutex_unlock(&data->update_lock); | ||
1569 | + return count; | ||
1570 | +invarg: | ||
1571 | + mutex_unlock(&data->update_lock); | ||
1572 | + return -EINVAL; | ||
1573 | +} | ||
1574 | + | ||
1575 | +static ssize_t reboot_mem_store(struct device *dev, | ||
1576 | + struct device_attribute *attr, const char *buf, size_t count) | ||
1577 | +{ | ||
1578 | + struct i2c_client *client = to_i2c_client(dev); | ||
1579 | + struct acclero_data *data = i2c_get_clientdata(client); | ||
1580 | + unsigned int ret_val, set_val; | ||
1581 | + unsigned long val; | ||
1582 | + | ||
1583 | + if (strict_strtoul(buf, 10, &val)) | ||
1584 | + return -EINVAL; | ||
1585 | + ret_val = i2c_smbus_read_byte_data(client, 0x21); | ||
1586 | + if (val == ACCEL_MEMORY_REBOOT) { | ||
1587 | + mutex_lock(&data->update_lock); | ||
1588 | + set_val = (ret_val | (1 << 6)); /* setting the 6th bit */ | ||
1589 | + i2c_write_current_data(client, 0x21, set_val); | ||
1590 | + mutex_unlock(&data->update_lock); | ||
1591 | + } else | ||
1592 | + return -EINVAL; | ||
1593 | + return count; | ||
1594 | +} | ||
1595 | + | ||
1596 | +static DEVICE_ATTR(data_rate, S_IRUGO | S_IWUSR, | ||
1597 | + data_rate_show, data_rate_store); | ||
1598 | +static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, | ||
1599 | + power_mode_show, power_mode_store); | ||
1600 | +static DEVICE_ATTR(reboot_mem, S_IWUSR, NULL, | ||
1601 | + reboot_mem_store); | ||
1602 | +static DEVICE_ATTR(x, S_IRUGO, x_pos_show, NULL); | ||
1603 | +static DEVICE_ATTR(y, S_IRUGO, y_pos_show, NULL); | ||
1604 | +static DEVICE_ATTR(z, S_IRUGO, z_pos_show, NULL); | ||
1605 | +static DEVICE_ATTR(curr_pos, S_IRUGO, xyz_pos_show, NULL); | ||
1606 | + | ||
1607 | +static struct attribute *mid_att_acclero[] = { | ||
1608 | + &dev_attr_data_rate.attr, | ||
1609 | + &dev_attr_power_state.attr, | ||
1610 | + &dev_attr_reboot_mem.attr, | ||
1611 | + &dev_attr_x.attr, | ||
1612 | + &dev_attr_y.attr, | ||
1613 | + &dev_attr_z.attr, | ||
1614 | + &dev_attr_curr_pos.attr, | ||
1615 | + NULL | ||
1616 | +}; | ||
1617 | + | ||
1618 | +static struct attribute_group m_acclero_gr = { | ||
1619 | + .name = "lis331dl", | ||
1620 | + .attrs = mid_att_acclero | ||
1621 | +}; | ||
1622 | + | ||
1623 | +static void accel_set_default_config(struct i2c_client *client) | ||
1624 | +{ | ||
1625 | + i2c_write_current_data(client, 0x20, 0x47); | ||
1626 | +} | ||
1627 | + | ||
1628 | +static int lis331dl_probe(struct i2c_client *client, | ||
1629 | + const struct i2c_device_id *id) | ||
1630 | +{ | ||
1631 | + int res; | ||
1632 | + struct acclero_data *data; | ||
1633 | + | ||
1634 | + data = kzalloc(sizeof(struct acclero_data), GFP_KERNEL); | ||
1635 | + if (data == NULL) { | ||
1636 | + printk(KERN_WARNING "lis331dl: Memory initi failed \n"); | ||
1637 | + return -ENOMEM; | ||
1638 | + } | ||
1639 | + mutex_init(&data->update_lock); | ||
1640 | + i2c_set_clientdata(client, data); | ||
1641 | + | ||
1642 | + res = sysfs_create_group(&client->dev.kobj, &m_acclero_gr); | ||
1643 | + if (res) { | ||
1644 | + printk(KERN_WARNING "lis331dl: Sysfs group failed!!\n"); | ||
1645 | + goto acclero_error1; | ||
1646 | + } | ||
1647 | + data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1648 | + if (IS_ERR(data->hwmon_dev)) { | ||
1649 | + res = PTR_ERR(data->hwmon_dev); | ||
1650 | + data->hwmon_dev = NULL; | ||
1651 | + sysfs_remove_group(&client->dev.kobj, &m_acclero_gr); | ||
1652 | + printk(KERN_WARNING "lis331dl: unable to register \ | ||
1653 | + hwmon device\n"); | ||
1654 | + goto acclero_error1; | ||
1655 | + } | ||
1656 | + accel_set_default_config(client); | ||
1657 | + | ||
1658 | + dev_info(&client->dev, "%s lis331dl: Accelerometer chip \ | ||
1659 | + foundn", client->name); | ||
1660 | + return res; | ||
1661 | + | ||
1662 | +acclero_error1: | ||
1663 | + i2c_set_clientdata(client, NULL); | ||
1664 | + kfree(data); | ||
1665 | + return res; | ||
1666 | +} | ||
1667 | + | ||
1668 | +static int lis331dl_remove(struct i2c_client *client) | ||
1669 | +{ | ||
1670 | + struct acclero_data *data = i2c_get_clientdata(client); | ||
1671 | + | ||
1672 | + hwmon_device_unregister(data->hwmon_dev); | ||
1673 | + sysfs_remove_group(&client->dev.kobj, &m_acclero_gr); | ||
1674 | + kfree(data); | ||
1675 | + return 0; | ||
1676 | +} | ||
1677 | + | ||
1678 | +static struct i2c_device_id lis331dl_id[] = { | ||
1679 | + { "i2c_accel", 0 }, | ||
1680 | + { } | ||
1681 | +}; | ||
1682 | + | ||
1683 | +MODULE_DEVICE_TABLE(i2c, lis331dl_id); | ||
1684 | + | ||
1685 | +static struct i2c_driver lis331dl_driver = { | ||
1686 | + .driver = { | ||
1687 | + .name = "lis331dl", | ||
1688 | + }, | ||
1689 | + .probe = lis331dl_probe, | ||
1690 | + .remove = lis331dl_remove, | ||
1691 | + .id_table = lis331dl_id, | ||
1692 | +}; | ||
1693 | + | ||
1694 | +static int __init sensor_lis331dl_init(void) | ||
1695 | +{ | ||
1696 | + int res; | ||
1697 | + | ||
1698 | + res = i2c_add_driver(&lis331dl_driver); | ||
1699 | + return res; | ||
1700 | +} | ||
1701 | + | ||
1702 | +static void __exit sensor_lis331dl_exit(void) | ||
1703 | +{ | ||
1704 | + i2c_del_driver(&lis331dl_driver); | ||
1705 | +} | ||
1706 | + | ||
1707 | +module_init(sensor_lis331dl_init); | ||
1708 | +module_exit(sensor_lis331dl_exit); | ||
1709 | --- a/drivers/misc/Kconfig | ||
1710 | +++ b/drivers/misc/Kconfig | ||
1711 | @@ -249,6 +249,13 @@ config SGI_GRU_DEBUG | ||
1712 | This option enables addition debugging code for the SGI GRU driver. If | ||
1713 | you are unsure, say N. | ||
1714 | |||
1715 | +config MRST_VIB | ||
1716 | + tristate "vibrator driver for Intel Moorestown platform" | ||
1717 | + help | ||
1718 | + Vibrator for Intel Moorestown platform. | ||
1719 | + | ||
1720 | + If unsure, say N. | ||
1721 | + | ||
1722 | config ISL29003 | ||
1723 | tristate "Intersil ISL29003 ambient light sensor" | ||
1724 | depends on I2C && SYSFS | ||
1725 | --- a/drivers/misc/Makefile | ||
1726 | +++ b/drivers/misc/Makefile | ||
1727 | @@ -22,6 +22,7 @@ obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfg | ||
1728 | obj-$(CONFIG_HP_ILO) += hpilo.o | ||
1729 | obj-$(CONFIG_MRST) += intel_mrst.o | ||
1730 | obj-$(CONFIG_ISL29003) += isl29003.o | ||
1731 | +obj-$(CONFIG_MRST_VIB) += mrst_vib.o | ||
1732 | obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o | ||
1733 | obj-$(CONFIG_DS1682) += ds1682.o | ||
1734 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o | ||
1735 | --- /dev/null | ||
1736 | +++ b/drivers/misc/mrst_vib.c | ||
1737 | @@ -0,0 +1,99 @@ | ||
1738 | +/* | ||
1739 | + * mrst_vib.c - Intel vibrator Driver | ||
1740 | + * | ||
1741 | + * Copyright (C) 2008 Intel Corp | ||
1742 | + * | ||
1743 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1744 | + * | ||
1745 | + * This program is free software; you can redistribute it and/or modify | ||
1746 | + * it under the terms of the GNU General Public License as published by | ||
1747 | + * the Free Software Foundation; version 2 of the License. | ||
1748 | + * | ||
1749 | + * This program is distributed in the hope that it will be useful, but | ||
1750 | + * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1751 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
1752 | + * General Public License for more details. | ||
1753 | + * | ||
1754 | + * You should have received a copy of the GNU General Public License along | ||
1755 | + * with this program; if not, write to the Free Software Foundation, Inc., | ||
1756 | + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
1757 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
1758 | + * | ||
1759 | + */ | ||
1760 | + | ||
1761 | +#include <linux/platform_device.h> | ||
1762 | +#include <linux/kernel.h> | ||
1763 | +#include <linux/sysfs.h> | ||
1764 | +#include <asm/ipc_defs.h> | ||
1765 | + | ||
1766 | + | ||
1767 | +MODULE_AUTHOR("Kalhan Trisal"); | ||
1768 | +MODULE_DESCRIPTION("Intel Moorestown Thermal Driver"); | ||
1769 | +MODULE_LICENSE("GPL v2"); | ||
1770 | + | ||
1771 | +#define VIB_START 1 | ||
1772 | +#define VIB_STOP 2 | ||
1773 | +static struct platform_device *vib_pdev; | ||
1774 | + | ||
1775 | +static ssize_t vib_store(struct device *dev, struct device_attribute *attr, | ||
1776 | + const char *buf, size_t count) | ||
1777 | +{ | ||
1778 | + | ||
1779 | + struct ipc_pmic_reg_data vib_power_reg_write = {0}; | ||
1780 | + unsigned long val; | ||
1781 | + | ||
1782 | + if (strict_strtoul(buf, 10, &val)) | ||
1783 | + return -EINVAL; | ||
1784 | + if (val == VIB_START) { | ||
1785 | + vib_power_reg_write.ioc = TRUE; | ||
1786 | + vib_power_reg_write.pmic_reg_data[0].register_address = 0x49; | ||
1787 | + vib_power_reg_write.pmic_reg_data[0].value = 0xAD; | ||
1788 | + vib_power_reg_write.num_entries = 1; | ||
1789 | + if (ipc_pmic_register_write(&vib_power_reg_write, TRUE)) { | ||
1790 | + printk(KERN_WARNING "mrst_vib: failed to turn ON \ | ||
1791 | + vib \n"); | ||
1792 | + return -EINVAL; | ||
1793 | + } | ||
1794 | + } else if (val == VIB_STOP) { | ||
1795 | + vib_power_reg_write.ioc = TRUE; | ||
1796 | + vib_power_reg_write.pmic_reg_data[0].register_address = 0x49; | ||
1797 | + vib_power_reg_write.pmic_reg_data[0].value = 0x14; | ||
1798 | + vib_power_reg_write.num_entries = 1; | ||
1799 | + if (ipc_pmic_register_write(&vib_power_reg_write, TRUE)) { | ||
1800 | + printk(KERN_WARNING "mrst_vib: failed to turn OFF \ | ||
1801 | + Vibrator \n"); | ||
1802 | + return -EINVAL; | ||
1803 | + } | ||
1804 | + } else | ||
1805 | + return -EINVAL; | ||
1806 | + | ||
1807 | + return count; | ||
1808 | +} | ||
1809 | + | ||
1810 | +static struct device_attribute dev_attr_vib = | ||
1811 | + __ATTR(vib, S_IWUSR, NULL, vib_store); | ||
1812 | + | ||
1813 | +static int __init mrst_vib_init(void) | ||
1814 | +{ | ||
1815 | + int res = 0; | ||
1816 | + | ||
1817 | + vib_pdev = platform_device_register_simple("mrst_vib", -1, NULL, 0); | ||
1818 | + if (IS_ERR(vib_pdev)) { | ||
1819 | + res = PTR_ERR(vib_pdev); | ||
1820 | + vib_pdev = NULL; | ||
1821 | + printk(KERN_WARNING "mrst_vib: unable to register platform \ | ||
1822 | + device\n"); | ||
1823 | + return res; | ||
1824 | + } | ||
1825 | + res = device_create_file(&vib_pdev->dev, &dev_attr_vib); | ||
1826 | + return res; | ||
1827 | +} | ||
1828 | + | ||
1829 | +static void __exit mrst_vib_exit(void) | ||
1830 | +{ | ||
1831 | + device_remove_file(&vib_pdev->dev, &dev_attr_vib); | ||
1832 | + platform_device_unregister(vib_pdev); | ||
1833 | +} | ||
1834 | + | ||
1835 | +module_init(mrst_vib_init); | ||
1836 | +module_exit(mrst_vib_exit); | ||