mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
New driver: DA9055
Added/improved support for new chips in existing drivers: Z650/670, N550/570, ADS7830, AMD 16h family -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJQxslVAAoJEMsfJm/On5mBCCIP/2zEvtwW2nEjlqlBIuIaKsW5 +8nGOZvyd9Td0ApuC/b4UgzG4BYkOuiHFyUJGwJBcEMetNJqr650TRfS9RrLsi1w vOrCsIgjioWpzCEwD8EkgHLXFNk9lXYK9jlkpl434WuPvSUKwN4QE46XtHoSfAye NUJBj9hwDv87P68lcg7MhEyZxEPzcInPTtXMGFOiPprAKHQHeDJReSnqx8oKbmBb 5ZD+zy+Byx1UyX1lqc77xjaInvGGW1OfUkljJb7iFdlXTqyNe0g2Chn07PMF5dJJ 7stNCQ/z1l+Mo4mmgvGTgHcjooeZL+HpD3XQG0rERCV0X8prKHV2ctGPEQUoCt6c OpV08OgsaLii+2x7+otL6svyD22FoFFxS5UP1EkYZPyGekf/C5I9Wh9f77xJ+hes PNki3TrnNUzVAZKYOH9JgW2MJ9oYjvKkskZoSytnEoPAs1fS4rJ0a5bQf2sryXdT xsDw57fdjqK7A9hPzc/lIae6TYK0iMnQ4wO9nWD7ftQlH6AOT5O4vYAbwoCEks/Q 6Bv3XCaBkt1GbWyCC+aXUWjvSdU0A3N/H7jaocwR9vcgoJmfwinJi10hVcgE1Kfu JVKQMvDFe4jV1j8hiQhGPSjxe+9suoaVBrWFB51W4DyDfJZQPOFd6+3om9/vGDb3 Y3opAqGVV7IsenVtPif8 =HQlU -----END PGP SIGNATURE----- Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging Pull hwmon updates from Guenter Roeck: "New driver: DA9055 Added/improved support for new chips in existing drivers: Z650/670, N550/570, ADS7830, AMD 16h family" * tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: hwmon: (da9055) Fix chan_mux[DA9055_ADC_ADCIN3] setting hwmon: DA9055 HWMON driver hwmon: (coretemp) List TjMax for Z650/670 and N550/570 hwmon: (coretemp) Drop N4xx, N5xx, D4xx, D5xx CPUs from tjmax table hwmon: (coretemp) Use model table instead of if/else to identify CPU models hwmon: da9052: Use da9052_reg_update for rmw operations hwmon: (coretemp) Drop dependency on PCI for TjMax detection on Atom CPUs hwmon: (ina2xx) use module_i2c_driver to simplify the code hwmon: (ads7828) add support for ADS7830 hwmon: (ads7828) driver cleanup x86,AMD: Power driver support for AMD's family 16h processors
This commit is contained in:
commit
a8936db7c2
@ -4,29 +4,47 @@ Kernel driver ads7828
|
||||
Supported chips:
|
||||
* Texas Instruments/Burr-Brown ADS7828
|
||||
Prefix: 'ads7828'
|
||||
Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4b
|
||||
Datasheet: Publicly available at the Texas Instruments website:
|
||||
http://focus.ti.com/lit/ds/symlink/ads7828.pdf
|
||||
|
||||
* Texas Instruments ADS7830
|
||||
Prefix: 'ads7830'
|
||||
Datasheet: Publicly available at the Texas Instruments website:
|
||||
http://focus.ti.com/lit/ds/symlink/ads7830.pdf
|
||||
|
||||
Authors:
|
||||
Steve Hardy <shardy@redhat.com>
|
||||
Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
Platform data
|
||||
-------------
|
||||
|
||||
* se_input: bool (default Y)
|
||||
Single ended operation - set to N for differential mode
|
||||
* int_vref: bool (default Y)
|
||||
Operate with the internal 2.5V reference - set to N for external reference
|
||||
* vref_mv: int (default 2500)
|
||||
If using an external reference, set this to the reference voltage in mV
|
||||
The ads7828 driver accepts an optional ads7828_platform_data structure (defined
|
||||
in include/linux/platform_data/ads7828.h). The structure fields are:
|
||||
|
||||
* diff_input: (bool) Differential operation
|
||||
set to true for differential mode, false for default single ended mode.
|
||||
|
||||
* ext_vref: (bool) External reference
|
||||
set to true if it operates with an external reference, false for default
|
||||
internal reference.
|
||||
|
||||
* vref_mv: (unsigned int) Voltage reference
|
||||
if using an external reference, set this to the reference voltage in mV,
|
||||
otherwise it will default to the internal value (2500mV). This value will be
|
||||
bounded with limits accepted by the chip, described in the datasheet.
|
||||
|
||||
If no structure is provided, the configuration defaults to single ended
|
||||
operation and internal voltage reference (2.5V).
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This driver implements support for the Texas Instruments ADS7828.
|
||||
This driver implements support for the Texas Instruments ADS7828 and ADS7830.
|
||||
|
||||
This device is a 12-bit 8-channel A-D converter.
|
||||
The ADS7828 device is a 12-bit 8-channel A/D converter, while the ADS7830 does
|
||||
8-bit sampling.
|
||||
|
||||
It can operate in single ended mode (8 +ve inputs) or in differential mode,
|
||||
where 4 differential pairs can be measured.
|
||||
@ -34,3 +52,7 @@ where 4 differential pairs can be measured.
|
||||
The chip also has the facility to use an external voltage reference. This
|
||||
may be required if your hardware supplies the ADS7828 from a 5V supply, see
|
||||
the datasheet for more details.
|
||||
|
||||
There is no reliable way to identify this chip, so the driver will not scan
|
||||
some addresses to try to auto-detect it. That means that you will have to
|
||||
statically declare the device in the platform support code.
|
||||
|
@ -98,8 +98,10 @@ Process Processor TjMax(C)
|
||||
|
||||
45nm Atom Processors
|
||||
D525/510/425/410 100
|
||||
Z670/650 90
|
||||
Z560/550/540/530P/530/520PT/520/515/510PT/510P 90
|
||||
Z510/500 90
|
||||
N570/550 100
|
||||
N475/470/455/450 100
|
||||
N280/270 90
|
||||
330/230 125
|
||||
|
47
Documentation/hwmon/da9055
Normal file
47
Documentation/hwmon/da9055
Normal file
@ -0,0 +1,47 @@
|
||||
Supported chips:
|
||||
* Dialog Semiconductors DA9055 PMIC
|
||||
Prefix: 'da9055'
|
||||
Datasheet: Datasheet is not publicly available.
|
||||
|
||||
Authors: David Dajun Chen <dchen@diasemi.com>
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The DA9055 provides an Analogue to Digital Converter (ADC) with 10 bits
|
||||
resolution and track and hold circuitry combined with an analogue input
|
||||
multiplexer. The analogue input multiplexer will allow conversion of up to 5
|
||||
different inputs. The track and hold circuit ensures stable input voltages at
|
||||
the input of the ADC during the conversion.
|
||||
|
||||
The ADC is used to measure the following inputs:
|
||||
Channel 0: VDDOUT - measurement of the system voltage
|
||||
Channel 1: ADC_IN1 - high impedance input (0 - 2.5V)
|
||||
Channel 2: ADC_IN2 - high impedance input (0 - 2.5V)
|
||||
Channel 3: ADC_IN3 - high impedance input (0 - 2.5V)
|
||||
Channel 4: Internal Tjunc. - sense (internal temp. sensor)
|
||||
|
||||
By using sysfs attributes we can measure the system voltage VDDOUT,
|
||||
chip junction temperature and auxiliary channels voltages.
|
||||
|
||||
Voltage Monitoring
|
||||
------------------
|
||||
|
||||
Voltages are sampled in a AUTO mode it can be manually sampled too and results
|
||||
are stored in a 10 bit ADC.
|
||||
|
||||
The system voltage is calculated as:
|
||||
Milli volt = ((ADC value * 1000) / 85) + 2500
|
||||
|
||||
The voltages on ADC channels 1, 2 and 3 are calculated as:
|
||||
Milli volt = (ADC value * 1000) / 102
|
||||
|
||||
Temperature Monitoring
|
||||
----------------------
|
||||
|
||||
Temperatures are sampled by a 10 bit ADC. Junction temperatures
|
||||
are monitored by the ADC channels.
|
||||
|
||||
The junction temperature is calculated:
|
||||
Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
|
||||
The junction temperature attribute is supported by the driver.
|
@ -334,6 +334,16 @@ config SENSORS_DA9052_ADC
|
||||
This driver can also be built as module. If so, the module
|
||||
will be called da9052-hwmon.
|
||||
|
||||
config SENSORS_DA9055
|
||||
tristate "Dialog Semiconductor DA9055 ADC"
|
||||
depends on MFD_DA9055
|
||||
help
|
||||
If you say yes here you get support for ADC on the Dialog
|
||||
Semiconductor DA9055 PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called da9055-hwmon.
|
||||
|
||||
config SENSORS_I5K_AMB
|
||||
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
|
||||
depends on PCI
|
||||
@ -455,7 +465,7 @@ config SENSORS_HIH6130
|
||||
|
||||
config SENSORS_CORETEMP
|
||||
tristate "Intel Core/Core2/Atom temperature sensor"
|
||||
depends on X86 && PCI
|
||||
depends on X86
|
||||
help
|
||||
If you say yes here you get support for the temperature
|
||||
sensor inside your CPU. Most of the family 6 CPUs
|
||||
@ -1106,11 +1116,12 @@ config SENSORS_ADS1015
|
||||
will be called ads1015.
|
||||
|
||||
config SENSORS_ADS7828
|
||||
tristate "Texas Instruments ADS7828"
|
||||
tristate "Texas Instruments ADS7828 and compatibles"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for Texas Instruments ADS7828
|
||||
12-bit 8-channel ADC device.
|
||||
If you say yes here you get support for Texas Instruments ADS7828 and
|
||||
ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while
|
||||
it is 8-bit on ADS7830.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called ads7828.
|
||||
|
@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
|
||||
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
|
||||
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
|
||||
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
|
||||
obj-$(CONFIG_SENSORS_DS620) += ds620.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
|
@ -1,12 +1,14 @@
|
||||
/*
|
||||
* ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
|
||||
* ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
|
||||
* (C) 2007 EADS Astrium
|
||||
*
|
||||
* This driver is based on the lm75 and other lm_sensors/hwmon drivers
|
||||
*
|
||||
* Written by Steve Hardy <shardy@redhat.com>
|
||||
*
|
||||
* Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
|
||||
* ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
|
||||
*
|
||||
* For further information, see the Documentation/hwmon/ads7828 file.
|
||||
*
|
||||
* 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
|
||||
@ -23,63 +25,48 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_data/ads7828.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* The ADS7828 registers */
|
||||
#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
|
||||
#define ADS7828_NCH 8 /* 8 channels supported */
|
||||
#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
|
||||
#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
|
||||
#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
|
||||
#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
|
||||
#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
|
||||
#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
|
||||
#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
|
||||
#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
|
||||
#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
|
||||
#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */
|
||||
#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */
|
||||
|
||||
/* Addresses to scan */
|
||||
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
|
||||
I2C_CLIENT_END };
|
||||
/* List of supported devices */
|
||||
enum ads7828_chips { ads7828, ads7830 };
|
||||
|
||||
/* Module parameters */
|
||||
static bool se_input = 1; /* Default is SE, 0 == diff */
|
||||
static bool int_vref = 1; /* Default is internal ref ON */
|
||||
static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
|
||||
module_param(se_input, bool, S_IRUGO);
|
||||
module_param(int_vref, bool, S_IRUGO);
|
||||
module_param(vref_mv, int, S_IRUGO);
|
||||
|
||||
/* Global Variables */
|
||||
static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
|
||||
static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
|
||||
|
||||
/* Each client has this additional data */
|
||||
/* Client specific data */
|
||||
struct ads7828_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock; /* mutex protect updates */
|
||||
char valid; /* !=0 if following fields are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
|
||||
struct mutex update_lock; /* Mutex protecting updates */
|
||||
unsigned long last_updated; /* Last updated time (in jiffies) */
|
||||
u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
|
||||
bool valid; /* Validity flag */
|
||||
bool diff_input; /* Differential input */
|
||||
bool ext_vref; /* External voltage reference */
|
||||
unsigned int vref_mv; /* voltage reference value */
|
||||
u8 cmd_byte; /* Command byte without channel bits */
|
||||
unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
|
||||
s32 (*read_channel)(const struct i2c_client *client, u8 command);
|
||||
};
|
||||
|
||||
/* Function declaration - necessary due to function dependencies */
|
||||
static int ads7828_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info);
|
||||
static int ads7828_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id);
|
||||
|
||||
static inline u8 channel_cmd_byte(int ch)
|
||||
/* Command byte C2,C1,C0 - see datasheet */
|
||||
static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
|
||||
{
|
||||
/* cmd byte C2,C1,C0 - see datasheet */
|
||||
u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
|
||||
cmd |= ads7828_cmd_byte;
|
||||
return cmd;
|
||||
return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
|
||||
}
|
||||
|
||||
/* Update data for the device (all 8 channels) */
|
||||
@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
|
||||
dev_dbg(&client->dev, "Starting ads7828 update\n");
|
||||
|
||||
for (ch = 0; ch < ADS7828_NCH; ch++) {
|
||||
u8 cmd = channel_cmd_byte(ch);
|
||||
data->adc_input[ch] =
|
||||
i2c_smbus_read_word_swapped(client, cmd);
|
||||
u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
|
||||
data->adc_input[ch] = data->read_channel(client, cmd);
|
||||
}
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
data->valid = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
|
||||
}
|
||||
|
||||
/* sysfs callback function */
|
||||
static ssize_t show_in(struct device *dev, struct device_attribute *da,
|
||||
static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct ads7828_data *data = ads7828_update_device(dev);
|
||||
/* Print value (in mV as specified in sysfs-interface documentation) */
|
||||
return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
|
||||
ads7828_lsb_resol)/1000);
|
||||
unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
|
||||
data->lsb_resol, 1000);
|
||||
|
||||
return sprintf(buf, "%d\n", value);
|
||||
}
|
||||
|
||||
#define in_reg(offset)\
|
||||
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
|
||||
NULL, offset)
|
||||
|
||||
in_reg(0);
|
||||
in_reg(1);
|
||||
in_reg(2);
|
||||
in_reg(3);
|
||||
in_reg(4);
|
||||
in_reg(5);
|
||||
in_reg(6);
|
||||
in_reg(7);
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
|
||||
static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
|
||||
static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
|
||||
static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
|
||||
static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
|
||||
|
||||
static struct attribute *ads7828_attributes[] = {
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = {
|
||||
static int ads7828_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ads7828_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ads7828_id[] = {
|
||||
{ "ads7828", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads7828_id);
|
||||
|
||||
/* This is the driver that will be inserted */
|
||||
static struct i2c_driver ads7828_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "ads7828",
|
||||
},
|
||||
.probe = ads7828_probe,
|
||||
.remove = ads7828_remove,
|
||||
.id_table = ads7828_id,
|
||||
.detect = ads7828_detect,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int ads7828_detect(struct i2c_client *client,
|
||||
struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = client->adapter;
|
||||
int ch;
|
||||
|
||||
/* Check we have a valid client */
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Now, we do the remaining detection. There is no identification
|
||||
* dedicated register so attempt to sanity check using knowledge of
|
||||
* the chip
|
||||
* - Read from the 8 channel addresses
|
||||
* - Check the top 4 bits of each result are not set (12 data bits)
|
||||
*/
|
||||
for (ch = 0; ch < ADS7828_NCH; ch++) {
|
||||
u16 in_data;
|
||||
u8 cmd = channel_cmd_byte(ch);
|
||||
in_data = i2c_smbus_read_word_swapped(client, cmd);
|
||||
if (in_data & 0xF000) {
|
||||
pr_debug("%s : Doesn't look like an ads7828 device\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client,
|
||||
static int ads7828_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct ads7828_platform_data *pdata = client->dev.platform_data;
|
||||
struct ads7828_data *data;
|
||||
int err;
|
||||
|
||||
@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client,
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pdata) {
|
||||
data->diff_input = pdata->diff_input;
|
||||
data->ext_vref = pdata->ext_vref;
|
||||
if (data->ext_vref)
|
||||
data->vref_mv = pdata->vref_mv;
|
||||
}
|
||||
|
||||
/* Bound Vref with min/max values if it was provided */
|
||||
if (data->vref_mv)
|
||||
data->vref_mv = SENSORS_LIMIT(data->vref_mv,
|
||||
ADS7828_EXT_VREF_MV_MIN,
|
||||
ADS7828_EXT_VREF_MV_MAX);
|
||||
else
|
||||
data->vref_mv = ADS7828_INT_VREF_MV;
|
||||
|
||||
/* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
|
||||
if (id->driver_data == ads7828) {
|
||||
data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
|
||||
data->read_channel = i2c_smbus_read_word_swapped;
|
||||
} else {
|
||||
data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256);
|
||||
data->read_channel = i2c_smbus_read_byte_data;
|
||||
}
|
||||
|
||||
data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
|
||||
if (!data->diff_input)
|
||||
data->cmd_byte |= ADS7828_CMD_SD_SE;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Register sysfs hooks */
|
||||
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
|
||||
if (err)
|
||||
return err;
|
||||
@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client,
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
err = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
error:
|
||||
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init sensors_ads7828_init(void)
|
||||
{
|
||||
/* Initialize the command byte according to module parameters */
|
||||
ads7828_cmd_byte = se_input ?
|
||||
ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
|
||||
ads7828_cmd_byte |= int_vref ?
|
||||
ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
|
||||
static const struct i2c_device_id ads7828_device_ids[] = {
|
||||
{ "ads7828", ads7828 },
|
||||
{ "ads7830", ads7830 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
|
||||
|
||||
/* Calculate the LSB resolution */
|
||||
ads7828_lsb_resol = (vref_mv*1000)/4096;
|
||||
static struct i2c_driver ads7828_driver = {
|
||||
.driver = {
|
||||
.name = "ads7828",
|
||||
},
|
||||
|
||||
return i2c_add_driver(&ads7828_driver);
|
||||
}
|
||||
.id_table = ads7828_device_ids,
|
||||
.probe = ads7828_probe,
|
||||
.remove = ads7828_remove,
|
||||
};
|
||||
|
||||
static void __exit sensors_ads7828_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ads7828_driver);
|
||||
}
|
||||
module_i2c_driver(ads7828_driver);
|
||||
|
||||
MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
|
||||
MODULE_DESCRIPTION("ADS7828 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(sensors_ads7828_init);
|
||||
module_exit(sensors_ads7828_exit);
|
||||
MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
|
||||
MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/msr.h>
|
||||
@ -197,14 +196,6 @@ struct tjmax {
|
||||
};
|
||||
|
||||
static const struct tjmax __cpuinitconst tjmax_table[] = {
|
||||
{ "CPU D410", 100000 },
|
||||
{ "CPU D425", 100000 },
|
||||
{ "CPU D510", 100000 },
|
||||
{ "CPU D525", 100000 },
|
||||
{ "CPU N450", 100000 },
|
||||
{ "CPU N455", 100000 },
|
||||
{ "CPU N470", 100000 },
|
||||
{ "CPU N475", 100000 },
|
||||
{ "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
|
||||
{ "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
|
||||
{ "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
|
||||
@ -212,6 +203,28 @@ static const struct tjmax __cpuinitconst tjmax_table[] = {
|
||||
{ "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
|
||||
};
|
||||
|
||||
struct tjmax_model {
|
||||
u8 model;
|
||||
u8 mask;
|
||||
int tjmax;
|
||||
};
|
||||
|
||||
#define ANY 0xff
|
||||
|
||||
static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
|
||||
{ 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */
|
||||
{ 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others
|
||||
* Note: Also matches 230 and 330,
|
||||
* which are covered by tjmax_table
|
||||
*/
|
||||
{ 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx)
|
||||
* Note: TjMax for E6xxT is 110C, but CPU type
|
||||
* is undetectable by software
|
||||
*/
|
||||
{ 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */
|
||||
{ 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
|
||||
};
|
||||
|
||||
static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||||
struct device *dev)
|
||||
{
|
||||
@ -222,7 +235,6 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||||
int usemsr_ee = 1;
|
||||
int err;
|
||||
u32 eax, edx;
|
||||
struct pci_dev *host_bridge;
|
||||
int i;
|
||||
|
||||
/* explicit tjmax table entries override heuristics */
|
||||
@ -231,32 +243,18 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
|
||||
return tjmax_table[i].tjmax;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
|
||||
const struct tjmax_model *tm = &tjmax_model_table[i];
|
||||
if (c->x86_model == tm->model &&
|
||||
(tm->mask == ANY || c->x86_mask == tm->mask))
|
||||
return tm->tjmax;
|
||||
}
|
||||
|
||||
/* Early chips have no MSR for TjMax */
|
||||
|
||||
if (c->x86_model == 0xf && c->x86_mask < 4)
|
||||
usemsr_ee = 0;
|
||||
|
||||
/* Atom CPUs */
|
||||
|
||||
if (c->x86_model == 0x1c || c->x86_model == 0x26
|
||||
|| c->x86_model == 0x27) {
|
||||
usemsr_ee = 0;
|
||||
|
||||
host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
|
||||
|
||||
if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL
|
||||
&& (host_bridge->device == 0xa000 /* NM10 based nettop */
|
||||
|| host_bridge->device == 0xa010)) /* NM10 based netbook */
|
||||
tjmax = 100000;
|
||||
else
|
||||
tjmax = 90000;
|
||||
|
||||
pci_dev_put(host_bridge);
|
||||
} else if (c->x86_model == 0x36) {
|
||||
usemsr_ee = 0;
|
||||
tjmax = 100000;
|
||||
}
|
||||
|
||||
if (c->x86_model > 0xe && usemsr_ee) {
|
||||
u8 platform_id;
|
||||
|
||||
|
@ -60,30 +60,17 @@ static inline int vbbat_reg_to_mV(int value)
|
||||
return DIV_ROUND_CLOSEST(value * 2500, 512);
|
||||
}
|
||||
|
||||
static int da9052_enable_vddout_channel(struct da9052 *da9052)
|
||||
static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret |= DA9052_ADCCONT_AUTOVDDEN;
|
||||
|
||||
return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
|
||||
return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
|
||||
DA9052_ADCCONT_AUTOVDDEN,
|
||||
DA9052_ADCCONT_AUTOVDDEN);
|
||||
}
|
||||
|
||||
static int da9052_disable_vddout_channel(struct da9052 *da9052)
|
||||
static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret &= ~DA9052_ADCCONT_AUTOVDDEN;
|
||||
|
||||
return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
|
||||
return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
|
||||
DA9052_ADCCONT_AUTOVDDEN, 0);
|
||||
}
|
||||
|
||||
static ssize_t da9052_read_vddout(struct device *dev,
|
||||
|
336
drivers/hwmon/da9055-hwmon.c
Normal file
336
drivers/hwmon/da9055-hwmon.c
Normal file
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* HWMON Driver for Dialog DA9055
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <linux/mfd/da9055/core.h>
|
||||
#include <linux/mfd/da9055/reg.h>
|
||||
|
||||
#define DA9055_ADCIN_DIV 102
|
||||
#define DA9055_VSYS_DIV 85
|
||||
|
||||
#define DA9055_ADC_VSYS 0
|
||||
#define DA9055_ADC_ADCIN1 1
|
||||
#define DA9055_ADC_ADCIN2 2
|
||||
#define DA9055_ADC_ADCIN3 3
|
||||
#define DA9055_ADC_TJUNC 4
|
||||
|
||||
struct da9055_hwmon {
|
||||
struct da9055 *da9055;
|
||||
struct device *class_device;
|
||||
struct mutex hwmon_lock;
|
||||
struct mutex irq_lock;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
static const char * const input_names[] = {
|
||||
[DA9055_ADC_VSYS] = "VSYS",
|
||||
[DA9055_ADC_ADCIN1] = "ADC IN1",
|
||||
[DA9055_ADC_ADCIN2] = "ADC IN2",
|
||||
[DA9055_ADC_ADCIN3] = "ADC IN3",
|
||||
[DA9055_ADC_TJUNC] = "CHIP TEMP",
|
||||
};
|
||||
|
||||
static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = {
|
||||
[DA9055_ADC_VSYS] = DA9055_ADC_MUX_VSYS,
|
||||
[DA9055_ADC_ADCIN1] = DA9055_ADC_MUX_ADCIN1,
|
||||
[DA9055_ADC_ADCIN2] = DA9055_ADC_MUX_ADCIN2,
|
||||
[DA9055_ADC_ADCIN3] = DA9055_ADC_MUX_ADCIN3,
|
||||
[DA9055_ADC_TJUNC] = DA9055_ADC_MUX_T_SENSE,
|
||||
};
|
||||
|
||||
static int da9055_adc_manual_read(struct da9055_hwmon *hwmon,
|
||||
unsigned char channel)
|
||||
{
|
||||
int ret;
|
||||
unsigned short calc_data;
|
||||
unsigned short data;
|
||||
unsigned char mux_sel;
|
||||
struct da9055 *da9055 = hwmon->da9055;
|
||||
|
||||
if (channel > DA9055_ADC_TJUNC)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&hwmon->irq_lock);
|
||||
|
||||
/* Selects desired MUX for manual conversion */
|
||||
mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV;
|
||||
|
||||
ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
/* Wait for an interrupt */
|
||||
if (!wait_for_completion_timeout(&hwmon->done,
|
||||
msecs_to_jiffies(500))) {
|
||||
dev_err(da9055->dev,
|
||||
"timeout waiting for ADC conversion interrupt\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
calc_data = (unsigned short)ret;
|
||||
data = calc_data << 2;
|
||||
|
||||
ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK);
|
||||
data |= calc_data;
|
||||
|
||||
ret = data;
|
||||
|
||||
err:
|
||||
mutex_unlock(&hwmon->irq_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
|
||||
{
|
||||
struct da9055_hwmon *hwmon = irq_data;
|
||||
|
||||
complete(&hwmon->done);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* Conversion function for VSYS and ADCINx */
|
||||
static inline int volt_reg_to_mV(int value, int channel)
|
||||
{
|
||||
if (channel == DA9055_ADC_VSYS)
|
||||
return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500;
|
||||
else
|
||||
return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV);
|
||||
}
|
||||
|
||||
static int da9055_enable_auto_mode(struct da9055 *da9055, int channel)
|
||||
{
|
||||
|
||||
return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel,
|
||||
1 << channel);
|
||||
|
||||
}
|
||||
|
||||
static int da9055_disable_auto_mode(struct da9055 *da9055, int channel)
|
||||
{
|
||||
|
||||
return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0);
|
||||
}
|
||||
|
||||
static ssize_t da9055_read_auto_ch(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
int ret, adc;
|
||||
int channel = to_sensor_dev_attr(devattr)->index;
|
||||
|
||||
mutex_lock(&hwmon->hwmon_lock);
|
||||
|
||||
ret = da9055_enable_auto_mode(hwmon->da9055, channel);
|
||||
if (ret < 0)
|
||||
goto hwmon_err;
|
||||
|
||||
usleep_range(10000, 10500);
|
||||
|
||||
adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel);
|
||||
if (adc < 0) {
|
||||
ret = adc;
|
||||
goto hwmon_err_release;
|
||||
}
|
||||
|
||||
ret = da9055_disable_auto_mode(hwmon->da9055, channel);
|
||||
if (ret < 0)
|
||||
goto hwmon_err;
|
||||
|
||||
mutex_unlock(&hwmon->hwmon_lock);
|
||||
|
||||
return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
|
||||
|
||||
hwmon_err_release:
|
||||
da9055_disable_auto_mode(hwmon->da9055, channel);
|
||||
hwmon_err:
|
||||
mutex_unlock(&hwmon->hwmon_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t da9055_read_tjunc(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
|
||||
int tjunc;
|
||||
int toffset;
|
||||
|
||||
tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC);
|
||||
if (tjunc < 0)
|
||||
return tjunc;
|
||||
|
||||
toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET);
|
||||
if (toffset < 0)
|
||||
return toffset;
|
||||
|
||||
/*
|
||||
* Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
|
||||
* T_OFFSET is a trim value used to improve accuracy of the result
|
||||
*/
|
||||
return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset)
|
||||
+ 3076332, 10000));
|
||||
}
|
||||
|
||||
static ssize_t da9055_hwmon_show_name(struct device *dev,
|
||||
struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
return sprintf(buf, "da9055-hwmon\n");
|
||||
}
|
||||
|
||||
static ssize_t show_label(struct device *dev,
|
||||
struct device_attribute *devattr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n",
|
||||
input_names[to_sensor_dev_attr(devattr)->index]);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL,
|
||||
DA9055_ADC_VSYS);
|
||||
static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
|
||||
DA9055_ADC_VSYS);
|
||||
static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL,
|
||||
DA9055_ADC_ADCIN1);
|
||||
static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL,
|
||||
DA9055_ADC_ADCIN1);
|
||||
static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL,
|
||||
DA9055_ADC_ADCIN2);
|
||||
static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL,
|
||||
DA9055_ADC_ADCIN2);
|
||||
static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL,
|
||||
DA9055_ADC_ADCIN3);
|
||||
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
|
||||
DA9055_ADC_ADCIN3);
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL,
|
||||
DA9055_ADC_TJUNC);
|
||||
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
|
||||
DA9055_ADC_TJUNC);
|
||||
|
||||
static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL);
|
||||
|
||||
static struct attribute *da9055_attr[] = {
|
||||
&dev_attr_name.attr,
|
||||
&sensor_dev_attr_in0_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in0_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in1_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in2_label.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_input.dev_attr.attr,
|
||||
&sensor_dev_attr_in3_label.dev_attr.attr,
|
||||
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_label.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr};
|
||||
|
||||
static int da9055_hwmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct da9055_hwmon *hwmon;
|
||||
int hwmon_irq, ret;
|
||||
|
||||
hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon),
|
||||
GFP_KERNEL);
|
||||
if (!hwmon)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&hwmon->hwmon_lock);
|
||||
mutex_init(&hwmon->irq_lock);
|
||||
|
||||
init_completion(&hwmon->done);
|
||||
hwmon->da9055 = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
platform_set_drvdata(pdev, hwmon);
|
||||
|
||||
hwmon_irq = platform_get_irq_byname(pdev, "HWMON");
|
||||
if (hwmon_irq < 0)
|
||||
return hwmon_irq;
|
||||
|
||||
hwmon_irq = regmap_irq_get_virq(hwmon->da9055->irq_data, hwmon_irq);
|
||||
if (hwmon_irq < 0)
|
||||
return hwmon_irq;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq,
|
||||
NULL, da9055_auxadc_irq,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
"adc-irq", hwmon);
|
||||
if (ret != 0) {
|
||||
dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hwmon->class_device = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(hwmon->class_device)) {
|
||||
ret = PTR_ERR(hwmon->class_device);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da9055_hwmon_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9055_hwmon *hwmon = platform_get_drvdata(pdev);
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
|
||||
hwmon_device_unregister(hwmon->class_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9055_hwmon_driver = {
|
||||
.probe = da9055_hwmon_probe,
|
||||
.remove = da9055_hwmon_remove,
|
||||
.driver = {
|
||||
.name = "da9055-hwmon",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(da9055_hwmon_driver);
|
||||
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
||||
MODULE_DESCRIPTION("DA9055 HWMON driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:da9055-hwmon");
|
@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
|
||||
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Family 16h Northbridge's function 4 PCI ID */
|
||||
#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
|
||||
|
||||
/* D18F3 */
|
||||
#define REG_NORTHBRIDGE_CAP 0xe8
|
||||
|
||||
@ -248,6 +251,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev)
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
|
||||
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
|
||||
|
@ -302,19 +302,8 @@ static struct i2c_driver ina2xx_driver = {
|
||||
.id_table = ina2xx_id,
|
||||
};
|
||||
|
||||
static int __init ina2xx_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ina2xx_driver);
|
||||
}
|
||||
|
||||
static void __exit ina2xx_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ina2xx_driver);
|
||||
}
|
||||
module_i2c_driver(ina2xx_driver);
|
||||
|
||||
MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
|
||||
MODULE_DESCRIPTION("ina2xx driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ina2xx_init);
|
||||
module_exit(ina2xx_exit);
|
||||
|
29
include/linux/platform_data/ads7828.h
Normal file
29
include/linux/platform_data/ads7828.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* TI ADS7828 A/D Converter platform data definition
|
||||
*
|
||||
* Copyright (c) 2012 Savoir-faire Linux Inc.
|
||||
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
*
|
||||
* For further information, see the Documentation/hwmon/ads7828 file.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _PDATA_ADS7828_H
|
||||
#define _PDATA_ADS7828_H
|
||||
|
||||
/**
|
||||
* struct ads7828_platform_data - optional ADS7828 connectivity info
|
||||
* @diff_input: Differential input mode.
|
||||
* @ext_vref: Use an external voltage reference.
|
||||
* @vref_mv: Voltage reference value, if external.
|
||||
*/
|
||||
struct ads7828_platform_data {
|
||||
bool diff_input;
|
||||
bool ext_vref;
|
||||
unsigned int vref_mv;
|
||||
};
|
||||
|
||||
#endif /* _PDATA_ADS7828_H */
|
Loading…
Reference in New Issue
Block a user