All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
@ 2011-01-25 14:35 Alan Cox
  2011-02-07 19:58 ` Matthew Garrett
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Cox @ 2011-01-25 14:35 UTC (permalink / raw)
  To: mjg, platform-driver-x86

From: Durgadoss R <durgadoss.r@intel.com>

This patch enables over current detection on the Intel Medfield
Platform. This driver provides sysfs interfaces to configure current
thresholds. When the current being drawn on the platform exceeds
the configured threshold, an interrupt is generated. This interrupt
can be used to bring the current consumption down by taking necessary
hardware or software actions.

Note that while we use hwmon style helpers and interface this is not an hwmon
device and hwmon has no common API with this hardware. After discussion with
the hwmon maintainers it was decided to make this an x86 platform driver.

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---

 Documentation/x86/intel_mid/intel_mid_ocd.txt |   86 +++
 drivers/platform/x86/Kconfig                  |    7 
 drivers/platform/x86/Makefile                 |    1 
 drivers/platform/x86/intel_mid_ocd.c          |  640 +++++++++++++++++++++++++
 4 files changed, 734 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/x86/intel_mid/intel_mid_ocd.txt
 create mode 100644 drivers/platform/x86/intel_mid_ocd.c


diff --git a/Documentation/x86/intel_mid/intel_mid_ocd.txt b/Documentation/x86/intel_mid/intel_mid_ocd.txt
new file mode 100644
index 0000000..d9483b0
--- /dev/null
+++ b/Documentation/x86/intel_mid/intel_mid_ocd.txt
@@ -0,0 +1,86 @@
+Kernel driver over current detection driver
+===========================================
+
+Supported systems:
+  * Intel Medfield Platform
+
+Author: Durgadoss R
+
+Description
+-----------
+
+This driver monitors the current drawn by the platform, and detects the
+peak current conditions. When the current drawn is more than the
+configured limit for a period of time (which is specified by a timer), an
+interrupt is generated. The current limit and the timer value can be
+configured at run time.
+
+The current thresholds aka BATTCURRENTLIMITS(BC) are of two types:
+	1.warning threshold(BC1)
+		at which the system should take actions to bring the
+		current consumption down.
+	2.shutdown threshold(BC2)
+		at which the hardware does a COLDOFF.
+
+The timer thresholds are of three types:
+	1.warning threshold(T1)
+		This corresponds to the first flag for time that the battery
+		current has been above BC1. An interrupt is generated to allow
+		software to correct the situation based on use-case.
+	2.hardware action threshold(T2)
+		This corresponds to the second flag for time that the battery
+		current has been above BC1. It signifies that the system
+		should control high current subsystems through hardware.
+		Besides a general interrupt, audio_volume_crush, vibra_disable
+		signals are sent.
+	3.shutdown threshold(T3)
+		This final flag signifies that when the system current exceeds
+		the threshold for more than T3, system should shutdown.
+
+Following table summarizes the exported sysfs files:
+
+bcu_status(RW)	     -  To enable/disable burst control unit.
+			0 - enables bcu, 1 - disables bcu.
+accumulation_time(RW)-  Time since last clearing/overflow of warning_count
+			in milli seconds. Writing 0 resets the acc_time and
+			also clears both the warning counters.
+warning_count(RO)    -  Two space seperated values that indicate the number
+			of times the current thresholds have been crossed.
+action_mask(RW)	     -  A hex value to enable/disable specific
+			actions taken when current violation happens.
+			bits [b4 b3 b2 b1 b0] control [a4 a3 a2 a1 a0] actions
+			respectively. a4 - camera output, a3 - sys burst,
+			a2 - SOC burst enable, a1 - vibra, a0 - audio output.
+			bits [b7 b6 b5] - Reserved.
+			Default value:08 (sys burst output is enabled).
+action_status(RO)    -  A hex value showing the status of actions taken
+			since the __last__ interrupt.
+			b7 - T3 violation
+			b6 - T2 violation
+			b5 - T1 violation
+			b4 - camera action taken status
+			b3 - sys burst disable action taken status
+			b2 - SOC burst disable action taken status
+			b1 - vibra disable
+			b0 - audio volume crush
+			A '1' in a bit position indicates that particular
+			action has been taken.
+current_warning(RW)  -  This gives the current(in mA) at which a warning is
+			generated. Range: 1400 to 4800. Default:3000
+current_shutdown(RW) -  This gives the current(in mA) at which system shutdown
+			is initiated. Range:1800 to 5800. Default:3800
+timer_warning(RW)    -  Time above current_warning limit at which interrupts
+			are trigerred(so that software can bring the current
+			consumption down). Values are in micro seconds.
+			Range:200 to 7700 in steps of 500
+timer_hw_action(RW)  -  Time above current_warning limit at which the system
+			is trigerred into hardware control to bring down the
+			current consumption. Values are in micro seconds.
+			Range:200 to 7700 in steps of 500
+timer_shutdown(RW)   -  Time above current_warning limit at which a hardware
+			shutdown event is trigerred. The timer values are in
+			micro seconds.
+			Range:1000 to 15000 in steps of 1000
+For all timer interfaces, tolerance shall be 5% maximum.
+All timers start running concurrently once current_warning/current_shutdown
+is crossed.
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 8ceea88..9515c9d 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -598,6 +598,13 @@ config GPIO_INTEL_PMIC
 	  Say Y here to support GPIO via the SCU IPC interface
 	  on Intel MID platforms.
 
+config INTEL_MID_OCD
+	tristate "Intel MID platform over-current detector"
+	depends on INTEL_SCU_IPC
+	---help---
+	  Say Y here to support over-current detection and handling on
+	  Intel Medfield MID platforms.
+
 config RAR_REGISTER
 	bool "Restricted Access Region Register Driver"
 	depends on PCI && X86_MRST
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index a24cd62..1bbb4f9 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)	+= toshiba_bluetooth.o
 obj-$(CONFIG_INTEL_SCU_IPC)	+= intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o
+obj-$(CONFIG_INTEL_MID_OCD)	+= intel_mid_ocd.o
 obj-$(CONFIG_RAR_REGISTER)	+= intel_rar_register.o
 obj-$(CONFIG_INTEL_IPS)		+= intel_ips.o
 obj-$(CONFIG_GPIO_INTEL_PMIC)	+= intel_pmic_gpio.o
diff --git a/drivers/platform/x86/intel_mid_ocd.c b/drivers/platform/x86/intel_mid_ocd.c
new file mode 100644
index 0000000..a1284a0
--- /dev/null
+++ b/drivers/platform/x86/intel_mid_ocd.c
@@ -0,0 +1,640 @@
+/*
+ * intel_mid_ocd.c - Intel Medfield Platform Over Current Detection Driver
+ *
+ *
+ * Copyright (C) 2010 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Author: Durgadoss R <durgadoss.r@intel.com>
+ */
+
+#define pr_fmt(fmt)  "intel_mid_ocd: " fmt
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+
+#include <asm/intel_scu_ipc.h>
+
+#define DRIVER_NAME "intel_mid_ocd"
+#define FIRMWARE_NAME "msic_cmd"
+
+/* Registers that govern current monitoring */
+#define BATTCURRENTLIMIT12	0x102
+#define BATTTIMELIMIT12		0x103
+#define BATTTIMELIMIT3		0x104
+#define BRSTCONFIGOUTPUTS	0x106
+#define BRSTCONFIGACTIONS	0x107
+#define BRSTCONTROLSTATUS	0x108
+
+#define BCUSTATUS		(1 << 7)
+
+/* Bits that enable sys burst input & output */
+#define SYSACTEN		(1 << 3)
+#define SYSOUTEN		(1 << 3)
+
+/* Status register */
+#define CAMSTAT			(1 << 4)
+#define SYSSTAT			(0x0F << 0)
+#define OVER_TIMER1		(1 << 5)
+#define OVER_TIMER2		(1 << 6)
+
+#define NUM_CURR_LIMITS		8
+#define NUM_TIME_LIMITS		15
+
+/* Base and offset for every time limit */
+#define TIME_LIMIT12_BASE	200
+#define TIME_LIMIT12_OFFSET	500
+#define TIME_LIMIT12_MAX	(TIME_LIMIT12_BASE + \
+				(TIME_LIMIT12_OFFSET * NUM_TIME_LIMITS))
+
+#define TIME_LIMIT3_BASE	200
+#define TIME_LIMIT3_OFFSET	1000
+#define TIME_LIMIT3_MAX		(TIME_LIMIT3_OFFSET * NUM_TIME_LIMITS)
+
+#define MAX_COUNT		0xFFFFFFFF
+
+static DEFINE_MUTEX(ocd_update_lock);
+
+/* stores the current thresholds(in mA) at which
+ * row 0: warning is generated
+ * row 1: system shut down is initiated
+ */
+static const int curr_thresholds[][NUM_CURR_LIMITS] = {
+			{1400, 1800, 2200, 2800, 3000, 3400, 3800, 4800},
+			{1800, 2200, 2800, 3000, 3800, 4800, 5800, 5800} };
+
+struct ocd_info {
+	unsigned long timer1_count;
+	unsigned long timer2_count;
+	unsigned long acc_time;
+	unsigned int irq;
+	uint8_t intrpt_status;
+	struct device *dev;
+	struct platform_device *pdev;
+};
+
+static int configure_bcu(int flag)
+{
+	int ret;
+	uint8_t data;
+
+	mutex_lock(&ocd_update_lock);
+
+	ret = intel_scu_ipc_ioread8(BRSTCONFIGACTIONS, &data);
+	if (ret)
+		goto ipc_fail;
+
+	/* Zero enables BCU and non-zero disables BCU */
+	if (!flag)
+		data &= (~BCUSTATUS);	/* enable bcu */
+	else
+		data |= BCUSTATUS;	/* disable bcu */
+
+	ret = intel_scu_ipc_iowrite8(BRSTCONFIGACTIONS, data);
+
+ipc_fail:
+	mutex_unlock(&ocd_update_lock);
+	return ret;
+}
+
+static ssize_t store_bcu_status(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	unsigned long val;
+
+	if (strict_strtoul(buf, 10, &val))
+		return -EINVAL;
+
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	return configure_bcu(val) ? -EINVAL : count;
+}
+
+static ssize_t show_bcu_status(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret;
+	uint8_t data;
+
+	ret = intel_scu_ipc_ioread8(BRSTCONFIGACTIONS, &data);
+	if (ret)
+		return ret;
+
+	ret = (data & BCUSTATUS) ? 1 : 0;
+
+	return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t store_action_mask(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	unsigned long data;
+
+	if (strict_strtoul(buf, 16, &data))
+		return -EINVAL;
+
+	ret = intel_scu_ipc_iowrite8(BRSTCONFIGOUTPUTS, (uint8_t)data);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t show_action_mask(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int ret;
+	uint8_t data;
+
+	ret = intel_scu_ipc_ioread8(BRSTCONFIGOUTPUTS, &data);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%.2x\n", data);
+}
+
+static ssize_t show_action_status(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ocd_info *cinfo = dev_get_drvdata(dev);
+
+	/* This shows the status of actions taken since the last interrupt */
+	return sprintf(buf, "%.2x\n", cinfo->intrpt_status);
+}
+
+static int get_current_value(int index, int value)
+{
+	int pos = 0;
+
+	if (index != 0 && index != 1)
+		return -EINVAL;
+
+	if (value < curr_thresholds[index][0] ||
+			value > curr_thresholds[index][NUM_CURR_LIMITS-1])
+		return -EINVAL;
+
+	/* Find the index of 'value' in the thresholds array */
+	while (pos < NUM_CURR_LIMITS && value >= curr_thresholds[index][pos])
+		++pos;
+
+	return pos - 1;
+}
+
+static ssize_t store_curr_thres(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int ret;
+	uint8_t data;
+	long curnt;
+	int pos;
+	struct sensor_device_attribute_2 *s_attr =
+					to_sensor_dev_attr_2(attr);
+
+	if (strict_strtol(buf, 10, &curnt))
+		return -EINVAL;
+
+	mutex_lock(&ocd_update_lock);
+
+	pos = get_current_value(s_attr->nr, (int)curnt);
+	if (pos < 0) {
+		ret = pos;
+		goto ipc_fail;
+	}
+
+	ret = intel_scu_ipc_ioread8(BATTCURRENTLIMIT12, &data);
+	if (ret)
+		goto ipc_fail;
+
+	if (s_attr->nr == 0)
+		/* set bits [0-2] to value of pos */
+		data = (data & 0xF8) | pos;
+	else
+		/* set bits [3-5] to value of pos */
+		data = (data & 0xC7) | (pos << 3);
+
+	ret = intel_scu_ipc_iowrite8(BATTCURRENTLIMIT12, data);
+	if (ret)
+		goto ipc_fail;
+
+	ret = count;
+
+ipc_fail:
+	mutex_unlock(&ocd_update_lock);
+	return ret;
+}
+
+static ssize_t show_curr_thres(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret, indx;
+	uint8_t data;
+	struct sensor_device_attribute_2 *s_attr =
+					to_sensor_dev_attr_2(attr);
+
+	WARN_ON(s_attr->nr != 0 && s_attr->nr != 1);
+
+	ret = intel_scu_ipc_ioread8(BATTCURRENTLIMIT12, &data);
+	if (ret)
+		return ret;
+
+	/* read bits [0-2] or [3-5] of data */
+	indx = (data >> (3 * s_attr->nr)) & 0x07;
+
+	return sprintf(buf, "%d\n", curr_thresholds[s_attr->nr][indx]);
+}
+
+static int get_timer_threshold(unsigned long time, int index)
+{
+	if (index == 0 || index == 1) {
+		if (time < TIME_LIMIT12_BASE || time > TIME_LIMIT12_MAX)
+			return -EINVAL;
+		return (time - TIME_LIMIT12_BASE) / TIME_LIMIT12_OFFSET;
+	} else {
+		if (time < TIME_LIMIT3_BASE || time > TIME_LIMIT3_MAX)
+			return -EINVAL;
+		return time / TIME_LIMIT3_OFFSET;
+	}
+}
+
+static ssize_t store_timer_thres(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	unsigned long time;
+	uint8_t data;
+	int ret, val;
+	struct sensor_device_attribute_2 *s_attr =
+					to_sensor_dev_attr_2(attr);
+
+	if (strict_strtoul(buf, 10, &time))
+		return -EINVAL;
+
+	val = get_timer_threshold(time, s_attr->nr);
+	if (val < 0)
+		return -EINVAL;
+
+	mutex_lock(&ocd_update_lock);
+
+	if (s_attr->nr == 2) {
+		ret = intel_scu_ipc_ioread8(BATTTIMELIMIT3, &data);
+		if (ret)
+			goto ipc_fail;
+		/* set bits [0-3] to val */
+		data = (data & 0xF0) | val;
+
+		ret = intel_scu_ipc_iowrite8(BATTTIMELIMIT3, data);
+		if (ret)
+			goto ipc_fail;
+	} else {
+		ret = intel_scu_ipc_ioread8(BATTTIMELIMIT12, &data);
+		if (ret)
+			goto ipc_fail;
+
+		if (s_attr->nr == 0)
+			/* set bits [0-3] to val */
+			data = (data & 0xF0) | val;
+		else
+			/* set bits [4-7] to val */
+			data = (data & 0x0F) | (val << 4);
+
+		ret = intel_scu_ipc_iowrite8(BATTTIMELIMIT12, data);
+		if (ret)
+			goto ipc_fail;
+	}
+	ret = count;
+
+ipc_fail:
+	mutex_unlock(&ocd_update_lock);
+	return ret;
+}
+
+static ssize_t show_timer_thres(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int ret, val;
+	uint8_t data;
+	int time;
+	struct sensor_device_attribute_2 *s_attr =
+					to_sensor_dev_attr_2(attr);
+
+	if (s_attr->nr == 0 || s_attr->nr == 1) {
+		ret = intel_scu_ipc_ioread8(BATTTIMELIMIT12, &data);
+		if (ret)
+			return ret;
+
+		val = s_attr->nr ? ((data >> 4) & 0x0F) : (data & 0x0F);
+		time = TIME_LIMIT12_BASE + val * TIME_LIMIT12_OFFSET;
+
+	} else if (s_attr->nr == 2) {
+		ret = intel_scu_ipc_ioread8(BATTTIMELIMIT3, &data);
+		if (ret)
+			return ret;
+
+		val = data & 0x0F;
+		time = (val) ? (val * TIME_LIMIT3_OFFSET) : TIME_LIMIT3_BASE;
+	} else
+		return -EINVAL;
+
+	return sprintf(buf, "%d\n", time);
+}
+
+static ssize_t show_warn_count(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ocd_info *cinfo = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%ld %ld\n", cinfo->timer1_count,
+							cinfo->timer2_count);
+}
+
+static ssize_t store_acc_time(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct ocd_info *cinfo = dev_get_drvdata(dev);
+	unsigned long time;
+
+	if (strict_strtoul(buf, 10, &time))
+		return -EINVAL;
+
+	/* Only 0 can be written to clear, otherwise return*/
+	if (time)
+		return -EINVAL;
+
+	/* Set the acc_time to 'now' */
+	cinfo->acc_time = jiffies;
+
+	/* Clear warning counters */
+	cinfo->timer1_count = cinfo->timer2_count = 0;
+
+	return count;
+}
+static ssize_t show_acc_time(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ocd_info *cinfo = dev_get_drvdata(dev);
+	long time_gap;
+
+	if (cinfo->acc_time == 0)
+		return sprintf(buf, "0\n");
+
+	/* Calculate the time gap in jiffies */
+	time_gap = jiffies - cinfo->acc_time;
+
+	/* Convert to milli secs and print */
+	return sprintf(buf, "%u\n", jiffies_to_msecs(time_gap));
+}
+
+static irqreturn_t ocd_handle_intrpt(int irq, void *dev_data)
+{
+	int ret;
+	uint8_t data;
+	struct ocd_info *cinfo = (struct ocd_info *)dev_data;
+
+	if (!cinfo)
+		return IRQ_NONE;
+
+	mutex_lock(&ocd_update_lock);
+
+	/* Interrupt came now */
+	cinfo->acc_time = jiffies;
+
+	/* Read the interrupt status register */
+	ret = intel_scu_ipc_ioread8(BRSTCONTROLSTATUS, &data);
+	if (ret)
+		goto ipc_fail;
+
+	/* Cache the interrupt status register */
+	cinfo->intrpt_status = data;
+
+	/* It's a timer1 interrupt. Increment the counter.
+	 * Reset timer1 and camera status bits */
+	if (data & OVER_TIMER1) {
+		cinfo->timer1_count++;
+		data &= (~(OVER_TIMER1 | CAMSTAT));
+	}
+
+	/* It's a timer2 interrupt. Increment the counter.
+	 * Reset timer2 and sys burst status bits */
+	if (data & OVER_TIMER2) {
+		cinfo->timer2_count++;
+		data &= (~(OVER_TIMER2 | SYSSTAT));
+	}
+
+	if (cinfo->timer1_count == MAX_COUNT ||
+				cinfo->timer2_count == MAX_COUNT) {
+		cinfo->timer1_count = cinfo->timer2_count = 0;
+		cinfo->acc_time = jiffies;
+	}
+
+	/* Write the masked data */
+	ret = intel_scu_ipc_iowrite8(BRSTCONTROLSTATUS, data);
+	if (ret)
+		goto ipc_fail;
+
+	mutex_unlock(&ocd_update_lock);
+	return IRQ_HANDLED;
+
+ipc_fail:
+	mutex_unlock(&ocd_update_lock);
+	dev_err(cinfo->dev, "ipc read/write failed");
+	return ret;
+}
+
+static int initialize_hw(struct ocd_info *cinfo)
+{
+	int ret;
+	uint8_t data;
+
+	ret = intel_scu_ipc_ioread8(BRSTCONFIGOUTPUTS, &data);
+	if (ret)
+		return ret;
+
+	/* Enable sys burst output signal */
+	ret = intel_scu_ipc_iowrite8(BRSTCONFIGOUTPUTS, (data | SYSOUTEN));
+	if (ret)
+		return ret;
+
+	ret = intel_scu_ipc_ioread8(BRSTCONFIGACTIONS, &data);
+	if (ret)
+		return ret;
+
+	/* Enable sys burst action signal*/
+	return intel_scu_ipc_iowrite8(BRSTCONFIGACTIONS, (data | SYSACTEN));
+}
+
+static SENSOR_DEVICE_ATTR_2(bcu_status, S_IRUGO | S_IWUSR,
+				show_bcu_status, store_bcu_status, 0, 0);
+
+static SENSOR_DEVICE_ATTR_2(action_mask, S_IRUGO | S_IWUSR,
+				show_action_mask, store_action_mask, 0, 0);
+
+static SENSOR_DEVICE_ATTR_2(current_warning, S_IRUGO | S_IWUSR,
+				show_curr_thres, store_curr_thres, 0, 0);
+static SENSOR_DEVICE_ATTR_2(current_shutdown, S_IRUGO | S_IWUSR,
+				show_curr_thres, store_curr_thres, 1, 0);
+
+static SENSOR_DEVICE_ATTR_2(timer_warning, S_IRUGO | S_IWUSR,
+				show_timer_thres, store_timer_thres, 0, 0);
+static SENSOR_DEVICE_ATTR_2(timer_hw_action, S_IRUGO | S_IWUSR,
+				show_timer_thres, store_timer_thres, 1, 0);
+static SENSOR_DEVICE_ATTR_2(timer_shutdown, S_IRUGO | S_IWUSR,
+				show_timer_thres, store_timer_thres, 2, 0);
+
+static SENSOR_DEVICE_ATTR_2(accumulation_time, S_IRUGO | S_IWUSR,
+					show_acc_time, store_acc_time, 0, 0);
+
+static SENSOR_DEVICE_ATTR_2(warning_count, S_IRUGO, show_warn_count,
+								NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(action_status, S_IRUGO, show_action_status,
+								NULL, 0, 0);
+
+static struct attribute *mid_ocd_attrs[] = {
+	&sensor_dev_attr_bcu_status.dev_attr.attr,
+	&sensor_dev_attr_action_mask.dev_attr.attr,
+	&sensor_dev_attr_current_warning.dev_attr.attr,
+	&sensor_dev_attr_current_shutdown.dev_attr.attr,
+	&sensor_dev_attr_timer_warning.dev_attr.attr,
+	&sensor_dev_attr_timer_hw_action.dev_attr.attr,
+	&sensor_dev_attr_timer_shutdown.dev_attr.attr,
+	&sensor_dev_attr_warning_count.dev_attr.attr,
+	&sensor_dev_attr_accumulation_time.dev_attr.attr,
+	&sensor_dev_attr_action_status.dev_attr.attr,
+	NULL
+};
+
+static struct attribute_group mid_ocd_gr = {
+	.name = "msic_current",
+	.attrs = mid_ocd_attrs
+};
+
+static int mid_ocd_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct ocd_info *cinfo = kzalloc(sizeof(struct ocd_info), GFP_KERNEL);
+
+	if (!cinfo) {
+		dev_err(&pdev->dev, "kzalloc failed\n");
+		return -ENOMEM;
+	}
+
+	cinfo->pdev = pdev;
+	cinfo->irq = platform_get_irq(pdev, 0);
+	platform_set_drvdata(pdev, cinfo);
+
+	/* Creating a sysfs group with mid_ocd_gr attributes */
+	ret = sysfs_create_group(&pdev->dev.kobj, &mid_ocd_gr);
+	if (ret) {
+		dev_err(&pdev->dev, "sysfs create group failed\n");
+		goto ocd_error1;
+	}
+
+	/* Enable interrupt */
+	ret = request_threaded_irq(cinfo->irq, NULL, ocd_handle_intrpt,
+						0, DRIVER_NAME, cinfo);
+	if (ret) {
+		dev_err(cinfo->dev, "request_threaded_irq failed:%d\n", ret);
+		goto ocd_error2;
+	}
+
+	ret = initialize_hw(cinfo);
+	if (ret)
+		goto ocd_error2;
+
+	ret = configure_bcu(1);
+	if (ret)
+		goto ocd_error2;
+
+	return 0;
+
+ocd_error2:
+	sysfs_remove_group(&pdev->dev.kobj, &mid_ocd_gr);
+ocd_error1:
+	kfree(cinfo);
+	return ret;
+}
+
+static int mid_ocd_resume(struct platform_device *pdev)
+{
+	int ret;
+	struct ocd_info *cinfo = platform_get_drvdata(pdev);
+
+	ret = initialize_hw(cinfo);
+	if (ret)
+		return ret;
+
+	return configure_bcu(0);
+}
+
+static int mid_ocd_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	return configure_bcu(1);
+}
+
+static int mid_ocd_remove(struct platform_device *pdev)
+{
+	struct ocd_info *cinfo = platform_get_drvdata(pdev);
+
+	if (cinfo) {
+		sysfs_remove_group(&pdev->dev.kobj, &mid_ocd_gr);
+		kfree(cinfo);
+	}
+	return 0;
+}
+
+/*********************************************************************
+ *		Driver initialisation and finalization
+ *********************************************************************/
+static const struct platform_device_id ocd_id_table[] = {
+	{ FIRMWARE_NAME, 1 },
+};
+
+static struct platform_driver mid_over_curr_detect_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = mid_ocd_probe,
+	.suspend = mid_ocd_suspend,
+	.resume = mid_ocd_resume,
+	.remove = __devexit_p(mid_ocd_remove),
+	.id_table = ocd_id_table,
+};
+
+static int __init mid_ocd_module_init(void)
+{
+	return platform_driver_register(&mid_over_curr_detect_driver);
+}
+
+static void __exit mid_ocd_module_exit(void)
+{
+	platform_driver_unregister(&mid_over_curr_detect_driver);
+}
+
+module_init(mid_ocd_module_init);
+module_exit(mid_ocd_module_exit);
+
+MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
+MODULE_DESCRIPTION("Intel Medfield Over Current Detection Driver");
+MODULE_LICENSE("GPL");

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-01-25 14:35 [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch Alan Cox
@ 2011-02-07 19:58 ` Matthew Garrett
  2011-02-08 10:45   ` Alan Cox
  0 siblings, 1 reply; 10+ messages in thread
From: Matthew Garrett @ 2011-02-07 19:58 UTC (permalink / raw)
  To: Alan Cox; +Cc: platform-driver-x86

hwmon includes support for exposing the instantaneous current draw. 
hwmon includes support for triggering events if a parameter crosses a 
threshold. I still don't see why this isn't an hwmon driver, perhaps 
with a small platform driver for the more estoric bits of the setup.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-07 19:58 ` Matthew Garrett
@ 2011-02-08 10:45   ` Alan Cox
  2011-02-08 13:52     ` Matthew Garrett
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Cox @ 2011-02-08 10:45 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Guenter Roeck

On Mon, 7 Feb 2011 19:58:43 +0000
Matthew Garrett <mjg59@srcf.ucam.org> wrote:

> hwmon includes support for exposing the instantaneous current draw. 
> hwmon includes support for triggering events if a parameter crosses a 
> threshold. I still don't see why this isn't an hwmon driver, perhaps 
> with a small platform driver for the more estoric bits of the setup.

The hwmon maintainer says its not. Explicitly so. Been there, had that
discussion a while ago (in fact we had it as well in December if you
remember and I pointed you at the hwmon list discussion

Cc'd Guenter and quoting this time

------------------------------

Seems to be a lot of chip specific stuff. Actually, you don't define a
single hwmon ABI attribute right now. So moving it to the x86 platform
code might be a better option.

One possibility might be to move the driver to the x86 platform code,
but add/use hwmon ABI attributes as much as possible, and register those
attributes as hwmon device if CONFIG_HWMON is defined. Several other
platform specific drivers already do the same.

------------------------------

Hence trying to move it to drivers/platform/x86


Alan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 10:45   ` Alan Cox
@ 2011-02-08 13:52     ` Matthew Garrett
  2011-02-08 14:08       ` Alan Cox
  0 siblings, 1 reply; 10+ messages in thread
From: Matthew Garrett @ 2011-02-08 13:52 UTC (permalink / raw)
  To: Alan Cox; +Cc: platform-driver-x86, Guenter Roeck

On Tue, Feb 08, 2011 at 10:45:35AM +0000, Alan Cox wrote:
> On Mon, 7 Feb 2011 19:58:43 +0000
> Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> 
> > hwmon includes support for exposing the instantaneous current draw. 
> > hwmon includes support for triggering events if a parameter crosses a 
> > threshold. I still don't see why this isn't an hwmon driver, perhaps 
> > with a small platform driver for the more estoric bits of the setup.
> 
> The hwmon maintainer says its not. Explicitly so. Been there, had that
> discussion a while ago (in fact we had it as well in December if you
> remember and I pointed you at the hwmon list discussion

The hwmon maintainer says that it's not an hwmon driver, not that it 
shouldn't be an hwmon driver.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 13:52     ` Matthew Garrett
@ 2011-02-08 14:08       ` Alan Cox
  2011-02-08 15:49         ` Guenter Roeck
  0 siblings, 1 reply; 10+ messages in thread
From: Alan Cox @ 2011-02-08 14:08 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Guenter Roeck

On Tue, 8 Feb 2011 13:52:28 +0000
Matthew Garrett <mjg59@srcf.ucam.org> wrote:

> On Tue, Feb 08, 2011 at 10:45:35AM +0000, Alan Cox wrote:
> > On Mon, 7 Feb 2011 19:58:43 +0000
> > Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> > 
> > > hwmon includes support for exposing the instantaneous current draw. 
> > > hwmon includes support for triggering events if a parameter crosses a 
> > > threshold. I still don't see why this isn't an hwmon driver, perhaps 
> > > with a small platform driver for the more estoric bits of the setup.
> > 
> > The hwmon maintainer says its not. Explicitly so. Been there, had that
> > discussion a while ago (in fact we had it as well in December if you
> > remember and I pointed you at the hwmon list discussion
> 
> The hwmon maintainer says that it's not an hwmon driver, not that it 
> shouldn't be an hwmon driver.

That's not how I interpret it, but he's Cc'd so I'll let him speak for
himself, failing that I'll stuff it in arch/x86/platform/mrst I guess

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 14:08       ` Alan Cox
@ 2011-02-08 15:49         ` Guenter Roeck
  2011-02-08 15:56           ` Matthew Garrett
  0 siblings, 1 reply; 10+ messages in thread
From: Guenter Roeck @ 2011-02-08 15:49 UTC (permalink / raw)
  To: Alan Cox; +Cc: Matthew Garrett, platform-driver-x86

On Tue, Feb 08, 2011 at 09:08:00AM -0500, Alan Cox wrote:
> On Tue, 8 Feb 2011 13:52:28 +0000
> Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> 
> > On Tue, Feb 08, 2011 at 10:45:35AM +0000, Alan Cox wrote:
> > > On Mon, 7 Feb 2011 19:58:43 +0000
> > > Matthew Garrett <mjg59@srcf.ucam.org> wrote:
> > > 
> > > > hwmon includes support for exposing the instantaneous current draw. 
> > > > hwmon includes support for triggering events if a parameter crosses a 

Not explicitly, really. Sure, one can write a driver which triggers such an event,
but afaik there is only one hwmon driver doing that right now, and doing so
is not part of the hwmon infrastructure.

> > > > threshold. I still don't see why this isn't an hwmon driver, perhaps 
> > > > with a small platform driver for the more estoric bits of the setup.
> > > 
> > > The hwmon maintainer says its not. Explicitly so. Been there, had that
> > > discussion a while ago (in fact we had it as well in December if you
> > > remember and I pointed you at the hwmon list discussion
> > 
> > The hwmon maintainer says that it's not an hwmon driver, not that it 
> > shouldn't be an hwmon driver.
> 
> That's not how I interpret it, but he's Cc'd so I'll let him speak for
> himself, failing that I'll stuff it in arch/x86/platform/mrst I guess

Seems to me there is some hair splitting going on here. Core element of
hwmon drivers is that there are reported temperatures, voltages, current,
power, humidity, etc. I don't see any of those here. All I see is various
current limits. Those are secondary attributes from hwmon perspective.
So I don't really see how this can be made a hwmon driver.

Anyway, didn't you have this discussion before ? Does this all have to be
repeated over and over again ? I agree with everything Alan has said
in the previous exchange last December. Repeating it won't change anything.

Guenter

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 15:49         ` Guenter Roeck
@ 2011-02-08 15:56           ` Matthew Garrett
  2011-02-08 16:09             ` Alan Cox
  2011-02-08 16:21             ` Guenter Roeck
  0 siblings, 2 replies; 10+ messages in thread
From: Matthew Garrett @ 2011-02-08 15:56 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Alan Cox, platform-driver-x86

On Tue, Feb 08, 2011 at 07:49:16AM -0800, Guenter Roeck wrote:

> Seems to me there is some hair splitting going on here. Core element of
> hwmon drivers is that there are reported temperatures, voltages, current,
> power, humidity, etc. I don't see any of those here. All I see is various
> current limits. Those are secondary attributes from hwmon perspective.
> So I don't really see how this can be made a hwmon driver.

Ok, if the hardware has no mechanism for reporting the instantaneous 
draw then I can see it not working well in an hwmon sense. But I'd 
really prefer to see this look far more generic than it does - surely 
other hardware has similar functionality?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 15:56           ` Matthew Garrett
@ 2011-02-08 16:09             ` Alan Cox
  2011-02-08 16:19               ` Matthew Garrett
  2011-02-08 16:21             ` Guenter Roeck
  1 sibling, 1 reply; 10+ messages in thread
From: Alan Cox @ 2011-02-08 16:09 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Guenter Roeck, platform-driver-x86

> Ok, if the hardware has no mechanism for reporting the instantaneous 
> draw then I can see it not working well in an hwmon sense. But I'd 
> really prefer to see this look far more generic than it does - surely 
> other hardware has similar functionality?

I've not seen any - not anything genericisable anyway. I guess in theory
you could dramatically extend the regulator API to do power draw
management, bus current monitoring and overcurrent callbacks but I'm not
sure it would make any sense. What you do with such events and how you
manage it is incredibly platform specific.

In the PC world it's not so bad because overcurrent is a fault state -
you whine about it and either shut down or cross fingers and keep going.
In embedded devices it's not that simple and it is actively managed.

I'm open to bright ideas!

Alan

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 16:09             ` Alan Cox
@ 2011-02-08 16:19               ` Matthew Garrett
  0 siblings, 0 replies; 10+ messages in thread
From: Matthew Garrett @ 2011-02-08 16:19 UTC (permalink / raw)
  To: Alan Cox; +Cc: Guenter Roeck, platform-driver-x86

On Tue, Feb 08, 2011 at 04:09:29PM +0000, Alan Cox wrote:
> > Ok, if the hardware has no mechanism for reporting the instantaneous 
> > draw then I can see it not working well in an hwmon sense. But I'd 
> > really prefer to see this look far more generic than it does - surely 
> > other hardware has similar functionality?
> 
> I've not seen any - not anything genericisable anyway. I guess in theory
> you could dramatically extend the regulator API to do power draw
> management, bus current monitoring and overcurrent callbacks but I'm not
> sure it would make any sense. What you do with such events and how you
> manage it is incredibly platform specific.
> 
> In the PC world it's not so bad because overcurrent is a fault state -
> you whine about it and either shut down or cross fingers and keep going.
> In embedded devices it's not that simple and it is actively managed.

Yeah, fair enough. I'll queue this up.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch
  2011-02-08 15:56           ` Matthew Garrett
  2011-02-08 16:09             ` Alan Cox
@ 2011-02-08 16:21             ` Guenter Roeck
  1 sibling, 0 replies; 10+ messages in thread
From: Guenter Roeck @ 2011-02-08 16:21 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: Alan Cox, platform-driver-x86

On Tue, Feb 08, 2011 at 10:56:29AM -0500, Matthew Garrett wrote:
> On Tue, Feb 08, 2011 at 07:49:16AM -0800, Guenter Roeck wrote:
> 
> > Seems to me there is some hair splitting going on here. Core element of
> > hwmon drivers is that there are reported temperatures, voltages, current,
> > power, humidity, etc. I don't see any of those here. All I see is various
> > current limits. Those are secondary attributes from hwmon perspective.
> > So I don't really see how this can be made a hwmon driver.
> 
> Ok, if the hardware has no mechanism for reporting the instantaneous 
> draw then I can see it not working well in an hwmon sense. But I'd 
> really prefer to see this look far more generic than it does - surely 
> other hardware has similar functionality?
> 
Might well be. Just like thermal subsystem drivers act on thermal information
and registers thermal drivers with the hwmon subsystem for reporting purposes,
it might well be that there could at some point be a "current" subsystem
doing something similar for currents. But that doesn't mean that it would make
sense to provide such functionality from within the hwmon subsystem.

I have no idea if your other question can be answered right now. Maybe a more generic
interface is possible, but one would need to see multiple implementations to determine
what can be generalized. I personally don't believe that it is possible to define
a useful generic interface without knowledge of multiple pieces of HW using that
interface.

If someone volunteers to create a generic API, ABI, and possibly a new subsystem
for current management, that person can go ahead and present that subsystem
to the community for consideration. I am all for it. But it would not be appropriate
to hold this driver hostage to the non-existence of such a subsystem.

Thanks,
Guenter

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2011-02-08 16:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-25 14:35 [PATCH RESEND] x86,mrst: Intel Medfield over-current detection patch Alan Cox
2011-02-07 19:58 ` Matthew Garrett
2011-02-08 10:45   ` Alan Cox
2011-02-08 13:52     ` Matthew Garrett
2011-02-08 14:08       ` Alan Cox
2011-02-08 15:49         ` Guenter Roeck
2011-02-08 15:56           ` Matthew Garrett
2011-02-08 16:09             ` Alan Cox
2011-02-08 16:19               ` Matthew Garrett
2011-02-08 16:21             ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.