From 7677794c9be14576b03dca46ec710103fba466ca Mon Sep 17 00:00:00 2001 From: "K. Cotulla Ivan" Date: Sun, 5 Sep 2010 20:42:10 +0200 Subject: [PATCH] htcleo: add lightsensor driver There are still power on problems, has to be fixed --- arch/arm/mach-msm/Makefile | 2 +- arch/arm/mach-msm/board-htcleo-bkl.c | 4 +- arch/arm/mach-msm/board-htcleo-ls.c | 359 ++++++++++++++++++ arch/arm/mach-msm/board-htcleo.c | 5 + .../include/mach/board-htcleo-microp.h | 1 + 5 files changed, 369 insertions(+), 2 deletions(-) create mode 100644 arch/arm/mach-msm/board-htcleo-ls.c diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 442f0726..6a43e039 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -119,7 +119,7 @@ obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-ts.o board-htcleo-mmc.o ieee754-df.o b obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-battery.o board-htcleo-log.o board-htcleo-audio.o board-htcleo-acoustic.o obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-bt.o board-htcleo-wifi.o board-htcleo-microp.o board-htcleo-bkl.o -obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-proximity.o board-htcleo-leds.o +obj-$(CONFIG_MACH_HTCLEO) += board-htcleo-proximity.o board-htcleo-leds.o board-htcleo-ls.o obj-$(CONFIG_MACH_HTCLEO) += clock-wince.o # MSM7x30 boards diff --git a/arch/arm/mach-msm/board-htcleo-bkl.c b/arch/arm/mach-msm/board-htcleo-bkl.c index 6000e346..95d65721 100644 --- a/arch/arm/mach-msm/board-htcleo-bkl.c +++ b/arch/arm/mach-msm/board-htcleo-bkl.c @@ -63,7 +63,9 @@ int htcleo_brightness_set_bkl(uint8_t value) value = 9; } // disable autobrigtness - data[0] = 0; +// CotullaTEST: Lsensor test, add 0x100 +// data[0] = 0; + data[0] = 1; data[1] = 0; ret = microp_i2c_write(MICROP_I2C_WCMD_AUTO_BL_CTL, data, 2); // 23 if (ret != 0) diff --git a/arch/arm/mach-msm/board-htcleo-ls.c b/arch/arm/mach-msm/board-htcleo-ls.c new file mode 100644 index 00000000..49a9f442 --- /dev/null +++ b/arch/arm/mach-msm/board-htcleo-ls.c @@ -0,0 +1,359 @@ +/* board-htcleo-ls.c +* +* Copyright (C) 2010 Cotulla +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* 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. +* +*/ + + +/* + +Light sensor support for HTC LEO +base code copied from microp + +because we have not interrupts, we use polling. polling time for now is 1 sec. +user may be able to adjust time in future + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "board-htcleo.h" + + +//#define CFG_LSENSOR_TYPE +//#define LSENSOR_ABLK_PLUS_ADC 1 +//#define LSENSOR_ABLK_ONLY 2 +//#define LSENSOR_ABLK_ONLY 2 + + +#define LSENSOR_POLL_PROMESHUTOK 5000 + +#define D(x...) printk(x) +// pr_info(x) + + +static uint16_t lsensor_adc_table[10] = +{ + 0x000, 0x001, 0x00F, 0x01E, 0x03C, 0x121, 0x190, 0x2BA, 0x26E, 0x3FF +}; + + +static struct lsensor_data +{ + struct input_dev *input_dev; + struct platform_device *dev; + struct delayed_work work; + uint32_t old_level; + int enabled; + int opened; +} the_data; + +int microp_read_lightsensor_value(uint32_t *val); + + +static DEFINE_MUTEX(api_lock); + +// range: adc: 0..1023, value: 0..9 +static void map_adc_to_level(uint32_t adc, uint32_t *value) +{ + int i; + + if (adc > 1024) + { + pr_err("map_adc_to_level: adc > 1024\n"); + *value = 5; // set some good value at error + return; + } + + for (i = 9; i >= 0; i--) + { + if (adc >= lsensor_adc_table[i]) + { + D("map_adc_to_level: %d -> %d\n", adc, i); + *value = i; + return; + } + } + // should not happen + *value = 5; // set some good value at error +} + +int lightsensor_read_value(uint32_t *val) +{ + int ret; + uint8_t data[2]; + + if (!val) + return -EIO; + + ret = microp_i2c_read(MICROP_I2C_RCMD_LSENSOR, data, 2); + if (ret < 0) + { + pr_err("%s: read ls fail\n", __func__); + return -EIO; + } + + *val = data[1] | (data[0] << 8); + printk("lsensor adc = %d\n", *val); + return 0; +} + +static void lightsensor_poll_function(struct work_struct *work) +{ + struct lsensor_data* p = &the_data; + uint32_t adc = 0, level = 0; + + D("@@@lsensor poll\n"); + if (!p->enabled) + { + D(" disable\n"); + return; + } + + lightsensor_read_value(&adc); + + + map_adc_to_level(adc, &level); + + //if (level != the_data.old_level) + { + input_report_abs(the_data.input_dev, ABS_MISC, (int)level); + input_sync(the_data.input_dev); + the_data.old_level = level; + } + schedule_delayed_work(&the_data.work, msecs_to_jiffies(LSENSOR_POLL_PROMESHUTOK)); +} + + +static int lightsensor_enable(void) +{ + struct lsensor_data* p = &the_data; + + D("@@@lightsensor_enable\n"); + + if (p->enabled) + { + pr_err("lsensor: already enabled\n"); + return 0; + } + the_data.old_level = -1; + + p->enabled = 1; + schedule_delayed_work(&the_data.work, msecs_to_jiffies(LSENSOR_POLL_PROMESHUTOK)); + + return 0; +} + +static int lightsensor_disable(void) +{ + struct lsensor_data* p = &the_data; + + D("@@@lightsensor_disable\n"); + + if (!p->enabled) + { + pr_err("lsensor: nothing to disable\n"); + return 0; + } + + p->enabled = 0; + cancel_delayed_work_sync(&the_data.work); + return 0; +} + + +static int lightsensor_open(struct inode *inode, struct file *file) +{ + int rc = 0; + + D("%s\n", __func__); + + mutex_lock(&api_lock); + if (the_data.opened) + { + pr_err("%s: already opened\n", __func__); + rc = -EBUSY; + } + the_data.opened = 1; + mutex_unlock(&api_lock); + return rc; +} + +static int lightsensor_release(struct inode *inode, struct file *file) +{ + D("%s\n", __func__); + + mutex_lock(&api_lock); + the_data.opened = 0; + mutex_unlock(&api_lock); + return 0; +} + +static long lightsensor_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int rc, val; + struct lsensor_data* p = &the_data; + + mutex_lock(&api_lock); + + pr_debug("%s cmd %d\n", __func__, _IOC_NR(cmd)); + if (!the_data.opened) + { + return -EIO; + } + + switch (cmd) + { + case LIGHTSENSOR_IOCTL_ENABLE: + if (get_user(val, (unsigned long __user *)arg)) + { + rc = -EFAULT; + break; + } + rc = val ? lightsensor_enable() : lightsensor_disable(); + break; + case LIGHTSENSOR_IOCTL_GET_ENABLED: + val = p->enabled; + pr_debug("%s enabled %d\n", __func__, val); + rc = put_user(val, (unsigned long __user *)arg); + break; + default: + pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd)); + rc = -EINVAL; + } + + mutex_unlock(&api_lock); + return rc; +} + +static struct file_operations lightsensor_fops = +{ + .owner = THIS_MODULE, + .open = lightsensor_open, + .release = lightsensor_release, + .unlocked_ioctl = lightsensor_ioctl +}; + +struct miscdevice lightsensor_misc = +{ + .minor = MISC_DYNAMIC_MINOR, + .name = "lightsensor", + .fops = &lightsensor_fops +}; + +////////////////////////////////////////////////////////////////////////// + + + +static int lsensor_probe(struct platform_device *pdev) +{ + int ret = -EIO; + struct input_dev *input_dev; + + D("%s: probe\n", __func__); + + platform_set_drvdata(pdev, &the_data); + the_data.dev = pdev; + + /* Light Sensor */ + /* + ret = device_create_file(&the_data->dev, &dev_attr_ls_adc); + ret = device_create_file(&the_data->dev, &dev_attr_ls_auto); + */ + input_dev = input_allocate_device(); + if (!input_dev) + { + pr_err("%s: could not allocate input device\n", __func__); + ret = -ENOMEM; + goto done; + } + the_data.input_dev = input_dev; + input_set_drvdata(input_dev, &the_data); + + input_dev->name = "lightsensor-level"; + + set_bit(EV_ABS, input_dev->evbit); + input_set_abs_params(input_dev, ABS_MISC, 0, 9, 0, 0); + + D("%s: registering input device\n", __func__); + + ret = input_register_device(input_dev); + if (ret < 0) + { + pr_err("%s: can not register input device\n", __func__); + goto err_free_input_device; + } + + D("%s: registering misc device\n", __func__); + + ret = misc_register(&lightsensor_misc); + if (ret < 0) + { + pr_err("%s: can not register misc device\n", __func__); + goto err_unregister_input_device; + } + + the_data.old_level = -1; + INIT_DELAYED_WORK(&the_data.work, lightsensor_poll_function); + + ret = 0; //lsensor_setup(); + if (!ret) + goto done; + + misc_deregister(&lightsensor_misc); +err_unregister_input_device: + input_unregister_device(input_dev); + goto done; +err_free_input_device: + input_free_device(input_dev); +done: + return ret; + + // device_remove_file(&client->dev, &dev_attr_ls_adc); + // device_remove_file(&client->dev, &dev_attr_ls_auto); + +} + +static struct platform_driver lsensor_driver = +{ + .probe = lsensor_probe, + .driver = + { + .name = "htcleo-lsensor", + .owner = THIS_MODULE + }, +}; + +static int __init lsensor_init(void) +{ + return platform_driver_register(&lsensor_driver); +} + +//device_initcall(lsensor_init); +late_initcall(lsensor_init); + +MODULE_AUTHOR("Cotulla"); +MODULE_DESCRIPTION("LEO LSensor driver"); +MODULE_LICENSE("GPL"); +// END OF FILE diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 39898fe5..f99eb1a9 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -188,6 +188,7 @@ static struct platform_device microp_devices[] = { }, { .name = "htcleo-backlight", + .id = -1, }, { .name = "htcleo-proximity", @@ -197,6 +198,10 @@ static struct platform_device microp_devices[] = { .name = "htcleo-leds", .id = -1, }, + { + .name = "htcleo-lsensor", + .id = -1, + }, }; static struct microp_i2c_platform_data microp_data = { diff --git a/arch/arm/mach-msm/include/mach/board-htcleo-microp.h b/arch/arm/mach-msm/include/mach/board-htcleo-microp.h index 560ef4a1..86f654ef 100644 --- a/arch/arm/mach-msm/include/mach/board-htcleo-microp.h +++ b/arch/arm/mach-msm/include/mach/board-htcleo-microp.h @@ -62,6 +62,7 @@ struct microp_i2c_client_data { #define MICROP_I2C_WCMD_LED_PWM 0x25 #define MICROP_I2C_WCMD_BL_EN 0x26 #define MICROP_I2C_RCMD_VERSION 0x30 +#define MICROP_I2C_RCMD_LSENSOR 0x33 #define MICROP_I2C_WCMD_ADC_TABLE 0x42 #define MICROP_I2C_WCMD_LED_CTRL 0x51 #define MICROP_I2C_WCMD_LED_MODE 0x53