linux红外对管(距离传感器)驱动 分析
来源:互联网 发布:ubuntu lts 安装 编辑:程序博客网 时间:2024/04/29 22:35
头文件:
/** filename: rohm_scm_proximity.h*/#ifndef __ROHM_SCM_PROXIMTIY__#define __ROHM_SCM_PROXIMTIY__#define ROHM_PROXIMITY "rohm_proximity"#define PROXIMITY_DEVICE "rohm_proximity"#include <linux/types.h>#include <linux/ioctl.h>#define ROHM_PROXIMITY_IOCTL_MAGIC 'r'#define ROHM_PROXIMITY_IOCTL_GET_ENABLED _IOR(ROHM_PROXIMITY_IOCTL_MAGIC, 1, int *)#define ROHM_PROXIMITY_IOCTL_ENABLE _IOW(ROHM_PROXIMITY_IOCTL_MAGIC, 2, int *)#endif
/*
* File: rohm_scm_proximity.c
* Based on:
* Author: Yunlong Wang <Yunlong.Wang@spreadtrum.com>
*
* Created: 2011-04-08
* Description: Rohm Proximity Sensor Driver
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/kernel.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/delay.h>
#include <linux/wakelock.h>
#include <mach/mfp.h>
#include <mach/adc_drvapi.h>
#include "rohm_scm_proximity.h"
#define PS_DEBUG 1
#define RHOM_PROXIMITY_DATA_POLL_TIMER 100
#define RHOM_PROXIMITY_THRESHOLD 500
#define RHOM_PROXIMITY_ADC_CHANNEL 1
//static int debug_level=0;
static int debug_level=1;
#if PS_DEBUG
#define PS_DBG(format, ...) \
if(debug_level == 1) \
printk(KERN_INFO "PROXIMITY: " format , ## __VA_ARGS__)
#else
#define PS_DBG(format, ...)
#endif
extern int sprd_3rdparty_gpio_proximity_trans;
extern int sprd_3rdparty_gpio_proximity_recv;
struct rohm_proximity_platform_data {
int gpio_trans; /*control transmit light*/
int gpio_recv; /*control recevie light*/
};
static struct rohm_proximity_platform_data proximity_platform_data;
static struct wake_lock prox_delayed_work_wake_lock;
static struct rohm_proximity_data {
struct input_dev *input_dev;
struct rohm_proximity_platform_data *pdata;
struct delayed_work work;
struct workqueue_struct *work_queue;
int enabled;
} proximity_data;
static int misc_opened;
static int proximity_start=0;
static struct platform_device rohm_proximity_device = {
.name = ROHM_PROXIMITY,
.id = -1,
.dev = {
.platform_data = &proximity_platform_data,
},
};
static int rohm_proximity_enable(struct rohm_proximity_data *data);
static int rohm_proximity_disable(struct rohm_proximity_data *data);
static ssize_t rohm_proximity_show_control(struct device* cd, struct device_attribute *attr, char* buf)
{
ssize_t ret = 0;
if(proximity_start==1)
sprintf(buf, "Proximity Start\n");
else
sprintf(buf, "Proximity Stop\n");
ret = strlen(buf) + 1;
return ret;
}
static ssize_t rohm_proximity_store_control(struct device* cd, struct device_attribute *attr, const char* buf, size_t len)
{
unsigned long on_off = simple_strtoul(buf, NULL, 10);
proximity_start = on_off;
if(on_off==1)
{
printk("Proximity Start\n");
rohm_proximity_enable(&proximity_data);
}
else
{
printk("Proximity Stop\n");
rohm_proximity_disable(&proximity_data);
}
return len;
}
static ssize_t rohm_proximity_show_debug(struct device* cd,struct device_attribute *attr, char* buf)
{
ssize_t ret = 0;
sprintf(buf, "ROHM Debug %d\n",debug_level);
ret = strlen(buf) + 1;
return ret;
}
static ssize_t rohm_proximity_store_debug(struct device* cd, struct device_attribute *attr,
const char* buf, size_t len)
{
unsigned long on_off = simple_strtoul(buf, NULL, 10);
debug_level = on_off;
printk("%s: debug_level=%d\n",__func__, debug_level);
return len;
}
static DEVICE_ATTR(control, S_IRUGO | S_IWUSR, rohm_proximity_show_control, rohm_proximity_store_control);
static DEVICE_ATTR(debug, S_IRUGO | S_IWUSR, rohm_proximity_show_debug, rohm_proximity_store_debug);
static int rohm_proximity_create_sysfs(struct platform_device *client)
{
struct device *dev = &(client->dev);
int err = 0;
PS_DBG("%s\n", __func__);
if ((err = device_create_file(dev, &dev_attr_control)))
goto err_out;
if ((err = device_create_file(dev, &dev_attr_debug)))
goto err_out;
return 0;
err_out:
return err;
}
static int rohm_proximity_get_adc(void)
{
int val;
val = ADC_GetValue(RHOM_PROXIMITY_ADC_CHANNEL, ADC_SCALE_3V);
return val;
}
static int rohm_proximity_report(struct rohm_proximity_data *data)
{
int data1, data2;
int val;
//get environment adc
gpio_set_value(data->pdata->gpio_recv, 1);
msleep(30); //for stable
data1 = rohm_proximity_get_adc();
//get infrared adc
gpio_set_value(data->pdata->gpio_trans, 1);
msleep(30);
data2 = rohm_proximity_get_adc();
val = (data2-data1)>RHOM_PROXIMITY_THRESHOLD? 0:1;
PS_DBG("data1=%d; data2=%d; proximity=%d\n", data1, data2, val);
/* 0 is close, 1 is far */
input_report_abs(data->input_dev, ABS_DISTANCE, val);
input_sync(data->input_dev);
gpio_set_value(data->pdata->gpio_recv, 0);
gpio_set_value(data->pdata->gpio_trans, 0);
return val;
}
static void rohm_proximity_start_work(int ms, struct rohm_proximity_data *data)
{
queue_delayed_work(data->work_queue, &data->work,msecs_to_jiffies(ms));
}
static void rohm_proximity_stop_work(struct rohm_proximity_data *data)
{
PS_DBG("%s\n", __func__);
cancel_rearming_delayed_workqueue(data->work_queue,&data->work);
flush_workqueue(data->work_queue);
}
static void rohm_proximity_work(struct work_struct *work)
{
struct rohm_proximity_data *data = container_of(work, struct rohm_proximity_data, work.work);
rohm_proximity_report(data);
rohm_proximity_start_work(RHOM_PROXIMITY_DATA_POLL_TIMER, data);
}
static int rohm_proximity_enable(struct rohm_proximity_data *data)
{
PS_DBG("%s\n", __func__);
data->enabled = 1;
wake_lock(&prox_delayed_work_wake_lock);
rohm_proximity_start_work(RHOM_PROXIMITY_DATA_POLL_TIMER, data);
return 0;
}
static int rohm_proximity_disable(struct rohm_proximity_data *data)
{
PS_DBG("%s\n", __func__);
data->enabled = 0;
wake_unlock(&prox_delayed_work_wake_lock);
rohm_proximity_stop_work(data);
return 0;
}
static int rohm_proximity_setup(struct rohm_proximity_data *ip)
{
struct rohm_proximity_platform_data *pdata = ip->pdata;
//config gpio
pdata->gpio_trans = sprd_3rdparty_gpio_proximity_trans;
pdata->gpio_recv = sprd_3rdparty_gpio_proximity_recv;
PS_DBG("%s, gpio_recv=%d; gpio_trans=%d\n", __func__, pdata->gpio_recv, pdata->gpio_trans);
gpio_direction_output(pdata->gpio_trans, 0);
gpio_direction_output(pdata->gpio_recv, 0);
//set control gpio low
gpio_set_value(pdata->gpio_trans, 0);
gpio_set_value(pdata->gpio_recv, 0);
//init adc
ADC_Init();
return 0;
}
static int rohm_proximity_open(struct inode *inode, struct file *file)
{
PS_DBG("%s\n", __func__);
if (misc_opened)
return -EBUSY;
misc_opened = 1;
return 0;
}
static int rohm_proximity_release(struct inode *inode, struct file *file)
{
PS_DBG("%s\n", __func__);
misc_opened = 0;
return rohm_proximity_disable(&proximity_data);
}
static long rohm_proximity_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int val;
PS_DBG("%s cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
case ROHM_PROXIMITY_IOCTL_ENABLE:
if (get_user(val, (unsigned long __user *)arg))
return -EFAULT;
if (val)
return rohm_proximity_enable(&proximity_data);
else
return rohm_proximity_disable(&proximity_data);
break;
case ROHM_PROXIMITY_IOCTL_GET_ENABLED:
return put_user(proximity_data.enabled, (unsigned long __user *)arg);
break;
default:
pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
return -EINVAL;
}
}
static struct file_operations rohm_proximity_fops = {
.owner = THIS_MODULE,
.open = rohm_proximity_open,
.release = rohm_proximity_release,
.unlocked_ioctl = rohm_proximity_ioctl
};
struct miscdevice rohm_proximity_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = PROXIMITY_DEVICE,
.fops = &rohm_proximity_fops
};
static int rohm_proximity_probe(struct platform_device *pdev)
{
int rc = -EIO;
struct input_dev *input_dev;
struct rohm_proximity_data *ip;
struct rohm_proximity_platform_data *pdata;
PS_DBG("%s\n", __func__);
wake_lock_init(&prox_delayed_work_wake_lock, WAKE_LOCK_SUSPEND, "prox_delayed_work");
pdata = pdev->dev.platform_data;
if (!pdata) {
pr_err("%s: missing pdata!\n", __func__);
goto done;
}
ip = &proximity_data;
platform_set_drvdata(pdev, ip);
PS_DBG("%s: allocating input device\n", __func__);
input_dev = input_allocate_device();
if (!input_dev) {
pr_err("%s: could not allocate input device\n", __func__);
rc = -ENOMEM;
goto done;
}
ip->input_dev = input_dev;
ip->pdata = pdata;
input_set_drvdata(input_dev, ip);
input_dev->name = "proximity";
input_dev->phys = "proximity";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_DISTANCE, 0, 1, 0, 0);
PS_DBG("%s: registering input device\n", __func__);
rc = input_register_device(input_dev);
if (rc < 0) {
pr_err("%s: could not register input device\n", __func__);
goto err_free_input_device;
}
PS_DBG("%s: registering misc device\n", __func__);
rc = misc_register(&rohm_proximity_misc);
if (rc < 0) {
pr_err("%s: could not register misc device\n", __func__);
goto err_unregister_input_device;
}
//create work queue
INIT_DELAYED_WORK(&ip->work, rohm_proximity_work);
ip->work_queue = create_singlethread_workqueue("proximity");
rohm_proximity_create_sysfs(pdev);
//rohm_proximity_enable(&proximity_data);//add by DO驱动自动启动,不用上层调用
rc = rohm_proximity_setup(ip);
if (!rc)
goto done;
misc_deregister(&rohm_proximity_misc);
err_unregister_input_device:
input_unregister_device(input_dev);
err_free_input_device:
input_free_device(input_dev);
wake_lock_destroy(&prox_delayed_work_wake_lock);
done:
PS_DBG("%s, Done\n", __func__);
return rc;
}
static int rohm_proximity_remove(struct platform_device *pdev)
{
struct rohm_proximity_platform_data *pdata=pdev->dev.platform_data;
cancel_rearming_delayed_workqueue(proximity_data.work_queue, &proximity_data.work);
flush_workqueue(proximity_data.work_queue);
destroy_workqueue(proximity_data.work_queue);
misc_deregister(&rohm_proximity_misc);
input_unregister_device(proximity_data.input_dev);
input_free_device(proximity_data.input_dev);
//unregister gpio
gpio_free(pdata->gpio_trans);
gpio_free(pdata->gpio_recv);
wake_lock_destroy(&prox_delayed_work_wake_lock);
return 0;
}
static struct platform_driver rohm_proximity_driver = {
.probe = rohm_proximity_probe,
.remove = rohm_proximity_remove,
.driver = {
.name = ROHM_PROXIMITY,
.owner = THIS_MODULE
},
};
static int __devinit rohm_proximity_init(void)
{
PS_DBG("%s\n",__func__);
platform_device_register(&rohm_proximity_device);
return platform_driver_register(&rohm_proximity_driver);
}
static void rohm_proximity_exit(void)
{
PS_DBG("%s\n",__func__);
platform_device_unregister(&rohm_proximity_device);
platform_driver_unregister(&rohm_proximity_driver);
}
module_init(rohm_proximity_init);
module_exit(rohm_proximity_exit);
MODULE_DESCRIPTION("Rohm Proximity driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:proximity sensor");
- linux红外对管(距离传感器)驱动 分析
- linux sensor 驱动之 psensor(proximity-sensor距离传感器)
- 距离传感器vcnl4010驱动总结
- 重力传感器驱动分析
- 树莓派红外反射传感器(Python程序)
- Android传感器(四):距离传感器
- 红外管的载波
- Linux内核学习实践之红外驱动分析—RCA38KHz软解码
- Linux内核学习实践之红外驱动分析—RCA38KHz软解码
- 光传感器和距离传感器TMD22713源代码执行过程分析
- 光传感器和距离传感器TMD22713源代码执行过程分析
- 光传感器和距离传感器TMD22713源代码执行过程分析
- iOS扬声器和听筒模式的切换以及距离传感器红外感应的设置
- 距离传感器
- 距离传感器
- 距离传感器
- Linux内存管技术分析
- linux传感器三之轴陀螺仪(MPU3050)驱动解析
- 嵌入式ARM CPU协处理器讲解
- 如何获取iphone\ipad的UUID(设备ID)号?
- Linux查看内存命令free
- vim使用技巧
- php操作memcache的使用测试总结
- linux红外对管(距离传感器)驱动 分析
- Smack 结合 Openfire服务器,建立IM通信,发送聊天消息
- ios中self的用法
- linux下mysql5.5.27 安装以及应用
- bigbulebutton
- 怎样获取iPhone/ipad的设备ID(UUID)号?
- 招聘新人面试心得
- linux 文件编码格式转换
- androidBitmap圆角与倒影实现