dect
/
linux-2.6
Archived
13
0
Fork 0

Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon: (ads1015) Make gain and datarate configurable
  hwmon: (ads1015) Drop dynamic attribute group
  hwmon: Add support for Texas Instruments ADS1015
  hwmon: New driver for SMSC SCH5627
  hwmon: (abituguru*) Update my email address
  hwmon: (lm75) Speed up detection
  hwmon: (lm75) Add detection of the National Semiconductor LM75A
  hp_accel: Fix driver name
  Move lis3lv02d drivers to drivers/misc
  Move hp_accel to drivers/platform/x86
  Let Kconfig handle lis3lv02d dependencies
  hwmon: (sht15) Fix integer overflow in humidity calculation
  hwmon: (sht15) Spelling fix
  hwmon: (w83795) Document pin mapping
This commit is contained in:
Linus Torvalds 2011-03-21 14:02:55 -07:00
commit afd8c40431
28 changed files with 1704 additions and 110 deletions

View File

@ -0,0 +1,73 @@
ADS1015 (I2C)
This device is a 12-bit A-D converter with 4 inputs.
The inputs can be used single ended or in certain differential combinations.
For configuration all possible combinations are mapped to 8 channels:
0: Voltage over AIN0 and AIN1.
1: Voltage over AIN0 and AIN3.
2: Voltage over AIN1 and AIN3.
3: Voltage over AIN2 and AIN3.
4: Voltage over AIN0 and GND.
5: Voltage over AIN1 and GND.
6: Voltage over AIN2 and GND.
7: Voltage over AIN3 and GND.
Each channel can be configured individually:
- pga is the programmable gain amplifier (values are full scale)
0: +/- 6.144 V
1: +/- 4.096 V
2: +/- 2.048 V (default)
3: +/- 1.024 V
4: +/- 0.512 V
5: +/- 0.256 V
- data_rate in samples per second
0: 128
1: 250
2: 490
3: 920
4: 1600 (default)
5: 2400
6: 3300
1) The /ads1015 node
Required properties:
- compatible : must be "ti,ads1015"
- reg : I2C bus address of the device
- #address-cells : must be <1>
- #size-cells : must be <0>
The node contains child nodes for each channel that the platform uses.
Example ADS1015 node:
ads1015@49 {
compatible = "ti,ads1015";
reg = <0x49>;
#address-cells = <1>;
#size-cells = <0>;
[ child node definitions... ]
}
2) channel nodes
Required properties:
- reg : the channel number
Optional properties:
- ti,gain : the programmable gain amplifier setting
- ti,datarate : the converter data rate
Example ADS1015 channel node:
channel@4 {
reg = <4>;
ti,gain = <3>;
ti,datarate = <5>;
};

View File

