summaryrefslogtreecommitdiff
path: root/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch1836
1 files changed, 1836 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch
new file mode 100644
index 000000000..fce452451
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-netbook-2.6.33.2/linux-2.6.34-moorestown-sensor-driver-1.1.patch
@@ -0,0 +1,1836 @@
+From cffaf6b15ff40cfbeafd0d4728ba3a5a5fb6155f Mon Sep 17 00:00:00 2001
+From: Alan Olsen <alan.r.olsen@intel.com>
+Date: Thu, 15 Oct 2009 14:26:47 -0700
+Subject: [PATCH 062/104] Moorestown Sensor drivers v1.1 consolidated patch
+
+This patch contains the following patches:
+
+Alpha2-1.1-1-5-mrst-Sensors-ALS-Driver-for-Moorestown.patch
+
+ [PATCH] ALS Driver for Moorestown Sensors
+
+ This patch single patch for Alpha2:2.0. ALS driver will read
+ the latest Lux measurement based on the light brightness and
+ will report the LUX output through sysfs interface.
+
+ Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
+
+Alpha2-1.1-2-5-mrst-Sensors-Compass-Driver-for-Moorestown.patch
+
+ [PATCH] Compass Driver for Moorestown Sensors
+ This patch single patch for Alpha2:2.0.This driver will report
+ the heading values in degrees to the sysfs interface.The vlaues
+ returned are head . e.g. 245.6
+
+ Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
+
+Alpha2-1.1-3-5-mrst-Sensors-Accelerometer-Driver-for-Moorestown.patch
+
+ [PATCH] Accelerometer Driver for Moorestown Sensors
+
+ This patch single patch for Alpha2:2.0.Accelerometer driver will
+ read the x,y,z coordinate registers and provide the information to
+ user through sysfs interface.
+
+ Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
+
+Alpha2-1.1-4-5-mrst-Sensors-Vibrator-Driver-for-Moorestown.patch
+
+ [PATCH] Vibrator Driver for Moorestown Sensors
+
+ This patch single patch for Alpha2:2.0.Vibrator can be switched
+ on/off using sysfs interface.
+
+ Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
+
+Alpha2-1.1-5-5-mrst-Sensors-Thermal-Driver-for-Moorestown.patch
+
+ [PATCH] Thermal Driver for Moorestown Sensors
+
+ Moorestown Platform has EMC1403 chip which support three thermal
+ devices, one thermal zone is used by the EMC1403 chip itself and
+ second is used by processor and third one is used for platform
+ (skin temperature).Driver support poll and interrupt
+ mode,min/max/crit configuration can be done using sysfs interface.
+
+ The driver also support interrupt mode when the temperature crosses the
+ threshold configured value the min/max/crit. ALERT/THERM interrupt will
+ be triggered and driver register its callback with GPE driver, and send
+ the events to OSPM power management to take action. OSPM will take
+ action and set the new threshold values till it doesnot get ALERT/THERM
+ events.temp1 is used for configuring internal EMC1403 chip diode, temp2
+ is used to configure processor diode and temp3 is used to configure the
+ platform diode.
+
+ The interrupt mode code has dependency MRST PMIC_GPIO/MAX7315/OSPM.Flag
+ is added to differentiate the generic functionality of the driver with
+ moorestown specific.
+
+ Signed-off-by: Kalhan Trisal <kalhan.trisal at intel.com>
+
+Signed-off-by: Alan Olsen <alan.r.olsen@intel.com>
+---
+ drivers/hwmon/Kconfig | 35 ++
+ drivers/hwmon/Makefile | 4
+ drivers/hwmon/emc1403.c | 731 +++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/hwmon/hmc6352.c | 250 ++++++++++++++++
+ drivers/hwmon/isl29020.c | 248 +++++++++++++++
+ drivers/hwmon/lis331dl.c | 322 ++++++++++++++++++++
+ drivers/misc/Kconfig | 7
+ drivers/misc/Makefile | 1
+ drivers/misc/mrst_vib.c | 99 ++++++
+ 9 files changed, 1697 insertions(+)
+ create mode 100644 drivers/hwmon/emc1403.c
+ create mode 100644 drivers/hwmon/hmc6352.c
+ create mode 100644 drivers/hwmon/isl29020.c
+ create mode 100644 drivers/hwmon/lis331dl.c
+ create mode 100644 drivers/misc/mrst_vib.c
+
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -28,6 +28,41 @@ config HWMON_VID
+ tristate
+ default n
+
++config SENSORS_ISL29020
++ tristate "Intersil ISL29020 ALS"
++ depends on I2C_MRST
++ help
++ If you say yes here you get support for the ALS Devices
++ Ambient Light Sensor monitoring chip.
++ Range values can be configured using sysfs.
++ Lux Data are accessible via sysfs.
++
++config SENSORS_HMC6352
++ tristate "Honeywell HMC6352 compass"
++ depends on I2C_MRST
++ help
++ If you say yes here you get support for the Compass Devices
++ Device can be configured using sysfs.
++ heading data can be accessible via sysfs.
++
++config SENSORS_LIS331DL
++ tristate "STMicroeletronics LIS331DL three-axis digital accelerometer"
++ depends on I2C_MRST
++ help
++ If you say yes here you get support for the Accelerometer Devices
++ Device can be configured using sysfs.
++ x y Z data can be accessible via sysfs.
++
++config SENSORS_EMC1403
++ tristate "SMSC EMC1403 Thermal"
++ depends on I2C_MRST && GPE && GPIO_MAX7315 && MSTWN_POWER_MGMT
++ help
++ If you say yes here you get support for the SMSC Devices
++ EMC1403 temperature monitoring chip.
++
++ Threshold values can be configured using sysfs.
++ Data from the different diode are accessible via sysfs.
++
+ config HWMON_DEBUG_CHIP
+ bool "Hardware Monitoring Chip debugging messages"
+ default n
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -99,6 +99,10 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7
+ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
+ obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
+ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
++obj-$(CONFIG_SENSORS_ISL29020) += isl29020.o
++obj-$(CONFIG_SENSORS_HMC6352) += hmc6352.o
++obj-$(CONFIG_SENSORS_LIS331DL) += lis331dl.o
++obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
+
+ ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
+ EXTRA_CFLAGS += -DDEBUG
+--- /dev/null
++++ b/drivers/hwmon/emc1403.c
+@@ -0,0 +1,731 @@
++/*
++ * emc1403.c - SMSC Thermal Driver
++ *
++ * Copyright (C) 2008 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/interrupt.h>
++#include <linux/workqueue.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++#include <linux/gpe.h>
++#include <linux/intel_mid.h>
++
++
++MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
++MODULE_DESCRIPTION("emc1403 Thermal Driver");
++MODULE_LICENSE("GPL v2");
++
++/* To support the interrupt mechanism for moorestown interrupt flag is added
++ * If the flag is not enabled it support generic emc1403 chip */
++
++#if defined(CONFIG_GPIO_LNWPMIC) && defined(CONFIG_GPIO_MAX7315) \
++ && defined(CONFIG_MSTWN_POWER_MGMT)
++#define MOORESTOWN_INTERRUPT_ENABLE
++#endif
++
++/* Limit status reg Therm/High/Low/Fault*/
++static const u8 THM_STAT_REG_TEMP[] = { 0x37, 0x35, 0x36, 0x1B, 0x02};
++
++/* Channel diode temp set */
++static const u8 THM_CHAN_TEMP[] = { 0x10, 0x08, 0x04, 0x02, 0x01 };
++
++/* Therm Limit reg store values */
++static const u8 THM_LIMIT_REG_TEMP[] = { 0x05, 0x06, 0x07, 0x08, 0x15, 0x16,
++ 0x19, 0x1A, 0x20, 0x21 };
++
++/* DATA REGISTERS */
++static const u8 THM_REG_CURR_TEMP[] = { 0x00, 0x01, 0x23 };
++
++#define THERMAL_PID_REG 0xfd
++#define THERMAL_SMSC_ID_REG 0xfe
++#define THERMAL_REVISION_REG 0xff
++#define THERMAL_ADC_UPDATE_BUSY 0x80
++#define I2C_THERMAL_SLAVE_ADDR 0x4C
++#define TEMP1 1
++#define TEMP2 2
++#define TEMP3 4
++#define IRQ_TYPE_MASK (1 << 15)
++#define HIGH_EVENT 1
++#define LOW_EVENT 2
++#define THERM_EVENT 3
++#define FAULT_EVENT 4
++#define ALERT_EVENT 1
++#define POWER_STA_ENABLE 0
++#define POWER_STA_DISABLE 1
++#define INTERRUPT_MODE_ENABLE 0
++#define INTERRUPT_MODE_DISABLE 1
++
++struct thermal_data {
++ struct i2c_client *client;
++ struct device *hwmon_dev;
++ int therm_irq;
++ int alert_irq;
++ struct work_struct therm_handler;
++ struct work_struct alert_handler;
++};
++
++static unsigned int i2c_read_current_data(struct i2c_client *client, u8 reg)
++{
++ unsigned int ret_val;
++
++ ret_val = i2c_smbus_read_byte_data(client, reg);
++ return ret_val;
++}
++
++static unsigned int i2c_write_current_data(struct i2c_client *client,
++ unsigned int reg, unsigned int value)
++{
++ int ret_val;
++
++ ret_val = i2c_smbus_write_byte_data(client, reg, value);
++ return ret_val;
++}
++
++static int calculate_offset(int type, int temp_ofs)
++{
++ int offset = 0;
++
++ switch (type) {
++ case TEMP1:
++ if (temp_ofs == 0)
++ offset = 1;
++ else if (temp_ofs == 1)
++ offset = 0;
++ else if (temp_ofs == 2)
++ offset = 8;
++ break;
++ case TEMP2:
++ if (temp_ofs == 0)
++ offset = 3;
++ else if (temp_ofs == 1)
++ offset = 2;
++ else if (temp_ofs == 2)
++ offset = 6;
++ break;
++ case TEMP3:
++ if (temp_ofs == 0)
++ offset = 5;
++ else if (temp_ofs == 1)
++ offset = 4;
++ else if (temp_ofs == 2)
++ offset = 7;
++ break;
++ default:
++ offset = -1;
++ printk(KERN_WARNING "emc1403: Invalid arg \n");
++ break;
++ }
++ return offset;
++
++}
++
++#ifdef MOORESTOWN_INTERRUPT_ENABLE
++static void status_reg_read(struct i2c_client *client)
++{
++ i2c_read_current_data(client, 0x36);
++ i2c_read_current_data(client, 0x35);
++ i2c_read_current_data(client, 0x1B);
++}
++
++/* when the thermal governor takes action we unmask the bit
++ * if the temp is lower tham threshold values then no new event will
++ * be raised else if the current temperature is still high the interrupt
++ * will be sent again */
++
++static void reg_unmask_intr(struct i2c_client *client, int offset,
++ int value)
++{
++ u8 ret_val, set_mask, ret = 0, alert = 0;
++
++ ret_val = i2c_read_current_data(client, 0x1F);
++ if (offset == 6 || offset == 7 || offset == 8) {
++ ret = i2c_read_current_data(client, 0x37); /* Themal status */
++ } else if (offset == 2 || offset == 3) {
++ if (((ret_val >> 1) & 1)) {
++ set_mask = (ret_val & 0x05);
++ alert = 1;
++ }
++ } else if (offset == 4 || offset == 5) {
++ if (((ret_val >> 2) & 1)) {
++ set_mask = (ret_val & 0x03);
++ alert = 1;
++ }
++ } else if (offset == 0 || offset == 1) {
++ if (ret_val & 1) {
++ set_mask = (ret_val & 0x06);
++ alert = 1;
++ }
++ }
++ /* only rest set the mask for alert events */
++ if (alert == 1) {
++ status_reg_read(client);
++ i2c_write_current_data(client, 0x1F, set_mask);
++ }
++}
++#endif
++
++static ssize_t show_temp_auto_offset(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
++ int temp_index = s_attr->index;
++ int temp_ofs = s_attr->nr;
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val = 0;
++ int ret_offset = 0;
++
++ ret_offset = calculate_offset(temp_index, temp_ofs);
++ if (ret_offset != -1) {
++ ret_val = i2c_read_current_data(client,
++ THM_LIMIT_REG_TEMP[ret_offset]);
++ return sprintf(buf, "%d\n", ret_val);
++ } else {
++ return -EINVAL;
++ }
++}
++
++static ssize_t store_temp_auto_offset(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
++ int temp_index = s_attr->index;
++ int temp_ofs = s_attr->nr;
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val;
++ int ret_offset = 0;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++ ret_offset = calculate_offset(temp_index, temp_ofs);
++ if (ret_offset != -1) {
++ i2c_write_current_data(client,
++ THM_LIMIT_REG_TEMP[ret_offset], val);
++#ifdef MOORESTOWN_INTERRUPT_ENABLE
++ reg_unmask_intr(client, ret_offset, val);
++#endif
++ return count;
++ } else {
++ return -EINVAL;
++ }
++}
++
++static ssize_t show_temp_hyst(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, THM_LIMIT_REG_TEMP[9]);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t store_temp_hyst(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val = 0;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++ i2c_write_current_data(client, THM_LIMIT_REG_TEMP[9], val);
++ return count;
++}
++
++static ssize_t show_temp1_curr_temp(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[0]);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t show_temp2_curr_temp(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[1]);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t show_temp3_curr_temp(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[2]);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t show_status_reg(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val1, ret_val2, ret_val3, ret_val4;
++
++ ret_val1 = i2c_read_current_data(client, 0x1F);
++ ret_val2 = i2c_read_current_data(client, 0x35);
++ ret_val3 = i2c_read_current_data(client, 0x36);
++ ret_val4 = i2c_read_current_data(client, 0x37);
++ return sprintf(buf, "alarm=%x,High=%x,Low=%x,Therm=%x \n",
++ ret_val1, ret_val2, ret_val3, ret_val4);
++}
++
++static ssize_t show_power_state(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, 0x03);
++ ret_val = ret_val & 0x40;
++ if (ret_val == 0x40)
++ ret_val = 1;
++ return sprintf(buf, "%x", ret_val);
++}
++
++static ssize_t store_power_state(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val = 0;
++ char curr_val;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++
++ curr_val = i2c_read_current_data(client, 0x03);
++ if (val == POWER_STA_ENABLE)
++ curr_val = curr_val & 0xBF;
++ else if (val == POWER_STA_DISABLE)
++ curr_val = curr_val | 0x40;
++ else
++ return -EINVAL;
++ i2c_write_current_data(client, 0x03, curr_val);
++ return count;
++}
++
++static ssize_t show_mode(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_read_current_data(client, 0x03);
++ ret_val = ret_val & 0x80;
++ if (ret_val == 0x80)
++ ret_val = 1;
++ return sprintf(buf, "%x", ret_val);
++}
++
++static ssize_t store_mode(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val = 0;
++ char curr_val;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++
++ curr_val = i2c_read_current_data(client, 0x03);
++ if (val == INTERRUPT_MODE_ENABLE)
++ curr_val = curr_val & 0x7F;
++ else if (val == INTERRUPT_MODE_DISABLE)
++ curr_val = curr_val | 0x80;
++ else
++ return -EINVAL;
++ i2c_write_current_data(client, 0x03, curr_val);
++ return count;
++}
++
++static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 0, 1);
++static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 1, 1);
++static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 2, 1);
++static DEVICE_ATTR(temp1_curr, S_IRUGO, show_temp1_curr_temp, NULL);
++
++static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 0, 2);
++static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 1, 2);
++static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 2, 2);
++static DEVICE_ATTR(temp2_curr, S_IRUGO, show_temp2_curr_temp, NULL);
++
++static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 0, 4);
++static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 1, 4);
++static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR,
++ show_temp_auto_offset, store_temp_auto_offset, 2, 4);
++static DEVICE_ATTR(temp3_curr, S_IRUGO, show_temp3_curr_temp, NULL);
++
++static DEVICE_ATTR(hyster, S_IRUGO | S_IWUSR, show_temp_hyst, store_temp_hyst);
++static DEVICE_ATTR(status, S_IRUGO, show_status_reg, NULL);
++
++static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
++ show_power_state, store_power_state);
++static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, show_mode, store_mode);
++
++static struct attribute *mid_att_thermal[] = {
++ &sensor_dev_attr_temp1_min.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &dev_attr_temp1_curr.attr,
++ &sensor_dev_attr_temp2_min.dev_attr.attr,
++ &sensor_dev_attr_temp2_max.dev_attr.attr,
++ &sensor_dev_attr_temp2_crit.dev_attr.attr,
++ &dev_attr_temp2_curr.attr,
++ &sensor_dev_attr_temp3_min.dev_attr.attr,
++ &sensor_dev_attr_temp3_max.dev_attr.attr,
++ &sensor_dev_attr_temp3_crit.dev_attr.attr,
++ &dev_attr_temp3_curr.attr,
++ &dev_attr_hyster.attr,
++ &dev_attr_status.attr,
++ &dev_attr_power_state.attr,
++ &dev_attr_mode.attr,
++ NULL
++};
++
++static struct attribute_group m_thermal_gr = {
++ .name = "emc1403",
++ .attrs = mid_att_thermal
++};
++
++static void emc1403_set_default_config(struct i2c_client *client)
++{
++ i2c_smbus_write_byte_data(client, 0x03, 0x00);
++ i2c_smbus_write_byte_data(client, 0x04, 0x02);
++ i2c_smbus_write_byte_data(client, 0x22, 0x00);
++}
++
++#ifdef MOORESTOWN_INTERRUPT_ENABLE
++static irqreturn_t therm_interrupt_handler(int id, void *dev)
++{
++ struct thermal_data *data = (struct thermal_data *)dev;
++ schedule_work(&data->therm_handler);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t alert_interrupt_handler(int id, void *dev)
++{
++ struct thermal_data *data = (struct thermal_data *)dev;
++ schedule_work(&data->alert_handler);
++
++ return IRQ_HANDLED;
++}
++
++/* when the device raise the interrupt we mask the interrupt
++ * bit for that device as the status register is R-C
++ * so that till thermal governor doesnot take action we need
++ * not to send continuous events */
++
++static int interrupt_status(struct i2c_client *client, u8 diode_reg_val,
++ u8 *status, u8 event)
++{
++ u8 crit_st = 0, set_mask = 0;
++
++ set_mask = i2c_read_current_data(client, 0x1F);
++ if (diode_reg_val & THM_CHAN_TEMP[3]) {
++ set_mask = (set_mask | 0x02);
++ crit_st = (crit_st | 2);
++ }
++ if (diode_reg_val & THM_CHAN_TEMP[2]) {
++ set_mask = (set_mask | 0x04);
++ crit_st = (crit_st | 4);
++ }
++ if (diode_reg_val & THM_CHAN_TEMP[4]) {
++ set_mask = (set_mask | 0x01);
++ crit_st = (crit_st | 1);
++ }
++ if (event == ALERT_EVENT)
++ i2c_smbus_write_byte_data(client, 0x1F, set_mask);
++ *status = crit_st;
++ return 0;
++}
++
++static void ospm_event(int event_id, int sensor_id, int curr_temp)
++{
++ if (event_id == THERM_EVENT) {
++ printk(KERN_ALERT "emc1403: Sensor Id = %d crit event \
++ temp = %d \n", sensor_id, curr_temp);
++ ospm_generate_netlink_event(sensor_id,
++ OSPM_EVENT_THERMAL_CRITICAL);
++ }
++ if (event_id == HIGH_EVENT) {
++ printk(KERN_ALERT "emc1403: Sensor Id = %d AUX1 event \
++ temp = %d \n", sensor_id, curr_temp);
++ ospm_generate_netlink_event(sensor_id,
++ OSPM_EVENT_THERMAL_AUX1);
++ }
++ if (event_id == LOW_EVENT) {
++ printk(KERN_ALERT "emc1403: Sensor Id = %d AUX0 event \
++ temp = %d \n", sensor_id, curr_temp);
++ ospm_generate_netlink_event(sensor_id,
++ OSPM_EVENT_THERMAL_AUX0);
++ }
++ if (event_id == FAULT_EVENT) {
++ printk(KERN_ALERT "emc1403: Sensor Id = %d Fault event \
++ temp = %d \n", sensor_id, curr_temp);
++ ospm_generate_netlink_event(sensor_id,
++ OSPM_EVENT_THERMAL_DEV_FAULT);
++ }
++}
++
++static void send_event(struct i2c_client *client, int status, int event_id)
++{
++ int ret_val;
++
++ if (status & TEMP1) {
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[0]);
++ ospm_event(event_id, TEMP_DEV_ID1, ret_val);
++ }
++ if (status & TEMP2) {
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[1]);
++ ospm_event(event_id, TEMP_DEV_ID2, ret_val);
++ }
++ if (status & TEMP3) {
++ ret_val = i2c_read_current_data(client, THM_REG_CURR_TEMP[2]);
++ ospm_event(event_id, TEMP_DEV_ID3, ret_val);
++ }
++}
++
++static void therm_handle_intrpt(struct work_struct *work)
++{
++ u8 status, reg_val;
++ struct thermal_data *data = container_of(work,
++ struct thermal_data, therm_handler);
++
++ /* check if therm_module_info is initialized */
++ if (!data)
++ return;
++ /* Which DIODE has raised the interrupt 0x1B
++ internal/External1/External2 */
++ reg_val = i2c_smbus_read_byte_data(data->client,
++ THM_STAT_REG_TEMP[0]);
++ interrupt_status(data->client, reg_val, &status, THERM_EVENT);
++ send_event(data->client, status, THERM_EVENT);
++}
++
++static void alert_handle_intrpt(struct work_struct *work)
++{
++ int sta_reg_val, reg_val;
++ u8 status;
++ struct thermal_data *data = container_of(work,
++ struct thermal_data, alert_handler);
++ if (!data)
++ return;
++ /* HIGH/ LOW / FAULT Alert has occured for */
++ reg_val = i2c_smbus_read_byte_data(data->client, THM_STAT_REG_TEMP[4]);
++ /* High status bit is set */
++ if (reg_val & THM_CHAN_TEMP[0]) {
++ /* Which DIODE has raised the interrupt 0x1B
++ internal/External1/External2 */
++ sta_reg_val = i2c_smbus_read_byte_data(data->client,
++ THM_STAT_REG_TEMP[1]);
++ interrupt_status(data->client, sta_reg_val, &status,
++ ALERT_EVENT);
++ send_event(data->client, status, HIGH_EVENT);
++ }
++ /* Low status bit is set */
++ if (reg_val & THM_CHAN_TEMP[1]) {
++ sta_reg_val = i2c_smbus_read_byte_data(data->client,
++ THM_STAT_REG_TEMP[2]);
++ interrupt_status(data->client, sta_reg_val, &status,
++ ALERT_EVENT);
++ send_event(data->client, status, LOW_EVENT);
++ }
++ /* Fault status bit is set */
++ if (reg_val & THM_CHAN_TEMP[2]) {
++ sta_reg_val = i2c_smbus_read_byte_data(data->client,
++ THM_STAT_REG_TEMP[3]);
++ interrupt_status(data->client, sta_reg_val, &status,
++ ALERT_EVENT);
++ send_event(data->client, status, FAULT_EVENT);
++ }
++}
++#endif
++
++static int emc1403_probe(struct i2c_client *new_client,
++ const struct i2c_device_id *id)
++{
++ int res = 0;
++ struct thermal_data *data;
++ u16 pid, smsc_id, revision;
++
++#ifdef MOORESTOWN_INTERRUPT_ENABLE
++ u16 t_irq, a_irq;
++#endif
++ data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
++
++ if (data == NULL) {
++ printk(KERN_WARNING "emc1403: Memory allocation failed");
++ return -ENOMEM;
++ }
++ data->client = new_client;
++ i2c_set_clientdata(new_client, data);
++
++ /* Check if thermal chip is SMSC and EMC1403 */
++ smsc_id = i2c_read_current_data(new_client,
++ THERMAL_SMSC_ID_REG);
++ if (smsc_id != 0x5d) {
++ printk(KERN_WARNING "emc1403: vendor id mismatch \n");
++ goto thermal_error1;
++ }
++ pid = i2c_read_current_data(new_client, THERMAL_PID_REG);
++ if (pid != 0x21) {
++ printk(KERN_WARNING "emc1403: Prod id mismatch \n");
++ goto thermal_error1;
++ }
++ revision = i2c_read_current_data(new_client,
++ THERMAL_REVISION_REG);
++ if (revision != 0x01) {
++ printk(KERN_WARNING "emc1403: Rev id mismatch is \n");
++ goto thermal_error1;
++ }
++ res = sysfs_create_group(&new_client->dev.kobj, &m_thermal_gr);
++ if (res) {
++ printk(KERN_WARNING "emc1403: create group failed! \n");
++ hwmon_device_unregister(data->hwmon_dev);
++ goto thermal_error1;
++ }
++ data->hwmon_dev = hwmon_device_register(&new_client->dev);
++ if (IS_ERR(data->hwmon_dev)) {
++ res = PTR_ERR(data->hwmon_dev);
++ data->hwmon_dev = NULL;
++ printk(KERN_WARNING "emc1403:Register hwmon dev Failed\n");
++ goto thermal_error1;
++ }
++#ifdef MOORESTOWN_INTERRUPT_ENABLE
++ INIT_WORK(&data->therm_handler, (void *)therm_handle_intrpt);
++ INIT_WORK(&data->alert_handler, (void *)alert_handle_intrpt);
++ t_irq = new_client->irq;
++ a_irq = *(short *)new_client->dev.platform_data;
++ data->therm_irq = t_irq & ~IRQ_TYPE_MASK;
++ data->alert_irq = a_irq & ~IRQ_TYPE_MASK;
++ /* interpret irq field */
++ if (data->therm_irq == 0x113) {
++ if (t_irq & IRQ_TYPE_MASK) {
++ /* irq -> GPE_ID */
++ res = request_gpe(data->therm_irq,
++ (gpio_function_t)therm_interrupt_handler,
++ data, DETECT_LEVEL_LOW);
++ if (res)
++ dev_crit(&new_client->dev, "%s(): cannot \
++ register therm gpe \n", __func__);
++ } else {
++ res = request_irq(data->therm_irq,
++ therm_interrupt_handler,
++ DETECT_LEVEL_LOW, "emc1403", data);
++ if (res)
++ dev_crit(&new_client->dev, "%s(): \
++ cannot get therm IRQ\n", __func__);
++ }
++ } else {
++ printk(KERN_WARNING"emc1403: IRQ mismatch \
++ sent for therm registration");
++ }
++ if (data->alert_irq == 0x114) {
++ if (a_irq & IRQ_TYPE_MASK) {
++ /* irq -> GPE_ID */
++ res = request_gpe(data->alert_irq,
++ (gpio_function_t)alert_interrupt_handler,
++ data, DETECT_LEVEL_LOW);
++ if (res)
++ dev_crit(&new_client->dev, "%s(): \
++ cannot register alert gpe \n", __func__);
++ } else {
++ res = request_irq(data->alert_irq,
++ alert_interrupt_handler, DETECT_LEVEL_LOW,
++ "emc1403", data);
++ if (res)
++ dev_crit(&new_client->dev, "%s(): cannot \
++ get alert IRQ\n", __func__);
++ }
++ } else {
++ printk(KERN_WARNING"emc1403: IRQ mismatch \
++ sent for alert registration");
++ }
++#endif
++ emc1403_set_default_config(new_client);
++ dev_info(&new_client->dev, "%s EMC1403 Thermal chip found \n",
++ new_client->name);
++ return res;
++thermal_error1:
++ i2c_set_clientdata(new_client, NULL);
++ kfree(data);
++ return res;
++}
++
++static int emc1403_remove(struct i2c_client *client)
++{
++ struct thermal_data *data = i2c_get_clientdata(client);
++
++ hwmon_device_unregister(data->hwmon_dev);
++ sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
++ kfree(data);
++ return 0;
++}
++
++static struct i2c_device_id emc1403_idtable[] = {
++ { "i2c_thermal", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, emc1403_idtable);
++
++static struct i2c_driver sensor_emc1403 = {
++ .driver = {
++ .name = "emc1403",
++ },
++ .probe = emc1403_probe,
++ .remove = emc1403_remove,
++ .id_table = emc1403_idtable,
++};
++
++static int __init sensor_emc1403_init(void)
++{
++ return i2c_add_driver(&sensor_emc1403);
++}
++
++static void __exit sensor_emc1403_exit(void)
++{
++ i2c_del_driver(&sensor_emc1403);
++}
++
++module_init(sensor_emc1403_init);
++module_exit(sensor_emc1403_exit);
+--- /dev/null
++++ b/drivers/hwmon/hmc6352.c
+@@ -0,0 +1,250 @@
++/*
++ * hmc6352.c - Honeywell Compass Driver
++ *
++ * 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++#include <asm/ipc_defs.h>
++
++
++MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
++MODULE_DESCRIPTION("hmc6352 Compass Driver");
++MODULE_LICENSE("GPL v2");
++
++/* internal return values */
++#define COMP_CALIB_START 1
++#define COMP_CALIB_STOP 2
++#define COMP_SLEEP_MODE 0
++#define COMP_ACTIVE_MODE 1
++
++struct compass_data {
++ struct device *hwmon_dev;
++};
++
++static ssize_t compass_calibration_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret;
++ unsigned long val;
++ char cmd[] = {0x43};
++ char cmd1[] = {0x45};
++ struct i2c_msg msg[] = {
++ { client->addr, 0, 1, cmd },
++ };
++ struct i2c_msg msg1[] = {
++ { client->addr, 0, 1, cmd1 },
++ };
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++ if (val == COMP_CALIB_START) {
++ client->addr = 0x21;
++ ret = i2c_transfer(client->adapter, msg, 1);
++ if (ret != 1) {
++ printk(KERN_WARNING "hmc6352_comp : i2c callib start \
++ cmd failed \n");
++ return ret;
++ }
++ } else if (val == COMP_CALIB_STOP) {
++ client->addr = 0x21;
++ ret = i2c_transfer(client->adapter, msg1, 1);
++ if (ret != 1) {
++ printk(KERN_WARNING " hmc6352_comp : i2c callib stop \
++ cmd failed \n");
++ return ret;
++ }
++ } else
++ return -EINVAL;
++
++ return count;
++}
++
++static ssize_t compass_heading_data_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++
++ struct i2c_client *client = to_i2c_client(dev);
++ char cmd[] = {0x41};
++ unsigned char i2c_data[2] = {0, 0};
++ unsigned int ret, ret_val;
++ struct i2c_msg msg[] = {
++ { client->addr, 0, 1, cmd },
++ };
++ struct i2c_msg msg1[] = {
++ { client->addr, I2C_M_RD, 2, i2c_data },
++ };
++
++ client->addr = 0x21;
++ ret = i2c_transfer(client->adapter, msg, 1);
++ if (ret != 1) {
++ printk(KERN_WARNING "hmc6352 : i2c cmd 0x41 failed \n");
++ return ret;
++ }
++ msleep(10); /* sending 0x41 cmd we need to wait for 7-10 milli second*/
++ ret = i2c_transfer(client->adapter, msg1, 1);
++ if (ret != 1) {
++ printk(KERN_WARNING "hmc6352 : i2c read data cmd failed \n");
++ return ret;
++ }
++ ret_val = i2c_data[0];
++ ret_val = ((ret_val << 8) | i2c_data[1]);
++ return sprintf(buf, "%d.%d\n", ret_val/10, ret_val%10);
++}
++
++static ssize_t compass_power_mode_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val;
++ unsigned int ret;
++ char cmd[] = {0x53};
++ char cmd1[] = {0x57};
++ struct i2c_msg msg[] = {
++ { client->addr, 0, 1, cmd },
++ };
++ struct i2c_msg msg1[] = {
++ { client->addr, 0, 1, cmd1 },
++ };
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++
++ if (val == COMP_SLEEP_MODE) {
++ ret = i2c_transfer(client->adapter, msg, 1);
++ if (ret != 1)
++ printk(KERN_WARNING "hmc6352: i2c cmd sleep mode \
++ failed \n");
++ } else if (val == COMP_ACTIVE_MODE) {
++ ret = i2c_transfer(client->adapter, msg1, 1);
++ if (ret != 1)
++ printk(KERN_WARNING "hmc6352: i2c cmd active mode \
++ failed \n");
++ } else
++ return -EINVAL;
++
++ return count;
++}
++
++static DEVICE_ATTR(heading, S_IRUGO, compass_heading_data_show, NULL);
++static DEVICE_ATTR(calibration, S_IWUSR, NULL, compass_calibration_store);
++static DEVICE_ATTR(power_state, S_IWUSR, NULL, compass_power_mode_store);
++
++static struct attribute *mid_att_compass[] = {
++ &dev_attr_heading.attr,
++ &dev_attr_calibration.attr,
++ &dev_attr_power_state.attr,
++ NULL
++};
++
++static struct attribute_group m_compass_gr = {
++ .name = "hmc6352",
++ .attrs = mid_att_compass
++};
++
++static int hmc6352_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ int res;
++ struct compass_data *data;
++
++ data = kzalloc(sizeof(struct compass_data), GFP_KERNEL);
++ if (data == NULL) {
++ printk(KERN_WARNING "hmc6352: Memory initialization failed");
++ return -ENOMEM;
++ }
++ i2c_set_clientdata(client, data);
++
++ res = sysfs_create_group(&client->dev.kobj, &m_compass_gr);
++ if (res) {
++ printk(KERN_WARNING "hmc6352: device_create_file failed!!\n");
++ goto compass_error1;
++ }
++ data->hwmon_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->hwmon_dev)) {
++ res = PTR_ERR(data->hwmon_dev);
++ data->hwmon_dev = NULL;
++ printk(KERN_WARNING "hmc6352: fail to register hwmon device\n");
++ sysfs_remove_group(&client->dev.kobj, &m_compass_gr);
++ goto compass_error1;
++ }
++ dev_info(&client->dev, "%s HMC6352 compass chip found \n",
++ client->name);
++ return res;
++
++compass_error1:
++ i2c_set_clientdata(client, NULL);
++ kfree(data);
++ return res;
++}
++
++static int hmc6352_remove(struct i2c_client *client)
++{
++ struct compass_data *data = i2c_get_clientdata(client);
++
++ hwmon_device_unregister(data->hwmon_dev);
++ sysfs_remove_group(&client->dev.kobj, &m_compass_gr);
++ kfree(data);
++ return 0;
++}
++
++static struct i2c_device_id hmc6352_id[] = {
++ { "i2c_compass", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, hmc6352_id);
++
++static struct i2c_driver hmc6352_driver = {
++ .driver = {
++ .name = "hmc6352",
++ },
++ .probe = hmc6352_probe,
++ .remove = hmc6352_remove,
++ .id_table = hmc6352_id,
++};
++
++static int __init sensor_hmc6352_init(void)
++{
++ int res;
++
++ res = i2c_add_driver(&hmc6352_driver);
++ return res;
++}
++
++static void __exit sensor_hmc6352_exit(void)
++{
++ i2c_del_driver(&hmc6352_driver);
++}
++
++module_init(sensor_hmc6352_init);
++module_exit(sensor_hmc6352_exit);
+--- /dev/null
++++ b/drivers/hwmon/isl29020.c
+@@ -0,0 +1,248 @@
++/*
++ * isl29020.c - Intersil ALS Driver
++ *
++ * Copyright (C) 2008 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++#include <asm/ipc_defs.h>
++
++MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
++MODULE_DESCRIPTION("intersil isl29020 ALS Driver");
++MODULE_LICENSE("GPL v2");
++
++#define ALS_MIN_RANGE_VAL 0
++#define ALS_MAX_RANGE_VAL 5
++#define POWER_STA_ENABLE 1
++#define POWER_STA_DISABLE 0
++
++struct als_data {
++ struct device *hwmon_dev;
++};
++
++static unsigned int i2c_write_current_data(struct i2c_client *client,
++ unsigned int reg, unsigned int value)
++{
++ int ret_val;
++
++ ret_val = i2c_smbus_write_byte_data(client, reg, value);
++ return ret_val;
++}
++
++static ssize_t als_sensing_range_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int val;
++
++ val = i2c_smbus_read_byte_data(client, 0x00);
++ return sprintf(buf, "%d000\n", 1 << (2 * (val & 3)));
++
++}
++
++static ssize_t als_lux_output_data_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned int ret_val, val;
++ unsigned long int lux, max_count;
++ int tempv1, tempv2;
++
++ max_count = 65535;
++ tempv1 = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */
++ tempv2 = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */
++ ret_val = tempv1;
++ ret_val = (ret_val << 8 | tempv2);
++ val = i2c_smbus_read_byte_data(client, 0x00);
++ lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / max_count;
++ return sprintf(buf, "%ld\n", lux);
++}
++
++static ssize_t als_sensing_range_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned int ret_val, set_val = 0;
++ unsigned long val;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++ ret_val = i2c_smbus_read_byte_data(client, 0x00);
++ ret_val = ret_val & 0xFC; /*reset the bit before setting them */
++ if (val == 1)
++ set_val = (ret_val | 0x00); /* setting the 1:0 bit */
++ else if (val == 2)
++ set_val = (ret_val | 0x01);
++ else if (val == 3)
++ set_val = (ret_val | 0x02);
++ else if (val == 4)
++ set_val = (ret_val | 0x03);
++ else
++ goto invarg;
++ i2c_write_current_data(client, 0x00, set_val);
++ return count;
++invarg:
++ return -EINVAL;
++}
++
++static ssize_t als_power_status_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_smbus_read_byte_data(client, 0x00);
++ ret_val = ret_val & 0x80;
++ if (ret_val == 0x80)
++ ret_val = 1;
++ return sprintf(buf, "%x", ret_val);
++}
++
++static ssize_t als_power_status_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t count)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ unsigned long val = 0;
++ char curr_val;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++
++ curr_val = i2c_smbus_read_byte_data(client, 0x00);
++ if (val == POWER_STA_ENABLE)
++ curr_val = curr_val | 0x80;
++ else if (val == POWER_STA_DISABLE)
++ curr_val = curr_val & 0x7F;
++ else
++ return -EINVAL;
++ i2c_write_current_data(client, 0x00, curr_val);
++ return count;
++}
++
++static DEVICE_ATTR(sensing_range, S_IRUGO | S_IWUSR,
++ als_sensing_range_show, als_sensing_range_store);
++static DEVICE_ATTR(lux_output, S_IRUGO, als_lux_output_data_show, NULL);
++static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
++ als_power_status_show, als_power_status_store);
++
++static struct attribute *mid_att_als[] = {
++ &dev_attr_sensing_range.attr,
++ &dev_attr_lux_output.attr,
++ &dev_attr_power_state.attr,
++ NULL
++};
++
++static struct attribute_group m_als_gr = {
++ .name = "isl29020",
++ .attrs = mid_att_als
++};
++
++static void als_set_default_config(struct i2c_client *client)
++{
++ i2c_write_current_data(client, 0x00, 0xc0);
++}
++
++static int isl29020_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ int res;
++ struct als_data *data;
++
++ data = kzalloc(sizeof(struct als_data), GFP_KERNEL);
++ if (data == NULL) {
++ printk(KERN_WARNING " isl29020: Memory initialization failed");
++ return -ENOMEM;
++ }
++ i2c_set_clientdata(client, data);
++
++ res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
++ if (res) {
++ printk(KERN_WARNING "isl29020: device create file failed!!\n");
++ goto als_error1;
++ }
++ data->hwmon_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->hwmon_dev)) {
++ res = PTR_ERR(data->hwmon_dev);
++ data->hwmon_dev = NULL;
++ sysfs_remove_group(&client->dev.kobj, &m_als_gr);
++ printk(KERN_ALERT "isl29020:unable to register hwmon device\n");
++ goto als_error1;
++ }
++ dev_info(&client->dev, "%s isl29020: ALS chip found \n", client->name);
++ als_set_default_config(client);
++ return res;
++
++als_error1:
++ i2c_set_clientdata(client, NULL);
++ kfree(data);
++ return res;
++}
++
++static int isl29020_remove(struct i2c_client *client)
++{
++ struct als_data *data = i2c_get_clientdata(client);
++
++ hwmon_device_unregister(data->hwmon_dev);
++ sysfs_remove_group(&client->dev.kobj, &m_als_gr);
++ kfree(data);
++ return 0;
++}
++
++static struct i2c_device_id isl29020_id[] = {
++ { "i2c_als", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, isl29020_id);
++
++static struct i2c_driver isl29020_driver = {
++ .driver = {
++ .name = "isl29020",
++ },
++ .probe = isl29020_probe,
++ .remove = isl29020_remove,
++ .id_table = isl29020_id,
++};
++
++static int __init sensor_isl29020_init(void)
++{
++ int res;
++
++ res = i2c_add_driver(&isl29020_driver);
++ return res;
++}
++
++static void __exit sensor_isl29020_exit(void)
++{
++ i2c_del_driver(&isl29020_driver);
++}
++
++module_init(sensor_isl29020_init);
++module_exit(sensor_isl29020_exit);
+--- /dev/null
++++ b/drivers/hwmon/lis331dl.c
+@@ -0,0 +1,322 @@
++/*
++ * lis331dl.c - ST LIS331DL Accelerometer Driver
++ *
++ * 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 <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
++#include <linux/hwmon-vid.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++
++
++MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com");
++MODULE_DESCRIPTION("STMacroelectronics LIS331DL Accelerometer Driver");
++MODULE_LICENSE("GPL v2");
++
++#define ACCEL_DATA_RATE_100HZ 0
++#define ACCEL_DATA_RATE_400HZ 1
++#define ACCEL_POWER_MODE_DOWN 0
++#define ACCEL_POWER_MODE_ACTIVE 1
++#define ACCEL_NORMAL_MODE 0
++#define ACCEL_MEMORY_REBOOT 1
++
++/* internal return values */
++
++struct acclero_data {
++ struct device *hwmon_dev;
++ struct mutex update_lock;
++};
++
++static unsigned int i2c_write_current_data(struct i2c_client *client,
++ unsigned int reg, unsigned int value)
++{
++ int ret_val;
++
++ ret_val = i2c_smbus_write_byte_data(client, reg, value);
++ return ret_val;
++}
++
++static ssize_t data_rate_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val, val;
++
++ val = i2c_smbus_read_byte_data(client, 0x20);
++ ret_val = (val & 0x80); /* 1= 400HZ 0= 100HZ */
++ if (ret_val == 0x80)
++ ret_val = 1;
++ return sprintf(buf, "%d\n", ret_val);
++
++}
++
++static ssize_t power_mode_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val, val;
++
++ val = i2c_smbus_read_byte_data(client, 0x20);
++ ret_val = (val & 0x40);
++ if (ret_val == 0x40)
++ ret_val = 1;
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t x_pos_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_smbus_read_byte_data(client, 0x29);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t y_pos_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_smbus_read_byte_data(client, 0x2B);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t z_pos_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ int ret_val;
++
++ ret_val = i2c_smbus_read_byte_data(client, 0x2D);
++ return sprintf(buf, "%d\n", ret_val);
++}
++
++static ssize_t xyz_pos_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int x, y, z;
++ struct i2c_client *client = to_i2c_client(dev);
++
++ x = i2c_smbus_read_byte_data(client, 0x29);
++ y = i2c_smbus_read_byte_data(client, 0x2B);
++ z = i2c_smbus_read_byte_data(client, 0x2D);
++ return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
++}
++
++static ssize_t data_rate_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, 0x20);
++
++ mutex_lock(&data->update_lock);
++ if (val == ACCEL_DATA_RATE_100HZ)
++ set_val = (ret_val & 0x7F); /* setting the 8th bit to 0 */
++ else if (val == ACCEL_DATA_RATE_400HZ)
++ set_val = (ret_val | (1 << 7));
++ else
++ goto invarg;
++
++ i2c_write_current_data(client, 0x20, set_val);
++ mutex_unlock(&data->update_lock);
++ return count;
++invarg:
++ mutex_unlock(&data->update_lock);
++ return -EINVAL;
++}
++
++static ssize_t power_mode_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, 0x20);
++
++ mutex_lock(&data->update_lock);
++ if (val == ACCEL_POWER_MODE_DOWN)
++ set_val = ret_val & 0xBF; /* if value id 0 */
++ else if (val == ACCEL_POWER_MODE_ACTIVE)
++ set_val = (ret_val | (1<<6)); /* if value is 1 */
++ else
++ goto invarg;
++
++ i2c_write_current_data(client, 0x20, set_val);
++ mutex_unlock(&data->update_lock);
++ return count;
++invarg:
++ mutex_unlock(&data->update_lock);
++ 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);
++static DEVICE_ATTR(curr_pos, S_IRUGO, xyz_pos_show, NULL);
++
++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,
++ &dev_attr_curr_pos.attr,
++ NULL
++};
++
++static struct attribute_group m_acclero_gr = {
++ .name = "lis331dl",
++ .attrs = mid_att_acclero
++};
++
++static void accel_set_default_config(struct i2c_client *client)
++{
++ i2c_write_current_data(client, 0x20, 0x47);
++}
++
++static int lis331dl_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ int res;
++ struct acclero_data *data;
++
++ data = kzalloc(sizeof(struct acclero_data), GFP_KERNEL);
++ if (data == NULL) {
++ printk(KERN_WARNING "lis331dl: Memory initi failed \n");
++ return -ENOMEM;
++ }
++ mutex_init(&data->update_lock);
++ i2c_set_clientdata(client, data);
++
++ res = sysfs_create_group(&client->dev.kobj, &m_acclero_gr);
++ if (res) {
++ printk(KERN_WARNING "lis331dl: Sysfs group failed!!\n");
++ goto acclero_error1;
++ }
++ data->hwmon_dev = hwmon_device_register(&client->dev);
++ if (IS_ERR(data->hwmon_dev)) {
++ res = PTR_ERR(data->hwmon_dev);
++ data->hwmon_dev = NULL;
++ sysfs_remove_group(&client->dev.kobj, &m_acclero_gr);
++ printk(KERN_WARNING "lis331dl: unable to register \
++ hwmon device\n");
++ goto acclero_error1;
++ }
++ accel_set_default_config(client);
++
++ dev_info(&client->dev, "%s lis331dl: Accelerometer chip \
++ foundn", client->name);
++ return res;
++
++acclero_error1:
++ i2c_set_clientdata(client, NULL);
++ kfree(data);
++ return res;
++}
++
++static int lis331dl_remove(struct i2c_client *client)
++{
++ struct acclero_data *data = i2c_get_clientdata(client);
++
++ hwmon_device_unregister(data->hwmon_dev);
++ sysfs_remove_group(&client->dev.kobj, &m_acclero_gr);
++ kfree(data);
++ return 0;
++}
++
++static struct i2c_device_id lis331dl_id[] = {
++ { "i2c_accel", 0 },
++ { }
++};
++
++MODULE_DEVICE_TABLE(i2c, lis331dl_id);
++
++static struct i2c_driver lis331dl_driver = {
++ .driver = {
++ .name = "lis331dl",
++ },
++ .probe = lis331dl_probe,
++ .remove = lis331dl_remove,
++ .id_table = lis331dl_id,
++};
++
++static int __init sensor_lis331dl_init(void)
++{
++ int res;
++
++ res = i2c_add_driver(&lis331dl_driver);
++ return res;
++}
++
++static void __exit sensor_lis331dl_exit(void)
++{
++ i2c_del_driver(&lis331dl_driver);
++}
++
++module_init(sensor_lis331dl_init);
++module_exit(sensor_lis331dl_exit);
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -249,6 +249,13 @@ config SGI_GRU_DEBUG
+ This option enables addition debugging code for the SGI GRU driver. If
+ you are unsure, say N.
+
++config MRST_VIB
++ tristate "vibrator driver for Intel Moorestown platform"
++ help
++ Vibrator for Intel Moorestown platform.
++
++ If unsure, say N.
++
+ config ISL29003
+ tristate "Intersil ISL29003 ambient light sensor"
+ depends on I2C && SYSFS
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfg
+ obj-$(CONFIG_HP_ILO) += hpilo.o
+ obj-$(CONFIG_MRST) += intel_mrst.o
+ obj-$(CONFIG_ISL29003) += isl29003.o
++obj-$(CONFIG_MRST_VIB) += mrst_vib.o
+ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
+ obj-$(CONFIG_DS1682) += ds1682.o
+ obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
+--- /dev/null
++++ b/drivers/misc/mrst_vib.c
+@@ -0,0 +1,99 @@
++/*
++ * mrst_vib.c - Intel vibrator Driver
++ *
++ * Copyright (C) 2008 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 <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/sysfs.h>
++#include <asm/ipc_defs.h>
++
++
++MODULE_AUTHOR("Kalhan Trisal");
++MODULE_DESCRIPTION("Intel Moorestown Thermal Driver");
++MODULE_LICENSE("GPL v2");
++
++#define VIB_START 1
++#define VIB_STOP 2
++static struct platform_device *vib_pdev;
++
++static ssize_t vib_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++
++ struct ipc_pmic_reg_data vib_power_reg_write = {0};
++ unsigned long val;
++
++ if (strict_strtoul(buf, 10, &val))
++ return -EINVAL;
++ if (val == VIB_START) {
++ vib_power_reg_write.ioc = TRUE;
++ vib_power_reg_write.pmic_reg_data[0].register_address = 0x49;
++ vib_power_reg_write.pmic_reg_data[0].value = 0xAD;
++ vib_power_reg_write.num_entries = 1;
++ if (ipc_pmic_register_write(&vib_power_reg_write, TRUE)) {
++ printk(KERN_WARNING "mrst_vib: failed to turn ON \
++ vib \n");
++ return -EINVAL;
++ }
++ } else if (val == VIB_STOP) {
++ vib_power_reg_write.ioc = TRUE;
++ vib_power_reg_write.pmic_reg_data[0].register_address = 0x49;
++ vib_power_reg_write.pmic_reg_data[0].value = 0x14;
++ vib_power_reg_write.num_entries = 1;
++ if (ipc_pmic_register_write(&vib_power_reg_write, TRUE)) {
++ printk(KERN_WARNING "mrst_vib: failed to turn OFF \
++ Vibrator \n");
++ return -EINVAL;
++ }
++ } else
++ return -EINVAL;
++
++ return count;
++}
++
++static struct device_attribute dev_attr_vib =
++ __ATTR(vib, S_IWUSR, NULL, vib_store);
++
++static int __init mrst_vib_init(void)
++{
++ int res = 0;
++
++ vib_pdev = platform_device_register_simple("mrst_vib", -1, NULL, 0);
++ if (IS_ERR(vib_pdev)) {
++ res = PTR_ERR(vib_pdev);
++ vib_pdev = NULL;
++ printk(KERN_WARNING "mrst_vib: unable to register platform \
++ device\n");
++ return res;
++ }
++ res = device_create_file(&vib_pdev->dev, &dev_attr_vib);
++ return res;
++}
++
++static void __exit mrst_vib_exit(void)
++{
++ device_remove_file(&vib_pdev->dev, &dev_attr_vib);
++ platform_device_unregister(vib_pdev);
++}
++
++module_init(mrst_vib_init);
++module_exit(mrst_vib_exit);