Commit b20f9e5b authored by Linus Torvalds's avatar Linus Torvalds

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

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/staging: (24 commits)
  hwmon: lis3: Release resources in case of failure
  hwmon: lis3: Short explanations of platform data fields
  hwmon: lis3: Enhance lis3 selftest with IRQ line test
  hwmon: lis3: use block read to access data registers
  hwmon: lis3: Adjust fuzziness for 8 bit device
  hwmon: lis3: New parameters to platform data
  hwmon: lis3: restore axis enabled bits
  hwmon: lis3: Power on corrections
  hwmon: lis3: Update coordinates at polled device open
  hwmon: lis3: Cleanup interrupt handling
  hwmon: lis3: regulator control
  hwmon: lis3: pm_runtime support
  Kirkwood: add fan support for Network Space Max v2
  hwmon: add generic GPIO fan driver
  hwmon: (coretemp) fix reading of microcode revision (v2)
  hwmon: ({core, pkg, via-cpu}temp) remove unnecessary CONFIG_HOTPLUG_CPU ifdefs
  hwmon: (pkgtemp) align driver initialization style with coretemp
  hwmon: LTC4261 Hardware monitoring driver
  hwmon: (lis3) add axes module parameter for custom axis-mapping
  hwmon: (hp_accel) Add HP Mini 510x family support
  ...
