htcleo: add lightsensor driver
There are still power on problems, has to be fixed
This commit is contained in:
parent
134b43d9fc
commit
7677794c9b
@ -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
|
||||
|
@ -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)
|
||||
|
359
arch/arm/mach-msm/board-htcleo-ls.c
Normal file
359
arch/arm/mach-msm/board-htcleo-ls.c
Normal file
@ -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 <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/lightsensor.h>
|
||||
#include <linux/earlysuspend.h>
|
||||
#include <mach/board-htcleo-microp.h>
|
||||
|
||||
#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
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user