@ -0,0 +1,72 @@
Kernel driver ads1015
=====================
Supported chips:
* Texas Instruments ADS1015
Prefix: 'ads1015'
Datasheet: Publicly available at the Texas Instruments website :
http://focus.ti.com/lit/ds/symlink/ads1015.pdf
Authors:
Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
Description
-----------
This driver implements support for the Texas Instruments ADS1015.
This device is a 12-bit A-D converter with 4 inputs.
The inputs can be used single ended or in certain differential combinations.
The inputs can be made available by 8 sysfs input files in0_input - in7_input:
in0: Voltage over AIN0 and AIN1.
in1: Voltage over AIN0 and AIN3.
in2: Voltage over AIN1 and AIN3.
in3: Voltage over AIN2 and AIN3.
in4: Voltage over AIN0 and GND.
in5: Voltage over AIN1 and GND.
in6: Voltage over AIN2 and GND.
in7: Voltage over AIN3 and GND.
Which inputs are available can be configured using platform data or devicetree.
By default all inputs are exported.
Platform Data
-------------
In linux/i2c/ads1015.h platform data is defined, channel_data contains
configuration data for the used input combinations:
- pga is the programmable gain amplifier (values are full scale)
0: +/- 6.144 V
1: +/- 4.096 V
2: +/- 2.048 V
3: +/- 1.024 V
4: +/- 0.512 V
5: +/- 0.256 V
- data_rate in samples per second
0: 128
1: 250
2: 490
3: 920
4: 1600
5: 2400
6: 3300
Example:
struct ads1015_platform_data data = {
.channel_data = {
[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
}
};
In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
(FS +/- 0.512 V, 2400 SPS) would be created.
Devicetree
----------
Configuration is also possible via devicetree:
Documentation/devicetree/bindings/hwmon/ads1015.txt

View File

@ -7,6 +7,11 @@ Supported chips:
Addresses scanned: I2C 0x48 - 0x4f
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
* National Semiconductor LM75A
Prefix: 'lm75a'
Addresses scanned: I2C 0x48 - 0x4f
Datasheet: Publicly available at the National Semiconductor website
http://www.national.com/
* Dallas Semiconductor DS75
Prefix: 'lm75'
Addresses scanned: I2C 0x48 - 0x4f

View File

@ -0,0 +1,22 @@
Kernel driver sch5627
=====================
Supported chips:
* SMSC SCH5627
Prefix: 'sch5627'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Application Note available upon request
Author: Hans de Goede <hdegoede@redhat.com>
Description
-----------
SMSC SCH5627 Super I/O chips include complete hardware monitoring
capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
The hardware monitoring part of the SMSC SCH5627 is accessed by talking
through an embedded microcontroller. An application note describing the
protocol for communicating with the microcontroller is available upon
request. Please mail me if you want a copy.

127
Documentation/hwmon/w83795 Normal file
View File

@ -0,0 +1,127 @@
Kernel driver w83795
====================
Supported chips:
* Winbond/Nuvoton W83795G
Prefix: 'w83795g'
Addresses scanned: I2C 0x2c - 0x2f
Datasheet: Available for download on nuvoton.com
* Winbond/Nuvoton W83795ADG
Prefix: 'w83795adg'
Addresses scanned: I2C 0x2c - 0x2f
Datasheet: Available for download on nuvoton.com
Authors:
Wei Song (Nuvoton)
Jean Delvare <khali@linux-fr.org>
Pin mapping
-----------
Here is a summary of the pin mapping for the W83795G and W83795ADG.
This can be useful to convert data provided by board manufacturers
into working libsensors configuration statements.
W83795G |
Pin | Name | Register | Sysfs attribute
------------------------------------------------------------------
13 | VSEN1 (VCORE1) | 10h | in0
14 | VSEN2 (VCORE2) | 11h | in1
15 | VSEN3 (VCORE3) | 12h | in2
16 | VSEN4 | 13h | in3
17 | VSEN5 | 14h | in4
18 | VSEN6 | 15h | in5
19 | VSEN7 | 16h | in6
20 | VSEN8 | 17h | in7
21 | VSEN9 | 18h | in8
22 | VSEN10 | 19h | in9
23 | VSEN11 | 1Ah | in10
28 | VTT | 1Bh | in11
24 | 3VDD | 1Ch | in12
25 | 3VSB | 1Dh | in13
26 | VBAT | 1Eh | in14
3 | VSEN12/TR5 | 1Fh | in15/temp5
4 | VSEN13/TR5 | 20h | in16/temp6
5/ 6 | VDSEN14/TR1/TD1 | 21h | in17/temp1
7/ 8 | VDSEN15/TR2/TD2 | 22h | in18/temp2
9/ 10 | VDSEN16/TR3/TD3 | 23h | in19/temp3
11/ 12 | VDSEN17/TR4/TD4 | 24h | in20/temp4
40 | FANIN1 | 2Eh | fan1
42 | FANIN2 | 2Fh | fan2
44 | FANIN3 | 30h | fan3
46 | FANIN4 | 31h | fan4
48 | FANIN5 | 32h | fan5
50 | FANIN6 | 33h | fan6
52 | FANIN7 | 34h | fan7
54 | FANIN8 | 35h | fan8
57 | FANIN9 | 36h | fan9
58 | FANIN10 | 37h | fan10
59 | FANIN11 | 38h | fan11
60 | FANIN12 | 39h | fan12
31 | FANIN13 | 3Ah | fan13
35 | FANIN14 | 3Bh | fan14
41 | FANCTL1 | 10h (bank 2) | pwm1
43 | FANCTL2 | 11h (bank 2) | pwm2
45 | FANCTL3 | 12h (bank 2) | pwm3
47 | FANCTL4 | 13h (bank 2) | pwm4
49 | FANCTL5 | 14h (bank 2) | pwm5
51 | FANCTL6 | 15h (bank 2) | pwm6
53 | FANCTL7 | 16h (bank 2) | pwm7
55 | FANCTL8 | 17h (bank 2) | pwm8
29/ 30 | PECI/TSI (DTS1) | 26h | temp7
29/ 30 | PECI/TSI (DTS2) | 27h | temp8
29/ 30 | PECI/TSI (DTS3) | 28h | temp9
29/ 30 | PECI/TSI (DTS4) | 29h | temp10
29/ 30 | PECI/TSI (DTS5) | 2Ah | temp11
29/ 30 | PECI/TSI (DTS6) | 2Bh | temp12
29/ 30 | PECI/TSI (DTS7) | 2Ch | temp13
29/ 30 | PECI/TSI (DTS8) | 2Dh | temp14
27 | CASEOPEN# | 46h | intrusion0
W83795ADG |
Pin | Name | Register | Sysfs attribute
------------------------------------------------------------------
10 | VSEN1 (VCORE1) | 10h | in0
11 | VSEN2 (VCORE2) | 11h | in1
12 | VSEN3 (VCORE3) | 12h | in2
13 | VSEN4 | 13h | in3
14 | VSEN5 | 14h | in4
15 | VSEN6 | 15h | in5
16 | VSEN7 | 16h | in6
17 | VSEN8 | 17h | in7
22 | VTT | 1Bh | in11
18 | 3VDD | 1Ch | in12
19 | 3VSB | 1Dh | in13
20 | VBAT | 1Eh | in14
48 | VSEN12/TR5 | 1Fh | in15/temp5
1 | VSEN13/TR5 | 20h | in16/temp6
2/ 3 | VDSEN14/TR1/TD1 | 21h | in17/temp1
4/ 5 | VDSEN15/TR2/TD2 | 22h | in18/temp2
6/ 7 | VDSEN16/TR3/TD3 | 23h | in19/temp3
8/ 9 | VDSEN17/TR4/TD4 | 24h | in20/temp4
32 | FANIN1 | 2Eh | fan1
34 | FANIN2 | 2Fh | fan2
36 | FANIN3 | 30h | fan3
37 | FANIN4 | 31h | fan4
38 | FANIN5 | 32h | fan5
39 | FANIN6 | 33h | fan6
40 | FANIN7 | 34h | fan7
41 | FANIN8 | 35h | fan8
43 | FANIN9 | 36h | fan9
44 | FANIN10 | 37h | fan10
45 | FANIN11 | 38h | fan11
46 | FANIN12 | 39h | fan12
24 | FANIN13 | 3Ah | fan13
28 | FANIN14 | 3Bh | fan14
33 | FANCTL1 | 10h (bank 2) | pwm1
35 | FANCTL2 | 11h (bank 2) | pwm2
23 | PECI (DTS1) | 26h | temp7
23 | PECI (DTS2) | 27h | temp8
23 | PECI (DTS3) | 28h | temp9
23 | PECI (DTS4) | 29h | temp10
23 | PECI (DTS5) | 2Ah | temp11
23 | PECI (DTS6) | 2Bh | temp12
23 | PECI (DTS7) | 2Ch | temp13
23 | PECI (DTS8) | 2Dh | temp14
21 | CASEOPEN# | 46h | intrusion0

View File

@ -17,8 +17,8 @@ Description
This driver provides support for the accelerometer found in various HP laptops
sporting the feature officially called "HP Mobile Data Protection System 3D" or
"HP 3D DriveGuard". It detects automatically laptops with this sensor. Known
models (full list can be found in drivers/hwmon/hp_accel.c) will have their
axis automatically oriented on standard way (eg: you can directly play
models (full list can be found in drivers/platform/x86/hp_accel.c) will have
their axis automatically oriented on standard way (eg: you can directly play
neverball). The accelerometer data is readable via
/sys/devices/platform/lis3lv02d. Reported values are scaled
to mg values (1/1000th of earth gravity).

View File

@ -198,7 +198,7 @@ F: Documentation/scsi/aacraid.txt
F: drivers/scsi/aacraid/
ABIT UGURU 1,2 HARDWARE MONITOR DRIVER
M: Hans de Goede <j.w.r.degoede@hhs.nl>
M: Hans de Goede <hdegoede@redhat.com>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/abituguru.c
@ -365,6 +365,14 @@ W: http://wiki-analog.com/ADP8860
S: Supported
F: drivers/video/backlight/adp8860_bl.c
ADS1015 HARDWARE MONITOR DRIVER
M: Dirk Eibach <eibach@gdsys.de>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/ads1015
F: drivers/hwmon/ads1015.c
F: include/linux/i2c/ads1015.h
ADT746X FAN DRIVER
M: Colin Leroy <colin@colino.net>
S: Maintained
@ -3913,8 +3921,8 @@ S: Supported
LIS3LV02D ACCELEROMETER DRIVER
M: Eric Piel <eric.piel@tremplin-utc.net>
S: Maintained
F: Documentation/hwmon/lis3lv02d
F: drivers/hwmon/lis3lv02d.*
F: Documentation/misc-devices/lis3lv02d
F: drivers/misc/lis3lv02d/
LLC (802.2)
M: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
@ -5769,6 +5777,13 @@ S: Supported
F: Documentation/hwmon/emc2103
F: drivers/hwmon/emc2103.c
SMSC SCH5627 HARDWARE MONITOR DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: lm-sensors@lm-sensors.org
S: Supported
F: Documentation/hwmon/sch5627
F: drivers/hwmon/sch5627.c
SMSC47B397 HARDWARE MONITOR DRIVER
M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: lm-sensors@lm-sensors.org

View File

@ -521,7 +521,7 @@ config SENSORS_LM75
- Dallas Semiconductor DS75 and DS1775
- Maxim MAX6625 and MAX6626
- Microchip MCP980x
- National Semiconductor LM75
- National Semiconductor LM75, LM75A
- NXP's LM75A
- ST Microelectronics STDS75
- TelCom (now Microchip) TCN75
@ -959,6 +959,25 @@ config SENSORS_SMSC47B397
This driver can also be built as a module. If so, the module
will be called smsc47b397.
config SENSORS_SCH5627
tristate "SMSC SCH5627"
help
If you say yes here you get support for the hardware monitoring
features of the SMSC SCH5627 Super-I/O chip.
This driver can also be built as a module. If so, the module
will be called sch5627.
config SENSORS_ADS1015
tristate "Texas Instruments ADS1015"
depends on I2C
help
If you say yes here you get support for Texas Instruments ADS1015
12-bit 4-input ADC device.
This driver can also be built as a module. If so, the module
will be called ads1015.
config SENSORS_ADS7828
tristate "Texas Instruments ADS7828"
depends on I2C
@ -1215,40 +1234,6 @@ config SENSORS_ULTRA45
This driver provides support for the Ultra45 workstation environmental
sensors.
config SENSORS_LIS3_SPI
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
depends on !ACPI && SPI_MASTER && INPUT
select INPUT_POLLDEV
default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via SPI. The accelerometer data is readable via
/sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
the laptop to act as a pinball machine-esque joystick.
This driver can also be built as modules. If so, the core module
will be called lis3lv02d and a specific module for the SPI transport
is called lis3lv02d_spi.
config SENSORS_LIS3_I2C
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
depends on I2C && INPUT
select INPUT_POLLDEV
default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via I2C. The accelerometer data is readable via
/sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
the device to act as a pinball machine-esque joystick.
This driver can also be built as modules. If so, the core module
will be called lis3lv02d and a specific module for the I2C transport
is called lis3lv02d_i2c.
config SENSORS_APPLESMC
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
depends on INPUT && X86
@ -1296,36 +1281,6 @@ config SENSORS_ATK0110
This driver can also be built as a module. If so, the module
will be called asus_atk0110.
config SENSORS_LIS3LV02D
tristate "STMicroeletronics LIS3* three-axis digital accelerometer"
depends on INPUT
select INPUT_POLLDEV
select NEW_LEDS
select LEDS_CLASS
default n
help
This driver provides support for the LIS3* accelerometers, such as the
LIS3LV02DL or the LIS331DL. In particular, it can be found in a number
of HP laptops, which have the "Mobile Data Protection System 3D" or
"3D DriveGuard" feature. On such systems the driver should load
automatically (via ACPI alias). The accelerometer might also be found
in other systems, connected via SPI or I2C. The accelerometer data is
readable via /sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
a laptop to act as a pinball machine-esque joystick. It provides also
a misc device which can be used to detect free-fall. On HP laptops,
if the led infrastructure is activated, support for a led indicating
disk protection will be provided as hp::hddprotect. For more
information on the feature, refer to Documentation/hwmon/lis3lv02d.
This driver can also be built as modules. If so, the core module
will be called lis3lv02d and a specific module for HP laptops will be
called hp_accel.
Say Y here if you have an applicable laptop and want to experience
the awesome power of lis3lv02d.
endif # ACPI
endif # HWMON

View File

@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o
obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o
obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o
obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o
@ -63,9 +64,6 @@ obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o
obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o
obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o
obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d.o lis3lv02d_spi.o
obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d.o lis3lv02d_i2c.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM73) += lm73.o
@ -93,6 +91,7 @@ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
obj-$(CONFIG_SENSORS_SHT15) += sht15.o
obj-$(CONFIG_SENSORS_SHT21) += sht21.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o

View File

@ -1,5 +1,5 @@
/*
abituguru.c Copyright (c) 2005-2006 Hans de Goede <j.w.r.degoede@hhs.nl>
abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1505,7 +1505,7 @@ static void __exit abituguru_exit(void)
platform_driver_unregister(&abituguru_driver);
}
MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Abit uGuru Sensor device");
MODULE_LICENSE("GPL");

View File

@ -1,7 +1,7 @@
/*
abituguru3.c
Copyright (c) 2006-2008 Hans de Goede <j.w.r.degoede@hhs.nl>
Copyright (c) 2006-2008 Hans de Goede <hdegoede@redhat.com>
Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk>
This program is free software; you can redistribute it and/or modify
@ -1266,7 +1266,7 @@ static void __exit abituguru3_exit(void)
platform_driver_unregister(&abituguru3_driver);
}
MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
MODULE_LICENSE("GPL");

337
drivers/hwmon/ads1015.c Normal file
View File

@ -0,0 +1,337 @@
/*
* ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC
* (C) Copyright 2010
* Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
*
* Based on the ads7828 driver by Steve Hardy.
*
* Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/i2c/ads1015.h>
/* ADS1015 registers */
enum {
ADS1015_CONVERSION = 0,
ADS1015_CONFIG = 1,
};
/* PGA fullscale voltages in mV */
static const unsigned int fullscale_table[8] = {
6144, 4096, 2048, 1024, 512, 256, 256, 256 };
/* Data rates in samples per second */
static const unsigned int data_rate_table[8] = {
128, 250, 490, 920, 1600, 2400, 3300, 3300 };
#define ADS1015_DEFAULT_CHANNELS 0xff
#define ADS1015_DEFAULT_PGA 2
#define ADS1015_DEFAULT_DATA_RATE 4
struct ads1015_data {
struct device *hwmon_dev;
struct mutex update_lock; /* mutex protect updates */
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
};
static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
{
s32 data = i2c_smbus_read_word_data(client, reg);
return (data < 0) ? data : swab16(data);
}
static s32 ads1015_write_reg(struct i2c_client *client, unsigned int reg,
u16 val)
{
return i2c_smbus_write_word_data(client, reg, swab16(val));
}
static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
int *value)
{
u16 config;
s16 conversion;
struct ads1015_data *data = i2c_get_clientdata(client);
unsigned int pga = data->channel_data[channel].pga;
int fullscale;
unsigned int data_rate = data->channel_data[channel].data_rate;
unsigned int conversion_time_ms;
int res;
mutex_lock(&data->update_lock);
/* get channel parameters */
res = ads1015_read_reg(client, ADS1015_CONFIG);
if (res < 0)
goto err_unlock;
config = res;
fullscale = fullscale_table[pga];
conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
/* setup and start single conversion */
config &= 0x001f;
config |= (1 << 15) | (1 << 8);
config |= (channel & 0x0007) << 12;
config |= (pga & 0x0007) << 9;
config |= (data_rate & 0x0007) << 5;
res = ads1015_write_reg(client, ADS1015_CONFIG, config);
if (res < 0)
goto err_unlock;
/* wait until conversion finished */
msleep(conversion_time_ms);
res = ads1015_read_reg(client, ADS1015_CONFIG);
if (res < 0)
goto err_unlock;
config = res;
if (!(config & (1 << 15))) {
/* conversion not finished in time */
res = -EIO;
goto err_unlock;
}
res = ads1015_read_reg(client, ADS1015_CONVERSION);
if (res < 0)
goto err_unlock;
conversion = res;
mutex_unlock(&data->update_lock);
*value = DIV_ROUND_CLOSEST(conversion * fullscale, 0x7ff0);
return 0;
err_unlock:
mutex_unlock(&data->update_lock);
return res;
}
/* sysfs callback function */
static ssize_t show_in(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
int in;
int res;
res = ads1015_read_value(client, attr->index, &in);
return (res < 0) ? res : sprintf(buf, "%d\n", in);
}
static const struct sensor_device_attribute ads1015_in[] = {
SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
};
/*
* Driver interface
*/
static int ads1015_remove(struct i2c_client *client)
{
struct ads1015_data *data = i2c_get_clientdata(client);
int k;
hwmon_device_unregister(data->hwmon_dev);
for (k = 0; k < ADS1015_CHANNELS; ++k)
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
kfree(data);
return 0;
}
#ifdef CONFIG_OF
static int ads1015_get_channels_config_of(struct i2c_client *client)
{
struct ads1015_data *data = i2c_get_clientdata(client);
struct device_node *node;
if (!client->dev.of_node
|| !of_get_next_child(client->dev.of_node, NULL))
return -EINVAL;
for_each_child_of_node(client->dev.of_node, node) {
const __be32 *property;
int len;
unsigned int channel;
unsigned int pga = ADS1015_DEFAULT_PGA;
unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
property = of_get_property(node, "reg", &len);
if (!property || len != sizeof(int)) {
dev_err(&client->dev, "invalid reg on %s\n",
node->full_name);
continue;
}
channel = be32_to_cpup(property);
if (channel > ADS1015_CHANNELS) {
dev_err(&client->dev,
"invalid channel index %d on %s\n",
channel, node->full_name);
continue;
}
property = of_get_property(node, "ti,gain", &len);
if (property && len == sizeof(int)) {
pga = be32_to_cpup(property);
if (pga > 6) {
dev_err(&client->dev,
"invalid gain on %s\n",
node->full_name);
}
}
property = of_get_property(node, "ti,datarate", &len);
if (property && len == sizeof(int)) {
data_rate = be32_to_cpup(property);
if (data_rate > 7) {
dev_err(&client->dev,
"invalid data_rate on %s\n",
node->full_name);
}
}
data->channel_data[channel].enabled = true;
data->channel_data[channel].pga = pga;
data->channel_data[channel].data_rate = data_rate;
}
return 0;
}
#endif
static void ads1015_get_channels_config(struct i2c_client *client)
{
unsigned int k;
struct ads1015_data *data = i2c_get_clientdata(client);
struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
/* prefer platform data */
if (pdata) {
memcpy(data->channel_data, pdata->channel_data,
sizeof(data->channel_data));
return;
}
#ifdef CONFIG_OF
if (!ads1015_get_channels_config_of(client))
return;
#endif
/* fallback on default configuration */
for (k = 0; k < ADS1015_CHANNELS; ++k) {
data->channel_data[k].enabled = true;
data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
}
}
static int ads1015_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ads1015_data *data;
int err;
unsigned int k;
data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* build sysfs attribute group */
ads1015_get_channels_config(client);
for (k = 0; k < ADS1015_CHANNELS; ++k) {
if (!data->channel_data[k].enabled)
continue;
err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
if (err)
goto exit_free;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove;
}
return 0;
exit_remove:
for (k = 0; k < ADS1015_CHANNELS; ++k)
device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
exit_free:
kfree(data);
exit:
return err;
}
static const struct i2c_device_id ads1015_id[] = {
{ "ads1015", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ads1015_id);
static struct i2c_driver ads1015_driver = {
.driver = {
.name = "ads1015",
},
.probe = ads1015_probe,
.remove = ads1015_remove,
.id_table = ads1015_id,
};
static int __init sensors_ads1015_init(void)
{
return i2c_add_driver(&ads1015_driver);
}
static void __exit sensors_ads1015_exit(void)
{
i2c_del_driver(&ads1015_driver);
}
MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>");
MODULE_DESCRIPTION("ADS1015 driver");
MODULE_LICENSE("GPL");
module_init(sensors_ads1015_init);
module_exit(sensors_ads1015_exit);

View File

@ -232,13 +232,16 @@ static const struct i2c_device_id lm75_ids[] = {
};
MODULE_DEVICE_TABLE(i2c, lm75_ids);
#define LM75A_ID 0xA1
/* Return 0 if detection is successful, -ENODEV otherwise */
static int lm75_detect(struct i2c_client *new_client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
int i;
int cur, conf, hyst, os;
int conf, hyst, os;
bool is_lm75a = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
@ -250,37 +253,58 @@ static int lm75_detect(struct i2c_client *new_client,
addresses 0x04-0x07 returning the last read value.
The cycling+unused addresses combination is not tested,
since it would significantly slow the detection down and would
hardly add any value. */
hardly add any value.
/* Unused addresses */
cur = i2c_smbus_read_word_data(new_client, 0);
conf = i2c_smbus_read_byte_data(new_client, 1);
hyst = i2c_smbus_read_word_data(new_client, 2);
if (i2c_smbus_read_word_data(new_client, 4) != hyst
|| i2c_smbus_read_word_data(new_client, 5) != hyst
|| i2c_smbus_read_word_data(new_client, 6) != hyst
|| i2c_smbus_read_word_data(new_client, 7) != hyst)
return -ENODEV;
os = i2c_smbus_read_word_data(new_client, 3);
if (i2c_smbus_read_word_data(new_client, 4) != os
|| i2c_smbus_read_word_data(new_client, 5) != os
|| i2c_smbus_read_word_data(new_client, 6) != os
|| i2c_smbus_read_word_data(new_client, 7) != os)
return -ENODEV;
The National Semiconductor LM75A is different than earlier
LM75s. It has an ID byte of 0xaX (where X is the chip
revision, with 1 being the only revision in existence) in
register 7, and unused registers return 0xff rather than the
last read value. */
/* Unused bits */
conf = i2c_smbus_read_byte_data(new_client, 1);
if (conf & 0xe0)
return -ENODEV;
/* Addresses cycling */
for (i = 8; i < 0xff; i += 8) {
if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
|| i2c_smbus_read_word_data(new_client, i + 2) != hyst
|| i2c_smbus_read_word_data(new_client, i + 3) != os)
/* First check for LM75A */
if (i2c_smbus_read_byte_data(new_client, 7) == LM75A_ID) {
/* LM75A returns 0xff on unused registers so
just to be sure we check for that too. */
if (i2c_smbus_read_byte_data(new_client, 4) != 0xff
|| i2c_smbus_read_byte_data(new_client, 5) != 0xff
|| i2c_smbus_read_byte_data(new_client, 6) != 0xff)
return -ENODEV;
is_lm75a = 1;
hyst = i2c_smbus_read_byte_data(new_client, 2);
os = i2c_smbus_read_byte_data(new_client, 3);
} else { /* Traditional style LM75 detection */
/* Unused addresses */
hyst = i2c_smbus_read_byte_data(new_client, 2);
if (i2c_smbus_read_byte_data(new_client, 4) != hyst
|| i2c_smbus_read_byte_data(new_client, 5) != hyst
|| i2c_smbus_read_byte_data(new_client, 6) != hyst
|| i2c_smbus_read_byte_data(new_client, 7) != hyst)
return -ENODEV;
os = i2c_smbus_read_byte_data(new_client, 3);
if (i2c_smbus_read_byte_data(new_client, 4) != os
|| i2c_smbus_read_byte_data(new_client, 5) != os
|| i2c_smbus_read_byte_data(new_client, 6) != os
|| i2c_smbus_read_byte_data(new_client, 7) != os)
return -ENODEV;
}
strlcpy(info->type, "lm75", I2C_NAME_SIZE);
/* Addresses cycling */
for (i = 8; i <= 248; i += 40) {
if (i2c_smbus_read_byte_data(new_client, i + 1) != conf
|| i2c_smbus_read_byte_data(new_client, i + 2) != hyst
|| i2c_smbus_read_byte_data(new_client, i + 3) != os)
return -ENODEV;
if (is_lm75a && i2c_smbus_read_byte_data(new_client, i + 7)
!= LM75A_ID)
return -ENODEV;
}
strlcpy(info->type, is_lm75a ? "lm75a" : "lm75", I2C_NAME_SIZE);
return 0;
}

858
drivers/hwmon/sch5627.c Normal file
View File

@ -0,0 +1,858 @@
/***************************************************************************
* Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#define DRVNAME "sch5627"
#define DEVNAME DRVNAME /* We only support one model */
#define SIO_SCH5627_EM_LD 0x0C /* Embedded Microcontroller LD */
#define SIO_UNLOCK_KEY 0x55 /* Key to enable Super-I/O */
#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
#define SIO_REG_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x66 /* Logical device address (2 bytes) */
#define SIO_SCH5627_ID 0xC6 /* Chipset ID */
#define REGION_LENGTH 9
#define SCH5627_HWMON_ID 0xa5
#define SCH5627_COMPANY_ID 0x5c
#define SCH5627_PRIMARY_ID 0xa0
#define SCH5627_REG_BUILD_CODE 0x39
#define SCH5627_REG_BUILD_ID 0x3a
#define SCH5627_REG_HWMON_ID 0x3c
#define SCH5627_REG_HWMON_REV 0x3d
#define SCH5627_REG_COMPANY_ID 0x3e
#define SCH5627_REG_PRIMARY_ID 0x3f
#define SCH5627_REG_CTRL 0x40
#define SCH5627_NO_TEMPS 8
#define SCH5627_NO_FANS 4
#define SCH5627_NO_IN 5
static const u16 SCH5627_REG_TEMP_MSB[SCH5627_NO_TEMPS] = {
0x2B, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x180, 0x181 };
static const u16 SCH5627_REG_TEMP_LSN[SCH5627_NO_TEMPS] = {
0xE2, 0xE1, 0xE1, 0xE5, 0xE5, 0xE6, 0x182, 0x182 };
static const u16 SCH5627_REG_TEMP_HIGH_NIBBLE[SCH5627_NO_TEMPS] = {
0, 0, 1, 1, 0, 0, 0, 1 };
static const u16 SCH5627_REG_TEMP_HIGH[SCH5627_NO_TEMPS] = {
0x61, 0x57, 0x59, 0x5B, 0x5D, 0x5F, 0x184, 0x186 };
static const u16 SCH5627_REG_TEMP_ABS[SCH5627_NO_TEMPS] = {
0x9B, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x1A8, 0x1A9 };
static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
0x2C, 0x2E, 0x30, 0x32 };
static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
0x62, 0x64, 0x66, 0x68 };
static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
0x22, 0x23, 0x24, 0x25, 0x189 };
static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
0xE4, 0xE4, 0xE3, 0xE3, 0x18A };
static const u16 SCH5627_REG_IN_HIGH_NIBBLE[SCH5627_NO_IN] = {
1, 0, 1, 0, 1 };
static const u16 SCH5627_REG_IN_FACTOR[SCH5627_NO_IN] = {
10745, 3660, 9765, 10745, 3660 };
static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
"VCC", "VTT", "VBAT", "VTR", "V_IN" };
struct sch5627_data {
unsigned short addr;
struct device *hwmon_dev;
u8 temp_max[SCH5627_NO_TEMPS];
u8 temp_crit[SCH5627_NO_TEMPS];
u16 fan_min[SCH5627_NO_FANS];
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 temp[SCH5627_NO_TEMPS];
u16 fan[SCH5627_NO_FANS];
u16 in[SCH5627_NO_IN];
};
static struct platform_device *sch5627_pdev;
/* Super I/O functions */
static inline int superio_inb(int base, int reg)
{
outb(reg, base);
return inb(base + 1);
}
static inline int superio_enter(int base)
{
/* Don't step on other drivers' I/O space by accident */
if (!request_muxed_region(base, 2, DRVNAME)) {
pr_err("I/O address 0x%04x already in use\n", base);
return -EBUSY;
}
outb(SIO_UNLOCK_KEY, base);
return 0;
}
static inline void superio_select(int base, int ld)
{
outb(SIO_REG_LDSEL, base);
outb(ld, base + 1);
}
static inline void superio_exit(int base)
{
outb(SIO_LOCK_KEY, base);
release_region(base, 2);
}
static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
{
u8 val;
int i;
/*
* According to SMSC for the commands we use the maximum time for
* the EM to respond is 15 ms, but testing shows in practice it
* responds within 15-32 reads, so we first busy poll, and if
* that fails sleep a bit and try again until we are way past
* the 15 ms maximum response time.
*/
const int max_busy_polls = 64;
const int max_lazy_polls = 32;
/* (Optional) Write-Clear the EC to Host Mailbox Register */
val = inb(data->addr + 1);
outb(val, data->addr + 1);
/* Set Mailbox Address Pointer to first location in Region 1 */
outb(0x00, data->addr + 2);
outb(0x80, data->addr + 3);
/* Write Request Packet Header */
outb(0x02, data->addr + 4); /* Access Type: VREG read */
outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */
outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */
/* Write Address field */
outb(reg & 0xff, data->addr + 6);
outb(reg >> 8, data->addr + 7);
/* Execute the Random Access Command */
outb(0x01, data->addr); /* Write 01h to the Host-to-EC register */
/* EM Interface Polling "Algorithm" */
for (i = 0; i < max_busy_polls + max_lazy_polls; i++) {
if (i >= max_busy_polls)
msleep(1);
/* Read Interrupt source Register */
val = inb(data->addr + 8);
/* Write Clear the interrupt source bits */
if (val)
outb(val, data->addr + 8);
/* Command Completed ? */
if (val & 0x01)
break;
}
if (i == max_busy_polls + max_lazy_polls) {
pr_err("Max retries exceeded reading virtual "
"register 0x%04hx (%d)\n", reg, 1);
return -EIO;
}
/*
* According to SMSC we may need to retry this, but sofar I've always
* seen this succeed in 1 try.
*/
for (i = 0; i < max_busy_polls; i++) {
/* Read EC-to-Host Register */
val = inb(data->addr + 1);
/* Command Completed ? */
if (val == 0x01)
break;
if (i == 0)
pr_warn("EC reports: 0x%02x reading virtual register "
"0x%04hx\n", (unsigned int)val, reg);
}
if (i == max_busy_polls) {
pr_err("Max retries exceeded reading virtual "
"register 0x%04hx (%d)\n", reg, 2);
return -EIO;
}
/*
* According to the SMSC app note we should now do:
*
* Set Mailbox Address Pointer to first location in Region 1 *
* outb(0x00, data->addr + 2);
* outb(0x80, data->addr + 3);
*
* But if we do that things don't work, so let's not.
*/
/* Read Data from Mailbox */
return inb(data->addr + 4);
}
static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg)
{
int lsb, msb;
/* Read LSB first, this will cause the matching MSB to be latched */
lsb = sch5627_read_virtual_reg(data, reg);
if (lsb < 0)
return lsb;
msb = sch5627_read_virtual_reg(data, reg + 1);
if (msb < 0)
return msb;
return lsb | (msb << 8);
}
static int sch5627_read_virtual_reg12(struct sch5627_data *data, u16 msb_reg,
u16 lsn_reg, int high_nibble)
{
int msb, lsn;
/* Read MSB first, this will cause the matching LSN to be latched */
msb = sch5627_read_virtual_reg(data, msb_reg);
if (msb < 0)
return msb;
lsn = sch5627_read_virtual_reg(data, lsn_reg);
if (lsn < 0)
return lsn;
if (high_nibble)
return (msb << 4) | (lsn >> 4);
else
return (msb << 4) | (lsn & 0x0f);
}
static struct sch5627_data *sch5627_update_device(struct device *dev)
{
struct sch5627_data *data = dev_get_drvdata(dev);
struct sch5627_data *ret = data;
int i, val;
mutex_lock(&data->update_lock);
/* Cache the values for 1 second */
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (i = 0; i < SCH5627_NO_TEMPS; i++) {
val = sch5627_read_virtual_reg12(data,
SCH5627_REG_TEMP_MSB[i],
SCH5627_REG_TEMP_LSN[i],
SCH5627_REG_TEMP_HIGH_NIBBLE[i]);
if (unlikely(val < 0)) {
ret = ERR_PTR(val);
goto abort;
}
data->temp[i] = val;
}
for (i = 0; i < SCH5627_NO_FANS; i++) {
val = sch5627_read_virtual_reg16(data,
SCH5627_REG_FAN[i]);
if (unlikely(val < 0)) {
ret = ERR_PTR(val);
goto abort;
}
data->fan[i] = val;
}
for (i = 0; i < SCH5627_NO_IN; i++) {
val = sch5627_read_virtual_reg12(data,
SCH5627_REG_IN_MSB[i],
SCH5627_REG_IN_LSN[i],
SCH5627_REG_IN_HIGH_NIBBLE[i]);
if (unlikely(val < 0)) {
ret = ERR_PTR(val);
goto abort;
}
data->in[i] = val;
}
data->last_updated = jiffies;
data->valid = 1;
}
abort:
mutex_unlock(&data->update_lock);
return ret;
}
static int __devinit sch5627_read_limits(struct sch5627_data *data)
{
int i, val;
for (i = 0; i < SCH5627_NO_TEMPS; i++) {
/*
* Note what SMSC calls ABS, is what lm_sensors calls max
* (aka high), and HIGH is what lm_sensors calls crit.
*/
val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_ABS[i]);
if (val < 0)
return val;
data->temp_max[i] = val;
val = sch5627_read_virtual_reg(data, SCH5627_REG_TEMP_HIGH[i]);
if (val < 0)
return val;
data->temp_crit[i] = val;
}
for (i = 0; i < SCH5627_NO_FANS; i++) {
val = sch5627_read_virtual_reg16(data, SCH5627_REG_FAN_MIN[i]);
if (val < 0)
return val;
data->fan_min[i] = val;
}
return 0;
}
static int reg_to_temp(u16 reg)
{
return (reg * 625) / 10 - 64000;
}
static int reg_to_temp_limit(u8 reg)
{
return (reg - 64) * 1000;
}
static int reg_to_rpm(u16 reg)
{
if (reg == 0)
return -EIO;
if (reg == 0xffff)
return 0;
return 5400540 / reg;
}
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME);
}
static ssize_t show_temp(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = sch5627_update_device(dev);
int val;
if (IS_ERR(data))
return PTR_ERR(data);
val = reg_to_temp(data->temp[attr->index]);
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_temp_fault(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = sch5627_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return snprintf(buf, PAGE_SIZE, "%d\n", data->temp[attr->index] == 0);
}
static ssize_t show_temp_max(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = dev_get_drvdata(dev);
int val;
val = reg_to_temp_limit(data->temp_max[attr->index]);
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_temp_crit(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = dev_get_drvdata(dev);
int val;
val = reg_to_temp_limit(data->temp_crit[attr->index]);
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_fan(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = sch5627_update_device(dev);
int val;
if (IS_ERR(data))
return PTR_ERR(data);
val = reg_to_rpm(data->fan[attr->index]);
if (val < 0)
return val;
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_fan_fault(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = sch5627_update_device(dev);
if (IS_ERR(data))
return PTR_ERR(data);
return snprintf(buf, PAGE_SIZE, "%d\n",
data->fan[attr->index] == 0xffff);
}
static ssize_t show_fan_min(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = dev_get_drvdata(dev);
int val = reg_to_rpm(data->fan_min[attr->index]);
if (val < 0)
return val;
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_in(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct sch5627_data *data = sch5627_update_device(dev);
int val;
if (IS_ERR(data))
return PTR_ERR(data);
val = DIV_ROUND_CLOSEST(
data->in[attr->index] * SCH5627_REG_IN_FACTOR[attr->index],
10000);
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
static ssize_t show_in_label(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return snprintf(buf, PAGE_SIZE, "%s\n",
SCH5627_IN_LABELS[attr->index]);
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4);
static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7);
static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3);
static SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4);
static SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_fault, S_IRUGO, show_temp_fault, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_fault, S_IRUGO, show_temp_fault, NULL, 7);
static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3);
static SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4);
static SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_max, S_IRUGO, show_temp_max, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_max, S_IRUGO, show_temp_max, NULL, 7);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2);
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3);
static SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4);
static SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5);
static SENSOR_DEVICE_ATTR(temp7_crit, S_IRUGO, show_temp_crit, NULL, 6);
static SENSOR_DEVICE_ATTR(temp8_crit, S_IRUGO, show_temp_crit, NULL, 7);
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3);
static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO, show_fan_min, NULL, 0);
static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO, show_fan_min, NULL, 1);
static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO, show_fan_min, NULL, 2);
static SENSOR_DEVICE_ATTR(fan4_min, S_IRUGO, show_fan_min, NULL, 3);
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_in_label, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_in_label, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_in_label, NULL, 2);
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_in_label, NULL, 3);
static struct attribute *sch5627_attributes[] = {
&dev_attr_name.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp5_input.dev_attr.attr,
&sensor_dev_attr_temp6_input.dev_attr.attr,
&sensor_dev_attr_temp7_input.dev_attr.attr,
&sensor_dev_attr_temp8_input.dev_attr.attr,
&sensor_dev_attr_temp1_fault.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp5_fault.dev_attr.attr,
&sensor_dev_attr_temp6_fault.dev_attr.attr,
&sensor_dev_attr_temp7_fault.dev_attr.attr,
&sensor_dev_attr_temp8_fault.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp5_max.dev_attr.attr,
&sensor_dev_attr_temp6_max.dev_attr.attr,
&sensor_dev_attr_temp7_max.dev_attr.attr,
&sensor_dev_attr_temp8_max.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp4_crit.dev_attr.attr,
&sensor_dev_attr_temp5_crit.dev_attr.attr,
&sensor_dev_attr_temp6_crit.dev_attr.attr,
&sensor_dev_attr_temp7_crit.dev_attr.attr,
&sensor_dev_attr_temp8_crit.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan1_fault.dev_attr.attr,
&sensor_dev_attr_fan2_fault.dev_attr.attr,
&sensor_dev_attr_fan3_fault.dev_attr.attr,
&sensor_dev_attr_fan4_fault.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
&sensor_dev_attr_in4_input.dev_attr.attr,
&sensor_dev_attr_in0_label.dev_attr.attr,
&sensor_dev_attr_in1_label.dev_attr.attr,
&sensor_dev_attr_in2_label.dev_attr.attr,
&sensor_dev_attr_in3_label.dev_attr.attr,
/* No in4_label as in4 is a generic input pin */
NULL
};
static const struct attribute_group sch5627_group = {
.attrs = sch5627_attributes,
};
static int sch5627_remove(struct platform_device *pdev)
{
struct sch5627_data *data = platform_get_drvdata(pdev);
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
static int __devinit sch5627_probe(struct platform_device *pdev)
{
struct sch5627_data *data;
int err, build_code, build_id, hwmon_rev, val;
data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
mutex_init(&data->update_lock);
platform_set_drvdata(pdev, data);
val = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_ID);
if (val < 0) {
err = val;
goto error;
}
if (val != SCH5627_HWMON_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "hwmon",
val, SCH5627_HWMON_ID);
err = -ENODEV;
goto error;
}
val = sch5627_read_virtual_reg(data, SCH5627_REG_COMPANY_ID);
if (val < 0) {
err = val;
goto error;
}
if (val != SCH5627_COMPANY_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "company",
val, SCH5627_COMPANY_ID);
err = -ENODEV;
goto error;
}
val = sch5627_read_virtual_reg(data, SCH5627_REG_PRIMARY_ID);
if (val < 0) {
err = val;
goto error;
}
if (val != SCH5627_PRIMARY_ID) {
pr_err("invalid %s id: 0x%02X (expected 0x%02X)\n", "primary",
val, SCH5627_PRIMARY_ID);
err = -ENODEV;
goto error;
}
build_code = sch5627_read_virtual_reg(data, SCH5627_REG_BUILD_CODE);
if (build_code < 0) {
err = build_code;
goto error;
}
build_id = sch5627_read_virtual_reg16(data, SCH5627_REG_BUILD_ID);
if (build_id < 0) {
err = build_id;
goto error;
}
hwmon_rev = sch5627_read_virtual_reg(data, SCH5627_REG_HWMON_REV);
if (hwmon_rev < 0) {
err = hwmon_rev;
goto error;
}
val = sch5627_read_virtual_reg(data, SCH5627_REG_CTRL);
if (val < 0) {
err = val;
goto error;
}
if (!(val & 0x01)) {
pr_err("hardware monitoring not enabled\n");
err = -ENODEV;
goto error;
}
/*
* Read limits, we do this only once as reading a register on
* the sch5627 is quite expensive (and they don't change).
*/
err = sch5627_read_limits(data);
if (err)
goto error;
pr_info("firmware build: code 0x%02X, id 0x%04X, hwmon: rev 0x%02X\n",
build_code, build_id, hwmon_rev);
/* Register sysfs interface files */
err = sysfs_create_group(&pdev->dev.kobj, &sch5627_group);
if (err)
goto error;
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
data->hwmon_dev = NULL;
goto error;
}
return 0;
error:
sch5627_remove(pdev);
return err;
}
static int __init sch5627_find(int sioaddr, unsigned short *address)
{
u8 devid;
int err = superio_enter(sioaddr);
if (err)
return err;
devid = superio_inb(sioaddr, SIO_REG_DEVID);
if (devid != SIO_SCH5627_ID) {
pr_debug("Unsupported device id: 0x%02x\n",
(unsigned int)devid);
err = -ENODEV;
goto exit;
}
superio_select(sioaddr, SIO_SCH5627_EM_LD);
if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
pr_warn("Device not activated\n");
err = -ENODEV;
goto exit;
}
/*
* Warning the order of the low / high byte is the other way around
* as on most other superio devices!!
*/
*address = superio_inb(sioaddr, SIO_REG_ADDR) |
superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
if (*address == 0) {
pr_warn("Base address not set\n");
err = -ENODEV;
goto exit;
}
pr_info("Found %s chip at %#hx\n", DEVNAME, *address);
exit:
superio_exit(sioaddr);
return err;
}
static int __init sch5627_device_add(unsigned short address)
{
struct resource res = {
.start = address,
.end = address + REGION_LENGTH - 1,
.flags = IORESOURCE_IO,
};
int err;
sch5627_pdev = platform_device_alloc(DRVNAME, address);
if (!sch5627_pdev)
return -ENOMEM;
res.name = sch5627_pdev->name;
err = acpi_check_resource_conflict(&res);
if (err)
goto exit_device_put;
err = platform_device_add_resources(sch5627_pdev, &res, 1);
if (err) {
pr_err("Device resource addition failed\n");
goto exit_device_put;
}
err = platform_device_add(sch5627_pdev);
if (err) {
pr_err("Device addition failed\n");
goto exit_device_put;
}
return 0;
exit_device_put:
platform_device_put(sch5627_pdev);
return err;
}
static struct platform_driver sch5627_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRVNAME,
},
.probe = sch5627_probe,
.remove = sch5627_remove,
};
static int __init sch5627_init(void)
{
int err = -ENODEV;
unsigned short address;
if (sch5627_find(0x4e, &address) && sch5627_find(0x2e, &address))
goto exit;
err = platform_driver_register(&sch5627_driver);
if (err)
goto exit;
err = sch5627_device_add(address);
if (err)
goto exit_driver;
return 0;
exit_driver:
platform_driver_unregister(&sch5627_driver);
exit:
return err;
}
static void __exit sch5627_exit(void)
{
platform_device_unregister(sch5627_pdev);
platform_driver_unregister(&sch5627_driver);
}
MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver");
MODULE_AUTHOR("Hans de Goede (hdegoede@redhat.com)");
MODULE_LICENSE("GPL");
module_init(sch5627_init);
module_exit(sch5627_exit);

