diff options
Diffstat (limited to 'arch/arm')
-rwxr-xr-x | arch/arm/mach-ux500/Kconfig | 7 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/Makefile | 1 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/board-mop500.c | 28 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/devices.c | 15 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/sensors1p.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-ux500/sensors1p.c | 316 |
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"); |