generic-poky/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-sen...

1837 lines
52 KiB
Diff

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);