View File

@ -333,11 +333,11 @@ static inline int sht15_calc_humid(struct sht15_data *data)
const int c1 = -4;
const int c2 = 40500; /* x 10 ^ -6 */
const int c3 = -2800; /* x10 ^ -9 */
const int c3 = -28; /* x 10 ^ -7 */
RHlinear = c1*1000
+ c2 * data->val_humid/1000
+ (data->val_humid * data->val_humid * c3)/1000000;
+ (data->val_humid * data->val_humid * c3) / 10000;
return (temp - 25000) * (10000 + 80 * data->val_humid)
/ 1000000 + RHlinear;
}
@ -610,7 +610,7 @@ static int __devexit sht15_remove(struct platform_device *pdev)
struct sht15_data *data = platform_get_drvdata(pdev);
/* Make sure any reads from the device are done and
* prevent new ones beginnning */
* prevent new ones from beginning */
mutex_lock(&data->read_lock);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);

View File

@ -2,6 +2,14 @@
# Misc strange devices
#
# This one has to live outside of the MISC_DEVICES conditional,
# because it may be selected by drivers/platform/x86/hp_accel.
config SENSORS_LIS3LV02D
tristate
depends on INPUT
select INPUT_POLLDEV
default n
menuconfig MISC_DEVICES
bool "Misc devices"
---help---
@ -462,5 +470,6 @@ source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
endif # MISC_DEVICES

