Index: linux-2.6.33/drivers/hwmon/Kconfig =================================================================== --- linux-2.6.33.orig/drivers/hwmon/Kconfig +++ linux-2.6.33/drivers/hwmon/Kconfig @@ -63,6 +63,13 @@ config SENSORS_EMC1403 Threshold values can be configured using sysfs. Data from the different diode are accessible via sysfs. +config SENSORS_MRST_ANALOG_ACCEL + tristate "Moorestown Analog Accelerometer" + depends on LNW_IPC + help + If you say yes here you get support for the Analog Accelerometer Devices + x y Z data can be accessed via sysfs. + config HWMON_DEBUG_CHIP bool "Hardware Monitoring Chip debugging messages" default n Index: linux-2.6.33/drivers/hwmon/Makefile =================================================================== --- linux-2.6.33.orig/drivers/hwmon/Makefile +++ linux-2.6.33/drivers/hwmon/Makefile @@ -103,6 +103,7 @@ obj-$(CONFIG_SENSORS_ISL29020) += isl290 obj-$(CONFIG_SENSORS_HMC6352) += hmc6352.o obj-$(CONFIG_SENSORS_LIS331DL) += lis331dl.o obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o +obj-$(CONFIG_SENSORS_MRST_ANALOG_ACCEL) += mrst_analog_accel.o ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG Index: linux-2.6.33/drivers/hwmon/mrst_analog_accel.c =================================================================== --- /dev/null +++ linux-2.6.33/drivers/hwmon/mrst_analog_accel.c @@ -0,0 +1,381 @@ +/* + * mrst_analog_accel.c - Intel analog accelerometer driver for Moorestown + * + * Copyright (C) 2009 Intel Corp + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * 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. + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Ramesh Agarwal"); +MODULE_DESCRIPTION("Intel Moorestown Analog Accelerometer Driver"); +MODULE_LICENSE("GPL v2"); + +/* PMIC ADC INTERRUPT REGISTERS */ +#define PMIC_ADC_ACC_REG_ADCINT 0x5F /*ADC interrupt register */ +#define PMIC_ADC_ACC_REG_MADCINT 0x60 /*ADC interrupt mask register */ + +/* PMIC ADC CONTROL REGISTERS */ +#define PMIC_ADC_ACC_REG_ADCCNTL1 0x61 /*ADC control register */ +#define PMIC_ADC_ACC_REG_ADCCNTL2 0x62 /*ADC gain regs channel 10-17 */ +#define PMIC_ADC_ACC_REG_ADCCNTL3 0x63 /*ADC gain regs channel 18-21 */ + +/* PMIC Data Register base */ +#define PMIC_ADC_DATA_REG_BASE 0x64 + +/* PMIC Channel Mapping Register base */ +#define PMIC_ADC_MAPPING_BASE 0xA4 + +/* Number of PMIC sample registers */ +#define PMIC_ADC_REG_MAX 32 /* Max no of available channel */ + +#define PMIC_ADC_X_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2)) +#define PMIC_ADC_X_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2) + 1) +#define PMIC_ADC_Y_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2) + 2) +#define PMIC_ADC_Y_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2) + 3) +#define PMIC_ADC_Z_REG_HIGH(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2) + 4) +#define PMIC_ADC_Z_REG_LOW(index) (PMIC_ADC_DATA_REG_BASE \ + + (index * 2) + 5) + +/* Number of registers to read at a time */ +#define REG_READ_PER_IPC 4 /* Read 4 at a time although the */ + /* IPC will support max 5 */ + +#define END_OF_CHANNEL_VALUE 0x1F /* Used to indicate the last */ + /* channel being used */ + +/* PMIC ADC channels for Accelero Meter */ +#define PMIC_ADC_ACC_ADC_ACC_CH14 0xE +#define PMIC_ADC_ACC_ADC_ACC_CH15 0xF +#define PMIC_ADC_ACC_ADC_ACC_CH16 0x10 + +static unsigned int mrst_analog_reg_idx; + +/* Use IPC to read the value of the register and display + * X value + */ +static ssize_t +mrst_analog_accel_x_axis_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int ret_val; + struct ipc_pmic_reg_data ipc_data; + + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.num_entries = 2; + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_X_REG_HIGH(mrst_analog_reg_idx); /* X Higher 8 bits */ + ipc_data.pmic_reg_data[1].register_address = + PMIC_ADC_X_REG_LOW(mrst_analog_reg_idx); /* X lower 3 bits */ + if (ipc_pmic_register_read(&ipc_data) != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC reg read using IPC failed\n"); + return -1; + } + ret_val = ipc_data.pmic_reg_data[0].value << 3; /* X higher 8 bits */ + /* lower 3 bits */ + ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07); + return sprintf(buf, "%d\n", ret_val); +} + +/* Use IPC to read the value of the register and display + * Y value */ +static ssize_t +mrst_analog_accel_y_axis_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int ret_val; + struct ipc_pmic_reg_data ipc_data; + + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.num_entries = 2; + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_Y_REG_HIGH(mrst_analog_reg_idx); /* Y higher 8 bits */ + ipc_data.pmic_reg_data[1].register_address = + PMIC_ADC_Y_REG_LOW(mrst_analog_reg_idx); /* Y lower 3 bits */ + if (ipc_pmic_register_read(&ipc_data) != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC reg read using IPC failed\n"); + return -1; + } + ret_val = ipc_data.pmic_reg_data[0].value << 3; /* Y higher 8 bits */ + /* Y lower 3 bits */ + ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07); + return sprintf(buf, "%d\n", ret_val); +} + +/* Use IPC to read the value of the register and display + * Z value */ +static ssize_t +mrst_analog_accel_z_axis_data_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int ret_val; + struct ipc_pmic_reg_data ipc_data; + + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.num_entries = 2; + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_Z_REG_HIGH(mrst_analog_reg_idx); + ipc_data.pmic_reg_data[1].register_address = + PMIC_ADC_Z_REG_LOW(mrst_analog_reg_idx); /* Z lower 3 bits */ + if (ipc_pmic_register_read(&ipc_data) != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC reg read using IPC failed\n"); + return -1; + } + ret_val = ipc_data.pmic_reg_data[0].value << 3; /* Z higher 8 bits */ + /* Z lower 3 bits */ + ret_val = ret_val | (ipc_data.pmic_reg_data[1].value & 0x07); + return sprintf(buf, "%d\n", ret_val); +} + + +static DEVICE_ATTR(acc_x_axis, S_IRUGO, + mrst_analog_accel_x_axis_data_show, NULL); +static DEVICE_ATTR(acc_y_axis, S_IRUGO, + mrst_analog_accel_y_axis_data_show, NULL); +static DEVICE_ATTR(acc_z_axis, S_IRUGO, + mrst_analog_accel_z_axis_data_show, NULL); + +static struct attribute *mid_att_acc[] = { + &dev_attr_acc_x_axis.attr, + &dev_attr_acc_y_axis.attr, + &dev_attr_acc_z_axis.attr, + NULL +}; + +static struct attribute_group m_analog_gr = { + .name = "mrst_analog_accel", + .attrs = mid_att_acc +}; + +static int +mrst_analog_accel_initialize(void) +{ + struct ipc_pmic_mod_reg_data ipc_mod_data; + struct ipc_pmic_reg_data ipc_data; + u8 retval = 0; + u8 mad_cntrl = 0; /* MADCINT register value */ + u8 adc_cntrl2 = 0; /* ADCCNTL2 register value */ + int i, j; + + /* Initialize the register index to use to be zero */ + mrst_analog_reg_idx = 0; + + /* check if the ADC is enabled or not + * Read ADCCNTL1 registers */ + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.num_entries = 1; + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_ACC_REG_ADCCNTL1; + ipc_data.pmic_reg_data[0].value = 0; + + retval = ipc_pmic_register_read(&ipc_data); + if (retval != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC register read failed\n"); + return retval; + } + + adc_cntrl2 = ipc_data.pmic_reg_data[0].value; + + if ((adc_cntrl2 >> 7) & 0x1) { + /* If the ADC is enabled find the set of registers to use + ** Loop through the channel mapping register to find out the + ** first free one + */ + for (i = 0; + (i < PMIC_ADC_REG_MAX) && (mrst_analog_reg_idx == 0); + i += REG_READ_PER_IPC) { + + ipc_data.num_entries = REG_READ_PER_IPC; + ipc_data.ioc = FALSE; /* No need to generate MSI */ + + /* Reading 4 regs at a time instead of reading each + * reg one by one since IPC is an expensive operation + */ + for (j = 0; j < REG_READ_PER_IPC; j++) { + ipc_data.pmic_reg_data[j].register_address = + PMIC_ADC_MAPPING_BASE + i + j; + ipc_data.pmic_reg_data[j].value = 0; + } + retval = ipc_pmic_register_read(&ipc_data); + if (retval != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC regs read failed\n"); + return retval; + } + for (j = 0; j < REG_READ_PER_IPC; j++) { + if (ipc_data.pmic_reg_data[j].value + == END_OF_CHANNEL_VALUE) { + mrst_analog_reg_idx = i + j; + break; + } + } + } + } + /* Check to see if there are enough registers to map the channel */ + if ((mrst_analog_reg_idx + 3) >= PMIC_ADC_REG_MAX) { + printk(KERN_ALERT + "\nmrst_analog_accel:Not enough regs to map the channels\n"); + return -1; + } + + /* Update the mapping registers for the accelerometer*/ + ipc_data.num_entries = 4; + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx; + ipc_data.pmic_reg_data[0].value = PMIC_ADC_ACC_ADC_ACC_CH14; + + ipc_data.pmic_reg_data[1].register_address = + PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 1; + ipc_data.pmic_reg_data[1].value = PMIC_ADC_ACC_ADC_ACC_CH15; + + ipc_data.pmic_reg_data[2].register_address = + PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 2; + ipc_data.pmic_reg_data[2].value = PMIC_ADC_ACC_ADC_ACC_CH16; + + ipc_data.pmic_reg_data[3].register_address = + PMIC_ADC_MAPPING_BASE + mrst_analog_reg_idx + 3 ; + ipc_data.pmic_reg_data[3].value = END_OF_CHANNEL_VALUE; + + retval = ipc_pmic_register_write(&ipc_data, FALSE); + if (retval != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC reg write failed\n"); + return retval; + } + + /* If the ADC was not enabled, enable it now */ + if (!(adc_cntrl2 >> 7) & 0x1) { + /* Mask the round robin completion interrupt */ + ipc_mod_data.ioc = FALSE; /* No need to generate MSI */ + ipc_mod_data.num_entries = 1; + mad_cntrl = 0x01; + ipc_mod_data.pmic_mod_reg_data[0].register_address = + PMIC_ADC_ACC_REG_MADCINT; + ipc_mod_data.pmic_mod_reg_data[0].value = mad_cntrl; + ipc_mod_data.pmic_mod_reg_data[0].bit_map = 0x01; + + retval = ipc_pmic_register_read_modify(&ipc_mod_data); + if (retval != 0) { + printk(KERN_ALERT + "\nmrst_analog_accel:PMIC reg modify failed\n"); + return retval; + } + + adc_cntrl2 = 0xc6; /*27ms delay,start round robin, + enable full power */ + ipc_data.ioc = FALSE; /* No need to generate MSI */ + ipc_data.num_entries = 1; + ipc_data.pmic_reg_data[0].register_address = + PMIC_ADC_ACC_REG_ADCCNTL1; + ipc_data.pmic_reg_data[0].value = adc_cntrl2; + retval = ipc_pmic_register_write(&ipc_data, FALSE); + if (retval != 0) + return retval; + } + return retval; +} + +static struct platform_device *mrst_analog_accel_pdev; +static struct device *mrst_analog_accel_hwmon; + +static int +mrst_analog_accel_unregister(void) +{ + + printk(KERN_ALERT "\nStart Exit\n\n"); + sysfs_remove_group(&mrst_analog_accel_hwmon->kobj, &m_analog_gr); + hwmon_device_unregister(mrst_analog_accel_hwmon); + platform_device_unregister(mrst_analog_accel_pdev); + printk(KERN_ALERT "\n\nEnd Exit\n"); + return 0; +} + + +static int __init +mrst_analog_accel_module_init(void) +{ + int retval = 0; + + mrst_analog_accel_pdev = + platform_device_register_simple("mrst_analog_accel", + 0, NULL, 0); + if (IS_ERR(mrst_analog_accel_pdev)) { + retval = PTR_ERR(mrst_analog_accel_pdev); + printk(KERN_ALERT + "\nmrst_analog_accel:Registration with the platform failed\n"); + goto accelero_reg_failed; + } + printk(KERN_ALERT + "\nmrst_analog_accel:Registered with the platform\n"); + + retval = mrst_analog_accel_initialize(); + if (retval == 0) { + retval = sysfs_create_group(&mrst_analog_accel_pdev->dev.kobj, + &m_analog_gr); + if (retval) { + printk(KERN_ALERT + "\nmrst_analog_accel:device_create_file 1 failed\n"); + goto accelero_reg_failed; + } + mrst_analog_accel_hwmon = + hwmon_device_register(&mrst_analog_accel_pdev->dev); + if (IS_ERR(mrst_analog_accel_hwmon)) { + retval = PTR_ERR(mrst_analog_accel_hwmon); + mrst_analog_accel_hwmon = NULL; + printk(KERN_ALERT + "\nmrst_analog_accel:Registration with hwmon failed\n"); + } + } else { + printk(KERN_ALERT + "\nmrst_analog_accel:Initialization failed: %d\n", retval); + } + +accelero_reg_failed: + return retval; +} + +static void __exit +mrst_analog_accel_module_exit(void) +{ + + mrst_analog_accel_unregister(); +} + +module_init(mrst_analog_accel_module_init); +module_exit(mrst_analog_accel_module_exit); Index: linux-2.6.33/drivers/hwmon/lis331dl.c =================================================================== --- linux-2.6.33.orig/drivers/hwmon/lis331dl.c +++ linux-2.6.33/drivers/hwmon/lis331dl.c @@ -186,33 +186,10 @@ invarg: return -EINVAL; } -static ssize_t reboot_mem_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct acclero_data *data = i2c_get_clientdata(client); - unsigned int ret_val, set_val; - unsigned long val; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - ret_val = i2c_smbus_read_byte_data(client, 0x21); - if (val == ACCEL_MEMORY_REBOOT) { - mutex_lock(&data->update_lock); - set_val = (ret_val | (1 << 6)); /* setting the 6th bit */ - i2c_write_current_data(client, 0x21, set_val); - mutex_unlock(&data->update_lock); - } else - return -EINVAL; - return count; -} - static DEVICE_ATTR(data_rate, S_IRUGO | S_IWUSR, data_rate_show, data_rate_store); static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, power_mode_show, power_mode_store); -static DEVICE_ATTR(reboot_mem, S_IWUSR, NULL, - reboot_mem_store); static DEVICE_ATTR(x, S_IRUGO, x_pos_show, NULL); static DEVICE_ATTR(y, S_IRUGO, y_pos_show, NULL); static DEVICE_ATTR(z, S_IRUGO, z_pos_show, NULL); @@ -221,7 +198,6 @@ static DEVICE_ATTR(curr_pos, S_IRUGO, xy static struct attribute *mid_att_acclero[] = { &dev_attr_data_rate.attr, &dev_attr_power_state.attr, - &dev_attr_reboot_mem.attr, &dev_attr_x.attr, &dev_attr_y.attr, &dev_attr_z.attr,