diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 63 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 4 | ||||
-rw-r--r-- | drivers/hwmon/ds1621.c | 172 | ||||
-rw-r--r-- | drivers/hwmon/fschmd.c | 229 | ||||
-rw-r--r-- | drivers/hwmon/hdaps.c | 66 | ||||
-rw-r--r-- | drivers/hwmon/hp_accel.c | 124 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.c | 288 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d.h | 20 | ||||
-rw-r--r-- | drivers/hwmon/lis3lv02d_spi.c | 114 | ||||
-rw-r--r-- | drivers/hwmon/lm95241.c | 527 | ||||
-rw-r--r-- | drivers/hwmon/ltc4215.c | 364 | ||||
-rw-r--r-- | drivers/hwmon/pcf8591.c | 325 | ||||
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 170 |
13 files changed, 2028 insertions, 438 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b4eea0292c1a..ce52bf2f235e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -343,12 +343,13 @@ config SENSORS_FSCPOS | |||
343 | will be called fscpos. | 343 | will be called fscpos. |
344 | 344 | ||
345 | config SENSORS_FSCHMD | 345 | config SENSORS_FSCHMD |
346 | tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" | 346 | tristate "Fujitsu Siemens Computers sensor chips" |
347 | depends on X86 && I2C | 347 | depends on X86 && I2C |
348 | help | 348 | help |
349 | If you say yes here you get support for various Fujitsu Siemens | 349 | If you say yes here you get support for the following Fujitsu |
350 | Computers sensor chips, including support for the integrated | 350 | Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, |
351 | watchdog. | 351 | Heimdall, Heracles, Hades and Syleus including support for the |
352 | integrated watchdog. | ||
352 | 353 | ||
353 | This is a merged driver for FSC sensor chips replacing the fscpos, | 354 | This is a merged driver for FSC sensor chips replacing the fscpos, |
354 | fscscy and fscher drivers and adding support for several other FSC | 355 | fscscy and fscher drivers and adding support for several other FSC |
@@ -570,6 +571,17 @@ config SENSORS_LM93 | |||
570 | This driver can also be built as a module. If so, the module | 571 | This driver can also be built as a module. If so, the module |
571 | will be called lm93. | 572 | will be called lm93. |
572 | 573 | ||
574 | config SENSORS_LTC4215 | ||
575 | tristate "Linear Technology LTC4215" | ||
576 | depends on I2C && EXPERIMENTAL | ||
577 | default n | ||
578 | help | ||
579 | If you say yes here you get support for Linear Technology LTC4215 | ||
580 | Hot Swap Controller I2C interface. | ||
581 | |||
582 | This driver can also be built as a module. If so, the module will | ||
583 | be called ltc4215. | ||
584 | |||
573 | config SENSORS_LTC4245 | 585 | config SENSORS_LTC4245 |
574 | tristate "Linear Technology LTC4245" | 586 | tristate "Linear Technology LTC4245" |
575 | depends on I2C && EXPERIMENTAL | 587 | depends on I2C && EXPERIMENTAL |
@@ -581,6 +593,15 @@ config SENSORS_LTC4245 | |||
581 | This driver can also be built as a module. If so, the module will | 593 | This driver can also be built as a module. If so, the module will |
582 | be called ltc4245. | 594 | be called ltc4245. |
583 | 595 | ||
596 | config SENSORS_LM95241 | ||
597 | tristate "National Semiconductor LM95241 sensor chip" | ||
598 | depends on I2C | ||
599 | help | ||
600 | If you say yes here you get support for LM95241 sensor chip. | ||
601 | |||
602 | This driver can also be built as a module. If so, the module | ||
603 | will be called lm95241. | ||
604 | |||
584 | config SENSORS_MAX1111 | 605 | config SENSORS_MAX1111 |
585 | tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip" | 606 | tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip" |
586 | depends on SPI_MASTER | 607 | depends on SPI_MASTER |
@@ -635,6 +656,20 @@ config SENSORS_PC87427 | |||
635 | This driver can also be built as a module. If so, the module | 656 | This driver can also be built as a module. If so, the module |
636 | will be called pc87427. | 657 | will be called pc87427. |
637 | 658 | ||
659 | config SENSORS_PCF8591 | ||
660 | tristate "Philips PCF8591 ADC/DAC" | ||
661 | depends on I2C | ||
662 | default n | ||
663 | help | ||
664 | If you say yes here you get support for Philips PCF8591 4-channel | ||
665 | ADC, 1-channel DAC chips. | ||
666 | |||
667 | This driver can also be built as a module. If so, the module | ||
668 | will be called pcf8591. | ||
669 | |||
670 | These devices are hard to detect and rarely found on mainstream | ||
671 | hardware. If unsure, say N. | ||
672 | |||
638 | config SENSORS_SIS5595 | 673 | config SENSORS_SIS5595 |
639 | tristate "Silicon Integrated Systems Corp. SiS5595" | 674 | tristate "Silicon Integrated Systems Corp. SiS5595" |
640 | depends on PCI | 675 | depends on PCI |
@@ -827,7 +862,7 @@ config SENSORS_W83627HF | |||
827 | will be called w83627hf. | 862 | will be called w83627hf. |
828 | 863 | ||
829 | config SENSORS_W83627EHF | 864 | config SENSORS_W83627EHF |
830 | tristate "Winbond W83627EHF/DHG" | 865 | tristate "Winbond W83627EHF/EHG/DHG, W83667HG" |
831 | select HWMON_VID | 866 | select HWMON_VID |
832 | help | 867 | help |
833 | If you say yes here you get support for the hardware | 868 | If you say yes here you get support for the hardware |
@@ -838,6 +873,8 @@ config SENSORS_W83627EHF | |||
838 | chip suited for specific Intel processors that use PECI such as | 873 | chip suited for specific Intel processors that use PECI such as |
839 | the Core 2 Duo. | 874 | the Core 2 Duo. |
840 | 875 | ||
876 | This driver also supports the W83667HG chip. | ||
877 | |||
841 | This driver can also be built as a module. If so, the module | 878 | This driver can also be built as a module. If so, the module |
842 | will be called w83627ehf. | 879 | will be called w83627ehf. |
843 | 880 | ||
@@ -895,6 +932,22 @@ config SENSORS_LIS3LV02D | |||
895 | Say Y here if you have an applicable laptop and want to experience | 932 | Say Y here if you have an applicable laptop and want to experience |
896 | the awesome power of lis3lv02d. | 933 | the awesome power of lis3lv02d. |
897 | 934 | ||
935 | config SENSORS_LIS3_SPI | ||
936 | tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" | ||
937 | depends on !ACPI && SPI_MASTER && INPUT | ||
938 | default n | ||
939 | help | ||
940 | This driver provides support for the LIS3LV02Dx accelerometer connected | ||
941 | via SPI. The accelerometer data is readable via | ||
942 | /sys/devices/platform/lis3lv02d. | ||
943 | |||
944 | This driver also provides an absolute input class device, allowing | ||
945 | the laptop to act as a pinball machine-esque joystick. | ||
946 | |||
947 | This driver can also be built as modules. If so, the core module | ||
948 | will be called lis3lv02d and a specific module for the SPI transport | ||
949 | is called lis3lv02d_spi. | ||
950 | |||
898 | config SENSORS_APPLESMC | 951 | config SENSORS_APPLESMC |
899 | tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" | 952 | tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" |
900 | depends on INPUT && X86 | 953 | depends on INPUT && X86 |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2e80f37f39eb..3a6b1f06f8f4 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -52,6 +52,7 @@ obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o | |||
52 | obj-$(CONFIG_SENSORS_IT87) += it87.o | 52 | obj-$(CONFIG_SENSORS_IT87) += it87.o |
53 | obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o | 53 | obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o |
54 | obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o | 54 | obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o |
55 | obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o | ||
55 | obj-$(CONFIG_SENSORS_LM63) += lm63.o | 56 | obj-$(CONFIG_SENSORS_LM63) += lm63.o |
56 | obj-$(CONFIG_SENSORS_LM70) += lm70.o | 57 | obj-$(CONFIG_SENSORS_LM70) += lm70.o |
57 | obj-$(CONFIG_SENSORS_LM75) += lm75.o | 58 | obj-$(CONFIG_SENSORS_LM75) += lm75.o |
@@ -64,12 +65,15 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o | |||
64 | obj-$(CONFIG_SENSORS_LM90) += lm90.o | 65 | obj-$(CONFIG_SENSORS_LM90) += lm90.o |
65 | obj-$(CONFIG_SENSORS_LM92) += lm92.o | 66 | obj-$(CONFIG_SENSORS_LM92) += lm92.o |
66 | obj-$(CONFIG_SENSORS_LM93) += lm93.o | 67 | obj-$(CONFIG_SENSORS_LM93) += lm93.o |
68 | obj-$(CONFIG_SENSORS_LM95241) += lm95241.o | ||
69 | obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o | ||
67 | obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o | 70 | obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o |
68 | obj-$(CONFIG_SENSORS_MAX1111) += max1111.o | 71 | obj-$(CONFIG_SENSORS_MAX1111) += max1111.o |
69 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o | 72 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o |
70 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | 73 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o |
71 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 74 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
72 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o | 75 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o |
76 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o | ||
73 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o | 77 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o |
74 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 78 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
75 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 79 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 7415381601c3..53f88f511816 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c | |||
@@ -81,71 +81,84 @@ struct ds1621_data { | |||
81 | u8 conf; /* Register encoding, combined */ | 81 | u8 conf; /* Register encoding, combined */ |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static int ds1621_probe(struct i2c_client *client, | 84 | /* Temperature registers are word-sized. |
85 | const struct i2c_device_id *id); | ||
86 | static int ds1621_detect(struct i2c_client *client, int kind, | ||
87 | struct i2c_board_info *info); | ||
88 | static void ds1621_init_client(struct i2c_client *client); | ||
89 | static int ds1621_remove(struct i2c_client *client); | ||
90 | static struct ds1621_data *ds1621_update_client(struct device *dev); | ||
91 | |||
92 | static const struct i2c_device_id ds1621_id[] = { | ||
93 | { "ds1621", ds1621 }, | ||
94 | { "ds1625", ds1621 }, | ||
95 | { } | ||
96 | }; | ||
97 | MODULE_DEVICE_TABLE(i2c, ds1621_id); | ||
98 | |||
99 | /* This is the driver that will be inserted */ | ||
100 | static struct i2c_driver ds1621_driver = { | ||
101 | .class = I2C_CLASS_HWMON, | ||
102 | .driver = { | ||
103 | .name = "ds1621", | ||
104 | }, | ||
105 | .probe = ds1621_probe, | ||
106 | .remove = ds1621_remove, | ||
107 | .id_table = ds1621_id, | ||
108 | .detect = ds1621_detect, | ||
109 | .address_data = &addr_data, | ||
110 | }; | ||
111 | |||
112 | /* All registers are word-sized, except for the configuration register. | ||
113 | DS1621 uses a high-byte first convention, which is exactly opposite to | 85 | DS1621 uses a high-byte first convention, which is exactly opposite to |
114 | the SMBus standard. */ | 86 | the SMBus standard. */ |
115 | static int ds1621_read_value(struct i2c_client *client, u8 reg) | 87 | static int ds1621_read_temp(struct i2c_client *client, u8 reg) |
116 | { | 88 | { |
117 | if (reg == DS1621_REG_CONF) | 89 | int ret; |
118 | return i2c_smbus_read_byte_data(client, reg); | 90 | |
119 | else | 91 | ret = i2c_smbus_read_word_data(client, reg); |
120 | return swab16(i2c_smbus_read_word_data(client, reg)); | 92 | if (ret < 0) |
93 | return ret; | ||
94 | return swab16(ret); | ||
121 | } | 95 | } |
122 | 96 | ||
123 | static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) | 97 | static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value) |
124 | { | 98 | { |
125 | if (reg == DS1621_REG_CONF) | 99 | return i2c_smbus_write_word_data(client, reg, swab16(value)); |
126 | return i2c_smbus_write_byte_data(client, reg, value); | ||
127 | else | ||
128 | return i2c_smbus_write_word_data(client, reg, swab16(value)); | ||
129 | } | 100 | } |
130 | 101 | ||
131 | static void ds1621_init_client(struct i2c_client *client) | 102 | static void ds1621_init_client(struct i2c_client *client) |
132 | { | 103 | { |
133 | int reg = ds1621_read_value(client, DS1621_REG_CONF); | 104 | u8 conf, new_conf; |
105 | |||
106 | new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | ||
134 | /* switch to continuous conversion mode */ | 107 | /* switch to continuous conversion mode */ |
135 | reg &= ~ DS1621_REG_CONFIG_1SHOT; | 108 | new_conf &= ~DS1621_REG_CONFIG_1SHOT; |
136 | 109 | ||
137 | /* setup output polarity */ | 110 | /* setup output polarity */ |
138 | if (polarity == 0) | 111 | if (polarity == 0) |
139 | reg &= ~DS1621_REG_CONFIG_POLARITY; | 112 | new_conf &= ~DS1621_REG_CONFIG_POLARITY; |
140 | else if (polarity == 1) | 113 | else if (polarity == 1) |
141 | reg |= DS1621_REG_CONFIG_POLARITY; | 114 | new_conf |= DS1621_REG_CONFIG_POLARITY; |
142 | 115 | ||
143 | ds1621_write_value(client, DS1621_REG_CONF, reg); | 116 | if (conf != new_conf) |
117 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); | ||
144 | 118 | ||
145 | /* start conversion */ | 119 | /* start conversion */ |
146 | i2c_smbus_write_byte(client, DS1621_COM_START); | 120 | i2c_smbus_write_byte(client, DS1621_COM_START); |
147 | } | 121 | } |
148 | 122 | ||
123 | static struct ds1621_data *ds1621_update_client(struct device *dev) | ||
124 | { | ||
125 | struct i2c_client *client = to_i2c_client(dev); | ||
126 | struct ds1621_data *data = i2c_get_clientdata(client); | ||
127 | u8 new_conf; | ||
128 | |||
129 | mutex_lock(&data->update_lock); | ||
130 | |||
131 | if (time_after(jiffies, data->last_updated + HZ + HZ / 2) | ||
132 | || !data->valid) { | ||
133 | int i; | ||
134 | |||
135 | dev_dbg(&client->dev, "Starting ds1621 update\n"); | ||
136 | |||
137 | data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | ||
138 | |||
139 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) | ||
140 | data->temp[i] = ds1621_read_temp(client, | ||
141 | DS1621_REG_TEMP[i]); | ||
142 | |||
143 | /* reset alarms if necessary */ | ||
144 | new_conf = data->conf; | ||
145 | if (data->temp[0] > data->temp[1]) /* input > min */ | ||
146 | new_conf &= ~DS1621_ALARM_TEMP_LOW; | ||
147 | if (data->temp[0] < data->temp[2]) /* input < max */ | ||
148 | new_conf &= ~DS1621_ALARM_TEMP_HIGH; | ||
149 | if (data->conf != new_conf) | ||
150 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, | ||
151 | new_conf); | ||
152 | |||
153 | data->last_updated = jiffies; | ||
154 | data->valid = 1; | ||
155 | } | ||
156 | |||
157 | mutex_unlock(&data->update_lock); | ||
158 | |||
159 | return data; | ||
160 | } | ||
161 | |||
149 | static ssize_t show_temp(struct device *dev, struct device_attribute *da, | 162 | static ssize_t show_temp(struct device *dev, struct device_attribute *da, |
150 | char *buf) | 163 | char *buf) |
151 | { | 164 | { |
@@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, | |||
160 | { | 173 | { |
161 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | 174 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
162 | struct i2c_client *client = to_i2c_client(dev); | 175 | struct i2c_client *client = to_i2c_client(dev); |
163 | struct ds1621_data *data = ds1621_update_client(dev); | 176 | struct ds1621_data *data = i2c_get_clientdata(client); |
164 | u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); | 177 | u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); |
165 | 178 | ||
166 | mutex_lock(&data->update_lock); | 179 | mutex_lock(&data->update_lock); |
167 | data->temp[attr->index] = val; | 180 | data->temp[attr->index] = val; |
168 | ds1621_write_value(client, DS1621_REG_TEMP[attr->index], | 181 | ds1621_write_temp(client, DS1621_REG_TEMP[attr->index], |
169 | data->temp[attr->index]); | 182 | data->temp[attr->index]); |
170 | mutex_unlock(&data->update_lock); | 183 | mutex_unlock(&data->update_lock); |
171 | return count; | 184 | return count; |
172 | } | 185 | } |
@@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind, | |||
228 | /* The NVB bit should be low if no EEPROM write has been | 241 | /* The NVB bit should be low if no EEPROM write has been |
229 | requested during the latest 10ms, which is highly | 242 | requested during the latest 10ms, which is highly |
230 | improbable in our case. */ | 243 | improbable in our case. */ |
231 | conf = ds1621_read_value(client, DS1621_REG_CONF); | 244 | conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); |
232 | if (conf & DS1621_REG_CONFIG_NVB) | 245 | if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) |
233 | return -ENODEV; | 246 | return -ENODEV; |
234 | /* The 7 lowest bits of a temperature should always be 0. */ | 247 | /* The 7 lowest bits of a temperature should always be 0. */ |
235 | for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { | 248 | for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { |
236 | temp = ds1621_read_value(client, DS1621_REG_TEMP[i]); | 249 | temp = i2c_smbus_read_word_data(client, |
237 | if (temp & 0x007f) | 250 | DS1621_REG_TEMP[i]); |
251 | if (temp < 0 || (temp & 0x7f00)) | ||
238 | return -ENODEV; | 252 | return -ENODEV; |
239 | } | 253 | } |
240 | } | 254 | } |
@@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client) | |||
294 | return 0; | 308 | return 0; |
295 | } | 309 | } |
296 | 310 | ||
311 | static const struct i2c_device_id ds1621_id[] = { | ||
312 | { "ds1621", ds1621 }, | ||
313 | { "ds1625", ds1621 }, | ||
314 | { } | ||
315 | }; | ||
316 | MODULE_DEVICE_TABLE(i2c, ds1621_id); | ||
297 | 317 | ||
298 | static struct ds1621_data *ds1621_update_client(struct device *dev) | 318 | /* This is the driver that will be inserted */ |
299 | { | 319 | static struct i2c_driver ds1621_driver = { |
300 | struct i2c_client *client = to_i2c_client(dev); | 320 | .class = I2C_CLASS_HWMON, |
301 | struct ds1621_data *data = i2c_get_clientdata(client); | 321 | .driver = { |
302 | u8 new_conf; | 322 | .name = "ds1621", |
303 | 323 | }, | |
304 | mutex_lock(&data->update_lock); | 324 | .probe = ds1621_probe, |
305 | 325 | .remove = ds1621_remove, | |
306 | if (time_after(jiffies, data->last_updated + HZ + HZ / 2) | 326 | .id_table = ds1621_id, |
307 | || !data->valid) { | 327 | .detect = ds1621_detect, |
308 | int i; | 328 | .address_data = &addr_data, |
309 | 329 | }; | |
310 | dev_dbg(&client->dev, "Starting ds1621 update\n"); | ||
311 | |||
312 | data->conf = ds1621_read_value(client, DS1621_REG_CONF); | ||
313 | |||
314 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) | ||
315 | data->temp[i] = ds1621_read_value(client, | ||
316 | DS1621_REG_TEMP[i]); | ||
317 | |||
318 | /* reset alarms if necessary */ | ||
319 | new_conf = data->conf; | ||
320 | if (data->temp[0] > data->temp[1]) /* input > min */ | ||
321 | new_conf &= ~DS1621_ALARM_TEMP_LOW; | ||
322 | if (data->temp[0] < data->temp[2]) /* input < max */ | ||
323 | new_conf &= ~DS1621_ALARM_TEMP_HIGH; | ||
324 | if (data->conf != new_conf) | ||
325 | ds1621_write_value(client, DS1621_REG_CONF, | ||
326 | new_conf); | ||
327 | |||
328 | data->last_updated = jiffies; | ||
329 | data->valid = 1; | ||
330 | } | ||
331 | |||
332 | mutex_unlock(&data->update_lock); | ||
333 | |||
334 | return data; | ||
335 | } | ||
336 | 330 | ||
337 | static int __init ds1621_init(void) | 331 | static int __init ds1621_init(void) |
338 | { | 332 | { |
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d07f4ef75092..ea955edde87e 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fschmd.c | 1 | /* fschmd.c |
2 | * | 2 | * |
3 | * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> | 3 | * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, | 21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, |
22 | * Scylla, Heracles and Heimdall chips | 22 | * Scylla, Heracles, Heimdall, Hades and Syleus chips |
23 | * | 23 | * |
24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 | 24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 |
25 | * (candidate) fschmd drivers: | 25 | * (candidate) fschmd drivers: |
@@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
56 | module_param(nowayout, int, 0); | 56 | module_param(nowayout, int, 0); |
57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
59 | I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | 59 | I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl); |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * The FSCHMD registers and other defines | 62 | * The FSCHMD registers and other defines |
@@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 | 75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 |
76 | 76 | ||
77 | /* watchdog */ | 77 | /* watchdog */ |
78 | #define FSCHMD_REG_WDOG_PRESET 0x28 | 78 | static const u8 FSCHMD_REG_WDOG_CONTROL[7] = |
79 | #define FSCHMD_REG_WDOG_STATE 0x23 | 79 | { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 }; |
80 | #define FSCHMD_REG_WDOG_CONTROL 0x21 | 80 | static const u8 FSCHMD_REG_WDOG_STATE[7] = |
81 | { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 }; | ||
82 | static const u8 FSCHMD_REG_WDOG_PRESET[7] = | ||
83 | { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a }; | ||
81 | 84 | ||
82 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 | 85 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 |
83 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ | 86 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ |
@@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
87 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 | 90 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 |
88 | 91 | ||
89 | /* voltages, weird order is to keep the same order as the old drivers */ | 92 | /* voltages, weird order is to keep the same order as the old drivers */ |
90 | static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; | 93 | static const u8 FSCHMD_REG_VOLT[7][6] = { |
94 | { 0x45, 0x42, 0x48 }, /* pos */ | ||
95 | { 0x45, 0x42, 0x48 }, /* her */ | ||
96 | { 0x45, 0x42, 0x48 }, /* scy */ | ||
97 | { 0x45, 0x42, 0x48 }, /* hrc */ | ||
98 | { 0x45, 0x42, 0x48 }, /* hmd */ | ||
99 | { 0x21, 0x20, 0x22 }, /* hds */ | ||
100 | { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ | ||
101 | }; | ||
102 | |||
103 | static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; | ||
91 | 104 | ||
92 | /* minimum pwm at which the fan is driven (pwm can by increased depending on | 105 | /* minimum pwm at which the fan is driven (pwm can by increased depending on |
93 | the temp. Notice that for the scy some fans share there minimum speed. | 106 | the temp. Notice that for the scy some fans share there minimum speed. |
94 | Also notice that with the scy the sensor order is different than with the | 107 | Also notice that with the scy the sensor order is different than with the |
95 | other chips, this order was in the 2.4 driver and kept for consistency. */ | 108 | other chips, this order was in the 2.4 driver and kept for consistency. */ |
96 | static const u8 FSCHMD_REG_FAN_MIN[5][6] = { | 109 | static const u8 FSCHMD_REG_FAN_MIN[7][7] = { |
97 | { 0x55, 0x65 }, /* pos */ | 110 | { 0x55, 0x65 }, /* pos */ |
98 | { 0x55, 0x65, 0xb5 }, /* her */ | 111 | { 0x55, 0x65, 0xb5 }, /* her */ |
99 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ | 112 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ |
100 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ | 113 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ |
101 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ | 114 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ |
115 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */ | ||
116 | { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ | ||
102 | }; | 117 | }; |
103 | 118 | ||
104 | /* actual fan speed */ | 119 | /* actual fan speed */ |
105 | static const u8 FSCHMD_REG_FAN_ACT[5][6] = { | 120 | static const u8 FSCHMD_REG_FAN_ACT[7][7] = { |
106 | { 0x0e, 0x6b, 0xab }, /* pos */ | 121 | { 0x0e, 0x6b, 0xab }, /* pos */ |
107 | { 0x0e, 0x6b, 0xbb }, /* her */ | 122 | { 0x0e, 0x6b, 0xbb }, /* her */ |
108 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ | 123 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ |
109 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ | 124 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ |
110 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ | 125 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ |
126 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */ | ||
127 | { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ | ||
111 | }; | 128 | }; |
112 | 129 | ||
113 | /* fan status registers */ | 130 | /* fan status registers */ |
114 | static const u8 FSCHMD_REG_FAN_STATE[5][6] = { | 131 | static const u8 FSCHMD_REG_FAN_STATE[7][7] = { |
115 | { 0x0d, 0x62, 0xa2 }, /* pos */ | 132 | { 0x0d, 0x62, 0xa2 }, /* pos */ |
116 | { 0x0d, 0x62, 0xb2 }, /* her */ | 133 | { 0x0d, 0x62, 0xb2 }, /* her */ |
117 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ | 134 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ |
118 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ | 135 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ |
119 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ | 136 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ |
137 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */ | ||
138 | { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ | ||
120 | }; | 139 | }; |
121 | 140 | ||
122 | /* fan ripple / divider registers */ | 141 | /* fan ripple / divider registers */ |
123 | static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { | 142 | static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = { |
124 | { 0x0f, 0x6f, 0xaf }, /* pos */ | 143 | { 0x0f, 0x6f, 0xaf }, /* pos */ |
125 | { 0x0f, 0x6f, 0xbf }, /* her */ | 144 | { 0x0f, 0x6f, 0xbf }, /* her */ |
126 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ | 145 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ |
127 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ | 146 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ |
128 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ | 147 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ |
148 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */ | ||
149 | { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ | ||
129 | }; | 150 | }; |
130 | 151 | ||
131 | static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; | 152 | static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 }; |
132 | 153 | ||
133 | /* Fan status register bitmasks */ | 154 | /* Fan status register bitmasks */ |
134 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ | 155 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ |
135 | #define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */ | 156 | #define FSCHMD_FAN_NOT_PRESENT 0x08 |
157 | #define FSCHMD_FAN_DISABLED 0x80 | ||
136 | 158 | ||
137 | 159 | ||
138 | /* actual temperature registers */ | 160 | /* actual temperature registers */ |
139 | static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { | 161 | static const u8 FSCHMD_REG_TEMP_ACT[7][11] = { |
140 | { 0x64, 0x32, 0x35 }, /* pos */ | 162 | { 0x64, 0x32, 0x35 }, /* pos */ |
141 | { 0x64, 0x32, 0x35 }, /* her */ | 163 | { 0x64, 0x32, 0x35 }, /* her */ |
142 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ | 164 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ |
143 | { 0x64, 0x32, 0x35 }, /* hrc */ | 165 | { 0x64, 0x32, 0x35 }, /* hrc */ |
144 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ | 166 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ |
167 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */ | ||
168 | { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ | ||
169 | 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, | ||
145 | }; | 170 | }; |
146 | 171 | ||
147 | /* temperature state registers */ | 172 | /* temperature state registers */ |
148 | static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | 173 | static const u8 FSCHMD_REG_TEMP_STATE[7][11] = { |
149 | { 0x71, 0x81, 0x91 }, /* pos */ | 174 | { 0x71, 0x81, 0x91 }, /* pos */ |
150 | { 0x71, 0x81, 0x91 }, /* her */ | 175 | { 0x71, 0x81, 0x91 }, /* her */ |
151 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ | 176 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ |
152 | { 0x71, 0x81, 0x91 }, /* hrc */ | 177 | { 0x71, 0x81, 0x91 }, /* hrc */ |
153 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ | 178 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ |
179 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */ | ||
180 | { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ | ||
181 | 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, | ||
154 | }; | 182 | }; |
155 | 183 | ||
156 | /* temperature high limit registers, FSC does not document these. Proven to be | 184 | /* temperature high limit registers, FSC does not document these. Proven to be |
@@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | |||
158 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers | 186 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers |
159 | at these addresses, but doesn't want to confirm they are the same as with | 187 | at these addresses, but doesn't want to confirm they are the same as with |
160 | the fscher?? */ | 188 | the fscher?? */ |
161 | static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { | 189 | static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { |
162 | { 0, 0, 0 }, /* pos */ | 190 | { 0, 0, 0 }, /* pos */ |
163 | { 0x76, 0x86, 0x96 }, /* her */ | 191 | { 0x76, 0x86, 0x96 }, /* her */ |
164 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ | 192 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ |
165 | { 0x76, 0x86, 0x96 }, /* hrc */ | 193 | { 0x76, 0x86, 0x96 }, /* hrc */ |
166 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ | 194 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ |
195 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */ | ||
196 | { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ | ||
197 | 0xba, 0xca, 0xda, 0xea, 0xfa }, | ||
167 | }; | 198 | }; |
168 | 199 | ||
169 | /* These were found through experimenting with an fscher, currently they are | 200 | /* These were found through experimenting with an fscher, currently they are |
170 | not used, but we keep them around for future reference. | 201 | not used, but we keep them around for future reference. |
202 | On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), | ||
203 | AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence | ||
204 | the fan speed. | ||
171 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; | 205 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; |
172 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ | 206 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ |
173 | 207 | ||
174 | static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; | 208 | static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; |
175 | 209 | ||
176 | /* temp status register bitmasks */ | 210 | /* temp status register bitmasks */ |
177 | #define FSCHMD_TEMP_WORKING 0x01 | 211 | #define FSCHMD_TEMP_WORKING 0x01 |
178 | #define FSCHMD_TEMP_ALERT 0x02 | 212 | #define FSCHMD_TEMP_ALERT 0x02 |
213 | #define FSCHMD_TEMP_DISABLED 0x80 | ||
179 | /* there only really is an alarm if the sensor is working and alert == 1 */ | 214 | /* there only really is an alarm if the sensor is working and alert == 1 */ |
180 | #define FSCHMD_TEMP_ALARM_MASK \ | 215 | #define FSCHMD_TEMP_ALARM_MASK \ |
181 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) | 216 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) |
@@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = { | |||
201 | { "fscscy", fscscy }, | 236 | { "fscscy", fscscy }, |
202 | { "fschrc", fschrc }, | 237 | { "fschrc", fschrc }, |
203 | { "fschmd", fschmd }, | 238 | { "fschmd", fschmd }, |
239 | { "fschds", fschds }, | ||
240 | { "fscsyl", fscsyl }, | ||
204 | { } | 241 | { } |
205 | }; | 242 | }; |
206 | MODULE_DEVICE_TABLE(i2c, fschmd_id); | 243 | MODULE_DEVICE_TABLE(i2c, fschmd_id); |
@@ -242,14 +279,14 @@ struct fschmd_data { | |||
242 | u8 watchdog_control; /* watchdog control register */ | 279 | u8 watchdog_control; /* watchdog control register */ |
243 | u8 watchdog_state; /* watchdog status register */ | 280 | u8 watchdog_state; /* watchdog status register */ |
244 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ | 281 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ |
245 | u8 volt[3]; /* 12, 5, battery voltage */ | 282 | u8 volt[6]; /* voltage */ |
246 | u8 temp_act[5]; /* temperature */ | 283 | u8 temp_act[11]; /* temperature */ |
247 | u8 temp_status[5]; /* status of sensor */ | 284 | u8 temp_status[11]; /* status of sensor */ |
248 | u8 temp_max[5]; /* high temp limit, notice: undocumented! */ | 285 | u8 temp_max[11]; /* high temp limit, notice: undocumented! */ |
249 | u8 fan_act[6]; /* fans revolutions per second */ | 286 | u8 fan_act[7]; /* fans revolutions per second */ |
250 | u8 fan_status[6]; /* fan status */ | 287 | u8 fan_status[7]; /* fan status */ |
251 | u8 fan_min[6]; /* fan min value for rps */ | 288 | u8 fan_min[7]; /* fan min value for rps */ |
252 | u8 fan_ripple[6]; /* divider for rps */ | 289 | u8 fan_ripple[7]; /* divider for rps */ |
253 | }; | 290 | }; |
254 | 291 | ||
255 | /* Global variables to hold information read from special DMI tables, which are | 292 | /* Global variables to hold information read from special DMI tables, which are |
@@ -257,8 +294,8 @@ struct fschmd_data { | |||
257 | protect these with a lock as they are only modified from our attach function | 294 | protect these with a lock as they are only modified from our attach function |
258 | which always gets called with the i2c-core lock held and never accessed | 295 | which always gets called with the i2c-core lock held and never accessed |
259 | before the attach function is done with them. */ | 296 | before the attach function is done with them. */ |
260 | static int dmi_mult[3] = { 490, 200, 100 }; | 297 | static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; |
261 | static int dmi_offset[3] = { 0, 0, 0 }; | 298 | static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; |
262 | static int dmi_vref = -1; | 299 | static int dmi_vref = -1; |
263 | 300 | ||
264 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that | 301 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that |
@@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev, | |||
450 | struct device_attribute *devattr, char *buf) | 487 | struct device_attribute *devattr, char *buf) |
451 | { | 488 | { |
452 | int index = to_sensor_dev_attr(devattr)->index; | 489 | int index = to_sensor_dev_attr(devattr)->index; |
453 | int val = fschmd_update_device(dev)->fan_min[index]; | 490 | struct fschmd_data *data = fschmd_update_device(dev); |
491 | int val = data->fan_min[index]; | ||
454 | 492 | ||
455 | /* 0 = allow turning off, 1-255 = 50-100% */ | 493 | /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
456 | if (val) | 494 | if (val || data->kind == fscsyl - 1) |
457 | val = val / 2 + 128; | 495 | val = val / 2 + 128; |
458 | 496 | ||
459 | return sprintf(buf, "%d\n", val); | 497 | return sprintf(buf, "%d\n", val); |
@@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, | |||
466 | struct fschmd_data *data = dev_get_drvdata(dev); | 504 | struct fschmd_data *data = dev_get_drvdata(dev); |
467 | unsigned long v = simple_strtoul(buf, NULL, 10); | 505 | unsigned long v = simple_strtoul(buf, NULL, 10); |
468 | 506 | ||
469 | /* register: 0 = allow turning off, 1-255 = 50-100% */ | 507 | /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
470 | if (v) { | 508 | if (v || data->kind == fscsyl - 1) { |
471 | v = SENSORS_LIMIT(v, 128, 255); | 509 | v = SENSORS_LIMIT(v, 128, 255); |
472 | v = (v - 128) * 2 + 1; | 510 | v = (v - 128) * 2 + 1; |
473 | } | 511 | } |
@@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev, | |||
522 | return count; | 560 | return count; |
523 | } | 561 | } |
524 | 562 | ||
563 | static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); | ||
564 | |||
525 | static struct sensor_device_attribute fschmd_attr[] = { | 565 | static struct sensor_device_attribute fschmd_attr[] = { |
526 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), | 566 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), |
527 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), | 567 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), |
528 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), | 568 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), |
529 | SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), | 569 | SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3), |
570 | SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4), | ||
571 | SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5), | ||
530 | }; | 572 | }; |
531 | 573 | ||
532 | static struct sensor_device_attribute fschmd_temp_attr[] = { | 574 | static struct sensor_device_attribute fschmd_temp_attr[] = { |
@@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = { | |||
550 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), | 592 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), |
551 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), | 593 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), |
552 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), | 594 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), |
595 | SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5), | ||
596 | SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5), | ||
597 | SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5), | ||
598 | SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5), | ||
599 | SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6), | ||
600 | SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6), | ||
601 | SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6), | ||
602 | SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6), | ||
603 | SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7), | ||
604 | SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7), | ||
605 | SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7), | ||
606 | SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7), | ||
607 | SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8), | ||
608 | SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8), | ||
609 | SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8), | ||
610 | SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8), | ||
611 | SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9), | ||
612 | SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9), | ||
613 | SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9), | ||
614 | SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9), | ||
615 | SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10), | ||
616 | SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10), | ||
617 | SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10), | ||
618 | SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10), | ||
553 | }; | 619 | }; |
554 | 620 | ||
555 | static struct sensor_device_attribute fschmd_fan_attr[] = { | 621 | static struct sensor_device_attribute fschmd_fan_attr[] = { |
@@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { | |||
589 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), | 655 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), |
590 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | 656 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, |
591 | store_pwm_auto_point1_pwm, 5), | 657 | store_pwm_auto_point1_pwm, 5), |
658 | SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6), | ||
659 | SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6), | ||
660 | SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6), | ||
661 | SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6), | ||
662 | SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | ||
663 | store_pwm_auto_point1_pwm, 6), | ||
592 | }; | 664 | }; |
593 | 665 | ||
594 | 666 | ||
@@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout) | |||
624 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); | 696 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); |
625 | 697 | ||
626 | /* Write new timeout value */ | 698 | /* Write new timeout value */ |
627 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET, | 699 | i2c_smbus_write_byte_data(data->client, |
628 | data->watchdog_preset); | 700 | FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); |
629 | /* Write new control register, do not trigger! */ | 701 | /* Write new control register, do not trigger! */ |
630 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 702 | i2c_smbus_write_byte_data(data->client, |
703 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
631 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); | 704 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); |
632 | 705 | ||
633 | ret = data->watchdog_preset * resolution; | 706 | ret = data->watchdog_preset * resolution; |
@@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data) | |||
662 | } | 735 | } |
663 | 736 | ||
664 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; | 737 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; |
665 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 738 | i2c_smbus_write_byte_data(data->client, |
666 | data->watchdog_control); | 739 | FSCHMD_REG_WDOG_CONTROL[data->kind], |
740 | data->watchdog_control); | ||
667 | leave: | 741 | leave: |
668 | mutex_unlock(&data->watchdog_lock); | 742 | mutex_unlock(&data->watchdog_lock); |
669 | return ret; | 743 | return ret; |
@@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data) | |||
682 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; | 756 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; |
683 | /* Don't store the stop flag in our watchdog control register copy, as | 757 | /* Don't store the stop flag in our watchdog control register copy, as |
684 | its a write only bit (read always returns 0) */ | 758 | its a write only bit (read always returns 0) */ |
685 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 759 | i2c_smbus_write_byte_data(data->client, |
760 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
686 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); | 761 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); |
687 | leave: | 762 | leave: |
688 | mutex_unlock(&data->watchdog_lock); | 763 | mutex_unlock(&data->watchdog_lock); |
@@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = { | |||
856 | 931 | ||
857 | /* DMI decode routine to read voltage scaling factors from special DMI tables, | 932 | /* DMI decode routine to read voltage scaling factors from special DMI tables, |
858 | which are available on FSC machines with an fscher or later chip. */ | 933 | which are available on FSC machines with an fscher or later chip. */ |
859 | static void fschmd_dmi_decode(const struct dmi_header *header) | 934 | static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) |
860 | { | 935 | { |
861 | int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; | 936 | int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; |
862 | 937 | ||
@@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header) | |||
912 | dmi_mult[i] = mult[i] * 10; | 987 | dmi_mult[i] = mult[i] * 10; |
913 | dmi_offset[i] = offset[i] * 10; | 988 | dmi_offset[i] = offset[i] * 10; |
914 | } | 989 | } |
990 | /* According to the docs there should be separate dmi entries | ||
991 | for the mult's and offsets of in3-5 of the syl, but on | ||
992 | my test machine these are not present */ | ||
993 | dmi_mult[3] = dmi_mult[2]; | ||
994 | dmi_mult[4] = dmi_mult[1]; | ||
995 | dmi_mult[5] = dmi_mult[2]; | ||
996 | dmi_offset[3] = dmi_offset[2]; | ||
997 | dmi_offset[4] = dmi_offset[1]; | ||
998 | dmi_offset[5] = dmi_offset[2]; | ||
915 | dmi_vref = vref; | 999 | dmi_vref = vref; |
916 | } | 1000 | } |
917 | } | 1001 | } |
@@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
920 | struct i2c_board_info *info) | 1004 | struct i2c_board_info *info) |
921 | { | 1005 | { |
922 | struct i2c_adapter *adapter = client->adapter; | 1006 | struct i2c_adapter *adapter = client->adapter; |
923 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", | ||
924 | "fschrc", "fschmd" }; | ||
925 | 1007 | ||
926 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 1008 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
927 | return -ENODEV; | 1009 | return -ENODEV; |
@@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
948 | kind = fschrc; | 1030 | kind = fschrc; |
949 | else if (!strcmp(id, "HMD")) | 1031 | else if (!strcmp(id, "HMD")) |
950 | kind = fschmd; | 1032 | kind = fschmd; |
1033 | else if (!strcmp(id, "HDS")) | ||
1034 | kind = fschds; | ||
1035 | else if (!strcmp(id, "SYL")) | ||
1036 | kind = fscsyl; | ||
951 | else | 1037 | else |
952 | return -ENODEV; | 1038 | return -ENODEV; |
953 | } | 1039 | } |
954 | 1040 | ||
955 | strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); | 1041 | strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE); |
956 | 1042 | ||
957 | return 0; | 1043 | return 0; |
958 | } | 1044 | } |
@@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client, | |||
961 | const struct i2c_device_id *id) | 1047 | const struct i2c_device_id *id) |
962 | { | 1048 | { |
963 | struct fschmd_data *data; | 1049 | struct fschmd_data *data; |
964 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | 1050 | const char * const names[7] = { "Poseidon", "Hermes", "Scylla", |
965 | "Heracles", "Heimdall" }; | 1051 | "Heracles", "Heimdall", "Hades", "Syleus" }; |
966 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; | 1052 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; |
967 | int i, err; | 1053 | int i, err; |
968 | enum chips kind = id->driver_data; | 1054 | enum chips kind = id->driver_data; |
@@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client, | |||
991 | 1077 | ||
992 | /* Read the special DMI table for fscher and newer chips */ | 1078 | /* Read the special DMI table for fscher and newer chips */ |
993 | if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { | 1079 | if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { |
994 | dmi_walk(fschmd_dmi_decode); | 1080 | dmi_walk(fschmd_dmi_decode, NULL); |
995 | if (dmi_vref == -1) { | 1081 | if (dmi_vref == -1) { |
996 | dev_warn(&client->dev, | 1082 | dev_warn(&client->dev, |
997 | "Couldn't get voltage scaling factors from " | 1083 | "Couldn't get voltage scaling factors from " |
@@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client, | |||
1000 | } | 1086 | } |
1001 | } | 1087 | } |
1002 | 1088 | ||
1089 | /* i2c kind goes from 1-6, we want from 0-5 to address arrays */ | ||
1090 | data->kind = kind - 1; | ||
1091 | |||
1003 | /* Read in some never changing registers */ | 1092 | /* Read in some never changing registers */ |
1004 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); | 1093 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); |
1005 | data->global_control = i2c_smbus_read_byte_data(client, | 1094 | data->global_control = i2c_smbus_read_byte_data(client, |
1006 | FSCHMD_REG_CONTROL); | 1095 | FSCHMD_REG_CONTROL); |
1007 | data->watchdog_control = i2c_smbus_read_byte_data(client, | 1096 | data->watchdog_control = i2c_smbus_read_byte_data(client, |
1008 | FSCHMD_REG_WDOG_CONTROL); | 1097 | FSCHMD_REG_WDOG_CONTROL[data->kind]); |
1009 | data->watchdog_state = i2c_smbus_read_byte_data(client, | 1098 | data->watchdog_state = i2c_smbus_read_byte_data(client, |
1010 | FSCHMD_REG_WDOG_STATE); | 1099 | FSCHMD_REG_WDOG_STATE[data->kind]); |
1011 | data->watchdog_preset = i2c_smbus_read_byte_data(client, | 1100 | data->watchdog_preset = i2c_smbus_read_byte_data(client, |
1012 | FSCHMD_REG_WDOG_PRESET); | 1101 | FSCHMD_REG_WDOG_PRESET[data->kind]); |
1013 | 1102 | ||
1014 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ | 1103 | err = device_create_file(&client->dev, &dev_attr_alert_led); |
1015 | data->kind = kind - 1; | 1104 | if (err) |
1105 | goto exit_detach; | ||
1016 | 1106 | ||
1017 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { | 1107 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { |
1018 | err = device_create_file(&client->dev, | 1108 | err = device_create_file(&client->dev, |
1019 | &fschmd_attr[i].dev_attr); | 1109 | &fschmd_attr[i].dev_attr); |
1020 | if (err) | 1110 | if (err) |
@@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1027 | show_temp_max) | 1117 | show_temp_max) |
1028 | continue; | 1118 | continue; |
1029 | 1119 | ||
1120 | if (kind == fscsyl) { | ||
1121 | if (i % 4 == 0) | ||
1122 | data->temp_status[i / 4] = | ||
1123 | i2c_smbus_read_byte_data(client, | ||
1124 | FSCHMD_REG_TEMP_STATE | ||
1125 | [data->kind][i / 4]); | ||
1126 | if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED) | ||
1127 | continue; | ||
1128 | } | ||
1129 | |||
1030 | err = device_create_file(&client->dev, | 1130 | err = device_create_file(&client->dev, |
1031 | &fschmd_temp_attr[i].dev_attr); | 1131 | &fschmd_temp_attr[i].dev_attr); |
1032 | if (err) | 1132 | if (err) |
@@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1040 | "pwm3_auto_point1_pwm")) | 1140 | "pwm3_auto_point1_pwm")) |
1041 | continue; | 1141 | continue; |
1042 | 1142 | ||
1143 | if (kind == fscsyl) { | ||
1144 | if (i % 5 == 0) | ||
1145 | data->fan_status[i / 5] = | ||
1146 | i2c_smbus_read_byte_data(client, | ||
1147 | FSCHMD_REG_FAN_STATE | ||
1148 | [data->kind][i / 5]); | ||
1149 | if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED) | ||
1150 | continue; | ||
1151 | } | ||
1152 | |||
1043 | err = device_create_file(&client->dev, | 1153 | err = device_create_file(&client->dev, |
1044 | &fschmd_fan_attr[i].dev_attr); | 1154 | &fschmd_fan_attr[i].dev_attr); |
1045 | if (err) | 1155 | if (err) |
@@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client) | |||
1126 | if (data->hwmon_dev) | 1236 | if (data->hwmon_dev) |
1127 | hwmon_device_unregister(data->hwmon_dev); | 1237 | hwmon_device_unregister(data->hwmon_dev); |
1128 | 1238 | ||
1129 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) | 1239 | device_remove_file(&client->dev, &dev_attr_alert_led); |
1240 | for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++) | ||
1130 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); | 1241 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); |
1131 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) | 1242 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) |
1132 | device_remove_file(&client->dev, | 1243 | device_remove_file(&client->dev, |
@@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1171 | data->temp_act[i] < data->temp_max[i]) | 1282 | data->temp_act[i] < data->temp_max[i]) |
1172 | i2c_smbus_write_byte_data(client, | 1283 | i2c_smbus_write_byte_data(client, |
1173 | FSCHMD_REG_TEMP_STATE[data->kind][i], | 1284 | FSCHMD_REG_TEMP_STATE[data->kind][i], |
1174 | FSCHMD_TEMP_ALERT); | 1285 | data->temp_status[i]); |
1175 | } | 1286 | } |
1176 | 1287 | ||
1177 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { | 1288 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { |
@@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1193 | data->fan_act[i]) | 1304 | data->fan_act[i]) |
1194 | i2c_smbus_write_byte_data(client, | 1305 | i2c_smbus_write_byte_data(client, |
1195 | FSCHMD_REG_FAN_STATE[data->kind][i], | 1306 | FSCHMD_REG_FAN_STATE[data->kind][i], |
1196 | FSCHMD_FAN_ALARM); | 1307 | data->fan_status[i]); |
1197 | } | 1308 | } |
1198 | 1309 | ||
1199 | for (i = 0; i < 3; i++) | 1310 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) |
1200 | data->volt[i] = i2c_smbus_read_byte_data(client, | 1311 | data->volt[i] = i2c_smbus_read_byte_data(client, |
1201 | FSCHMD_REG_VOLT[i]); | 1312 | FSCHMD_REG_VOLT[data->kind][i]); |
1202 | 1313 | ||
1203 | data->last_updated = jiffies; | 1314 | data->last_updated = jiffies; |
1204 | data->valid = 1; | 1315 | data->valid = 1; |
@@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void) | |||
1220 | } | 1331 | } |
1221 | 1332 | ||
1222 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | 1333 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
1223 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " | 1334 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades " |
1224 | "Heimdall driver"); | 1335 | "and Syleus driver"); |
1225 | MODULE_LICENSE("GPL"); | 1336 | MODULE_LICENSE("GPL"); |
1226 | 1337 | ||
1227 | module_init(fschmd_init); | 1338 | module_init(fschmd_init); |
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index a4d92d246d52..d3612a1f1981 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c | |||
@@ -65,6 +65,10 @@ | |||
65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ | 65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ |
66 | #define HDAPS_INPUT_FLAT 4 | 66 | #define HDAPS_INPUT_FLAT 4 |
67 | 67 | ||
68 | #define HDAPS_X_AXIS (1 << 0) | ||
69 | #define HDAPS_Y_AXIS (1 << 1) | ||
70 | #define HDAPS_BOTH_AXES (HDAPS_X_AXIS | HDAPS_Y_AXIS) | ||
71 | |||
68 | static struct platform_device *pdev; | 72 | static struct platform_device *pdev; |
69 | static struct input_polled_dev *hdaps_idev; | 73 | static struct input_polled_dev *hdaps_idev; |
70 | static unsigned int hdaps_invert; | 74 | static unsigned int hdaps_invert; |
@@ -182,11 +186,11 @@ static int __hdaps_read_pair(unsigned int port1, unsigned int port2, | |||
182 | km_activity = inb(HDAPS_PORT_KMACT); | 186 | km_activity = inb(HDAPS_PORT_KMACT); |
183 | __device_complete(); | 187 | __device_complete(); |
184 | 188 | ||
185 | /* if hdaps_invert is set, negate the two values */ | 189 | /* hdaps_invert is a bitvector to negate the axes */ |
186 | if (hdaps_invert) { | 190 | if (hdaps_invert & HDAPS_X_AXIS) |
187 | *x = -*x; | 191 | *x = -*x; |
192 | if (hdaps_invert & HDAPS_Y_AXIS) | ||
188 | *y = -*y; | 193 | *y = -*y; |
189 | } | ||
190 | 194 | ||
191 | return 0; | 195 | return 0; |
192 | } | 196 | } |
@@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev, | |||
436 | { | 440 | { |
437 | int invert; | 441 | int invert; |
438 | 442 | ||
439 | if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0)) | 443 | if (sscanf(buf, "%d", &invert) != 1 || |
444 | invert < 0 || invert > HDAPS_BOTH_AXES) | ||
440 | return -EINVAL; | 445 | return -EINVAL; |
441 | 446 | ||
442 | hdaps_invert = invert; | 447 | hdaps_invert = invert; |
@@ -483,56 +488,52 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id) | |||
483 | /* hdaps_dmi_match_invert - found an inverted match. */ | 488 | /* hdaps_dmi_match_invert - found an inverted match. */ |
484 | static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) | 489 | static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) |
485 | { | 490 | { |
486 | hdaps_invert = 1; | 491 | hdaps_invert = (unsigned long)id->driver_data; |
487 | printk(KERN_INFO "hdaps: inverting axis readings.\n"); | 492 | printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n", |
493 | hdaps_invert); | ||
488 | return hdaps_dmi_match(id); | 494 | return hdaps_dmi_match(id); |
489 | } | 495 | } |
490 | 496 | ||
491 | #define HDAPS_DMI_MATCH_NORMAL(vendor, model) { \ | 497 | #define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) { \ |
492 | .ident = vendor " " model, \ | ||
493 | .callback = hdaps_dmi_match, \ | ||
494 | .matches = { \ | ||
495 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ | ||
496 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ | ||
497 | } \ | ||
498 | } | ||
499 | |||
500 | #define HDAPS_DMI_MATCH_INVERT(vendor, model) { \ | ||
501 | .ident = vendor " " model, \ | 498 | .ident = vendor " " model, \ |
502 | .callback = hdaps_dmi_match_invert, \ | 499 | .callback = hdaps_dmi_match_invert, \ |
500 | .driver_data = (void *)axes, \ | ||
503 | .matches = { \ | 501 | .matches = { \ |
504 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ | 502 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ |
505 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ | 503 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ |
506 | } \ | 504 | } \ |
507 | } | 505 | } |
508 | 506 | ||
507 | #define HDAPS_DMI_MATCH_NORMAL(vendor, model) \ | ||
508 | HDAPS_DMI_MATCH_INVERT(vendor, model, 0) | ||
509 | |||
509 | /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match | 510 | /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match |
510 | "ThinkPad T42p", so the order of the entries matters. | 511 | "ThinkPad T42p", so the order of the entries matters. |
511 | If your ThinkPad is not recognized, please update to latest | 512 | If your ThinkPad is not recognized, please update to latest |
512 | BIOS. This is especially the case for some R52 ThinkPads. */ | 513 | BIOS. This is especially the case for some R52 ThinkPads. */ |
513 | static struct dmi_system_id __initdata hdaps_whitelist[] = { | 514 | static struct dmi_system_id __initdata hdaps_whitelist[] = { |
514 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"), | 515 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES), |
515 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), | 516 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), |
516 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), | 517 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), |
517 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"), | 518 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"), |
518 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"), | 519 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES), |
519 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"), | 520 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES), |
520 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"), | 521 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES), |
521 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"), | 522 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"), |
522 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"), | 523 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES), |
523 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"), | 524 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"), |
524 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"), | 525 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"), |
525 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"), | 526 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES), |
526 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"), | 527 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES), |
527 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"), | 528 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES), |
528 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"), | 529 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"), |
529 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"), | 530 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS), |
530 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"), | 531 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES), |
531 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"), | 532 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES), |
532 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"), | 533 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES), |
533 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), | 534 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), |
534 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"), | 535 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES), |
535 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"), | 536 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES), |
536 | { .ident = NULL } | 537 | { .ident = NULL } |
537 | }; | 538 | }; |
538 | 539 | ||
@@ -627,8 +628,9 @@ static void __exit hdaps_exit(void) | |||
627 | module_init(hdaps_init); | 628 | module_init(hdaps_init); |
628 | module_exit(hdaps_exit); | 629 | module_exit(hdaps_exit); |
629 | 630 | ||
630 | module_param_named(invert, hdaps_invert, bool, 0); | 631 | module_param_named(invert, hdaps_invert, int, 0); |
631 | MODULE_PARM_DESC(invert, "invert data along each axis"); | 632 | MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, " |
633 | "2 invert y-axis, 3 invert both axes."); | ||
632 | 634 | ||
633 | MODULE_AUTHOR("Robert Love"); | 635 | MODULE_AUTHOR("Robert Love"); |
634 | MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver"); | 636 | MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver"); |
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index 29c83b5b9697..55d3dc565be6 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c | |||
@@ -85,25 +85,31 @@ MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); | |||
85 | 85 | ||
86 | /** | 86 | /** |
87 | * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. | 87 | * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. |
88 | * @handle: the handle of the device | 88 | * @lis3: pointer to the device struct |
89 | * | 89 | * |
90 | * Returns AE_OK on success. | 90 | * Returns 0 on success. |
91 | */ | 91 | */ |
92 | acpi_status lis3lv02d_acpi_init(acpi_handle handle) | 92 | int lis3lv02d_acpi_init(struct lis3lv02d *lis3) |
93 | { | 93 | { |
94 | return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); | 94 | struct acpi_device *dev = lis3->bus_priv; |
95 | if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI, | ||
96 | NULL, NULL) != AE_OK) | ||
97 | return -EINVAL; | ||
98 | |||
99 | return 0; | ||
95 | } | 100 | } |
96 | 101 | ||
97 | /** | 102 | /** |
98 | * lis3lv02d_acpi_read - ACPI ALRD method: read a register | 103 | * lis3lv02d_acpi_read - ACPI ALRD method: read a register |
99 | * @handle: the handle of the device | 104 | * @lis3: pointer to the device struct |
100 | * @reg: the register to read | 105 | * @reg: the register to read |
101 | * @ret: result of the operation | 106 | * @ret: result of the operation |
102 | * | 107 | * |
103 | * Returns AE_OK on success. | 108 | * Returns 0 on success. |
104 | */ | 109 | */ |
105 | acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) | 110 | int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret) |
106 | { | 111 | { |
112 | struct acpi_device *dev = lis3->bus_priv; | ||
107 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 113 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
108 | struct acpi_object_list args = { 1, &arg0 }; | 114 | struct acpi_object_list args = { 1, &arg0 }; |
109 | unsigned long long lret; | 115 | unsigned long long lret; |
@@ -111,21 +117,22 @@ acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) | |||
111 | 117 | ||
112 | arg0.integer.value = reg; | 118 | arg0.integer.value = reg; |
113 | 119 | ||
114 | status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); | 120 | status = acpi_evaluate_integer(dev->handle, "ALRD", &args, &lret); |
115 | *ret = lret; | 121 | *ret = lret; |
116 | return status; | 122 | return (status != AE_OK) ? -EINVAL : 0; |
117 | } | 123 | } |
118 | 124 | ||
119 | /** | 125 | /** |
120 | * lis3lv02d_acpi_write - ACPI ALWR method: write to a register | 126 | * lis3lv02d_acpi_write - ACPI ALWR method: write to a register |
121 | * @handle: the handle of the device | 127 | * @lis3: pointer to the device struct |
122 | * @reg: the register to write to | 128 | * @reg: the register to write to |
123 | * @val: the value to write | 129 | * @val: the value to write |
124 | * | 130 | * |
125 | * Returns AE_OK on success. | 131 | * Returns 0 on success. |
126 | */ | 132 | */ |
127 | acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) | 133 | int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val) |
128 | { | 134 | { |
135 | struct acpi_device *dev = lis3->bus_priv; | ||
129 | unsigned long long ret; /* Not used when writting */ | 136 | unsigned long long ret; /* Not used when writting */ |
130 | union acpi_object in_obj[2]; | 137 | union acpi_object in_obj[2]; |
131 | struct acpi_object_list args = { 2, in_obj }; | 138 | struct acpi_object_list args = { 2, in_obj }; |
@@ -135,12 +142,15 @@ acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) | |||
135 | in_obj[1].type = ACPI_TYPE_INTEGER; | 142 | in_obj[1].type = ACPI_TYPE_INTEGER; |
136 | in_obj[1].integer.value = val; | 143 | in_obj[1].integer.value = val; |
137 | 144 | ||
138 | return acpi_evaluate_integer(handle, "ALWR", &args, &ret); | 145 | if (acpi_evaluate_integer(dev->handle, "ALWR", &args, &ret) != AE_OK) |
146 | return -EINVAL; | ||
147 | |||
148 | return 0; | ||
139 | } | 149 | } |
140 | 150 | ||
141 | static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) | 151 | static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) |
142 | { | 152 | { |
143 | adev.ac = *((struct axis_conversion *)dmi->driver_data); | 153 | lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data); |
144 | printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); | 154 | printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); |
145 | 155 | ||
146 | return 1; | 156 | return 1; |
@@ -187,6 +197,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
187 | AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), | 197 | AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), |
188 | AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), | 198 | AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), |
189 | AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), | 199 | AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), |
200 | AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), | ||
190 | AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), | 201 | AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), |
191 | AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), | 202 | AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), |
192 | AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), | 203 | AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), |
@@ -201,6 +212,8 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
201 | PRODUCT_NAME, "HP Pavilion dv5", | 212 | PRODUCT_NAME, "HP Pavilion dv5", |
202 | BOARD_NAME, "3600", | 213 | BOARD_NAME, "3600", |
203 | y_inverted), | 214 | y_inverted), |
215 | AXIS_DMI_MATCH("DV7", "HP Pavilion dv7", x_inverted), | ||
216 | AXIS_DMI_MATCH("HP8710", "HP Compaq 8710", y_inverted), | ||
204 | { NULL, } | 217 | { NULL, } |
205 | /* Laptop models without axis info (yet): | 218 | /* Laptop models without axis info (yet): |
206 | * "NC6910" "HP Compaq 6910" | 219 | * "NC6910" "HP Compaq 6910" |
@@ -214,7 +227,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
214 | 227 | ||
215 | static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) | 228 | static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) |
216 | { | 229 | { |
217 | acpi_handle handle = adev.device->handle; | 230 | struct acpi_device *dev = lis3_dev.bus_priv; |
218 | unsigned long long ret; /* Not used when writing */ | 231 | unsigned long long ret; /* Not used when writing */ |
219 | union acpi_object in_obj[1]; | 232 | union acpi_object in_obj[1]; |
220 | struct acpi_object_list args = { 1, in_obj }; | 233 | struct acpi_object_list args = { 1, in_obj }; |
@@ -222,7 +235,7 @@ static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness | |||
222 | in_obj[0].type = ACPI_TYPE_INTEGER; | 235 | in_obj[0].type = ACPI_TYPE_INTEGER; |
223 | in_obj[0].integer.value = !!value; | 236 | in_obj[0].integer.value = !!value; |
224 | 237 | ||
225 | acpi_evaluate_integer(handle, "ALED", &args, &ret); | 238 | acpi_evaluate_integer(dev->handle, "ALED", &args, &ret); |
226 | } | 239 | } |
227 | 240 | ||
228 | static struct delayed_led_classdev hpled_led = { | 241 | static struct delayed_led_classdev hpled_led = { |
@@ -254,28 +267,11 @@ static void lis3lv02d_enum_resources(struct acpi_device *device) | |||
254 | acpi_status status; | 267 | acpi_status status; |
255 | 268 | ||
256 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, | 269 | status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, |
257 | lis3lv02d_get_resource, &adev.irq); | 270 | lis3lv02d_get_resource, &lis3_dev.irq); |
258 | if (ACPI_FAILURE(status)) | 271 | if (ACPI_FAILURE(status)) |
259 | printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); | 272 | printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n"); |
260 | } | 273 | } |
261 | 274 | ||
262 | static s16 lis3lv02d_read_16(acpi_handle handle, int reg) | ||
263 | { | ||
264 | u8 lo, hi; | ||
265 | |||
266 | adev.read(handle, reg - 1, &lo); | ||
267 | adev.read(handle, reg, &hi); | ||
268 | /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ | ||
269 | return (s16)((hi << 8) | lo); | ||
270 | } | ||
271 | |||
272 | static s16 lis3lv02d_read_8(acpi_handle handle, int reg) | ||
273 | { | ||
274 | s8 lo; | ||
275 | adev.read(handle, reg, &lo); | ||
276 | return lo; | ||
277 | } | ||
278 | |||
279 | static int lis3lv02d_add(struct acpi_device *device) | 275 | static int lis3lv02d_add(struct acpi_device *device) |
280 | { | 276 | { |
281 | int ret; | 277 | int ret; |
@@ -283,51 +279,35 @@ static int lis3lv02d_add(struct acpi_device *device) | |||
283 | if (!device) | 279 | if (!device) |
284 | return -EINVAL; | 280 | return -EINVAL; |
285 | 281 | ||
286 | adev.device = device; | 282 | lis3_dev.bus_priv = device; |
287 | adev.init = lis3lv02d_acpi_init; | 283 | lis3_dev.init = lis3lv02d_acpi_init; |
288 | adev.read = lis3lv02d_acpi_read; | 284 | lis3_dev.read = lis3lv02d_acpi_read; |
289 | adev.write = lis3lv02d_acpi_write; | 285 | lis3_dev.write = lis3lv02d_acpi_write; |
290 | strcpy(acpi_device_name(device), DRIVER_NAME); | 286 | strcpy(acpi_device_name(device), DRIVER_NAME); |
291 | strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); | 287 | strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); |
292 | device->driver_data = &adev; | 288 | device->driver_data = &lis3_dev; |
293 | 289 | ||
294 | lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami); | 290 | /* obtain IRQ number of our device from ACPI */ |
295 | switch (adev.whoami) { | 291 | lis3lv02d_enum_resources(device); |
296 | case LIS_DOUBLE_ID: | ||
297 | printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); | ||
298 | adev.read_data = lis3lv02d_read_16; | ||
299 | adev.mdps_max_val = 2048; | ||
300 | break; | ||
301 | case LIS_SINGLE_ID: | ||
302 | printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); | ||
303 | adev.read_data = lis3lv02d_read_8; | ||
304 | adev.mdps_max_val = 128; | ||
305 | break; | ||
306 | default: | ||
307 | printk(KERN_ERR DRIVER_NAME | ||
308 | ": unknown sensor type 0x%X\n", adev.whoami); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | 292 | ||
312 | /* If possible use a "standard" axes order */ | 293 | /* If possible use a "standard" axes order */ |
313 | if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { | 294 | if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { |
314 | printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " | 295 | printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " |
315 | "using default axes configuration\n"); | 296 | "using default axes configuration\n"); |
316 | adev.ac = lis3lv02d_axis_normal; | 297 | lis3_dev.ac = lis3lv02d_axis_normal; |
317 | } | 298 | } |
318 | 299 | ||
319 | INIT_WORK(&hpled_led.work, delayed_set_status_worker); | 300 | /* call the core layer do its init */ |
320 | ret = led_classdev_register(NULL, &hpled_led.led_classdev); | 301 | ret = lis3lv02d_init_device(&lis3_dev); |
321 | if (ret) | 302 | if (ret) |
322 | return ret; | 303 | return ret; |
323 | 304 | ||
324 | /* obtain IRQ number of our device from ACPI */ | 305 | INIT_WORK(&hpled_led.work, delayed_set_status_worker); |
325 | lis3lv02d_enum_resources(adev.device); | 306 | ret = led_classdev_register(NULL, &hpled_led.led_classdev); |
326 | |||
327 | ret = lis3lv02d_init_device(&adev); | ||
328 | if (ret) { | 307 | if (ret) { |
308 | lis3lv02d_joystick_disable(); | ||
309 | lis3lv02d_poweroff(&lis3_dev); | ||
329 | flush_work(&hpled_led.work); | 310 | flush_work(&hpled_led.work); |
330 | led_classdev_unregister(&hpled_led.led_classdev); | ||
331 | return ret; | 311 | return ret; |
332 | } | 312 | } |
333 | 313 | ||
@@ -340,7 +320,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) | |||
340 | return -EINVAL; | 320 | return -EINVAL; |
341 | 321 | ||
342 | lis3lv02d_joystick_disable(); | 322 | lis3lv02d_joystick_disable(); |
343 | lis3lv02d_poweroff(device->handle); | 323 | lis3lv02d_poweroff(&lis3_dev); |
344 | 324 | ||
345 | flush_work(&hpled_led.work); | 325 | flush_work(&hpled_led.work); |
346 | led_classdev_unregister(&hpled_led.led_classdev); | 326 | led_classdev_unregister(&hpled_led.led_classdev); |
@@ -353,19 +333,19 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) | |||
353 | static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) | 333 | static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) |
354 | { | 334 | { |
355 | /* make sure the device is off when we suspend */ | 335 | /* make sure the device is off when we suspend */ |
356 | lis3lv02d_poweroff(device->handle); | 336 | lis3lv02d_poweroff(&lis3_dev); |
357 | return 0; | 337 | return 0; |
358 | } | 338 | } |
359 | 339 | ||
360 | static int lis3lv02d_resume(struct acpi_device *device) | 340 | static int lis3lv02d_resume(struct acpi_device *device) |
361 | { | 341 | { |
362 | /* put back the device in the right state (ACPI might turn it on) */ | 342 | /* put back the device in the right state (ACPI might turn it on) */ |
363 | mutex_lock(&adev.lock); | 343 | mutex_lock(&lis3_dev.lock); |
364 | if (adev.usage > 0) | 344 | if (lis3_dev.usage > 0) |
365 | lis3lv02d_poweron(device->handle); | 345 | lis3lv02d_poweron(&lis3_dev); |
366 | else | 346 | else |
367 | lis3lv02d_poweroff(device->handle); | 347 | lis3lv02d_poweroff(&lis3_dev); |
368 | mutex_unlock(&adev.lock); | 348 | mutex_unlock(&lis3_dev.lock); |
369 | return 0; | 349 | return 0; |
370 | } | 350 | } |
371 | #else | 351 | #else |
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index 8bb2158f0453..778eb7795983 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
38 | #include <linux/miscdevice.h> | 38 | #include <linux/miscdevice.h> |
39 | #include <acpi/acpi_drivers.h> | ||
40 | #include <asm/atomic.h> | 39 | #include <asm/atomic.h> |
41 | #include "lis3lv02d.h" | 40 | #include "lis3lv02d.h" |
42 | 41 | ||
@@ -53,13 +52,30 @@ | |||
53 | * joystick. | 52 | * joystick. |
54 | */ | 53 | */ |
55 | 54 | ||
56 | struct acpi_lis3lv02d adev = { | 55 | struct lis3lv02d lis3_dev = { |
57 | .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait), | 56 | .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), |
58 | }; | 57 | }; |
59 | 58 | ||
60 | EXPORT_SYMBOL_GPL(adev); | 59 | EXPORT_SYMBOL_GPL(lis3_dev); |
61 | 60 | ||
62 | static int lis3lv02d_add_fs(struct acpi_device *device); | 61 | static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) |
62 | { | ||
63 | s8 lo; | ||
64 | if (lis3->read(lis3, reg, &lo) < 0) | ||
65 | return 0; | ||
66 | |||
67 | return lo; | ||
68 | } | ||
69 | |||
70 | static s16 lis3lv02d_read_16(struct lis3lv02d *lis3, int reg) | ||
71 | { | ||
72 | u8 lo, hi; | ||
73 | |||
74 | lis3->read(lis3, reg - 1, &lo); | ||
75 | lis3->read(lis3, reg, &hi); | ||
76 | /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ | ||
77 | return (s16)((hi << 8) | lo); | ||
78 | } | ||
63 | 79 | ||
64 | /** | 80 | /** |
65 | * lis3lv02d_get_axis - For the given axis, give the value converted | 81 | * lis3lv02d_get_axis - For the given axis, give the value converted |
@@ -78,36 +94,36 @@ static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) | |||
78 | 94 | ||
79 | /** | 95 | /** |
80 | * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer | 96 | * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer |
81 | * @handle: the handle to the device | 97 | * @lis3: pointer to the device struct |
82 | * @x: where to store the X axis value | 98 | * @x: where to store the X axis value |
83 | * @y: where to store the Y axis value | 99 | * @y: where to store the Y axis value |
84 | * @z: where to store the Z axis value | 100 | * @z: where to store the Z axis value |
85 | * | 101 | * |
86 | * Note that 40Hz input device can eat up about 10% CPU at 800MHZ | 102 | * Note that 40Hz input device can eat up about 10% CPU at 800MHZ |
87 | */ | 103 | */ |
88 | static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z) | 104 | static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) |
89 | { | 105 | { |
90 | int position[3]; | 106 | int position[3]; |
91 | 107 | ||
92 | position[0] = adev.read_data(handle, OUTX); | 108 | position[0] = lis3_dev.read_data(lis3, OUTX); |
93 | position[1] = adev.read_data(handle, OUTY); | 109 | position[1] = lis3_dev.read_data(lis3, OUTY); |
94 | position[2] = adev.read_data(handle, OUTZ); | 110 | position[2] = lis3_dev.read_data(lis3, OUTZ); |
95 | 111 | ||
96 | *x = lis3lv02d_get_axis(adev.ac.x, position); | 112 | *x = lis3lv02d_get_axis(lis3_dev.ac.x, position); |
97 | *y = lis3lv02d_get_axis(adev.ac.y, position); | 113 | *y = lis3lv02d_get_axis(lis3_dev.ac.y, position); |
98 | *z = lis3lv02d_get_axis(adev.ac.z, position); | 114 | *z = lis3lv02d_get_axis(lis3_dev.ac.z, position); |
99 | } | 115 | } |
100 | 116 | ||
101 | void lis3lv02d_poweroff(acpi_handle handle) | 117 | void lis3lv02d_poweroff(struct lis3lv02d *lis3) |
102 | { | 118 | { |
103 | adev.is_on = 0; | 119 | lis3_dev.is_on = 0; |
104 | } | 120 | } |
105 | EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); | 121 | EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); |
106 | 122 | ||
107 | void lis3lv02d_poweron(acpi_handle handle) | 123 | void lis3lv02d_poweron(struct lis3lv02d *lis3) |
108 | { | 124 | { |
109 | adev.is_on = 1; | 125 | lis3_dev.is_on = 1; |
110 | adev.init(handle); | 126 | lis3_dev.init(lis3); |
111 | } | 127 | } |
112 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); | 128 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); |
113 | 129 | ||
@@ -116,13 +132,13 @@ EXPORT_SYMBOL_GPL(lis3lv02d_poweron); | |||
116 | * device will always be on until a call to lis3lv02d_decrease_use(). Not to be | 132 | * device will always be on until a call to lis3lv02d_decrease_use(). Not to be |
117 | * used from interrupt context. | 133 | * used from interrupt context. |
118 | */ | 134 | */ |
119 | static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) | 135 | static void lis3lv02d_increase_use(struct lis3lv02d *dev) |
120 | { | 136 | { |
121 | mutex_lock(&dev->lock); | 137 | mutex_lock(&dev->lock); |
122 | dev->usage++; | 138 | dev->usage++; |
123 | if (dev->usage == 1) { | 139 | if (dev->usage == 1) { |
124 | if (!dev->is_on) | 140 | if (!dev->is_on) |
125 | lis3lv02d_poweron(dev->device->handle); | 141 | lis3lv02d_poweron(dev); |
126 | } | 142 | } |
127 | mutex_unlock(&dev->lock); | 143 | mutex_unlock(&dev->lock); |
128 | } | 144 | } |
@@ -131,12 +147,12 @@ static void lis3lv02d_increase_use(struct acpi_lis3lv02d *dev) | |||
131 | * To be called whenever a usage of the device is stopped. | 147 | * To be called whenever a usage of the device is stopped. |
132 | * It will make sure to turn off the device when there is not usage. | 148 | * It will make sure to turn off the device when there is not usage. |
133 | */ | 149 | */ |
134 | static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev) | 150 | static void lis3lv02d_decrease_use(struct lis3lv02d *dev) |
135 | { | 151 | { |
136 | mutex_lock(&dev->lock); | 152 | mutex_lock(&dev->lock); |
137 | dev->usage--; | 153 | dev->usage--; |
138 | if (dev->usage == 0) | 154 | if (dev->usage == 0) |
139 | lis3lv02d_poweroff(dev->device->handle); | 155 | lis3lv02d_poweroff(dev); |
140 | mutex_unlock(&dev->lock); | 156 | mutex_unlock(&dev->lock); |
141 | } | 157 | } |
142 | 158 | ||
@@ -147,10 +163,10 @@ static irqreturn_t lis302dl_interrupt(int irq, void *dummy) | |||
147 | * the lid is closed. This leads to interrupts as soon as a little move | 163 | * the lid is closed. This leads to interrupts as soon as a little move |
148 | * is done. | 164 | * is done. |
149 | */ | 165 | */ |
150 | atomic_inc(&adev.count); | 166 | atomic_inc(&lis3_dev.count); |
151 | 167 | ||
152 | wake_up_interruptible(&adev.misc_wait); | 168 | wake_up_interruptible(&lis3_dev.misc_wait); |
153 | kill_fasync(&adev.async_queue, SIGIO, POLL_IN); | 169 | kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); |
154 | return IRQ_HANDLED; | 170 | return IRQ_HANDLED; |
155 | } | 171 | } |
156 | 172 | ||
@@ -158,10 +174,10 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) | |||
158 | { | 174 | { |
159 | int ret; | 175 | int ret; |
160 | 176 | ||
161 | if (test_and_set_bit(0, &adev.misc_opened)) | 177 | if (test_and_set_bit(0, &lis3_dev.misc_opened)) |
162 | return -EBUSY; /* already open */ | 178 | return -EBUSY; /* already open */ |
163 | 179 | ||
164 | atomic_set(&adev.count, 0); | 180 | atomic_set(&lis3_dev.count, 0); |
165 | 181 | ||
166 | /* | 182 | /* |
167 | * The sensor can generate interrupts for free-fall and direction | 183 | * The sensor can generate interrupts for free-fall and direction |
@@ -174,25 +190,25 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file) | |||
174 | * io-apic is not configurable (and generates a warning) but I keep it | 190 | * io-apic is not configurable (and generates a warning) but I keep it |
175 | * in case of support for other hardware. | 191 | * in case of support for other hardware. |
176 | */ | 192 | */ |
177 | ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, | 193 | ret = request_irq(lis3_dev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING, |
178 | DRIVER_NAME, &adev); | 194 | DRIVER_NAME, &lis3_dev); |
179 | 195 | ||
180 | if (ret) { | 196 | if (ret) { |
181 | clear_bit(0, &adev.misc_opened); | 197 | clear_bit(0, &lis3_dev.misc_opened); |
182 | printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq); | 198 | printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); |
183 | return -EBUSY; | 199 | return -EBUSY; |
184 | } | 200 | } |
185 | lis3lv02d_increase_use(&adev); | 201 | lis3lv02d_increase_use(&lis3_dev); |
186 | printk("lis3: registered interrupt %d\n", adev.irq); | 202 | printk("lis3: registered interrupt %d\n", lis3_dev.irq); |
187 | return 0; | 203 | return 0; |
188 | } | 204 | } |
189 | 205 | ||
190 | static int lis3lv02d_misc_release(struct inode *inode, struct file *file) | 206 | static int lis3lv02d_misc_release(struct inode *inode, struct file *file) |
191 | { | 207 | { |
192 | fasync_helper(-1, file, 0, &adev.async_queue); | 208 | fasync_helper(-1, file, 0, &lis3_dev.async_queue); |
193 | lis3lv02d_decrease_use(&adev); | 209 | lis3lv02d_decrease_use(&lis3_dev); |
194 | free_irq(adev.irq, &adev); | 210 | free_irq(lis3_dev.irq, &lis3_dev); |
195 | clear_bit(0, &adev.misc_opened); /* release the device */ | 211 | clear_bit(0, &lis3_dev.misc_opened); /* release the device */ |
196 | return 0; | 212 | return 0; |
197 | } | 213 | } |
198 | 214 | ||
@@ -207,10 +223,10 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, | |||
207 | if (count < 1) | 223 | if (count < 1) |
208 | return -EINVAL; | 224 | return -EINVAL; |
209 | 225 | ||
210 | add_wait_queue(&adev.misc_wait, &wait); | 226 | add_wait_queue(&lis3_dev.misc_wait, &wait); |
211 | while (true) { | 227 | while (true) { |
212 | set_current_state(TASK_INTERRUPTIBLE); | 228 | set_current_state(TASK_INTERRUPTIBLE); |
213 | data = atomic_xchg(&adev.count, 0); | 229 | data = atomic_xchg(&lis3_dev.count, 0); |
214 | if (data) | 230 | if (data) |
215 | break; | 231 | break; |
216 | 232 | ||
@@ -240,22 +256,22 @@ static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, | |||
240 | 256 | ||
241 | out: | 257 | out: |
242 | __set_current_state(TASK_RUNNING); | 258 | __set_current_state(TASK_RUNNING); |
243 | remove_wait_queue(&adev.misc_wait, &wait); | 259 | remove_wait_queue(&lis3_dev.misc_wait, &wait); |
244 | 260 | ||
245 | return retval; | 261 | return retval; |
246 | } | 262 | } |
247 | 263 | ||
248 | static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) | 264 | static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) |
249 | { | 265 | { |
250 | poll_wait(file, &adev.misc_wait, wait); | 266 | poll_wait(file, &lis3_dev.misc_wait, wait); |
251 | if (atomic_read(&adev.count)) | 267 | if (atomic_read(&lis3_dev.count)) |
252 | return POLLIN | POLLRDNORM; | 268 | return POLLIN | POLLRDNORM; |
253 | return 0; | 269 | return 0; |
254 | } | 270 | } |
255 | 271 | ||
256 | static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) | 272 | static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) |
257 | { | 273 | { |
258 | return fasync_helper(fd, file, on, &adev.async_queue); | 274 | return fasync_helper(fd, file, on, &lis3_dev.async_queue); |
259 | } | 275 | } |
260 | 276 | ||
261 | static const struct file_operations lis3lv02d_misc_fops = { | 277 | static const struct file_operations lis3lv02d_misc_fops = { |
@@ -283,12 +299,12 @@ static int lis3lv02d_joystick_kthread(void *data) | |||
283 | int x, y, z; | 299 | int x, y, z; |
284 | 300 | ||
285 | while (!kthread_should_stop()) { | 301 | while (!kthread_should_stop()) { |
286 | lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); | 302 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); |
287 | input_report_abs(adev.idev, ABS_X, x - adev.xcalib); | 303 | input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib); |
288 | input_report_abs(adev.idev, ABS_Y, y - adev.ycalib); | 304 | input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib); |
289 | input_report_abs(adev.idev, ABS_Z, z - adev.zcalib); | 305 | input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib); |
290 | 306 | ||
291 | input_sync(adev.idev); | 307 | input_sync(lis3_dev.idev); |
292 | 308 | ||
293 | try_to_freeze(); | 309 | try_to_freeze(); |
294 | msleep_interruptible(MDPS_POLL_INTERVAL); | 310 | msleep_interruptible(MDPS_POLL_INTERVAL); |
@@ -299,11 +315,11 @@ static int lis3lv02d_joystick_kthread(void *data) | |||
299 | 315 | ||
300 | static int lis3lv02d_joystick_open(struct input_dev *input) | 316 | static int lis3lv02d_joystick_open(struct input_dev *input) |
301 | { | 317 | { |
302 | lis3lv02d_increase_use(&adev); | 318 | lis3lv02d_increase_use(&lis3_dev); |
303 | adev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); | 319 | lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d"); |
304 | if (IS_ERR(adev.kthread)) { | 320 | if (IS_ERR(lis3_dev.kthread)) { |
305 | lis3lv02d_decrease_use(&adev); | 321 | lis3lv02d_decrease_use(&lis3_dev); |
306 | return PTR_ERR(adev.kthread); | 322 | return PTR_ERR(lis3_dev.kthread); |
307 | } | 323 | } |
308 | 324 | ||
309 | return 0; | 325 | return 0; |
@@ -311,45 +327,46 @@ static int lis3lv02d_joystick_open(struct input_dev *input) | |||
311 | 327 | ||
312 | static void lis3lv02d_joystick_close(struct input_dev *input) | 328 | static void lis3lv02d_joystick_close(struct input_dev *input) |
313 | { | 329 | { |
314 | kthread_stop(adev.kthread); | 330 | kthread_stop(lis3_dev.kthread); |
315 | lis3lv02d_decrease_use(&adev); | 331 | lis3lv02d_decrease_use(&lis3_dev); |
316 | } | 332 | } |
317 | 333 | ||
318 | static inline void lis3lv02d_calibrate_joystick(void) | 334 | static inline void lis3lv02d_calibrate_joystick(void) |
319 | { | 335 | { |
320 | lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib); | 336 | lis3lv02d_get_xyz(&lis3_dev, |
337 | &lis3_dev.xcalib, &lis3_dev.ycalib, &lis3_dev.zcalib); | ||
321 | } | 338 | } |
322 | 339 | ||
323 | int lis3lv02d_joystick_enable(void) | 340 | int lis3lv02d_joystick_enable(void) |
324 | { | 341 | { |
325 | int err; | 342 | int err; |
326 | 343 | ||
327 | if (adev.idev) | 344 | if (lis3_dev.idev) |
328 | return -EINVAL; | 345 | return -EINVAL; |
329 | 346 | ||
330 | adev.idev = input_allocate_device(); | 347 | lis3_dev.idev = input_allocate_device(); |
331 | if (!adev.idev) | 348 | if (!lis3_dev.idev) |
332 | return -ENOMEM; | 349 | return -ENOMEM; |
333 | 350 | ||
334 | lis3lv02d_calibrate_joystick(); | 351 | lis3lv02d_calibrate_joystick(); |
335 | 352 | ||
336 | adev.idev->name = "ST LIS3LV02DL Accelerometer"; | 353 | lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer"; |
337 | adev.idev->phys = DRIVER_NAME "/input0"; | 354 | lis3_dev.idev->phys = DRIVER_NAME "/input0"; |
338 | adev.idev->id.bustype = BUS_HOST; | 355 | lis3_dev.idev->id.bustype = BUS_HOST; |
339 | adev.idev->id.vendor = 0; | 356 | lis3_dev.idev->id.vendor = 0; |
340 | adev.idev->dev.parent = &adev.pdev->dev; | 357 | lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev; |
341 | adev.idev->open = lis3lv02d_joystick_open; | 358 | lis3_dev.idev->open = lis3lv02d_joystick_open; |
342 | adev.idev->close = lis3lv02d_joystick_close; | 359 | lis3_dev.idev->close = lis3lv02d_joystick_close; |
343 | 360 | ||
344 | set_bit(EV_ABS, adev.idev->evbit); | 361 | set_bit(EV_ABS, lis3_dev.idev->evbit); |
345 | input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); | 362 | input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); |
346 | input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); | 363 | input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); |
347 | input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3); | 364 | input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); |
348 | 365 | ||
349 | err = input_register_device(adev.idev); | 366 | err = input_register_device(lis3_dev.idev); |
350 | if (err) { | 367 | if (err) { |
351 | input_free_device(adev.idev); | 368 | input_free_device(lis3_dev.idev); |
352 | adev.idev = NULL; | 369 | lis3_dev.idev = NULL; |
353 | } | 370 | } |
354 | 371 | ||
355 | return err; | 372 | return err; |
@@ -358,71 +375,40 @@ EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); | |||
358 | 375 | ||
359 | void lis3lv02d_joystick_disable(void) | 376 | void lis3lv02d_joystick_disable(void) |
360 | { | 377 | { |
361 | if (!adev.idev) | 378 | if (!lis3_dev.idev) |
362 | return; | 379 | return; |
363 | 380 | ||
364 | misc_deregister(&lis3lv02d_misc_device); | 381 | misc_deregister(&lis3lv02d_misc_device); |
365 | input_unregister_device(adev.idev); | 382 | input_unregister_device(lis3_dev.idev); |
366 | adev.idev = NULL; | 383 | lis3_dev.idev = NULL; |
367 | } | 384 | } |
368 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); | 385 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); |
369 | 386 | ||
370 | /* | ||
371 | * Initialise the accelerometer and the various subsystems. | ||
372 | * Should be rather independant of the bus system. | ||
373 | */ | ||
374 | int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) | ||
375 | { | ||
376 | mutex_init(&dev->lock); | ||
377 | lis3lv02d_add_fs(dev->device); | ||
378 | lis3lv02d_increase_use(dev); | ||
379 | |||
380 | if (lis3lv02d_joystick_enable()) | ||
381 | printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); | ||
382 | |||
383 | printk("lis3_init_device: irq %d\n", dev->irq); | ||
384 | |||
385 | /* if we did not get an IRQ from ACPI - we have nothing more to do */ | ||
386 | if (!dev->irq) { | ||
387 | printk(KERN_ERR DRIVER_NAME | ||
388 | ": No IRQ in ACPI. Disabling /dev/freefall\n"); | ||
389 | goto out; | ||
390 | } | ||
391 | |||
392 | printk("lis3: registering device\n"); | ||
393 | if (misc_register(&lis3lv02d_misc_device)) | ||
394 | printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); | ||
395 | out: | ||
396 | lis3lv02d_decrease_use(dev); | ||
397 | return 0; | ||
398 | } | ||
399 | EXPORT_SYMBOL_GPL(lis3lv02d_init_device); | ||
400 | |||
401 | /* Sysfs stuff */ | 387 | /* Sysfs stuff */ |
402 | static ssize_t lis3lv02d_position_show(struct device *dev, | 388 | static ssize_t lis3lv02d_position_show(struct device *dev, |
403 | struct device_attribute *attr, char *buf) | 389 | struct device_attribute *attr, char *buf) |
404 | { | 390 | { |
405 | int x, y, z; | 391 | int x, y, z; |
406 | 392 | ||
407 | lis3lv02d_increase_use(&adev); | 393 | lis3lv02d_increase_use(&lis3_dev); |
408 | lis3lv02d_get_xyz(adev.device->handle, &x, &y, &z); | 394 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); |
409 | lis3lv02d_decrease_use(&adev); | 395 | lis3lv02d_decrease_use(&lis3_dev); |
410 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); | 396 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); |
411 | } | 397 | } |
412 | 398 | ||
413 | static ssize_t lis3lv02d_calibrate_show(struct device *dev, | 399 | static ssize_t lis3lv02d_calibrate_show(struct device *dev, |
414 | struct device_attribute *attr, char *buf) | 400 | struct device_attribute *attr, char *buf) |
415 | { | 401 | { |
416 | return sprintf(buf, "(%d,%d,%d)\n", adev.xcalib, adev.ycalib, adev.zcalib); | 402 | return sprintf(buf, "(%d,%d,%d)\n", lis3_dev.xcalib, lis3_dev.ycalib, lis3_dev.zcalib); |
417 | } | 403 | } |
418 | 404 | ||
419 | static ssize_t lis3lv02d_calibrate_store(struct device *dev, | 405 | static ssize_t lis3lv02d_calibrate_store(struct device *dev, |
420 | struct device_attribute *attr, | 406 | struct device_attribute *attr, |
421 | const char *buf, size_t count) | 407 | const char *buf, size_t count) |
422 | { | 408 | { |
423 | lis3lv02d_increase_use(&adev); | 409 | lis3lv02d_increase_use(&lis3_dev); |
424 | lis3lv02d_calibrate_joystick(); | 410 | lis3lv02d_calibrate_joystick(); |
425 | lis3lv02d_decrease_use(&adev); | 411 | lis3lv02d_decrease_use(&lis3_dev); |
426 | return count; | 412 | return count; |
427 | } | 413 | } |
428 | 414 | ||
@@ -434,9 +420,9 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, | |||
434 | u8 ctrl; | 420 | u8 ctrl; |
435 | int val; | 421 | int val; |
436 | 422 | ||
437 | lis3lv02d_increase_use(&adev); | 423 | lis3lv02d_increase_use(&lis3_dev); |
438 | adev.read(adev.device->handle, CTRL_REG1, &ctrl); | 424 | lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); |
439 | lis3lv02d_decrease_use(&adev); | 425 | lis3lv02d_decrease_use(&lis3_dev); |
440 | val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; | 426 | val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; |
441 | return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); | 427 | return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); |
442 | } | 428 | } |
@@ -458,23 +444,73 @@ static struct attribute_group lis3lv02d_attribute_group = { | |||
458 | }; | 444 | }; |
459 | 445 | ||
460 | 446 | ||
461 | static int lis3lv02d_add_fs(struct acpi_device *device) | 447 | static int lis3lv02d_add_fs(struct lis3lv02d *lis3) |
462 | { | 448 | { |
463 | adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); | 449 | lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); |
464 | if (IS_ERR(adev.pdev)) | 450 | if (IS_ERR(lis3_dev.pdev)) |
465 | return PTR_ERR(adev.pdev); | 451 | return PTR_ERR(lis3_dev.pdev); |
466 | 452 | ||
467 | return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); | 453 | return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); |
468 | } | 454 | } |
469 | 455 | ||
470 | int lis3lv02d_remove_fs(void) | 456 | int lis3lv02d_remove_fs(void) |
471 | { | 457 | { |
472 | sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); | 458 | sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); |
473 | platform_device_unregister(adev.pdev); | 459 | platform_device_unregister(lis3_dev.pdev); |
474 | return 0; | 460 | return 0; |
475 | } | 461 | } |
476 | EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); | 462 | EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); |
477 | 463 | ||
464 | /* | ||
465 | * Initialise the accelerometer and the various subsystems. | ||
466 | * Should be rather independant of the bus system. | ||
467 | */ | ||
468 | int lis3lv02d_init_device(struct lis3lv02d *dev) | ||
469 | { | ||
470 | dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); | ||
471 | |||
472 | switch (dev->whoami) { | ||
473 | case LIS_DOUBLE_ID: | ||
474 | printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n"); | ||
475 | dev->read_data = lis3lv02d_read_16; | ||
476 | dev->mdps_max_val = 2048; | ||
477 | break; | ||
478 | case LIS_SINGLE_ID: | ||
479 | printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n"); | ||
480 | dev->read_data = lis3lv02d_read_8; | ||
481 | dev->mdps_max_val = 128; | ||
482 | break; | ||
483 | default: | ||
484 | printk(KERN_ERR DRIVER_NAME | ||
485 | ": unknown sensor type 0x%X\n", lis3_dev.whoami); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | mutex_init(&dev->lock); | ||
490 | lis3lv02d_add_fs(dev); | ||
491 | lis3lv02d_increase_use(dev); | ||
492 | |||
493 | if (lis3lv02d_joystick_enable()) | ||
494 | printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); | ||
495 | |||
496 | printk("lis3_init_device: irq %d\n", dev->irq); | ||
497 | |||
498 | /* bail if we did not get an IRQ from the bus layer */ | ||
499 | if (!dev->irq) { | ||
500 | printk(KERN_ERR DRIVER_NAME | ||
501 | ": No IRQ. Disabling /dev/freefall\n"); | ||
502 | goto out; | ||
503 | } | ||
504 | |||
505 | printk("lis3: registering device\n"); | ||
506 | if (misc_register(&lis3lv02d_misc_device)) | ||
507 | printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); | ||
508 | out: | ||
509 | lis3lv02d_decrease_use(dev); | ||
510 | return 0; | ||
511 | } | ||
512 | EXPORT_SYMBOL_GPL(lis3lv02d_init_device); | ||
513 | |||
478 | MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); | 514 | MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); |
479 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | 515 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); |
480 | MODULE_LICENSE("GPL"); | 516 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index 75972bf372ff..745ec96806d4 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h | |||
@@ -159,14 +159,14 @@ struct axis_conversion { | |||
159 | s8 z; | 159 | s8 z; |
160 | }; | 160 | }; |
161 | 161 | ||
162 | struct acpi_lis3lv02d { | 162 | struct lis3lv02d { |
163 | struct acpi_device *device; /* The ACPI device */ | 163 | void *bus_priv; /* used by the bus layer only */ |
164 | acpi_status (*init) (acpi_handle handle); | 164 | int (*init) (struct lis3lv02d *lis3); |
165 | acpi_status (*write) (acpi_handle handle, int reg, u8 val); | 165 | int (*write) (struct lis3lv02d *lis3, int reg, u8 val); |
166 | acpi_status (*read) (acpi_handle handle, int reg, u8 *ret); | 166 | int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); |
167 | 167 | ||
168 | u8 whoami; /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */ | 168 | u8 whoami; /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */ |
169 | s16 (*read_data) (acpi_handle handle, int reg); | 169 | s16 (*read_data) (struct lis3lv02d *lis3, int reg); |
170 | int mdps_max_val; | 170 | int mdps_max_val; |
171 | 171 | ||
172 | struct input_dev *idev; /* input device */ | 172 | struct input_dev *idev; /* input device */ |
@@ -187,11 +187,11 @@ struct acpi_lis3lv02d { | |||
187 | unsigned long misc_opened; /* bit0: whether the device is open */ | 187 | unsigned long misc_opened; /* bit0: whether the device is open */ |
188 | }; | 188 | }; |
189 | 189 | ||
190 | int lis3lv02d_init_device(struct acpi_lis3lv02d *dev); | 190 | int lis3lv02d_init_device(struct lis3lv02d *lis3); |
191 | int lis3lv02d_joystick_enable(void); | 191 | int lis3lv02d_joystick_enable(void); |
192 | void lis3lv02d_joystick_disable(void); | 192 | void lis3lv02d_joystick_disable(void); |
193 | void lis3lv02d_poweroff(acpi_handle handle); | 193 | void lis3lv02d_poweroff(struct lis3lv02d *lis3); |
194 | void lis3lv02d_poweron(acpi_handle handle); | 194 | void lis3lv02d_poweron(struct lis3lv02d *lis3); |
195 | int lis3lv02d_remove_fs(void); | 195 | int lis3lv02d_remove_fs(void); |
196 | 196 | ||
197 | extern struct acpi_lis3lv02d adev; | 197 | extern struct lis3lv02d lis3_dev; |
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c new file mode 100644 index 000000000000..07ae74b0e191 --- /dev/null +++ b/drivers/hwmon/lis3lv02d_spi.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * lis3lv02d_spi - SPI glue layer for lis3lv02d | ||
3 | * | ||
4 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * publishhed by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | |||
20 | #include "lis3lv02d.h" | ||
21 | |||
22 | #define DRV_NAME "lis3lv02d_spi" | ||
23 | #define LIS3_SPI_READ 0x80 | ||
24 | |||
25 | static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) | ||
26 | { | ||
27 | struct spi_device *spi = lis3->bus_priv; | ||
28 | int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); | ||
29 | if (ret < 0) | ||
30 | return -EINVAL; | ||
31 | |||
32 | *v = (u8) ret; | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) | ||
37 | { | ||
38 | u8 tmp[2] = { reg, val }; | ||
39 | struct spi_device *spi = lis3->bus_priv; | ||
40 | return spi_write(spi, tmp, sizeof(tmp)); | ||
41 | } | ||
42 | |||
43 | static int lis3_spi_init(struct lis3lv02d *lis3) | ||
44 | { | ||
45 | u8 reg; | ||
46 | int ret; | ||
47 | |||
48 | /* power up the device */ | ||
49 | ret = lis3->read(lis3, CTRL_REG1, ®); | ||
50 | if (ret < 0) | ||
51 | return ret; | ||
52 | |||
53 | reg |= CTRL1_PD0; | ||
54 | return lis3->write(lis3, CTRL_REG1, reg); | ||
55 | } | ||
56 | |||
57 | static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 }; | ||
58 | |||
59 | static int __devinit lis302dl_spi_probe(struct spi_device *spi) | ||
60 | { | ||
61 | int ret; | ||
62 | |||
63 | spi->bits_per_word = 8; | ||
64 | spi->mode = SPI_MODE_0; | ||
65 | ret = spi_setup(spi); | ||
66 | if (ret < 0) | ||
67 | return ret; | ||
68 | |||
69 | lis3_dev.bus_priv = spi; | ||
70 | lis3_dev.init = lis3_spi_init; | ||
71 | lis3_dev.read = lis3_spi_read; | ||
72 | lis3_dev.write = lis3_spi_write; | ||
73 | lis3_dev.irq = spi->irq; | ||
74 | lis3_dev.ac = lis3lv02d_axis_normal; | ||
75 | spi_set_drvdata(spi, &lis3_dev); | ||
76 | |||
77 | ret = lis3lv02d_init_device(&lis3_dev); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | static int __devexit lis302dl_spi_remove(struct spi_device *spi) | ||
82 | { | ||
83 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); | ||
84 | lis3lv02d_joystick_disable(); | ||
85 | lis3lv02d_poweroff(lis3); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static struct spi_driver lis302dl_spi_driver = { | ||
90 | .driver = { | ||
91 | .name = DRV_NAME, | ||
92 | .owner = THIS_MODULE, | ||
93 | }, | ||
94 | .probe = lis302dl_spi_probe, | ||
95 | .remove = __devexit_p(lis302dl_spi_remove), | ||
96 | }; | ||
97 | |||
98 | static int __init lis302dl_init(void) | ||
99 | { | ||
100 | return spi_register_driver(&lis302dl_spi_driver); | ||
101 | } | ||
102 | |||
103 | static void __exit lis302dl_exit(void) | ||
104 | { | ||
105 | spi_unregister_driver(&lis302dl_spi_driver); | ||
106 | } | ||
107 | |||
108 | module_init(lis302dl_init); | ||
109 | module_exit(lis302dl_exit); | ||
110 | |||
111 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | ||
112 | MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); | ||
113 | MODULE_LICENSE("GPL"); | ||
114 | |||
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c new file mode 100644 index 000000000000..091d95f38aaa --- /dev/null +++ b/drivers/hwmon/lm95241.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* | ||
2 | * lm95241.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | * monitoring | ||
4 | * Copyright (C) 2008 Davide Rizzo <elpa-rizzo@gmail.com> | ||
5 | * | ||
6 | * Based on the max1619 driver. The LM95241 is a sensor chip made by National | ||
7 | * Semiconductors. | ||
8 | * It reports up to three temperatures (its own plus up to | ||
9 | * two external ones). Complete datasheet can be | ||
10 | * obtained from National's website at: | ||
11 | * http://www.national.com/ds.cgi/LM/LM95241.pdf | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
26 | */ | ||
27 | |||
28 | #include <linux/module.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/jiffies.h> | ||
32 | #include <linux/i2c.h> | ||
33 | #include <linux/hwmon.h> | ||
34 | #include <linux/hwmon-sysfs.h> | ||
35 | #include <linux/err.h> | ||
36 | #include <linux/mutex.h> | ||
37 | #include <linux/sysfs.h> | ||
38 | |||
39 | static const unsigned short normal_i2c[] = { | ||
40 | 0x19, 0x2a, 0x2b, I2C_CLIENT_END}; | ||
41 | |||
42 | /* Insmod parameters */ | ||
43 | I2C_CLIENT_INSMOD_1(lm95241); | ||
44 | |||
45 | /* LM95241 registers */ | ||
46 | #define LM95241_REG_R_MAN_ID 0xFE | ||
47 | #define LM95241_REG_R_CHIP_ID 0xFF | ||
48 | #define LM95241_REG_R_STATUS 0x02 | ||
49 | #define LM95241_REG_RW_CONFIG 0x03 | ||
50 | #define LM95241_REG_RW_REM_FILTER 0x06 | ||
51 | #define LM95241_REG_RW_TRUTHERM 0x07 | ||
52 | #define LM95241_REG_W_ONE_SHOT 0x0F | ||
53 | #define LM95241_REG_R_LOCAL_TEMPH 0x10 | ||
54 | #define LM95241_REG_R_REMOTE1_TEMPH 0x11 | ||
55 | #define LM95241_REG_R_REMOTE2_TEMPH 0x12 | ||
56 | #define LM95241_REG_R_LOCAL_TEMPL 0x20 | ||
57 | #define LM95241_REG_R_REMOTE1_TEMPL 0x21 | ||
58 | #define LM95241_REG_R_REMOTE2_TEMPL 0x22 | ||
59 | #define LM95241_REG_RW_REMOTE_MODEL 0x30 | ||
60 | |||
61 | /* LM95241 specific bitfields */ | ||
62 | #define CFG_STOP 0x40 | ||
63 | #define CFG_CR0076 0x00 | ||
64 | #define CFG_CR0182 0x10 | ||
65 | #define CFG_CR1000 0x20 | ||
66 | #define CFG_CR2700 0x30 | ||
67 | #define R1MS_SHIFT 0 | ||
68 | #define R2MS_SHIFT 2 | ||
69 | #define R1MS_MASK (0x01 << (R1MS_SHIFT)) | ||
70 | #define R2MS_MASK (0x01 << (R2MS_SHIFT)) | ||
71 | #define R1DF_SHIFT 1 | ||
72 | #define R2DF_SHIFT 2 | ||
73 | #define R1DF_MASK (0x01 << (R1DF_SHIFT)) | ||
74 | #define R2DF_MASK (0x01 << (R2DF_SHIFT)) | ||
75 | #define R1FE_MASK 0x01 | ||
76 | #define R2FE_MASK 0x05 | ||
77 | #define TT1_SHIFT 0 | ||
78 | #define TT2_SHIFT 4 | ||
79 | #define TT_OFF 0 | ||
80 | #define TT_ON 1 | ||
81 | #define TT_MASK 7 | ||
82 | #define MANUFACTURER_ID 0x01 | ||
83 | #define DEFAULT_REVISION 0xA4 | ||
84 | |||
85 | /* Conversions and various macros */ | ||
86 | #define TEMP_FROM_REG(val_h, val_l) (((val_h) & 0x80 ? (val_h) - 0x100 : \ | ||
87 | (val_h)) * 1000 + (val_l) * 1000 / 256) | ||
88 | |||
89 | /* Functions declaration */ | ||
90 | static int lm95241_attach_adapter(struct i2c_adapter *adapter); | ||
91 | static int lm95241_detect(struct i2c_adapter *adapter, int address, | ||
92 | int kind); | ||
93 | static void lm95241_init_client(struct i2c_client *client); | ||
94 | static int lm95241_detach_client(struct i2c_client *client); | ||
95 | static struct lm95241_data *lm95241_update_device(struct device *dev); | ||
96 | |||
97 | /* Driver data (common to all clients) */ | ||
98 | static struct i2c_driver lm95241_driver = { | ||
99 | .driver = { | ||
100 | .name = "lm95241", | ||
101 | }, | ||
102 | .attach_adapter = lm95241_attach_adapter, | ||
103 | .detach_client = lm95241_detach_client, | ||
104 | }; | ||
105 | |||
106 | /* Client data (each client gets its own) */ | ||
107 | struct lm95241_data { | ||
108 | struct i2c_client client; | ||
109 | struct device *hwmon_dev; | ||
110 | struct mutex update_lock; | ||
111 | unsigned long last_updated, rate; /* in jiffies */ | ||
112 | char valid; /* zero until following fields are valid */ | ||
113 | /* registers values */ | ||
114 | u8 local_h, local_l; /* local */ | ||
115 | u8 remote1_h, remote1_l; /* remote1 */ | ||
116 | u8 remote2_h, remote2_l; /* remote2 */ | ||
117 | u8 config, model, trutherm; | ||
118 | }; | ||
119 | |||
120 | /* Sysfs stuff */ | ||
121 | #define show_temp(value) \ | ||
122 | static ssize_t show_##value(struct device *dev, \ | ||
123 | struct device_attribute *attr, char *buf) \ | ||
124 | { \ | ||
125 | struct lm95241_data *data = lm95241_update_device(dev); \ | ||
126 | snprintf(buf, PAGE_SIZE - 1, "%d\n", \ | ||
127 | TEMP_FROM_REG(data->value##_h, data->value##_l)); \ | ||
128 | return strlen(buf); \ | ||
129 | } | ||
130 | show_temp(local); | ||
131 | show_temp(remote1); | ||
132 | show_temp(remote2); | ||
133 | |||
134 | static ssize_t show_rate(struct device *dev, struct device_attribute *attr, | ||
135 | char *buf) | ||
136 | { | ||
137 | struct lm95241_data *data = lm95241_update_device(dev); | ||
138 | |||
139 | snprintf(buf, PAGE_SIZE - 1, "%lu\n", 1000 * data->rate / HZ); | ||
140 | return strlen(buf); | ||
141 | } | ||
142 | |||
143 | static ssize_t set_rate(struct device *dev, struct device_attribute *attr, | ||
144 | const char *buf, size_t count) | ||
145 | { | ||
146 | struct i2c_client *client = to_i2c_client(dev); | ||
147 | struct lm95241_data *data = i2c_get_clientdata(client); | ||
148 | |||
149 | strict_strtol(buf, 10, &data->rate); | ||
150 | data->rate = data->rate * HZ / 1000; | ||
151 | |||
152 | return count; | ||
153 | } | ||
154 | |||
155 | #define show_type(flag) \ | ||
156 | static ssize_t show_type##flag(struct device *dev, \ | ||
157 | struct device_attribute *attr, char *buf) \ | ||
158 | { \ | ||
159 | struct i2c_client *client = to_i2c_client(dev); \ | ||
160 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
161 | \ | ||
162 | snprintf(buf, PAGE_SIZE - 1, \ | ||
163 | data->model & R##flag##MS_MASK ? "1\n" : "2\n"); \ | ||
164 | return strlen(buf); \ | ||
165 | } | ||
166 | show_type(1); | ||
167 | show_type(2); | ||
168 | |||
169 | #define show_min(flag) \ | ||
170 | static ssize_t show_min##flag(struct device *dev, \ | ||
171 | struct device_attribute *attr, char *buf) \ | ||
172 | { \ | ||
173 | struct i2c_client *client = to_i2c_client(dev); \ | ||
174 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
175 | \ | ||
176 | snprintf(buf, PAGE_SIZE - 1, \ | ||
177 | data->config & R##flag##DF_MASK ? \ | ||
178 | "-127000\n" : "0\n"); \ | ||
179 | return strlen(buf); \ | ||
180 | } | ||
181 | show_min(1); | ||
182 | show_min(2); | ||
183 | |||
184 | #define show_max(flag) \ | ||
185 | static ssize_t show_max##flag(struct device *dev, \ | ||
186 | struct device_attribute *attr, char *buf) \ | ||
187 | { \ | ||
188 | struct i2c_client *client = to_i2c_client(dev); \ | ||
189 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
190 | \ | ||
191 | snprintf(buf, PAGE_SIZE - 1, \ | ||
192 | data->config & R##flag##DF_MASK ? \ | ||
193 | "127000\n" : "255000\n"); \ | ||
194 | return strlen(buf); \ | ||
195 | } | ||
196 | show_max(1); | ||
197 | show_max(2); | ||
198 | |||
199 | #define set_type(flag) \ | ||
200 | static ssize_t set_type##flag(struct device *dev, \ | ||
201 | struct device_attribute *attr, \ | ||
202 | const char *buf, size_t count) \ | ||
203 | { \ | ||
204 | struct i2c_client *client = to_i2c_client(dev); \ | ||
205 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
206 | \ | ||
207 | long val; \ | ||
208 | strict_strtol(buf, 10, &val); \ | ||
209 | \ | ||
210 | if ((val == 1) || (val == 2)) { \ | ||
211 | \ | ||
212 | mutex_lock(&data->update_lock); \ | ||
213 | \ | ||
214 | data->trutherm &= ~(TT_MASK << TT##flag##_SHIFT); \ | ||
215 | if (val == 1) { \ | ||
216 | data->model |= R##flag##MS_MASK; \ | ||
217 | data->trutherm |= (TT_ON << TT##flag##_SHIFT); \ | ||
218 | } \ | ||
219 | else { \ | ||
220 | data->model &= ~R##flag##MS_MASK; \ | ||
221 | data->trutherm |= (TT_OFF << TT##flag##_SHIFT); \ | ||
222 | } \ | ||
223 | \ | ||
224 | data->valid = 0; \ | ||
225 | \ | ||
226 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, \ | ||
227 | data->model); \ | ||
228 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, \ | ||
229 | data->trutherm); \ | ||
230 | \ | ||
231 | mutex_unlock(&data->update_lock); \ | ||
232 | \ | ||
233 | } \ | ||
234 | return count; \ | ||
235 | } | ||
236 | set_type(1); | ||
237 | set_type(2); | ||
238 | |||
239 | #define set_min(flag) \ | ||
240 | static ssize_t set_min##flag(struct device *dev, \ | ||
241 | struct device_attribute *devattr, const char *buf, size_t count) \ | ||
242 | { \ | ||
243 | struct i2c_client *client = to_i2c_client(dev); \ | ||
244 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
245 | \ | ||
246 | long val; \ | ||
247 | strict_strtol(buf, 10, &val); \ | ||
248 | \ | ||
249 | mutex_lock(&data->update_lock); \ | ||
250 | \ | ||
251 | if (val < 0) \ | ||
252 | data->config |= R##flag##DF_MASK; \ | ||
253 | else \ | ||
254 | data->config &= ~R##flag##DF_MASK; \ | ||
255 | \ | ||
256 | data->valid = 0; \ | ||
257 | \ | ||
258 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | ||
259 | data->config); \ | ||
260 | \ | ||
261 | mutex_unlock(&data->update_lock); \ | ||
262 | \ | ||
263 | return count; \ | ||
264 | } | ||
265 | set_min(1); | ||
266 | set_min(2); | ||
267 | |||
268 | #define set_max(flag) \ | ||
269 | static ssize_t set_max##flag(struct device *dev, \ | ||
270 | struct device_attribute *devattr, const char *buf, size_t count) \ | ||
271 | { \ | ||
272 | struct i2c_client *client = to_i2c_client(dev); \ | ||
273 | struct lm95241_data *data = i2c_get_clientdata(client); \ | ||
274 | \ | ||
275 | long val; \ | ||
276 | strict_strtol(buf, 10, &val); \ | ||
277 | \ | ||
278 | mutex_lock(&data->update_lock); \ | ||
279 | \ | ||
280 | if (val <= 127000) \ | ||
281 | data->config |= R##flag##DF_MASK; \ | ||
282 | else \ | ||
283 | data->config &= ~R##flag##DF_MASK; \ | ||
284 | \ | ||
285 | data->valid = 0; \ | ||
286 | \ | ||
287 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, \ | ||
288 | data->config); \ | ||
289 | \ | ||
290 | mutex_unlock(&data->update_lock); \ | ||
291 | \ | ||
292 | return count; \ | ||
293 | } | ||
294 | set_max(1); | ||
295 | set_max(2); | ||
296 | |||
297 | static DEVICE_ATTR(temp1_input, S_IRUGO, show_local, NULL); | ||
298 | static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote1, NULL); | ||
299 | static DEVICE_ATTR(temp3_input, S_IRUGO, show_remote2, NULL); | ||
300 | static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type1, set_type1); | ||
301 | static DEVICE_ATTR(temp3_type, S_IWUSR | S_IRUGO, show_type2, set_type2); | ||
302 | static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min1, set_min1); | ||
303 | static DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min2, set_min2); | ||
304 | static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max1, set_max1); | ||
305 | static DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max2, set_max2); | ||
306 | static DEVICE_ATTR(rate, S_IWUSR | S_IRUGO, show_rate, set_rate); | ||
307 | |||
308 | static struct attribute *lm95241_attributes[] = { | ||
309 | &dev_attr_temp1_input.attr, | ||
310 | &dev_attr_temp2_input.attr, | ||
311 | &dev_attr_temp3_input.attr, | ||
312 | &dev_attr_temp2_type.attr, | ||
313 | &dev_attr_temp3_type.attr, | ||
314 | &dev_attr_temp2_min.attr, | ||
315 | &dev_attr_temp3_min.attr, | ||
316 | &dev_attr_temp2_max.attr, | ||
317 | &dev_attr_temp3_max.attr, | ||
318 | &dev_attr_rate.attr, | ||
319 | NULL | ||
320 | }; | ||
321 | |||
322 | static const struct attribute_group lm95241_group = { | ||
323 | .attrs = lm95241_attributes, | ||
324 | }; | ||
325 | |||
326 | /* Init/exit code */ | ||
327 | static int lm95241_attach_adapter(struct i2c_adapter *adapter) | ||
328 | { | ||
329 | if (!(adapter->class & I2C_CLASS_HWMON)) | ||
330 | return 0; | ||
331 | return i2c_probe(adapter, &addr_data, lm95241_detect); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * The following function does more than just detection. If detection | ||
336 | * succeeds, it also registers the new chip. | ||
337 | */ | ||
338 | static int lm95241_detect(struct i2c_adapter *adapter, int address, int kind) | ||
339 | { | ||
340 | struct i2c_client *new_client; | ||
341 | struct lm95241_data *data; | ||
342 | int err = 0; | ||
343 | const char *name = ""; | ||
344 | |||
345 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
346 | goto exit; | ||
347 | |||
348 | data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL); | ||
349 | if (!data) { | ||
350 | err = -ENOMEM; | ||
351 | goto exit; | ||
352 | } | ||
353 | |||
354 | /* The common I2C client data is placed right before the | ||
355 | LM95241-specific data. */ | ||
356 | new_client = &data->client; | ||
357 | i2c_set_clientdata(new_client, data); | ||
358 | new_client->addr = address; | ||
359 | new_client->adapter = adapter; | ||
360 | new_client->driver = &lm95241_driver; | ||
361 | new_client->flags = 0; | ||
362 | |||
363 | /* | ||
364 | * Now we do the remaining detection. A negative kind means that | ||
365 | * the driver was loaded with no force parameter (default), so we | ||
366 | * must both detect and identify the chip. A zero kind means that | ||
367 | * the driver was loaded with the force parameter, the detection | ||
368 | * step shall be skipped. A positive kind means that the driver | ||
369 | * was loaded with the force parameter and a given kind of chip is | ||
370 | * requested, so both the detection and the identification steps | ||
371 | * are skipped. | ||
372 | */ | ||
373 | if (kind < 0) { /* detection */ | ||
374 | if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) | ||
375 | != MANUFACTURER_ID) | ||
376 | || (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) | ||
377 | < DEFAULT_REVISION)) { | ||
378 | dev_dbg(&adapter->dev, | ||
379 | "LM95241 detection failed at 0x%02x.\n", | ||
380 | address); | ||
381 | goto exit_free; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (kind <= 0) { /* identification */ | ||
386 | if ((i2c_smbus_read_byte_data(new_client, LM95241_REG_R_MAN_ID) | ||
387 | == MANUFACTURER_ID) | ||
388 | && (i2c_smbus_read_byte_data(new_client, LM95241_REG_R_CHIP_ID) | ||
389 | >= DEFAULT_REVISION)) { | ||
390 | |||
391 | kind = lm95241; | ||
392 | |||
393 | if (kind <= 0) { /* identification failed */ | ||
394 | dev_info(&adapter->dev, "Unsupported chip\n"); | ||
395 | goto exit_free; | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | |||
400 | if (kind == lm95241) | ||
401 | name = "lm95241"; | ||
402 | |||
403 | /* We can fill in the remaining client fields */ | ||
404 | strlcpy(new_client->name, name, I2C_NAME_SIZE); | ||
405 | data->valid = 0; | ||
406 | mutex_init(&data->update_lock); | ||
407 | |||
408 | /* Tell the I2C layer a new client has arrived */ | ||
409 | err = i2c_attach_client(new_client); | ||
410 | if (err) | ||
411 | goto exit_free; | ||
412 | |||
413 | /* Initialize the LM95241 chip */ | ||
414 | lm95241_init_client(new_client); | ||
415 | |||
416 | /* Register sysfs hooks */ | ||
417 | err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group); | ||
418 | if (err) | ||
419 | goto exit_detach; | ||
420 | |||
421 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | ||
422 | if (IS_ERR(data->hwmon_dev)) { | ||
423 | err = PTR_ERR(data->hwmon_dev); | ||
424 | goto exit_remove_files; | ||
425 | } | ||
426 | |||
427 | return 0; | ||
428 | |||
429 | exit_remove_files: | ||
430 | sysfs_remove_group(&new_client->dev.kobj, &lm95241_group); | ||
431 | exit_detach: | ||
432 | i2c_detach_client(new_client); | ||
433 | exit_free: | ||
434 | kfree(data); | ||
435 | exit: | ||
436 | return err; | ||
437 | } | ||
438 | |||
439 | static void lm95241_init_client(struct i2c_client *client) | ||
440 | { | ||
441 | struct lm95241_data *data = i2c_get_clientdata(client); | ||
442 | |||
443 | data->rate = HZ; /* 1 sec default */ | ||
444 | data->valid = 0; | ||
445 | data->config = CFG_CR0076; | ||
446 | data->model = 0; | ||
447 | data->trutherm = (TT_OFF << TT1_SHIFT) | (TT_OFF << TT2_SHIFT); | ||
448 | |||
449 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_CONFIG, | ||
450 | data->config); | ||
451 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REM_FILTER, | ||
452 | R1FE_MASK | R2FE_MASK); | ||
453 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_TRUTHERM, | ||
454 | data->trutherm); | ||
455 | i2c_smbus_write_byte_data(client, LM95241_REG_RW_REMOTE_MODEL, | ||
456 | data->model); | ||
457 | } | ||
458 | |||
459 | static int lm95241_detach_client(struct i2c_client *client) | ||
460 | { | ||
461 | struct lm95241_data *data = i2c_get_clientdata(client); | ||
462 | int err; | ||
463 | |||
464 | hwmon_device_unregister(data->hwmon_dev); | ||
465 | sysfs_remove_group(&client->dev.kobj, &lm95241_group); | ||
466 | |||
467 | err = i2c_detach_client(client); | ||
468 | if (err) | ||
469 | return err; | ||
470 | |||
471 | kfree(data); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static struct lm95241_data *lm95241_update_device(struct device *dev) | ||
476 | { | ||
477 | struct i2c_client *client = to_i2c_client(dev); | ||
478 | struct lm95241_data *data = i2c_get_clientdata(client); | ||
479 | |||
480 | mutex_lock(&data->update_lock); | ||
481 | |||
482 | if (time_after(jiffies, data->last_updated + data->rate) || | ||
483 | !data->valid) { | ||
484 | dev_dbg(&client->dev, "Updating lm95241 data.\n"); | ||
485 | data->local_h = | ||
486 | i2c_smbus_read_byte_data(client, | ||
487 | LM95241_REG_R_LOCAL_TEMPH); | ||
488 | data->local_l = | ||
489 | i2c_smbus_read_byte_data(client, | ||
490 | LM95241_REG_R_LOCAL_TEMPL); | ||
491 | data->remote1_h = | ||
492 | i2c_smbus_read_byte_data(client, | ||
493 | LM95241_REG_R_REMOTE1_TEMPH); | ||
494 | data->remote1_l = | ||
495 | i2c_smbus_read_byte_data(client, | ||
496 | LM95241_REG_R_REMOTE1_TEMPL); | ||
497 | data->remote2_h = | ||
498 | i2c_smbus_read_byte_data(client, | ||
499 | LM95241_REG_R_REMOTE2_TEMPH); | ||
500 | data->remote2_l = | ||
501 | i2c_smbus_read_byte_data(client, | ||
502 | LM95241_REG_R_REMOTE2_TEMPL); | ||
503 | data->last_updated = jiffies; | ||
504 | data->valid = 1; | ||
505 | } | ||
506 | |||
507 | mutex_unlock(&data->update_lock); | ||
508 | |||
509 | return data; | ||
510 | } | ||
511 | |||
512 | static int __init sensors_lm95241_init(void) | ||
513 | { | ||
514 | return i2c_add_driver(&lm95241_driver); | ||
515 | } | ||
516 | |||
517 | static void __exit sensors_lm95241_exit(void) | ||
518 | { | ||
519 | i2c_del_driver(&lm95241_driver); | ||
520 | } | ||
521 | |||
522 | MODULE_AUTHOR("Davide Rizzo <elpa-rizzo@gmail.com>"); | ||
523 | MODULE_DESCRIPTION("LM95241 sensor driver"); | ||
524 | MODULE_LICENSE("GPL"); | ||
525 | |||
526 | module_init(sensors_lm95241_init); | ||
527 | module_exit(sensors_lm95241_exit); | ||
diff --git a/drivers/hwmon/ltc4215.c b/drivers/hwmon/ltc4215.c new file mode 100644 index 000000000000..9386e2a39211 --- /dev/null +++ b/drivers/hwmon/ltc4215.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Driver for Linear Technology LTC4215 I2C Hot Swap Controller | ||
3 | * | ||
4 | * Copyright (C) 2009 Ira W. Snyder <iws@ovro.caltech.edu> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * Datasheet: | ||
11 | * http://www.linear.com/pc/downloadDocument.do?navId=H0,C1,C1003,C1006,C1163,P17572,D12697 | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/hwmon.h> | ||
21 | #include <linux/hwmon-sysfs.h> | ||
22 | |||
23 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; | ||
24 | |||
25 | /* Insmod parameters */ | ||
26 | I2C_CLIENT_INSMOD_1(ltc4215); | ||
27 | |||
28 | /* Here are names of the chip's registers (a.k.a. commands) */ | ||
29 | enum ltc4215_cmd { | ||
30 | LTC4215_CONTROL = 0x00, /* rw */ | ||
31 | LTC4215_ALERT = 0x01, /* rw */ | ||
32 | LTC4215_STATUS = 0x02, /* ro */ | ||
33 | LTC4215_FAULT = 0x03, /* rw */ | ||
34 | LTC4215_SENSE = 0x04, /* rw */ | ||
35 | LTC4215_SOURCE = 0x05, /* rw */ | ||
36 | LTC4215_ADIN = 0x06, /* rw */ | ||
37 | }; | ||
38 | |||
39 | struct ltc4215_data { | ||
40 | struct device *hwmon_dev; | ||
41 | |||
42 | struct mutex update_lock; | ||
43 | bool valid; | ||
44 | unsigned long last_updated; /* in jiffies */ | ||
45 | |||
46 | /* Registers */ | ||
47 | u8 regs[7]; | ||
48 | }; | ||
49 | |||
50 | static struct ltc4215_data *ltc4215_update_device(struct device *dev) | ||
51 | { | ||
52 | struct i2c_client *client = to_i2c_client(dev); | ||
53 | struct ltc4215_data *data = i2c_get_clientdata(client); | ||
54 | s32 val; | ||
55 | int i; | ||
56 | |||
57 | mutex_lock(&data->update_lock); | ||
58 | |||
59 | /* The chip's A/D updates 10 times per second */ | ||
60 | if (time_after(jiffies, data->last_updated + HZ / 10) || !data->valid) { | ||
61 | |||
62 | dev_dbg(&client->dev, "Starting ltc4215 update\n"); | ||
63 | |||
64 | /* Read all registers */ | ||
65 | for (i = 0; i < ARRAY_SIZE(data->regs); i++) { | ||
66 | val = i2c_smbus_read_byte_data(client, i); | ||
67 | if (unlikely(val < 0)) | ||
68 | data->regs[i] = 0; | ||
69 | else | ||
70 | data->regs[i] = val; | ||
71 | } | ||
72 | |||
73 | data->last_updated = jiffies; | ||
74 | data->valid = 1; | ||
75 | } | ||
76 | |||
77 | mutex_unlock(&data->update_lock); | ||
78 | |||
79 | return data; | ||
80 | } | ||
81 | |||
82 | /* Return the voltage from the given register in millivolts */ | ||
83 | static int ltc4215_get_voltage(struct device *dev, u8 reg) | ||
84 | { | ||
85 | struct ltc4215_data *data = ltc4215_update_device(dev); | ||
86 | const u8 regval = data->regs[reg]; | ||
87 | u32 voltage = 0; | ||
88 | |||
89 | switch (reg) { | ||
90 | case LTC4215_SENSE: | ||
91 | /* 151 uV per increment */ | ||
92 | voltage = regval * 151 / 1000; | ||
93 | break; | ||
94 | case LTC4215_SOURCE: | ||
95 | /* 60.5 mV per increment */ | ||
96 | voltage = regval * 605 / 10; | ||
97 | break; | ||
98 | case LTC4215_ADIN: | ||
99 | /* The ADIN input is divided by 12.5, and has 4.82 mV | ||
100 | * per increment, so we have the additional multiply */ | ||
101 | voltage = regval * 482 * 125 / 1000; | ||
102 | break; | ||
103 | default: | ||
104 | /* If we get here, the developer messed up */ | ||
105 | WARN_ON_ONCE(1); | ||
106 | break; | ||
107 | } | ||
108 | |||
109 | return voltage; | ||
110 | } | ||
111 | |||
112 | /* Return the current from the sense resistor in mA */ | ||
113 | static unsigned int ltc4215_get_current(struct device *dev) | ||
114 | { | ||
115 | struct ltc4215_data *data = ltc4215_update_device(dev); | ||
116 | |||
117 | /* The strange looking conversions that follow are fixed-point | ||
118 | * math, since we cannot do floating point in the kernel. | ||
119 | * | ||
120 | * Step 1: convert sense register to microVolts | ||
121 | * Step 2: convert voltage to milliAmperes | ||
122 | * | ||
123 | * If you play around with the V=IR equation, you come up with | ||
124 | * the following: X uV / Y mOhm == Z mA | ||
125 | * | ||
126 | * With the resistors that are fractions of a milliOhm, we multiply | ||
127 | * the voltage and resistance by 10, to shift the decimal point. | ||
128 | * Now we can use the normal division operator again. | ||
129 | */ | ||
130 | |||
131 | /* Calculate voltage in microVolts (151 uV per increment) */ | ||
132 | const unsigned int voltage = data->regs[LTC4215_SENSE] * 151; | ||
133 | |||
134 | /* Calculate current in milliAmperes (4 milliOhm sense resistor) */ | ||
135 | const unsigned int curr = voltage / 4; | ||
136 | |||
137 | return curr; | ||
138 | } | ||
139 | |||
140 | static ssize_t ltc4215_show_voltage(struct device *dev, | ||
141 | struct device_attribute *da, | ||
142 | char *buf) | ||
143 | { | ||
144 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
145 | const int voltage = ltc4215_get_voltage(dev, attr->index); | ||
146 | |||
147 | return snprintf(buf, PAGE_SIZE, "%d\n", voltage); | ||
148 | } | ||
149 | |||
150 | static ssize_t ltc4215_show_current(struct device *dev, | ||
151 | struct device_attribute *da, | ||
152 | char *buf) | ||
153 | { | ||
154 | const unsigned int curr = ltc4215_get_current(dev); | ||
155 | |||
156 | return snprintf(buf, PAGE_SIZE, "%u\n", curr); | ||
157 | } | ||
158 | |||
159 | static ssize_t ltc4215_show_power(struct device *dev, | ||
160 | struct device_attribute *da, | ||
161 | char *buf) | ||
162 | { | ||
163 | const unsigned int curr = ltc4215_get_current(dev); | ||
164 | const int output_voltage = ltc4215_get_voltage(dev, LTC4215_ADIN); | ||
165 | |||
166 | /* current in mA * voltage in mV == power in uW */ | ||
167 | const unsigned int power = abs(output_voltage * curr); | ||
168 | |||
169 | return snprintf(buf, PAGE_SIZE, "%u\n", power); | ||
170 | } | ||
171 | |||
172 | static ssize_t ltc4215_show_alarm(struct device *dev, | ||
173 | struct device_attribute *da, | ||
174 | char *buf) | ||
175 | { | ||
176 | struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(da); | ||
177 | struct ltc4215_data *data = ltc4215_update_device(dev); | ||
178 | const u8 reg = data->regs[attr->index]; | ||
179 | const u32 mask = attr->nr; | ||
180 | |||
181 | return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0); | ||
182 | } | ||
183 | |||
184 | /* These macros are used below in constructing device attribute objects | ||
185 | * for use with sysfs_create_group() to make a sysfs device file | ||
186 | * for each register. | ||
187 | */ | ||
188 | |||
189 | #define LTC4215_VOLTAGE(name, ltc4215_cmd_idx) \ | ||
190 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ | ||
191 | ltc4215_show_voltage, NULL, ltc4215_cmd_idx) | ||
192 | |||
193 | #define LTC4215_CURRENT(name) \ | ||
194 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ | ||
195 | ltc4215_show_current, NULL, 0); | ||
196 | |||
197 | #define LTC4215_POWER(name) \ | ||
198 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, \ | ||
199 | ltc4215_show_power, NULL, 0); | ||
200 | |||
201 | #define LTC4215_ALARM(name, mask, reg) \ | ||
202 | static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \ | ||
203 | ltc4215_show_alarm, NULL, (mask), reg) | ||
204 | |||
205 | /* Construct a sensor_device_attribute structure for each register */ | ||
206 | |||
207 | /* Current */ | ||
208 | LTC4215_CURRENT(curr1_input); | ||
209 | LTC4215_ALARM(curr1_max_alarm, (1 << 2), LTC4215_STATUS); | ||
210 | |||
211 | /* Power (virtual) */ | ||
212 | LTC4215_POWER(power1_input); | ||
213 | LTC4215_ALARM(power1_alarm, (1 << 3), LTC4215_STATUS); | ||
214 | |||
215 | /* Input Voltage */ | ||
216 | LTC4215_VOLTAGE(in1_input, LTC4215_ADIN); | ||
217 | LTC4215_ALARM(in1_max_alarm, (1 << 0), LTC4215_STATUS); | ||
218 | LTC4215_ALARM(in1_min_alarm, (1 << 1), LTC4215_STATUS); | ||
219 | |||
220 | /* Output Voltage */ | ||
221 | LTC4215_VOLTAGE(in2_input, LTC4215_SOURCE); | ||
222 | |||
223 | /* Finally, construct an array of pointers to members of the above objects, | ||
224 | * as required for sysfs_create_group() | ||
225 | */ | ||
226 | static struct attribute *ltc4215_attributes[] = { | ||
227 | &sensor_dev_attr_curr1_input.dev_attr.attr, | ||
228 | &sensor_dev_attr_curr1_max_alarm.dev_attr.attr, | ||
229 | |||
230 | &sensor_dev_attr_power1_input.dev_attr.attr, | ||
231 | &sensor_dev_attr_power1_alarm.dev_attr.attr, | ||
232 | |||
233 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
234 | &sensor_dev_attr_in1_max_alarm.dev_attr.attr, | ||
235 | &sensor_dev_attr_in1_min_alarm.dev_attr.attr, | ||
236 | |||
237 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
238 | |||
239 | NULL, | ||
240 | }; | ||
241 | |||
242 | static const struct attribute_group ltc4215_group = { | ||
243 | .attrs = ltc4215_attributes, | ||
244 | }; | ||
245 | |||
246 | static int ltc4215_probe(struct i2c_client *client, | ||
247 | const struct i2c_device_id *id) | ||
248 | { | ||
249 | struct ltc4215_data *data; | ||
250 | int ret; | ||
251 | |||
252 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
253 | if (!data) { | ||
254 | ret = -ENOMEM; | ||
255 | goto out_kzalloc; | ||
256 | } | ||
257 | |||
258 | i2c_set_clientdata(client, data); | ||
259 | mutex_init(&data->update_lock); | ||
260 | |||
261 | /* Initialize the LTC4215 chip */ | ||
262 | /* TODO */ | ||
263 | |||
264 | /* Register sysfs hooks */ | ||
265 | ret = sysfs_create_group(&client->dev.kobj, <c4215_group); | ||
266 | if (ret) | ||
267 | goto out_sysfs_create_group; | ||
268 | |||
269 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
270 | if (IS_ERR(data->hwmon_dev)) { | ||
271 | ret = PTR_ERR(data->hwmon_dev); | ||
272 | goto out_hwmon_device_register; | ||
273 | } | ||
274 | |||
275 | return 0; | ||
276 | |||
277 | out_hwmon_device_register: | ||
278 | sysfs_remove_group(&client->dev.kobj, <c4215_group); | ||
279 | out_sysfs_create_group: | ||
280 | kfree(data); | ||
281 | out_kzalloc: | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | static int ltc4215_remove(struct i2c_client *client) | ||
286 | { | ||
287 | struct ltc4215_data *data = i2c_get_clientdata(client); | ||
288 | |||
289 | hwmon_device_unregister(data->hwmon_dev); | ||
290 | sysfs_remove_group(&client->dev.kobj, <c4215_group); | ||
291 | |||
292 | kfree(data); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int ltc4215_detect(struct i2c_client *client, | ||
298 | int kind, | ||
299 | struct i2c_board_info *info) | ||
300 | { | ||
301 | struct i2c_adapter *adapter = client->adapter; | ||
302 | |||
303 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
304 | return -ENODEV; | ||
305 | |||
306 | if (kind < 0) { /* probed detection - check the chip type */ | ||
307 | s32 v; /* 8 bits from the chip, or -ERRNO */ | ||
308 | |||
309 | /* | ||
310 | * Register 0x01 bit b7 is reserved, expect 0 | ||
311 | * Register 0x03 bit b6 and b7 are reserved, expect 0 | ||
312 | */ | ||
313 | v = i2c_smbus_read_byte_data(client, LTC4215_ALERT); | ||
314 | if (v < 0 || (v & (1 << 7)) != 0) | ||
315 | return -ENODEV; | ||
316 | |||
317 | v = i2c_smbus_read_byte_data(client, LTC4215_FAULT); | ||
318 | if (v < 0 || (v & ((1 << 6) | (1 << 7))) != 0) | ||
319 | return -ENODEV; | ||
320 | } | ||
321 | |||
322 | strlcpy(info->type, "ltc4215", I2C_NAME_SIZE); | ||
323 | dev_info(&adapter->dev, "ltc4215 %s at address 0x%02x\n", | ||
324 | kind < 0 ? "probed" : "forced", | ||
325 | client->addr); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static const struct i2c_device_id ltc4215_id[] = { | ||
331 | { "ltc4215", ltc4215 }, | ||
332 | { } | ||
333 | }; | ||
334 | MODULE_DEVICE_TABLE(i2c, ltc4215_id); | ||
335 | |||
336 | /* This is the driver that will be inserted */ | ||
337 | static struct i2c_driver ltc4215_driver = { | ||
338 | .class = I2C_CLASS_HWMON, | ||
339 | .driver = { | ||
340 | .name = "ltc4215", | ||
341 | }, | ||
342 | .probe = ltc4215_probe, | ||
343 | .remove = ltc4215_remove, | ||
344 | .id_table = ltc4215_id, | ||
345 | .detect = ltc4215_detect, | ||
346 | .address_data = &addr_data, | ||
347 | }; | ||
348 | |||
349 | static int __init ltc4215_init(void) | ||
350 | { | ||
351 | return i2c_add_driver(<c4215_driver); | ||
352 | } | ||
353 | |||
354 | static void __exit ltc4215_exit(void) | ||
355 | { | ||
356 | i2c_del_driver(<c4215_driver); | ||
357 | } | ||
358 | |||
359 | MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); | ||
360 | MODULE_DESCRIPTION("LTC4215 driver"); | ||
361 | MODULE_LICENSE("GPL"); | ||
362 | |||
363 | module_init(ltc4215_init); | ||
364 | module_exit(ltc4215_exit); | ||
diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c new file mode 100644 index 000000000000..1d7ffebd679d --- /dev/null +++ b/drivers/hwmon/pcf8591.c | |||
@@ -0,0 +1,325 @@ | |||
1 | /* | ||
2 | Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> | ||
3 | Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with | ||
4 | the help of Jean Delvare <khali@linux-fr.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/mutex.h> | ||
26 | |||
27 | /* Addresses to scan */ | ||
28 | static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c, | ||
29 | 0x4d, 0x4e, 0x4f, I2C_CLIENT_END }; | ||
30 | |||
31 | /* Insmod parameters */ | ||
32 | I2C_CLIENT_INSMOD_1(pcf8591); | ||
33 | |||
34 | static int input_mode; | ||
35 | module_param(input_mode, int, 0); | ||
36 | MODULE_PARM_DESC(input_mode, | ||
37 | "Analog input mode:\n" | ||
38 | " 0 = four single ended inputs\n" | ||
39 | " 1 = three differential inputs\n" | ||
40 | " 2 = single ended and differential mixed\n" | ||
41 | " 3 = two differential inputs\n"); | ||
42 | |||
43 | /* The PCF8591 control byte | ||
44 | 7 6 5 4 3 2 1 0 | ||
45 | | 0 |AOEF| AIP | 0 |AINC| AICH | */ | ||
46 | |||
47 | /* Analog Output Enable Flag (analog output active if 1) */ | ||
48 | #define PCF8591_CONTROL_AOEF 0x40 | ||
49 | |||
50 | /* Analog Input Programming | ||
51 | 0x00 = four single ended inputs | ||
52 | 0x10 = three differential inputs | ||
53 | 0x20 = single ended and differential mixed | ||
54 | 0x30 = two differential inputs */ | ||
55 | #define PCF8591_CONTROL_AIP_MASK 0x30 | ||
56 | |||
57 | /* Autoincrement Flag (switch on if 1) */ | ||
58 | #define PCF8591_CONTROL_AINC 0x04 | ||
59 | |||
60 | /* Channel selection | ||
61 | 0x00 = channel 0 | ||
62 | 0x01 = channel 1 | ||
63 | 0x02 = channel 2 | ||
64 | 0x03 = channel 3 */ | ||
65 | #define PCF8591_CONTROL_AICH_MASK 0x03 | ||
66 | |||
67 | /* Initial values */ | ||
68 | #define PCF8591_INIT_CONTROL ((input_mode << 4) | PCF8591_CONTROL_AOEF) | ||
69 | #define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ | ||
70 | |||
71 | /* Conversions */ | ||
72 | #define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg)) | ||
73 | |||
74 | struct pcf8591_data { | ||
75 | struct mutex update_lock; | ||
76 | |||
77 | u8 control; | ||
78 | u8 aout; | ||
79 | }; | ||
80 | |||
81 | static void pcf8591_init_client(struct i2c_client *client); | ||
82 | static int pcf8591_read_channel(struct device *dev, int channel); | ||
83 | |||
84 | /* following are the sysfs callback functions */ | ||
85 | #define show_in_channel(channel) \ | ||
86 | static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \ | ||
87 | { \ | ||
88 | return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ | ||
89 | } \ | ||
90 | static DEVICE_ATTR(in##channel##_input, S_IRUGO, \ | ||
91 | show_in##channel##_input, NULL); | ||
92 | |||
93 | show_in_channel(0); | ||
94 | show_in_channel(1); | ||
95 | show_in_channel(2); | ||
96 | show_in_channel(3); | ||
97 | |||
98 | static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) | ||
99 | { | ||
100 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | ||
101 | return sprintf(buf, "%d\n", data->aout * 10); | ||
102 | } | ||
103 | |||
104 | static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
105 | { | ||
106 | unsigned int value; | ||
107 | struct i2c_client *client = to_i2c_client(dev); | ||
108 | struct pcf8591_data *data = i2c_get_clientdata(client); | ||
109 | if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { | ||
110 | data->aout = value; | ||
111 | i2c_smbus_write_byte_data(client, data->control, data->aout); | ||
112 | return count; | ||
113 | } | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, | ||
118 | show_out0_ouput, set_out0_output); | ||
119 | |||
120 | static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) | ||
121 | { | ||
122 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | ||
123 | return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); | ||
124 | } | ||
125 | |||
126 | static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
127 | { | ||
128 | struct i2c_client *client = to_i2c_client(dev); | ||
129 | struct pcf8591_data *data = i2c_get_clientdata(client); | ||
130 | unsigned long val = simple_strtoul(buf, NULL, 10); | ||
131 | |||
132 | mutex_lock(&data->update_lock); | ||
133 | if (val) | ||
134 | data->control |= PCF8591_CONTROL_AOEF; | ||
135 | else | ||
136 | data->control &= ~PCF8591_CONTROL_AOEF; | ||
137 | i2c_smbus_write_byte(client, data->control); | ||
138 | mutex_unlock(&data->update_lock); | ||
139 | return count; | ||
140 | } | ||
141 | |||
142 | static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, | ||
143 | show_out0_enable, set_out0_enable); | ||
144 | |||
145 | static struct attribute *pcf8591_attributes[] = { | ||
146 | &dev_attr_out0_enable.attr, | ||
147 | &dev_attr_out0_output.attr, | ||
148 | &dev_attr_in0_input.attr, | ||
149 | &dev_attr_in1_input.attr, | ||
150 | NULL | ||
151 | }; | ||
152 | |||
153 | static const struct attribute_group pcf8591_attr_group = { | ||
154 | .attrs = pcf8591_attributes, | ||
155 | }; | ||
156 | |||
157 | static struct attribute *pcf8591_attributes_opt[] = { | ||
158 | &dev_attr_in2_input.attr, | ||
159 | &dev_attr_in3_input.attr, | ||
160 | NULL | ||
161 | }; | ||
162 | |||
163 | static const struct attribute_group pcf8591_attr_group_opt = { | ||
164 | .attrs = pcf8591_attributes_opt, | ||
165 | }; | ||
166 | |||
167 | /* | ||
168 | * Real code | ||
169 | */ | ||
170 | |||
171 | /* Return 0 if detection is successful, -ENODEV otherwise */ | ||
172 | static int pcf8591_detect(struct i2c_client *client, int kind, | ||
173 | struct i2c_board_info *info) | ||
174 | { | ||
175 | struct i2c_adapter *adapter = client->adapter; | ||
176 | |||
177 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE | ||
178 | | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | ||
179 | return -ENODEV; | ||
180 | |||
181 | /* Now, we would do the remaining detection. But the PCF8591 is plainly | ||
182 | impossible to detect! Stupid chip. */ | ||
183 | |||
184 | strlcpy(info->type, "pcf8591", I2C_NAME_SIZE); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int pcf8591_probe(struct i2c_client *client, | ||
190 | const struct i2c_device_id *id) | ||
191 | { | ||
192 | struct pcf8591_data *data; | ||
193 | int err; | ||
194 | |||
195 | if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { | ||
196 | err = -ENOMEM; | ||
197 | goto exit; | ||
198 | } | ||
199 | |||
200 | i2c_set_clientdata(client, data); | ||
201 | mutex_init(&data->update_lock); | ||
202 | |||
203 | /* Initialize the PCF8591 chip */ | ||
204 | pcf8591_init_client(client); | ||
205 | |||
206 | /* Register sysfs hooks */ | ||
207 | err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); | ||
208 | if (err) | ||
209 | goto exit_kfree; | ||
210 | |||
211 | /* Register input2 if not in "two differential inputs" mode */ | ||
212 | if (input_mode != 3) { | ||
213 | if ((err = device_create_file(&client->dev, | ||
214 | &dev_attr_in2_input))) | ||
215 | goto exit_sysfs_remove; | ||
216 | } | ||
217 | |||
218 | /* Register input3 only in "four single ended inputs" mode */ | ||
219 | if (input_mode == 0) { | ||
220 | if ((err = device_create_file(&client->dev, | ||
221 | &dev_attr_in3_input))) | ||
222 | goto exit_sysfs_remove; | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | |||
227 | exit_sysfs_remove: | ||
228 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | ||
229 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | ||
230 | exit_kfree: | ||
231 | kfree(data); | ||
232 | exit: | ||
233 | return err; | ||
234 | } | ||
235 | |||
236 | static int pcf8591_remove(struct i2c_client *client) | ||
237 | { | ||
238 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | ||
239 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | ||
240 | kfree(i2c_get_clientdata(client)); | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | /* Called when we have found a new PCF8591. */ | ||
245 | static void pcf8591_init_client(struct i2c_client *client) | ||
246 | { | ||
247 | struct pcf8591_data *data = i2c_get_clientdata(client); | ||
248 | data->control = PCF8591_INIT_CONTROL; | ||
249 | data->aout = PCF8591_INIT_AOUT; | ||
250 | |||
251 | i2c_smbus_write_byte_data(client, data->control, data->aout); | ||
252 | |||
253 | /* The first byte transmitted contains the conversion code of the | ||
254 | previous read cycle. FLUSH IT! */ | ||
255 | i2c_smbus_read_byte(client); | ||
256 | } | ||
257 | |||
258 | static int pcf8591_read_channel(struct device *dev, int channel) | ||
259 | { | ||
260 | u8 value; | ||
261 | struct i2c_client *client = to_i2c_client(dev); | ||
262 | struct pcf8591_data *data = i2c_get_clientdata(client); | ||
263 | |||
264 | mutex_lock(&data->update_lock); | ||
265 | |||
266 | if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) { | ||
267 | data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) | ||
268 | | channel; | ||
269 | i2c_smbus_write_byte(client, data->control); | ||
270 | |||
271 | /* The first byte transmitted contains the conversion code of | ||
272 | the previous read cycle. FLUSH IT! */ | ||
273 | i2c_smbus_read_byte(client); | ||
274 | } | ||
275 | value = i2c_smbus_read_byte(client); | ||
276 | |||
277 | mutex_unlock(&data->update_lock); | ||
278 | |||
279 | if ((channel == 2 && input_mode == 2) || | ||
280 | (channel != 3 && (input_mode == 1 || input_mode == 3))) | ||
281 | return (10 * REG_TO_SIGNED(value)); | ||
282 | else | ||
283 | return (10 * value); | ||
284 | } | ||
285 | |||
286 | static const struct i2c_device_id pcf8591_id[] = { | ||
287 | { "pcf8591", 0 }, | ||
288 | { } | ||
289 | }; | ||
290 | MODULE_DEVICE_TABLE(i2c, pcf8591_id); | ||
291 | |||
292 | static struct i2c_driver pcf8591_driver = { | ||
293 | .driver = { | ||
294 | .name = "pcf8591", | ||
295 | }, | ||
296 | .probe = pcf8591_probe, | ||
297 | .remove = pcf8591_remove, | ||
298 | .id_table = pcf8591_id, | ||
299 | |||
300 | .class = I2C_CLASS_HWMON, /* Nearest choice */ | ||
301 | .detect = pcf8591_detect, | ||
302 | .address_data = &addr_data, | ||
303 | }; | ||
304 | |||
305 | static int __init pcf8591_init(void) | ||
306 | { | ||
307 | if (input_mode < 0 || input_mode > 3) { | ||
308 | printk(KERN_WARNING "pcf8591: invalid input_mode (%d)\n", | ||
309 | input_mode); | ||
310 | input_mode = 0; | ||
311 | } | ||
312 | return i2c_add_driver(&pcf8591_driver); | ||
313 | } | ||
314 | |||
315 | static void __exit pcf8591_exit(void) | ||
316 | { | ||
317 | i2c_del_driver(&pcf8591_driver); | ||
318 | } | ||
319 | |||
320 | MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>"); | ||
321 | MODULE_DESCRIPTION("PCF8591 driver"); | ||
322 | MODULE_LICENSE("GPL"); | ||
323 | |||
324 | module_init(pcf8591_init); | ||
325 | module_exit(pcf8591_exit); | ||
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index feae743ba991..e64b42058b21 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -36,6 +36,7 @@ | |||
36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 | 36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 |
37 | 0x8860 0xa1 | 37 | 0x8860 0xa1 |
38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 | 38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 |
39 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 | ||
39 | */ | 40 | */ |
40 | 41 | ||
41 | #include <linux/module.h> | 42 | #include <linux/module.h> |
@@ -52,12 +53,13 @@ | |||
52 | #include <asm/io.h> | 53 | #include <asm/io.h> |
53 | #include "lm75.h" | 54 | #include "lm75.h" |
54 | 55 | ||
55 | enum kinds { w83627ehf, w83627dhg }; | 56 | enum kinds { w83627ehf, w83627dhg, w83667hg }; |
56 | 57 | ||
57 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ | 58 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ |
58 | static const char * w83627ehf_device_names[] = { | 59 | static const char * w83627ehf_device_names[] = { |
59 | "w83627ehf", | 60 | "w83627ehf", |
60 | "w83627dhg", | 61 | "w83627dhg", |
62 | "w83667hg", | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | static unsigned short force_id; | 65 | static unsigned short force_id; |
@@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
71 | */ | 73 | */ |
72 | 74 | ||
73 | #define W83627EHF_LD_HWM 0x0b | 75 | #define W83627EHF_LD_HWM 0x0b |
76 | #define W83667HG_LD_VID 0x0d | ||
74 | 77 | ||
75 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ | 78 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ |
76 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | 79 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ |
@@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
83 | #define SIO_W83627EHF_ID 0x8850 | 86 | #define SIO_W83627EHF_ID 0x8850 |
84 | #define SIO_W83627EHG_ID 0x8860 | 87 | #define SIO_W83627EHG_ID 0x8860 |
85 | #define SIO_W83627DHG_ID 0xa020 | 88 | #define SIO_W83627DHG_ID 0xa020 |
89 | #define SIO_W83667HG_ID 0xa510 | ||
86 | #define SIO_ID_MASK 0xFFF0 | 90 | #define SIO_ID_MASK 0xFFF0 |
87 | 91 | ||
88 | static inline void | 92 | static inline void |
@@ -289,6 +293,7 @@ struct w83627ehf_data { | |||
289 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | 293 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ |
290 | u8 pwm_enable[4]; /* 1->manual | 294 | u8 pwm_enable[4]; /* 1->manual |
291 | 2->thermal cruise (also called SmartFan I) */ | 295 | 2->thermal cruise (also called SmartFan I) */ |
296 | u8 pwm_num; /* number of pwm */ | ||
292 | u8 pwm[4]; | 297 | u8 pwm[4]; |
293 | u8 target_temp[4]; | 298 | u8 target_temp[4]; |
294 | u8 tolerance[4]; | 299 | u8 tolerance[4]; |
@@ -298,6 +303,9 @@ struct w83627ehf_data { | |||
298 | 303 | ||
299 | u8 vid; | 304 | u8 vid; |
300 | u8 vrm; | 305 | u8 vrm; |
306 | |||
307 | u8 temp3_disable; | ||
308 | u8 in6_skip; | ||
301 | }; | 309 | }; |
302 | 310 | ||
303 | struct w83627ehf_sio_data { | 311 | struct w83627ehf_sio_data { |
@@ -866,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) | |||
866 | return sprintf(buf, "%d\n", (int)data->temp_type[nr]); | 874 | return sprintf(buf, "%d\n", (int)data->temp_type[nr]); |
867 | } | 875 | } |
868 | 876 | ||
869 | static struct sensor_device_attribute sda_temp[] = { | 877 | static struct sensor_device_attribute sda_temp_input[] = { |
870 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), | 878 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), |
871 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), | 879 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), |
872 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), | 880 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), |
881 | }; | ||
882 | |||
883 | static struct sensor_device_attribute sda_temp_max[] = { | ||
873 | SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, | 884 | SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, |
874 | store_temp1_max, 0), | 885 | store_temp1_max, 0), |
875 | SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, | 886 | SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, |
876 | store_temp_max, 0), | 887 | store_temp_max, 0), |
877 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, | 888 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, |
878 | store_temp_max, 1), | 889 | store_temp_max, 1), |
890 | }; | ||
891 | |||
892 | static struct sensor_device_attribute sda_temp_max_hyst[] = { | ||
879 | SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, | 893 | SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, |
880 | store_temp1_max_hyst, 0), | 894 | store_temp1_max_hyst, 0), |
881 | SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 895 | SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
882 | store_temp_max_hyst, 0), | 896 | store_temp_max_hyst, 0), |
883 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 897 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
884 | store_temp_max_hyst, 1), | 898 | store_temp_max_hyst, 1), |
899 | }; | ||
900 | |||
901 | static struct sensor_device_attribute sda_temp_alarm[] = { | ||
885 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), | 902 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), |
886 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), | 903 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), |
887 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), | 904 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), |
905 | }; | ||
906 | |||
907 | static struct sensor_device_attribute sda_temp_type[] = { | ||
888 | SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), | 908 | SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), |
889 | SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), | 909 | SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), |
890 | SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), | 910 | SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), |
@@ -1181,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1181 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) | 1201 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) |
1182 | device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); | 1202 | device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); |
1183 | for (i = 0; i < data->in_num; i++) { | 1203 | for (i = 0; i < data->in_num; i++) { |
1204 | if ((i == 6) && data->in6_skip) | ||
1205 | continue; | ||
1184 | device_remove_file(dev, &sda_in_input[i].dev_attr); | 1206 | device_remove_file(dev, &sda_in_input[i].dev_attr); |
1185 | device_remove_file(dev, &sda_in_alarm[i].dev_attr); | 1207 | device_remove_file(dev, &sda_in_alarm[i].dev_attr); |
1186 | device_remove_file(dev, &sda_in_min[i].dev_attr); | 1208 | device_remove_file(dev, &sda_in_min[i].dev_attr); |
@@ -1192,15 +1214,22 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1192 | device_remove_file(dev, &sda_fan_div[i].dev_attr); | 1214 | device_remove_file(dev, &sda_fan_div[i].dev_attr); |
1193 | device_remove_file(dev, &sda_fan_min[i].dev_attr); | 1215 | device_remove_file(dev, &sda_fan_min[i].dev_attr); |
1194 | } | 1216 | } |
1195 | for (i = 0; i < 4; i++) { | 1217 | for (i = 0; i < data->pwm_num; i++) { |
1196 | device_remove_file(dev, &sda_pwm[i].dev_attr); | 1218 | device_remove_file(dev, &sda_pwm[i].dev_attr); |
1197 | device_remove_file(dev, &sda_pwm_mode[i].dev_attr); | 1219 | device_remove_file(dev, &sda_pwm_mode[i].dev_attr); |
1198 | device_remove_file(dev, &sda_pwm_enable[i].dev_attr); | 1220 | device_remove_file(dev, &sda_pwm_enable[i].dev_attr); |
1199 | device_remove_file(dev, &sda_target_temp[i].dev_attr); | 1221 | device_remove_file(dev, &sda_target_temp[i].dev_attr); |
1200 | device_remove_file(dev, &sda_tolerance[i].dev_attr); | 1222 | device_remove_file(dev, &sda_tolerance[i].dev_attr); |
1201 | } | 1223 | } |
1202 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) | 1224 | for (i = 0; i < 3; i++) { |
1203 | device_remove_file(dev, &sda_temp[i].dev_attr); | 1225 | if ((i == 2) && data->temp3_disable) |
1226 | continue; | ||
1227 | device_remove_file(dev, &sda_temp_input[i].dev_attr); | ||
1228 | device_remove_file(dev, &sda_temp_max[i].dev_attr); | ||
1229 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); | ||
1230 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); | ||
1231 | device_remove_file(dev, &sda_temp_type[i].dev_attr); | ||
1232 | } | ||
1204 | 1233 | ||
1205 | device_remove_file(dev, &dev_attr_name); | 1234 | device_remove_file(dev, &dev_attr_name); |
1206 | device_remove_file(dev, &dev_attr_cpu0_vid); | 1235 | device_remove_file(dev, &dev_attr_cpu0_vid); |
@@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) | |||
1222 | for (i = 0; i < 2; i++) { | 1251 | for (i = 0; i < 2; i++) { |
1223 | tmp = w83627ehf_read_value(data, | 1252 | tmp = w83627ehf_read_value(data, |
1224 | W83627EHF_REG_TEMP_CONFIG[i]); | 1253 | W83627EHF_REG_TEMP_CONFIG[i]); |
1254 | if ((i == 1) && data->temp3_disable) | ||
1255 | continue; | ||
1225 | if (tmp & 0x01) | 1256 | if (tmp & 0x01) |
1226 | w83627ehf_write_value(data, | 1257 | w83627ehf_write_value(data, |
1227 | W83627EHF_REG_TEMP_CONFIG[i], | 1258 | W83627EHF_REG_TEMP_CONFIG[i], |
@@ -1272,8 +1303,17 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1272 | data->name = w83627ehf_device_names[sio_data->kind]; | 1303 | data->name = w83627ehf_device_names[sio_data->kind]; |
1273 | platform_set_drvdata(pdev, data); | 1304 | platform_set_drvdata(pdev, data); |
1274 | 1305 | ||
1275 | /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */ | 1306 | /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ |
1276 | data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10; | 1307 | data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; |
1308 | /* 667HG has 3 pwms */ | ||
1309 | data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4; | ||
1310 | |||
1311 | /* Check temp3 configuration bit for 667HG */ | ||
1312 | if (sio_data->kind == w83667hg) { | ||
1313 | data->temp3_disable = w83627ehf_read_value(data, | ||
1314 | W83627EHF_REG_TEMP_CONFIG[1]) & 0x01; | ||
1315 | data->in6_skip = !data->temp3_disable; | ||
1316 | } | ||
1277 | 1317 | ||
1278 | /* Initialize the chip */ | 1318 | /* Initialize the chip */ |
1279 | w83627ehf_init_device(data); | 1319 | w83627ehf_init_device(data); |
@@ -1281,44 +1321,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1281 | data->vrm = vid_which_vrm(); | 1321 | data->vrm = vid_which_vrm(); |
1282 | superio_enter(sio_data->sioreg); | 1322 | superio_enter(sio_data->sioreg); |
1283 | /* Read VID value */ | 1323 | /* Read VID value */ |
1284 | superio_select(sio_data->sioreg, W83627EHF_LD_HWM); | 1324 | if (sio_data->kind == w83667hg) { |
1285 | if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { | 1325 | /* W83667HG has different pins for VID input and output, so |
1286 | /* Set VID input sensibility if needed. In theory the BIOS | 1326 | we can get the VID input values directly at logical device D |
1287 | should have set it, but in practice it's not always the | 1327 | 0xe3. */ |
1288 | case. We only do it for the W83627EHF/EHG because the | 1328 | superio_select(sio_data->sioreg, W83667HG_LD_VID); |
1289 | W83627DHG is more complex in this respect. */ | 1329 | data->vid = superio_inb(sio_data->sioreg, 0xe3); |
1290 | if (sio_data->kind == w83627ehf) { | ||
1291 | en_vrm10 = superio_inb(sio_data->sioreg, | ||
1292 | SIO_REG_EN_VRM10); | ||
1293 | if ((en_vrm10 & 0x08) && data->vrm == 90) { | ||
1294 | dev_warn(dev, "Setting VID input voltage to " | ||
1295 | "TTL\n"); | ||
1296 | superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, | ||
1297 | en_vrm10 & ~0x08); | ||
1298 | } else if (!(en_vrm10 & 0x08) && data->vrm == 100) { | ||
1299 | dev_warn(dev, "Setting VID input voltage to " | ||
1300 | "VRM10\n"); | ||
1301 | superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, | ||
1302 | en_vrm10 | 0x08); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA); | ||
1307 | if (sio_data->kind == w83627ehf) /* 6 VID pins only */ | ||
1308 | data->vid &= 0x3f; | ||
1309 | |||
1310 | err = device_create_file(dev, &dev_attr_cpu0_vid); | 1330 | err = device_create_file(dev, &dev_attr_cpu0_vid); |
1311 | if (err) | 1331 | if (err) |
1312 | goto exit_release; | 1332 | goto exit_release; |
1313 | } else { | 1333 | } else { |
1314 | dev_info(dev, "VID pins in output mode, CPU VID not " | 1334 | superio_select(sio_data->sioreg, W83627EHF_LD_HWM); |
1315 | "available\n"); | 1335 | if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { |
1336 | /* Set VID input sensibility if needed. In theory the | ||
1337 | BIOS should have set it, but in practice it's not | ||
1338 | always the case. We only do it for the W83627EHF/EHG | ||
1339 | because the W83627DHG is more complex in this | ||
1340 | respect. */ | ||
1341 | if (sio_data->kind == w83627ehf) { | ||
1342 | en_vrm10 = superio_inb(sio_data->sioreg, | ||
1343 | SIO_REG_EN_VRM10); | ||
1344 | if ((en_vrm10 & 0x08) && data->vrm == 90) { | ||
1345 | dev_warn(dev, "Setting VID input " | ||
1346 | "voltage to TTL\n"); | ||
1347 | superio_outb(sio_data->sioreg, | ||
1348 | SIO_REG_EN_VRM10, | ||
1349 | en_vrm10 & ~0x08); | ||
1350 | } else if (!(en_vrm10 & 0x08) | ||
1351 | && data->vrm == 100) { | ||
1352 | dev_warn(dev, "Setting VID input " | ||
1353 | "voltage to VRM10\n"); | ||
1354 | superio_outb(sio_data->sioreg, | ||
1355 | SIO_REG_EN_VRM10, | ||
1356 | en_vrm10 | 0x08); | ||
1357 | } | ||
1358 | } | ||
1359 | |||
1360 | data->vid = superio_inb(sio_data->sioreg, | ||
1361 | SIO_REG_VID_DATA); | ||
1362 | if (sio_data->kind == w83627ehf) /* 6 VID pins only */ | ||
1363 | data->vid &= 0x3f; | ||
1364 | |||
1365 | err = device_create_file(dev, &dev_attr_cpu0_vid); | ||
1366 | if (err) | ||
1367 | goto exit_release; | ||
1368 | } else { | ||
1369 | dev_info(dev, "VID pins in output mode, CPU VID not " | ||
1370 | "available\n"); | ||
1371 | } | ||
1316 | } | 1372 | } |
1317 | 1373 | ||
1318 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | 1374 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ |
1319 | 1375 | if (sio_data->kind == w83667hg) { | |
1320 | fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2; | 1376 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; |
1321 | fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6; | 1377 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; |
1378 | } else { | ||
1379 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | ||
1380 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); | ||
1381 | } | ||
1322 | superio_exit(sio_data->sioreg); | 1382 | superio_exit(sio_data->sioreg); |
1323 | 1383 | ||
1324 | /* It looks like fan4 and fan5 pins can be alternatively used | 1384 | /* It looks like fan4 and fan5 pins can be alternatively used |
@@ -1329,9 +1389,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1329 | 1389 | ||
1330 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ | 1390 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ |
1331 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | 1391 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); |
1332 | if ((i & (1 << 2)) && (!fan4pin)) | 1392 | if ((i & (1 << 2)) && fan4pin) |
1333 | data->has_fan |= (1 << 3); | 1393 | data->has_fan |= (1 << 3); |
1334 | if (!(i & (1 << 1)) && (!fan5pin)) | 1394 | if (!(i & (1 << 1)) && fan5pin) |
1335 | data->has_fan |= (1 << 4); | 1395 | data->has_fan |= (1 << 4); |
1336 | 1396 | ||
1337 | /* Read fan clock dividers immediately */ | 1397 | /* Read fan clock dividers immediately */ |
@@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1344 | goto exit_remove; | 1404 | goto exit_remove; |
1345 | 1405 | ||
1346 | /* if fan4 is enabled create the sf3 files for it */ | 1406 | /* if fan4 is enabled create the sf3 files for it */ |
1347 | if (data->has_fan & (1 << 3)) | 1407 | if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) |
1348 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { | 1408 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { |
1349 | if ((err = device_create_file(dev, | 1409 | if ((err = device_create_file(dev, |
1350 | &sda_sf3_arrays_fan4[i].dev_attr))) | 1410 | &sda_sf3_arrays_fan4[i].dev_attr))) |
1351 | goto exit_remove; | 1411 | goto exit_remove; |
1352 | } | 1412 | } |
1353 | 1413 | ||
1354 | for (i = 0; i < data->in_num; i++) | 1414 | for (i = 0; i < data->in_num; i++) { |
1415 | if ((i == 6) && data->in6_skip) | ||
1416 | continue; | ||
1355 | if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) | 1417 | if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) |
1356 | || (err = device_create_file(dev, | 1418 | || (err = device_create_file(dev, |
1357 | &sda_in_alarm[i].dev_attr)) | 1419 | &sda_in_alarm[i].dev_attr)) |
@@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1360 | || (err = device_create_file(dev, | 1422 | || (err = device_create_file(dev, |
1361 | &sda_in_max[i].dev_attr))) | 1423 | &sda_in_max[i].dev_attr))) |
1362 | goto exit_remove; | 1424 | goto exit_remove; |
1425 | } | ||
1363 | 1426 | ||
1364 | for (i = 0; i < 5; i++) { | 1427 | for (i = 0; i < 5; i++) { |
1365 | if (data->has_fan & (1 << i)) { | 1428 | if (data->has_fan & (1 << i)) { |
@@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1372 | || (err = device_create_file(dev, | 1435 | || (err = device_create_file(dev, |
1373 | &sda_fan_min[i].dev_attr))) | 1436 | &sda_fan_min[i].dev_attr))) |
1374 | goto exit_remove; | 1437 | goto exit_remove; |
1375 | if (i < 4 && /* w83627ehf only has 4 pwm */ | 1438 | if (i < data->pwm_num && |
1376 | ((err = device_create_file(dev, | 1439 | ((err = device_create_file(dev, |
1377 | &sda_pwm[i].dev_attr)) | 1440 | &sda_pwm[i].dev_attr)) |
1378 | || (err = device_create_file(dev, | 1441 | || (err = device_create_file(dev, |
@@ -1387,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1387 | } | 1450 | } |
1388 | } | 1451 | } |
1389 | 1452 | ||
1390 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) | 1453 | for (i = 0; i < 3; i++) { |
1391 | if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) | 1454 | if ((i == 2) && data->temp3_disable) |
1455 | continue; | ||
1456 | if ((err = device_create_file(dev, | ||
1457 | &sda_temp_input[i].dev_attr)) | ||
1458 | || (err = device_create_file(dev, | ||
1459 | &sda_temp_max[i].dev_attr)) | ||
1460 | || (err = device_create_file(dev, | ||
1461 | &sda_temp_max_hyst[i].dev_attr)) | ||
1462 | || (err = device_create_file(dev, | ||
1463 | &sda_temp_alarm[i].dev_attr)) | ||
1464 | || (err = device_create_file(dev, | ||
1465 | &sda_temp_type[i].dev_attr))) | ||
1392 | goto exit_remove; | 1466 | goto exit_remove; |
1467 | } | ||
1393 | 1468 | ||
1394 | err = device_create_file(dev, &dev_attr_name); | 1469 | err = device_create_file(dev, &dev_attr_name); |
1395 | if (err) | 1470 | if (err) |
@@ -1442,6 +1517,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1442 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; | 1517 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; |
1443 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; | 1518 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; |
1444 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; | 1519 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; |
1520 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; | ||
1445 | 1521 | ||
1446 | u16 val; | 1522 | u16 val; |
1447 | const char *sio_name; | 1523 | const char *sio_name; |
@@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1466 | sio_data->kind = w83627dhg; | 1542 | sio_data->kind = w83627dhg; |
1467 | sio_name = sio_name_W83627DHG; | 1543 | sio_name = sio_name_W83627DHG; |
1468 | break; | 1544 | break; |
1545 | case SIO_W83667HG_ID: | ||
1546 | sio_data->kind = w83667hg; | ||
1547 | sio_name = sio_name_W83667HG; | ||
1548 | break; | ||
1469 | default: | 1549 | default: |
1470 | if (val != 0xffff) | 1550 | if (val != 0xffff) |
1471 | pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", | 1551 | pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", |