View File

@ -42,3 +42,4 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
obj-y += lis3lv02d/

View File

@ -0,0 +1,37 @@
#
# STMicroelectonics LIS3LV02D and similar accelerometers
#
config SENSORS_LIS3_SPI
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
depends on !ACPI && SPI_MASTER && INPUT
select SENSORS_LIS3LV02D
default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via SPI. The accelerometer data is readable via
/sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
the laptop to act as a pinball machine-esque joystick.
This driver can also be built as modules. If so, the core module
will be called lis3lv02d and a specific module for the SPI transport
is called lis3lv02d_spi.
config SENSORS_LIS3_I2C
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)"
depends on I2C && INPUT
select SENSORS_LIS3LV02D
default n
help
This driver provides support for the LIS3LV02Dx accelerometer connected
via I2C. The accelerometer data is readable via
/sys/devices/platform/lis3lv02d.
This driver also provides an absolute input class device, allowing
the device to act as a pinball machine-esque joystick.
This driver can also be built as modules. If so, the core module
will be called lis3lv02d and a specific module for the I2C transport
is called lis3lv02d_i2c.

View File

@ -0,0 +1,7 @@
#
# STMicroelectonics LIS3LV02D and similar accelerometers
#
obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o
obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o
obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o

View File

@ -38,7 +38,7 @@
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/pm_runtime.h>
#include <asm/atomic.h>
#include <linux/atomic.h>
#include "lis3lv02d.h"
#define DRIVER_NAME "lis3lv02d"
@ -88,7 +88,6 @@
struct lis3lv02d lis3_dev = {
.misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait),
};
EXPORT_SYMBOL_GPL(lis3_dev);
/* just like param_set_int() but does sanity-check so that it won't point

View File

@ -33,7 +33,7 @@
#include <linux/delay.h>
#include "lis3lv02d.h"
#define DRV_NAME "lis3lv02d_i2c"
#define DRV_NAME "lis3lv02d_i2c"
static const char reg_vdd[] = "Vdd";
static const char reg_vdd_io[] = "Vdd_IO";

View File

@ -138,6 +138,24 @@ config TC1100_WMI
This is a driver for the WMI extensions (wireless and bluetooth power
control) of the HP Compaq TC1100 tablet.
config HP_ACCEL
tristate "HP laptop accelerometer"
depends on INPUT && ACPI
select SENSORS_LIS3LV02D
select NEW_LEDS
select LEDS_CLASS
help
This driver provides support for the "Mobile Data Protection System 3D"
or "3D DriveGuard" feature of HP laptops. On such systems the driver
should load automatically (via ACPI alias).
Support for a led indicating disk protection will be provided as
hp::hddprotect. For more information on the feature, refer to
Documentation/hwmon/lis3lv02d.
To compile this driver as a module, choose M here: the module will
be called hp_accel.
config HP_WMI
tristate "HP WMI extras"
depends on ACPI_WMI

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o

View File

@ -35,11 +35,11 @@
#include <linux/freezer.h>
#include <linux/uaccess.h>
#include <linux/leds.h>
#include <linux/atomic.h>
#include <acpi/acpi_drivers.h>
#include <asm/atomic.h>
#include "lis3lv02d.h"
#include "../../misc/lis3lv02d/lis3lv02d.h"
#define DRIVER_NAME "lis3lv02d"
#define DRIVER_NAME "hp_accel"
#define ACPI_MDPS_CLASS "accelerometer"
/* Delayed LEDs infrastructure ------------------------------------ */
@ -402,4 +402,3 @@ MODULE_LICENSE("GPL");
module_init(lis3lv02d_init_module);
module_exit(lis3lv02d_exit_module);

View File

@ -0,0 +1,36 @@
/*
* Platform Data for ADS1015 12-bit 4-input ADC
* (C) Copyright 2010
* Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LINUX_ADS1015_H
#define LINUX_ADS1015_H
#define ADS1015_CHANNELS 8
struct ads1015_channel_data {
bool enabled;
unsigned int pga;
unsigned int data_rate;
};
struct ads1015_platform_data {
struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
};
#endif /* LINUX_ADS1015_H */