parents 52605627 b11e7b3f
Kernel driver ltc4261
=====================
Supported chips:
* Linear Technology LTC4261
Prefix: 'ltc4261'
Addresses scanned: -
Datasheet:
http://cds.linear.com/docs/Datasheet/42612fb.pdf
Author: Guenter Roeck <guenter.roeck@ericsson.com>
Description
-----------
The LTC4261/LTC4261-2 negative voltage Hot Swap controllers allow a board
to be safely inserted and removed from a live backplane.
Usage Notes
-----------
This driver does not probe for LTC4261 devices, since there is no register
which can be safely used to identify the chip. You will have to instantiate
the devices explicitly.
Example: the following will load the driver for an LTC4261 at address 0x10
on I2C bus #1:
$ modprobe ltc4261
$ echo ltc4261 0x10 > /sys/bus/i2c/devices/i2c-1/new_device
Sysfs entries
-------------
Voltage readings provided by this driver are reported as obtained from the ADC
registers. If a set of voltage divider resistors is installed, calculate the
real voltage by multiplying the reported value with (R1+R2)/R2, where R1 is the
value of the divider resistor against the measured voltage and R2 is the value
of the divider resistor against Ground.
Current reading provided by this driver is reported as obtained from the ADC
Current Sense register. The reported value assumes that a 1 mOhm sense resistor
is installed. If a different sense resistor is installed, calculate the real
current by dividing the reported value by the sense resistor value in mOhm.
The chip has two voltage sensors, but only one set of voltage alarm status bits.
In many many designs, those alarms are associated with the ADIN2 sensor, due to
the proximity of the ADIN2 pin to the OV pin. ADIN2 is, however, not available
on all chip variants. To ensure that the alarm condition is reported to the user,
report it with both voltage sensors.
in1_input ADIN2 voltage (mV)
in1_min_alarm ADIN/ADIN2 Undervoltage alarm
in1_max_alarm ADIN/ADIN2 Overvoltage alarm
in2_input ADIN voltage (mV)
in2_min_alarm ADIN/ADIN2 Undervoltage alarm
in2_max_alarm ADIN/ADIN2 Overvoltage alarm
curr1_input SENSE current (mA)
curr1_alarm SENSE overcurrent alarm
......@@ -3765,6 +3765,13 @@ L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/sym53c8xx_2/
LTC4261 HARDWARE MONITOR DRIVER
M: Guenter Roeck <linux@roeck-us.net>
L: lm-sensors@lm-sensors.org
S: Maintained
F: Documentation/hwmon/ltc4261
F: drivers/hwmon/ltc4261.c
LTP (Linux Test Project)
M: Rishikesh K Rajak <risrajak@linux.vnet.ibm.com>
M: Garrett Cooper <yanegomi@gmail.com>
......
......@@ -30,6 +30,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/leds.h>
#include <linux/gpio-fan.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
......@@ -136,6 +137,46 @@ static struct platform_device netspace_v2_leds = {
},
};
/*****************************************************************************
* GPIO fan
****************************************************************************/
/* Designed for fan 40x40x16: ADDA AD0412LB-D50 6000rpm@12v */
static struct gpio_fan_speed netspace_max_v2_fan_speed[] = {
{ 0, 0 },
{ 1500, 15 },
{ 1700, 14 },
{ 1800, 13 },
{ 2100, 12 },
{ 3100, 11 },
{ 3300, 10 },
{ 4300, 9 },
{ 5500, 8 },
};
static unsigned netspace_max_v2_fan_ctrl[] = { 22, 7, 33, 23 };
static struct gpio_fan_alarm netspace_max_v2_fan_alarm = {
.gpio = 25,
.active_low = 1,
};
static struct gpio_fan_platform_data netspace_max_v2_fan_data = {
.num_ctrl = ARRAY_SIZE(netspace_max_v2_fan_ctrl),
.ctrl = netspace_max_v2_fan_ctrl,
.alarm = &netspace_max_v2_fan_alarm,
.num_speed = ARRAY_SIZE(netspace_max_v2_fan_speed),
.speed = netspace_max_v2_fan_speed,
};
static struct platform_device netspace_max_v2_gpio_fan = {
.name = "gpio-fan",
.id = -1,
.dev = {
.platform_data = &netspace_max_v2_fan_data,
},
};
/*****************************************************************************
* General Setup
****************************************************************************/
......@@ -205,6 +246,8 @@ static void __init netspace_v2_init(void)
platform_device_register(&netspace_v2_leds);
platform_device_register(&netspace_v2_gpio_leds);
platform_device_register(&netspace_v2_gpio_buttons);
if (machine_is_netspace_max_v2())
platform_device_register(&netspace_max_v2_gpio_fan);
if (gpio_request(NETSPACE_V2_GPIO_POWER_OFF, "power-off") == 0 &&
gpio_direction_output(NETSPACE_V2_GPIO_POWER_OFF, 0) == 0)
......
......@@ -399,6 +399,15 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
config SENSORS_GPIO_FAN
tristate "GPIO fan"
depends on GENERIC_GPIO
help
If you say yes here you get support for fans connected to GPIO lines.
This driver can also be built as a module. If so, the module
will be called gpio-fan.
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
depends on X86 && PCI && EXPERIMENTAL
......@@ -654,6 +663,17 @@ config SENSORS_LTC4245
This driver can also be built as a module. If so, the module will
be called ltc4245.
config SENSORS_LTC4261
tristate "Linear Technology LTC4261"
depends on I2C && EXPERIMENTAL
default n
help
If you say yes here you get support for Linear Technology LTC4261
Negative Voltage Hot Swap Controller I2C interface.
This driver can also be built as a module. If so, the module will
be called ltc4261.
config SENSORS_LM95241
tristate "National Semiconductor LM95241 sensor chip"
depends on I2C
......
......@@ -51,6 +51,7 @@ obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
......@@ -79,6 +80,7 @@ obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_LM95241) += lm95241.o
obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
......
......@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
......@@ -280,11 +279,9 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
case 0x1a:
dev_warn(dev, "TjMax is assumed as 100 C!\n");
return 100000;
break;
case 0x17:
case 0x1c: /* Atom CPUs */
return adjust_tjmax(c, id, dev);
break;
default:
dev_warn(dev, "CPU (model=0x%x) is not supported yet,"
" using default TjMax of 100C.\n", c->x86_model);
......@@ -292,6 +289,15 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
}
}
static void __devinit get_ucode_rev_on_cpu(void *edx)
{
u32 eax;
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
sync_core();
rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
}
static int __devinit coretemp_probe(struct platform_device *pdev)
{
struct coretemp_data *data;
......@@ -327,8 +333,15 @@ static int __devinit coretemp_probe(struct platform_device *pdev)
if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
/* check for microcode update */
rdmsr_on_cpu(data->id, MSR_IA32_UCODE_REV, &eax, &edx);
if (edx < 0x39) {
err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
&edx, 1);
if (err) {
dev_err(&pdev->dev,
"Cannot determine microcode revision of "
"CPU#%u (%d)!\n", data->id, err);
err = -ENODEV;
goto exit_free;
} else if (edx < 0x39) {
err = -ENODEV;
dev_err(&pdev->dev,
"Errata AE18 not fixed, update BIOS or "
......@@ -490,7 +503,7 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
return err;
}
static void coretemp_device_remove(unsigned int cpu)
static void __cpuinit coretemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p;
unsigned int i;
......@@ -569,9 +582,8 @@ static int __init coretemp_init(void)
static void __exit coretemp_exit(void)
{
struct pdev_entry *p, *n;
#ifdef CONFIG_HOTPLUG_CPU
unregister_hotcpu_notifier(&coretemp_cpu_notifier);
#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
......
This diff is collapsed.
......@@ -146,7 +146,7 @@ int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
{
lis3_dev.ac = *((struct axis_conversion *)dmi->driver_data);
lis3_dev.ac = *((union axis_conversion *)dmi->driver_data);
printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident);
return 1;
......@@ -154,16 +154,19 @@ static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi)
/* Represents, for each axis seen by userspace, the corresponding hw axis (+1).
* If the value is negative, the opposite of the hw value is used. */
static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
static struct axis_conversion lis3lv02d_axis_xy_rotated_right = {2, -1, 3};
static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
#define DEFINE_CONV(name, x, y, z) \
static union axis_conversion lis3lv02d_axis_##name = \
{ .as_array = { x, y, z } }
DEFINE_CONV(normal, 1, 2, 3);
DEFINE_CONV(y_inverted, 1, -2, 3);
DEFINE_CONV(x_inverted, -1, 2, 3);
DEFINE_CONV(z_inverted, 1, 2, -3);
DEFINE_CONV(xy_swap, 2, 1, 3);
DEFINE_CONV(xy_rotated_left, -2, 1, 3);
DEFINE_CONV(xy_rotated_left_usd, -2, 1, -3);
DEFINE_CONV(xy_swap_inverted, -2, -1, 3);
DEFINE_CONV(xy_rotated_right, 2, -1, 3);
DEFINE_CONV(xy_swap_yz_inverted, 2, -1, -3);
#define AXIS_DMI_MATCH(_ident, _name, _axis) { \
.ident = _ident, \
......@@ -222,7 +225,7 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB452x", "HP ProBook 452", y_inverted),
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
AXIS_DMI_MATCH("Mini5102", "HP Mini 5102", xy_rotated_left_usd),
AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
{ NULL, }
/* Laptop models without axis info (yet):
* "NC6910" "HP Compaq 6910"
......@@ -299,7 +302,10 @@ static int lis3lv02d_add(struct acpi_device *device)
lis3lv02d_enum_resources(device);
/* If possible use a "standard" axes order */
if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
if (lis3_dev.ac.x && lis3_dev.ac.y && lis3_dev.ac.z) {
printk(KERN_INFO DRIVER_NAME ": Using custom axes %d,%d,%d\n",
lis3_dev.ac.x, lis3_dev.ac.y, lis3_dev.ac.z);
} else if (dmi_check_system(lis3lv02d_dmi_ids) == 0) {
printk(KERN_INFO DRIVER_NAME ": laptop model unknown, "
"using default axes configuration\n");
lis3_dev.ac = lis3lv02d_axis_normal;
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
*/
#include <linux/platform_device.h>
#include <linux/input-polldev.h>
#include <linux/regulator/consumer.h>
/*
* This driver tries to support the "digital" accelerometer chips from
......@@ -45,6 +46,7 @@ enum lis3_reg {
CTRL_REG1 = 0x20,
CTRL_REG2 = 0x21,
CTRL_REG3 = 0x22,
CTRL_REG4 = 0x23,
HP_FILTER_RESET = 0x23,
STATUS_REG = 0x27,
OUTX_L = 0x28,
......@@ -93,6 +95,7 @@ enum lis3lv02d_reg {
};
enum lis3_who_am_i {
WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
......@@ -118,6 +121,13 @@ enum lis3lv02d_ctrl1_8b {
CTRL1_DR = 0x80,
};
enum lis3lv02d_ctrl1_3dc {
CTRL1_ODR0 = 0x10,
CTRL1_ODR1 = 0x20,
CTRL1_ODR2 = 0x40,
CTRL1_ODR3 = 0x80,
};
enum lis3lv02d_ctrl2 {
CTRL2_DAS = 0x01,
CTRL2_SIM = 0x02,
......@@ -129,9 +139,18 @@ enum lis3lv02d_ctrl2 {
CTRL2_FS = 0x80, /* Full Scale selection */
};
enum lis3lv02d_ctrl4_3dc {
CTRL4_SIM = 0x01,
CTRL4_ST0 = 0x02,
CTRL4_ST1 = 0x04,
CTRL4_FS0 = 0x10,
CTRL4_FS1 = 0x20,
};
enum lis302d_ctrl2 {
HP_FF_WU2 = 0x08,
HP_FF_WU1 = 0x04,
CTRL2_BOOT_8B = 0x40,
};
enum lis3lv02d_ctrl3 {
......@@ -206,19 +225,33 @@ enum lis3lv02d_click_src_8b {
CLICK_IA = 0x40,
};
struct axis_conversion {
s8 x;
s8 y;
s8 z;
enum lis3lv02d_reg_state {
LIS3_REG_OFF = 0x00,
LIS3_REG_ON = 0x01,
};
union axis_conversion {
struct {
int x, y, z;
};
int as_array[3];
};
struct lis3lv02d {
void *bus_priv; /* used by the bus layer only */
struct device *pm_dev; /* for pm_runtime purposes */
int (*init) (struct lis3lv02d *lis3);
int (*write) (struct lis3lv02d *lis3, int reg, u8 val);
int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret);
int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret);
int (*reg_ctrl) (struct lis3lv02d *lis3, bool state);
int *odrs; /* Supported output data rates */
u8 *regs; /* Regs to store / restore */
int regs_size;
u8 *reg_cache;
bool regs_stored;
u8 odr_mask; /* ODR bit mask */
u8 whoami; /* indicates measurement precision */
s16 (*read_data) (struct lis3lv02d *lis3, int reg);
......@@ -231,14 +264,18 @@ struct lis3lv02d {
struct input_polled_dev *idev; /* input device */
struct platform_device *pdev; /* platform device */
struct regulator_bulk_data regulators[2];
atomic_t count; /* interrupt count after last read */
struct axis_conversion ac; /* hw -> logical axis */
union axis_conversion ac; /* hw -> logical axis */
int mapped_btns[3];
u32 irq; /* IRQ number */
struct fasync_struct *async_queue; /* queue for the misc device */
wait_queue_head_t misc_wait; /* Wait queue for the misc device */
unsigned long misc_opened; /* bit0: whether the device is open */
int data_ready_count[2];
atomic_t wake_thread;
unsigned char irq_cfg;
struct lis3lv02d_platform_data *pdata; /* for passing board config */
struct mutex mutex; /* Serialize poll and selftest */
......
......@@ -29,10 +29,30 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include "lis3lv02d.h"
#define DRV_NAME "lis3lv02d_i2c"
static const char reg_vdd[] = "Vdd";
static const char reg_vdd_io[] = "Vdd_IO";
static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state)
{
int ret;
if (state == LIS3_REG_OFF) {
ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators),
lis3->regulators);
} else {
ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators),
lis3->regulators);
/* Chip needs time to wakeup. Not mentioned in datasheet */
usleep_range(10000, 20000);
}
return ret;
}
static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value)
{
struct i2c_client *c = lis3->bus_priv;
......@@ -46,24 +66,38 @@ static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v)
return 0;
}
static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len,
u8 *v)
{
struct i2c_client *c = lis3->bus_priv;
reg |= (1 << 7); /* 7th bit enables address auto incrementation */
return i2c_smbus_read_i2c_block_data(c, reg, len, v);
}
static int lis3_i2c_init(struct lis3lv02d *lis3)
{
u8 reg;
int ret;
if (lis3->reg_ctrl)
lis3_reg_ctrl(lis3, LIS3_REG_ON);
lis3->read(lis3, WHO_AM_I, &reg);
if (reg != lis3->whoami)
printk(KERN_ERR "lis3: power on failure\n");
/* power up the device */
ret = lis3->read(lis3, CTRL_REG1, &reg);
if (ret < 0)
return ret;
reg |= CTRL1_PD0;
reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
return lis3->write(lis3, CTRL_REG1, reg);
}
/* Default axis mapping but it can be overwritten by platform data */
static struct axis_conversion lis3lv02d_axis_map = { LIS3_DEV_X,
LIS3_DEV_Y,
LIS3_DEV_Z };
static union axis_conversion lis3lv02d_axis_map =
{ .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
......@@ -72,6 +106,15 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
if (pdata) {
/* Regulator control is optional */
if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL)
lis3_dev.reg_ctrl = lis3_reg_ctrl;
if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
(i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_I2C_BLOCK)))
lis3_dev.blkread = lis3_i2c_blockread;
if (pdata->axis_x)
lis3lv02d_axis_map.x = pdata->axis_x;
......@@ -88,6 +131,16 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
goto fail;
}
if (lis3_dev.reg_ctrl) {
lis3_dev.regulators[0].supply = reg_vdd;
lis3_dev.regulators[1].supply = reg_vdd_io;
ret = regulator_bulk_get(&client->dev,
ARRAY_SIZE(lis3_dev.regulators),
lis3_dev.regulators);
if (ret < 0)
goto fail;
}
lis3_dev.pdata = pdata;
lis3_dev.bus_priv = client;
lis3_dev.init = lis3_i2c_init;
......@@ -95,10 +148,24 @@ static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
lis3_dev.write = lis3_i2c_write;
lis3_dev.irq = client->irq;
lis3_dev.ac = lis3lv02d_axis_map;
lis3_dev.pm_dev = &client->dev;
i2c_set_clientdata(client, &lis3_dev);
/* Provide power over the init call */
if (lis3_dev.reg_ctrl)
lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON);
ret = lis3lv02d_init_device(&lis3_dev);
if (lis3_dev.reg_ctrl)
lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF);
if (ret == 0)
return 0;
fail:
if (pdata && pdata->release_resources)
pdata->release_resources();
return ret;
}
......@@ -111,14 +178,18 @@ static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client)
pdata->release_resources();
lis3lv02d_joystick_disable();
lis3lv02d_poweroff(lis3);
lis3lv02d_remove_fs(&lis3_dev);
return lis3lv02d_remove_fs(&lis3_dev);
if (lis3_dev.reg_ctrl)
regulator_bulk_free(ARRAY_SIZE(lis3->regulators),
lis3_dev.regulators);
return 0;
}
#ifdef CONFIG_PM
static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
static int lis3lv02d_i2c_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
......@@ -126,18 +197,21 @@ static int lis3lv02d_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
return 0;
}
static int lis3lv02d_i2c_resume(struct i2c_client *client)
static int lis3lv02d_i2c_resume(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
if (!lis3->pdata || !lis3->pdata->wakeup_flags)
/*
* pm_runtime documentation says that devices should always
* be powered on at resume. Pm_runtime turns them off after system
* wide resume is complete.
*/
if (!lis3->pdata || !lis3->pdata->wakeup_flags ||
pm_runtime_suspended(dev))
lis3lv02d_poweron(lis3);
return 0;
}
static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
{
lis3lv02d_i2c_suspend(client, PMSG_SUSPEND);
return 0;
}
#else
#define lis3lv02d_i2c_suspend NULL
......@@ -145,6 +219,24 @@ static void lis3lv02d_i2c_shutdown(struct i2c_client *client)
#define lis3lv02d_i2c_shutdown NULL
#endif
static int lis3_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
lis3lv02d_poweroff(lis3);
return 0;
}
static int lis3_i2c_runtime_resume(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct lis3lv02d *lis3 = i2c_get_clientdata(client);
lis3lv02d_poweron(lis3);
return 0;
}
static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", 0 },
{}
......@@ -152,14 +244,20 @@ static const struct i2c_device_id lis3lv02d_id[] = {
MODULE_DEVICE_TABLE(i2c, lis3lv02d_id);
static const struct dev_pm_ops lis3_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend,
lis3lv02d_i2c_resume)
SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend,
lis3_i2c_runtime_resume,
NULL)
};
static struct i2c_driver lis3lv02d_i2c_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &lis3_pm_ops,
},
.suspend = lis3lv02d_i2c_suspend,
.shutdown = lis3lv02d_i2c_shutdown,
.resume = lis3lv02d_i2c_resume,
.probe = lis3lv02d_i2c_probe,
.remove = __devexit_p(lis3lv02d_i2c_remove),
.id_table = lis3lv02d_id,
......
......@@ -50,11 +50,12 @@ static int lis3_spi_init(struct lis3lv02d *lis3)
if (ret < 0)
return ret;
reg |= CTRL1_PD0;
reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
return lis3->write(lis3, CTRL_REG1, reg);
}
static struct axis_conversion lis3lv02d_axis_normal = { 1, 2, 3 };
static union axis_conversion lis3lv02d_axis_normal =
{ .as_array = { 1, 2, 3 } };
static int __devinit lis302dl_spi_probe(struct spi_device *spi)
{
......
/*
* Driver for Linear Technology LTC4261 I2C Negative Voltage Hot Swap Controller
*
* Copyright (C) 2010 Ericsson AB.
*
* Derived from:
*
* Driver for Linear Technology LTC4245 I2C Multiple Supply Hot Swap Controller
* Copyright (C) 2008 Ira W. Snyder <iws@ovro.caltech.edu>
*
* Datasheet: http://cds.linear.com/docs/Datasheet/42612fb.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/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
/* chip registers */
#define LTC4261_STATUS 0x00 /* readonly */
#define LTC4261_FAULT 0x01
#define LTC4261_ALERT 0x02
#define LTC4261_CONTROL 0x03
#define LTC4261_SENSE_H 0x04
#define LTC4261_SENSE_L 0x05
#define LTC4261_ADIN2_H 0x06
#define LTC4261_ADIN2_L 0x07
#define LTC4261_ADIN_H 0x08
#define LTC4261_ADIN_L 0x09
/*
* Fault register bits
*/
#define FAULT_OV (1<<0)
#define FAULT_UV (1<<1)
#define FAULT_OC (1<<2)
struct ltc4261_data {
struct device *hwmon_dev;
struct mutex update_lock;
bool valid;
unsigned long last_updated; /* in jiffies */
/* Registers */
u8 regs[10];
};
static struct ltc4261_data *ltc4261_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ltc4261_data *data = i2c_get_clientdata(client);
struct ltc4261_data *ret = data;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ / 4) || !data->valid) {
int i;
/* Read registers -- 0x00 to 0x09 */
for (i = 0; i < ARRAY_SIZE(data->regs); i++) {
int val;
val = i2c_smbus_read_byte_data(client, i);
if (unlikely(val < 0)) {
dev_dbg(dev,
"Failed to read ADC value: error %d",
val);
ret = ERR_PTR(val);
goto abort;
}
data->regs[i] = val;
}
data->last_updated = jiffies;
data->valid = 1;
}
abort:
mutex_unlock(&data->update_lock);
return ret;
}
/* Return the voltage from the given register in mV or mA */
static int ltc4261_get_value(struct ltc4261_data *data, u8 reg)
{
u32 val;
val = (data->regs[reg] << 2) + (data->regs[reg + 1] >> 6);
switch (reg) {
case LTC4261_ADIN_H:
case LTC4261_ADIN2_H:
/* 2.5mV resolution. Convert to mV. */
val = val * 25 / 10;
break;
case LTC4261_SENSE_H:
/*
* 62.5uV resolution. Convert to current as measured with
* an 1 mOhm sense resistor, in mA. If a different sense
* resistor is installed, calculate the actual current by
* dividing the reported current by the sense resistor value
* in mOhm.
*/
val = val * 625 / 10;
break;
default:
/* If we get here, the developer messed up */
WARN_ON_ONCE(1);
val = 0;
break;
}
return val;
}
static ssize_t ltc4261_show_value(struct device *dev,
struct device_attribute *da, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ltc4261_data *data = ltc4261_update_device(dev);
int value;
if (IS_ERR(data))
return PTR_ERR(data);
value = ltc4261_get_value(data, attr->index);
return snprintf(buf, PAGE_SIZE, "%d\n", value);
}
static ssize_t ltc4261_show_bool(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);
struct ltc4261_data *data = ltc4261_update_device(dev);
u8 fault;
if (IS_ERR(data))
return PTR_ERR(data);
fault = data->regs[LTC4261_FAULT] & attr->index;
if (fault) /* Clear reported faults in chip register */
i2c_smbus_write_byte_data(client, LTC4261_FAULT, ~fault);
return snprintf(buf, PAGE_SIZE, "%d\n", fault ? 1 : 0);
}
/*
* These macros are used below in constructing device attribute objects
* for use with sysfs_create_group() to make a sysfs device file
* for each register.
*/
#define LTC4261_VALUE(name, ltc4261_cmd_idx) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
ltc4261_show_value, NULL, ltc4261_cmd_idx)
#define LTC4261_BOOL(name, mask) \
static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
ltc4261_show_bool, NULL, (mask))
/*
* Input voltages.
*/
LTC4261_VALUE(in1_input, LTC4261_ADIN_H);
LTC4261_VALUE(in2_input, LTC4261_ADIN2_H);
/*
* Voltage alarms. The chip has only one set of voltage alarm status bits,
* triggered by input voltage alarms. In many designs, those alarms are
* associated with the ADIN2 sensor, due to the proximity of the ADIN2 pin
* to the OV pin. ADIN2 is, however, not available on all chip variants.
* To ensure that the alarm condition is reported to the user, report it
* with both voltage sensors.
*/
LTC4261_BOOL(in1_min_alarm, FAULT_UV);
LTC4261_BOOL(in1_max_alarm, FAULT_OV);
LTC4261_BOOL(in2_min_alarm, FAULT_UV);
LTC4261_BOOL(in2_max_alarm, FAULT_OV);
/* Currents (via sense resistor) */
LTC4261_VALUE(curr1_input, LTC4261_SENSE_H);
/* Overcurrent alarm */
LTC4261_BOOL(curr1_max_alarm, FAULT_OC);
static struct attribute *ltc4261_attributes[] = {
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in1_min_alarm.dev_attr.attr,
&sensor_dev_attr_in1_max_alarm.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in2_min_alarm.dev_attr.attr,
&sensor_dev_attr_in2_max_alarm.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_curr1_max_alarm.dev_attr.attr,
NULL,
};
static const struct attribute_group ltc4261_group = {
.attrs = ltc4261_attributes,
};
static int ltc4261_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = client->adapter;
struct ltc4261_data *data;
int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
if (i2c_smbus_read_byte_data(client, LTC4261_STATUS) < 0) {
dev_err(&client->dev, "Failed to read register %d:%02x:%02x\n",
adapter->id, client->addr, LTC4261_STATUS);
return -ENODEV;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto out_kzalloc;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
/* Clear faults */
i2c_smbus_write_byte_data(client, LTC4261_FAULT, 0x00);
/* Register sysfs hooks */
ret = sysfs_create_group(&client->dev.kobj, &ltc4261_group);
if (ret)
goto out_sysfs_create_group;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
goto out_hwmon_device_register;
}
return 0;
out_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
out_sysfs_create_group:
kfree(data);
out_kzalloc:
return ret;
}
static int ltc4261_remove(struct i2c_client *client)
{
struct ltc4261_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ltc4261_group);
kfree(data);
return 0;
}
static const struct i2c_device_id ltc4261_id[] = {
{"ltc4261", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ltc4261_id);
/* This is the driver that will be inserted */
static struct i2c_driver ltc4261_driver = {
.driver = {
.name = "ltc4261",
},
.probe = ltc4261_probe,
.remove = ltc4261_remove,
.id_table = ltc4261_id,
};
static int __init ltc4261_init(void)
{
return i2c_add_driver(&ltc4261_driver);
}
static void __exit ltc4261_exit(void)
{
i2c_del_driver(&ltc4261_driver);
}
MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
MODULE_DESCRIPTION("LTC4261 driver");
MODULE_LICENSE("GPL");
module_init(ltc4261_init);
module_exit(ltc4261_exit);
......@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
......@@ -35,6 +34,7 @@
#include <linux/cpu.h>
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/smp.h>
#define DRVNAME "pkgtemp"
......@@ -339,8 +339,7 @@ static int __cpuinit pkgtemp_device_add(unsigned int cpu)
return err;
}
#ifdef CONFIG_HOTPLUG_CPU
static void pkgtemp_device_remove(unsigned int cpu)
static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p;
unsigned int i;
......@@ -387,12 +386,10 @@ static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb,
static struct notifier_block pkgtemp_cpu_notifier __refdata = {
.notifier_call = pkgtemp_cpu_callback,
};
#endif /* !CONFIG_HOTPLUG_CPU */
static int __init pkgtemp_init(void)
{
int i, err = -ENODEV;
struct pdev_entry *p, *n;
/* quick check if we run Intel */
if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
......@@ -402,31 +399,23 @@ static int __init pkgtemp_init(void)
if (err)
goto exit;
for_each_online_cpu(i) {
err = pkgtemp_device_add(i);
if (err)
goto exit_devices_unreg;
}
for_each_online_cpu(i)
pkgtemp_device_add(i);
#ifndef CONFIG_HOTPLUG_CPU
if (list_empty(&pdev_list)) {
err = -ENODEV;
goto exit_driver_unreg;
}
#endif
#ifdef CONFIG_HOTPLUG_CPU
register_hotcpu_notifier(&pkgtemp_cpu_notifier);
#endif
return 0;
exit_devices_unreg:
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
list_del(&p->list);
kfree(p);
}
mutex_unlock(&pdev_list_mutex);
#ifndef CONFIG_HOTPLUG_CPU
exit_driver_unreg:
platform_driver_unregister(&pkgtemp_driver);
#endif
exit:
return err;
}
......@@ -434,9 +423,8 @@ static int __init pkgtemp_init(void)
static void __exit pkgtemp_exit(void)
{
struct pdev_entry *p, *n;
#ifdef CONFIG_HOTPLUG_CPU
unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
......
......@@ -22,10 +22,8 @@
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/sysfs.h>
#include <linux/hwmon-sysfs.h>
......@@ -237,8 +235,7 @@ static int __cpuinit via_cputemp_device_add(unsigned int cpu)
return err;
}
#ifdef CONFIG_HOTPLUG_CPU
static void via_cputemp_device_remove(unsigned int cpu)
static void __cpuinit via_cputemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p, *n;
mutex_lock(&pdev_list_mutex);
......@@ -272,7 +269,6 @@ static int __cpuinit via_cputemp_cpu_callback(struct notifier_block *nfb,
static struct notifier_block via_cputemp_cpu_notifier __refdata = {
.notifier_call = via_cputemp_cpu_callback,
};
#endif /* !CONFIG_HOTPLUG_CPU */
static int __init via_cputemp_init(void)
{
......@@ -313,9 +309,7 @@ static int __init via_cputemp_init(void)
goto exit_driver_unreg;
}
#ifdef CONFIG_HOTPLUG_CPU
register_hotcpu_notifier(&via_cputemp_cpu_notifier);
#endif
return 0;
exit_devices_unreg:
......@@ -335,9 +329,8 @@ static int __init via_cputemp_init(void)
static void __exit via_cputemp_exit(void)
{
struct pdev_entry *p, *n;
#ifdef CONFIG_HOTPLUG_CPU
unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
#endif
mutex_lock(&pdev_list_mutex);
list_for_each_entry_safe(p, n, &pdev_list, list) {
platform_device_unregister(p->pdev);
......
/*
* include/linux/gpio-fan.h
*
* Platform data structure for GPIO fan driver
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#ifndef __LINUX_GPIO_FAN_H
#define __LINUX_GPIO_FAN_H
struct gpio_fan_alarm {
unsigned gpio;
unsigned active_low;
};
struct gpio_fan_speed {
int rpm;
int ctrl_val;
};
struct gpio_fan_platform_data {
int num_ctrl;
unsigned *ctrl; /* fan control GPIOs. */
struct gpio_fan_alarm *alarm; /* fan alarm GPIO. */
/*
* Speed conversion array: rpm from/to GPIO bit field.
* This array _must_ be sorted in ascending rpm order.
*/
int num_speed;
struct gpio_fan_speed *speed;
};
#endif /* __LINUX_GPIO_FAN_H */
#ifndef __LIS3LV02D_H_
#define __LIS3LV02D_H_
/**
* struct lis3lv02d_platform_data - lis3 chip family platform data
* @click_flags: Click detection unit configuration
* @click_thresh_x: Click detection unit x axis threshold
* @click_thresh_y: Click detection unit y axis threshold
* @click_thresh_z: Click detection unit z axis threshold
* @click_time_limit: Click detection unit time parameter
* @click_latency: Click detection unit latency parameter
* @click_window: Click detection unit window parameter
* @irq_cfg: On chip irq source and type configuration (click /
* data available / wake up, open drain, polarity)
* @irq_flags1: Additional irq triggering flags for irq channel 0
* @irq_flags2: Additional irq triggering flags for irq channel 1
* @duration1: Wake up unit 1 duration parameter
* @duration2: Wake up unit 2 duration parameter
* @wakeup_flags: Wake up unit 1 flags
* @wakeup_thresh: Wake up unit 1 threshold value
* @wakeup_flags2: Wake up unit 2 flags
* @wakeup_thresh2: Wake up unit 2 threshold value
* @hipass_ctrl: High pass filter control (enable / disable, cut off
* frequency)
* @axis_x: Sensor orientation remapping for x-axis
* @axis_y: Sensor orientation remapping for y-axis
* @axis_z: Sensor orientation remapping for z-axis
* @driver_features: Enable bits for different features. Disabled by default
* @default_rate: Default sampling rate. 0 means reset default
* @setup_resources: Interrupt line setup call back function
* @release_resources: Interrupt line release call back function
* @st_min_limits[3]: Selftest acceptance minimum values
* @st_max_limits[3]: Selftest acceptance maximum values
* @irq2: Irq line 2 number
*
* Platform data is used to setup the sensor chip. Meaning of the different
* chip features can be found from the data sheet. It is publicly available
* at www.st.com web pages. Currently the platform data is used
* only for the 8 bit device. The 8 bit device has two wake up / free fall
* detection units and click detection unit. There are plenty of ways to
* configure the chip which makes is quite hard to explain deeper meaning of
* the fields here. Behaviour of the detection blocks varies heavily depending
* on the configuration. For example, interrupt detection block can use high
* pass filtered data which makes it react to the changes in the acceleration.
* Irq_flags can be used to enable interrupt detection on the both edges.
* With proper chip configuration this produces interrupt when some trigger
* starts and when it goes away.
*/
struct lis3lv02d_platform_data {
/* please note: the 'click' feature is only supported for
* LIS[32]02DL variants of the chip and will be ignored for
......@@ -36,7 +82,10 @@ struct lis3lv02d_platform_data {
#define LIS3_IRQ_OPEN_DRAIN (1 << 6)
#define LIS3_IRQ_ACTIVE_LOW (1 << 7)
unsigned char irq_cfg;
unsigned char irq_flags1; /* Additional irq edge / level flags */
unsigned char irq_flags2; /* Additional irq edge / level flags */
unsigned char duration1;
unsigned char duration2;
#define LIS3_WAKEUP_X_LO (1 << 0)
#define LIS3_WAKEUP_X_HI (1 << 1)
#define LIS3_WAKEUP_Y_LO (1 << 2)
......@@ -64,6 +113,10 @@ struct lis3lv02d_platform_data {
s8 axis_x;
s8 axis_y;
s8 axis_z;
#define LIS3_USE_REGULATOR_CTRL 0x01
#define LIS3_USE_BLOCK_READ 0x02
u16 driver_features;
int default_rate;
int (*setup_resources)(void);
int (*release_resources)(void);
/* Limits for selftest are specified in chip data sheet */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment