aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-ux500
diff options
context:
space:
mode:
authorJonas Aaberg <jonas.aberg@stericsson.com>2010-04-07 13:41:56 +0200
committerJohn Rigby <john.rigby@linaro.org>2010-09-02 22:45:01 -0600
commit16c38ee65b1ba497dc02055c9cdf80b24caeb117 (patch)
tree8de2d86afa7e6430d853e2fceec77d131a2442ac /arch/arm/mach-ux500
parent76b78592a87aa40573ae081028671e5089bf0166 (diff)
downloadlinux-2.6.34-ux500-16c38ee65b1ba497dc02055c9cdf80b24caeb117.tar.gz
One pin Sensor driver added. Support for proximity sensor (Osram SFH7741) and HAL switch (Samsung HED54XXU11).
Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Diffstat (limited to 'arch/arm/mach-ux500')
-rwxr-xr-xarch/arm/mach-ux500/Kconfig7
-rwxr-xr-xarch/arm/mach-ux500/Makefile1
-rwxr-xr-xarch/arm/mach-ux500/board-mop500.c28
-rwxr-xr-xarch/arm/mach-ux500/devices.c15
-rw-r--r--arch/arm/mach-ux500/include/mach/sensors1p.h24
-rw-r--r--arch/arm/mach-ux500/sensors1p.c316
6 files changed, 391 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 1fcca90e04b..df96996d521 100755
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -65,6 +65,13 @@ config U8500_PM
config ARCH_HAS_CPU_IDLE_WAIT
def_bool y
+config SENSORS1P_MOP
+ tristate "HAL and Proximity sensors support"
+ depends on GPIO_STMPE2401 || GPIO_TC35892
+ default y
+ help
+ Add support for Osram's SFH7741 Proximity Sensor and Samsumg HED54XXU11 HAL Switch
+
source "arch/arm/mach-ux500/Kconfig-arch"
config FORCE_MAX_ZONEORDER
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index b3cacce4237..6be02d614aa 100755
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o
obj-$(CONFIG_U8500_CPUIDLE) += cpuidle.o
obj-$(CONFIG_U8500_CPUFREQ) += cpufreq.o
obj-$(CONFIG_U8500_PM) += pm.o
+obj-$(CONFIG_SENSORS1P_MOP) += sensors1p.o
obj-$(CONFIG_USB) += musb_db8500.o
ifeq ($(CONFIG_MFD_STE_CONN), m)
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index ee9b35ab7dc..5923b9986bc 100755
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -27,6 +27,7 @@
#include <mach/stmpe2401.h>
#include <mach/stmpe1601.h>
#include <mach/tc35892.h>
+#include <mach/sensors1p.h>
#include <mach/av8100_p.h>
#include <mach/ab8500.h>
#include <mach/ab8500_bm.h>
@@ -805,6 +806,30 @@ static struct platform_device keypad_device = {
};
#endif /* CONFIG_KEYPAD_U8500 */
+#ifdef CONFIG_SENSORS1P_MOP
+static struct sensors1p_config sensors1p_config = {
+ /* SFH7741 */
+ .proximity = {
+ .pin = EGPIO_PIN_7,
+ .startup_time = 120, /* ms */
+ .regulator = "v-proximity",
+ },
+ /* HED54XXU11 */
+ .hal = {
+ .pin = EGPIO_PIN_8,
+ .startup_time = 100, /* Actually, I have no clue. */
+ .regulator = "v-hal",
+ },
+};
+
+static struct platform_device sensors1p_device = {
+ .name = "sensors1p",
+ .dev = {
+ .platform_data = (void *)&sensors1p_config,
+ },
+};
+#endif
+
static struct i2s_board_info stm_i2s_board_info[] __initdata = {
{
.modalias = "i2s_device.0",
@@ -903,6 +928,9 @@ static struct platform_device *u8500_platform_devices[] __initdata = {
#ifdef CONFIG_KEYPAD_U8500
&keypad_device,
#endif
+#ifdef CONFIG_SENSORS1P_MOP
+ &sensors1p_device,
+#endif
};
diff --git a/arch/arm/mach-ux500/devices.c b/arch/arm/mach-ux500/devices.c
index 943a2de145f..22e7884858a 100755
--- a/arch/arm/mach-ux500/devices.c
+++ b/arch/arm/mach-ux500/devices.c
@@ -808,6 +808,10 @@ static struct platform_device db8500_vana_regulator_dev = {
},
};
+#ifdef CONFIG_SENSORS1P_MOP
+extern struct platform_device sensors1p_device;
+#endif
+
/* VAUX1 supply */
#define AB8500_VAUXN_LDO_MIN_VOLTAGE (1100000)
#define AB8500_VAUXN_LDO_MAX_VOLTAGE (3300000)
@@ -837,6 +841,17 @@ static struct regulator_consumer_supply ab8500_vaux1_consumers[] = {
.supply = "v-mcde",
},
#endif
+#ifdef CONFIG_SENSORS1P_MOP
+ {
+ .dev = &sensors1p_device.dev,
+ .supply = "v-proximity",
+ },
+ {
+ .dev = &sensors1p_device.dev,
+ .supply = "v-hal",
+ },
+#endif
+
};
static struct regulator_init_data ab8500_vaux1_init = {
diff --git a/arch/arm/mach-ux500/include/mach/sensors1p.h b/arch/arm/mach-ux500/include/mach/sensors1p.h
new file mode 100644
index 00000000000..544e1d8bab5
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/sensors1p.h
@@ -0,0 +1,24 @@
+
+/*
+ * Copyright (C) 2009-2010 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Header file for 1 pin gpio sensors;
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+
+#ifndef __ASM_ARCH_SFH7741_H
+#define __ASM_ARCH_SFH7741_H
+
+struct sensor_config {
+ int pin;
+ int startup_time; /* in ms */
+ char regulator[32];
+};
+
+struct sensors1p_config {
+ struct sensor_config hal;
+ struct sensor_config proximity;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/sensors1p.c b/arch/arm/mach-ux500/sensors1p.c
new file mode 100644
index 00000000000..17cb0291e27
--- /dev/null
+++ b/arch/arm/mach-ux500/sensors1p.c
@@ -0,0 +1,316 @@
+
+/*
+ * Copyright (C) 2009-2010 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * Simple userspace interface for
+ * Proximity Sensor Osram SFH 7741 and HAL switch Samsung HED54XXU11
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ * This driver is only there for making Android happy. It is not ment
+ * for mainline.
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/sensors1p.h>
+#ifndef CONFIG_REGULATOR
+#include <mach/ab8500.h>
+#endif
+
+struct sensor {
+ struct regulator *regulator;
+ int pin;
+ int startup_time;
+ int active;
+ u64 when_enabled;
+};
+
+struct sensors1p {
+ struct sensor hal;
+ struct sensor proximity;
+};
+
+#ifndef CONFIG_REGULATOR
+static void force_power_on(void)
+{
+ /* Force VAUX1 to be active */
+ int val;
+ /* High power */
+ val = ab8500_read(AB8500_REGU_CTRL2,
+ AB8500_REGU_VAUX12_REGU_REG);
+ val |= 0x1;
+ ab8500_write(AB8500_REGU_CTRL2,
+ AB8500_REGU_VAUX12_REGU_REG, val);
+
+ /* 2.5V*/
+ val = ab8500_read(AB8500_REGU_CTRL2,
+ AB8500_REGU_VAUX1_SEL_REG);
+ val |= 0x8;
+ ab8500_write(AB8500_REGU_CTRL2,
+ AB8500_REGU_VAUX1_SEL_REG, val);
+}
+
+#endif
+
+
+static int sensors1p_power_write(struct device *dev,
+ struct sensor *s, const char *buf)
+{
+ int val;
+
+ if (sscanf(buf, "%d", &val) != 1)
+ return -EINVAL;
+
+ if (val != 0 && val != 1)
+ return -EINVAL;
+
+ if (val != s->active) {
+ if (val) {
+ regulator_enable(s->regulator);
+ s->when_enabled = get_jiffies_64() +
+ msecs_to_jiffies(s->startup_time);
+#ifndef CONFIG_REGULATOR
+ force_power_on();
+#endif
+ } else
+ regulator_disable(s->regulator);
+ }
+ s->active = val;
+
+ return strnlen(buf, PAGE_SIZE);
+
+}
+
+static ssize_t sensors1p_sysfs_hal_active_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+
+
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_power_write(dev, &s->hal, buf);
+
+}
+
+static ssize_t sensors1p_sysfs_proximity_active_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+
+
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_power_write(dev, &s->proximity, buf);
+
+}
+
+
+static ssize_t sensors1p_sysfs_hal_active_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sprintf(buf, "%d", s->hal.active);
+}
+
+static ssize_t sensors1p_sysfs_proximity_active_get(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sprintf(buf, "%d", s->proximity.active);
+}
+
+
+
+static int sensors1p_read(struct device *dev, struct sensor *s, char *buf)
+{
+ int ret;
+
+ if (!s->active)
+ return -EINVAL;
+
+ /* Only wait if read() is called before the sensor is up and running
+ * Since jiffies wraps, always sleep maximum time.
+ */
+ if (time_before64(get_jiffies_64(), s->when_enabled))
+ mdelay(s->startup_time);
+
+ /* For some odd reason, setting direction in the probe function fails */
+ ret = gpio_direction_input(s->pin);
+
+ if (ret)
+ dev_err(dev, "Failed to set GPIO pin %d to input.\n", s->pin);
+ else
+ ret = gpio_get_value(s->pin);
+
+ return sprintf(buf, "%d", ret);
+}
+
+static ssize_t sensors1p_sysfs_hal_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_read(dev, &s->hal, buf);
+}
+
+static ssize_t sensors1p_sysfs_proximity_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensors1p *s = platform_get_drvdata(container_of(dev,
+ struct platform_device,
+ dev));
+ return sensors1p_read(dev, &s->proximity, buf);
+}
+
+
+static DEVICE_ATTR(proximity_activate, 0666,
+ sensors1p_sysfs_proximity_active_get,
+ sensors1p_sysfs_proximity_active_set);
+static DEVICE_ATTR(hal_activate, 0666,
+ sensors1p_sysfs_hal_active_get,
+ sensors1p_sysfs_hal_active_set);
+static DEVICE_ATTR(proximity, 0444, sensors1p_sysfs_proximity_show, NULL);
+static DEVICE_ATTR(hal, 0444, sensors1p_sysfs_hal_show, NULL);
+
+static struct attribute *sensors1p_attrs[] = {
+ &dev_attr_proximity_activate.attr,
+ &dev_attr_hal_activate.attr,
+ &dev_attr_proximity.attr,
+ &dev_attr_hal.attr,
+ NULL,
+};
+
+static struct attribute_group sensors1p_attr_group = {
+ .name = NULL,
+ .attrs = sensors1p_attrs,
+};
+
+static int __init sensors1p_probe(struct platform_device *pdev)
+{
+ int err = -EINVAL;
+ struct sensors1p_config *c;
+ struct sensors1p *s = NULL;
+
+ if (!pdev)
+ goto out;
+
+ c = pdev->dev.platform_data;
+
+ if (c == NULL) {
+ dev_err(&pdev->dev, "Error: Missconfigured.\n");
+ goto out;
+ }
+
+ s = kzalloc(sizeof(struct sensors1p), GFP_KERNEL);
+
+ if (s == NULL) {
+ dev_err(&pdev->dev,
+ "Could not allocate struct memory!\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ s->hal.pin = c->hal.pin;
+ s->proximity.pin = c->proximity.pin;
+
+ s->hal.startup_time = s->hal.startup_time;
+ s->proximity.startup_time = s->proximity.startup_time;
+
+
+ s->hal.regulator = regulator_get(&pdev->dev, c->hal.regulator);
+
+ if (s->hal.regulator == NULL) {
+ dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n",
+ c->hal.regulator);
+ goto out;
+ }
+ s->proximity.regulator = regulator_get(&pdev->dev,
+ c->proximity.regulator);
+
+ if (s->proximity.regulator == NULL) {
+ dev_err(&pdev->dev, "regulator_get(\"%s\") failed.\n",
+ c->proximity.regulator);
+ goto out;
+ }
+
+#ifndef CONFIG_REGULATOR
+ force_power_on();
+#endif
+
+ err = sysfs_create_group(&pdev->dev.kobj, &sensors1p_attr_group);
+
+ if (err) {
+ dev_err(&pdev->dev, "Failed to create sysfs entries.\n");
+ goto out;
+ }
+
+ platform_set_drvdata(pdev, s);
+
+ return 0;
+out:
+ if (s) {
+ if (s->proximity.regulator)
+ regulator_put(s->proximity.regulator);
+
+ if (s->hal.regulator)
+ regulator_put(s->hal.regulator);
+ }
+ kfree(s);
+ return err;
+}
+
+static int __exit sensors1p_remove(struct platform_device *pdev)
+{
+ struct sensors1p *s = platform_get_drvdata(pdev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &sensors1p_attr_group);
+ regulator_put(s->hal.regulator);
+ regulator_put(s->proximity.regulator);
+ kfree(s);
+ return 0;
+}
+
+static struct platform_driver sensors1p_driver = {
+ .probe = sensors1p_probe,
+ .remove = __exit_p(sensors1p_remove),
+ .driver = {
+ .name = "sensors1p",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sensors1p_init(void)
+{
+ return platform_driver_register(&sensors1p_driver);
+}
+
+static void __exit sensors1p_exit(void)
+{
+ platform_driver_unregister(&sensors1p_driver);
+}
+
+late_initcall(sensors1p_init);
+module_exit(sensors1p_exit);
+
+MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
+MODULE_DESCRIPTION("One pin gpio sensors driver (Proximity+HAL)");
+MODULE_LICENSE("GPLv2");