#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/of_gpio.h>
#include <linux/sunxi-gpio.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <asm/io.h>
#define LEFT_RIGHT_TIMER_PERIOD_MS 8
#define IR_TIMER_PERIOD_MS 15
#define LASER_CTRL_DRIVER_NAME "laser_ctrl"
enum LASER_ID {
LEFT_LASER = 0,
MIDDLE_LASER = 1,
RIGHT_LASER = 2,
IR_LASER = 3,
LASER_NUM = 4,
};
struct laser_ctrl {
struct gpio_config left_laser;
struct gpio_config right_laser;
struct gpio_config ir_laser;
struct gpio_config strobe;
unsigned int left_laser_io;
unsigned int right_laser_io;
unsigned int ir_laser_io;
unsigned int strobe_io;
int strobe_irq;
int strobe_irq_count;
struct timer_list left_timer;
struct timer_list right_timer;
struct timer_list ir_timer;
int left_right_timerperiod;
int ir_timerperiod;
spinlock_t lock;
unsigned long state;
};
unsigned int os_gpio_request(struct gpio_config *pin_cfg)
{
unsigned int ret = 0;
if (pin_cfg->gpio == GPIO_INDEX_INVALID)
return 0;
ret = gpio_request(pin_cfg->gpio, NULL);
if (ret != 0) {
pr_err("%s failed, gpio=%d, ret=0x%x\n", __func__, pin_cfg->gpio, ret);
return 0;
}
return pin_cfg->gpio;
}
int os_gpio_release(unsigned int p_handler)
{
gpio_free(p_handler);
return 0;
}
int os_gpio_set(struct gpio_config *pin_cfg)
{
int ret = 0;
char pin_name[32];
__u32 config;
if (pin_cfg->gpio == GPIO_INDEX_INVALID)
return 0;
sunxi_gpio_to_name(pin_cfg->gpio, pin_name);
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_FUNC, pin_cfg->mul_sel);
pin_config_set(SUNXI_PINCTRL, pin_name, config);
if (pin_cfg->pull != GPIO_PULL_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_PUD, pin_cfg->pull);
pin_config_set(SUNXI_PINCTRL, pin_name, config);
}
if (pin_cfg->drv_level != GPIO_DRVLVL_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DRV, pin_cfg->drv_level);
pin_config_set(SUNXI_PINCTRL, pin_name, config);
}
if (pin_cfg->data != GPIO_DATA_DEFAULT) {
config = SUNXI_PINCFG_PACK(SUNXI_PINCFG_TYPE_DAT, pin_cfg->data);
pin_config_set(SUNXI_PINCTRL, pin_name, config);
}
return ret;
}
static void left_timer_func(unsigned long arg)
{
struct laser_ctrl *ctrl = (struct laser_ctrl*)arg;
unsigned long flags = 0;
spin_lock_irqsave(&ctrl->lock, flags);
if(test_bit(LEFT_LASER, &ctrl->state)) {
pr_info("time is up, timer closes left laser\n");
__gpio_set_value(ctrl->left_laser_io, 0);
clear_bit(LEFT_LASER, &ctrl->state);
}
spin_unlock_irqrestore(&ctrl->lock, flags);
}
static void right_timer_func(unsigned long arg)
{
struct laser_ctrl *ctrl = (struct laser_ctrl*)arg;
unsigned long flags = 0;
spin_lock_irqsave(&ctrl->lock, flags);
if(test_bit(RIGHT_LASER, &ctrl->state)) {
pr_info("time is up, timer closes right laser\n");
__gpio_set_value(ctrl->right_laser_io, 0);
clear_bit(RIGHT_LASER, &ctrl->state);
}
spin_unlock_irqrestore(&ctrl->lock, flags);
}
static void ir_timer_func(unsigned long arg)
{
struct laser_ctrl *ctrl = (struct laser_ctrl*)arg;
unsigned long flags = 0;
spin_lock_irqsave(&ctrl->lock, flags);
if(test_bit(IR_LASER, &ctrl->state)) {
pr_info("time is up, timer closes ir laser\n");
__gpio_set_value(ctrl->ir_laser_io, 0);
clear_bit(IR_LASER, &ctrl->state);
}
spin_unlock_irqrestore(&ctrl->lock, flags);
}
static unsigned int request_irq_trig_type(struct laser_ctrl *ctrl)
{
unsigned int trig_type = 0;
int val;
val = __gpio_get_value(ctrl->strobe_io);
if(val) {
trig_type |= BIT(0);
} else {
trig_type |= BIT(1);
}
return trig_type;
}
static irqreturn_t strobe_isr(int irq, void *dev_id)
{
struct laser_ctrl *ctrl = (struct laser_ctrl*)dev_id;
unsigned int index, trig_type;
unsigned long flags = 0;
spin_lock_irqsave(&ctrl->lock, flags);
/* fix me */
trig_type = request_irq_trig_type(ctrl);
index = (ctrl->strobe_irq_count / 2) % LASER_NUM;
pr_info("%s: index=%d, trig_type=0x%x\n", __func__, index, trig_type);
if(trig_type & IRQF_TRIGGER_RISING) {
switch(index) {
case LEFT_LASER:
if(!test_bit(LEFT_LASER, &ctrl->state)) {
/* consecutive rising edges might be detected because of jitters, */
/* prevent repeated activation of the timer here */
if(!timer_pending(&ctrl->left_timer)) {
ctrl->left_timer.function = left_timer_func;
ctrl->left_timer.expires=jiffies + msecs_to_jiffies(ctrl->left_right_timerperiod);
ctrl->left_timer.data = (unsigned long)ctrl;
add_timer(&ctrl->left_timer);
}
__gpio_set_value(ctrl->left_laser_io, 1);
set_bit(LEFT_LASER, &ctrl->state);
}
break;
case RIGHT_LASER:
if(!test_bit(RIGHT_LASER, &ctrl->state)) {
if(!timer_pending(&ctrl->right_timer)) {
ctrl->right_timer.function = right_timer_func;
ctrl->right_timer.expires=jiffies + msecs_to_jiffies(ctrl->left_right_timerperiod);
ctrl->right_timer.data = (unsigned long)ctrl;
add_timer(&ctrl->right_timer);
}
__gpio_set_value(ctrl->right_laser_io, 1);
set_bit(RIGHT_LASER, &ctrl->state);
}
break;
case IR_LASER:
if(!test_bit(IR_LASER, &ctrl->state)) {
if(!timer_pending(&ctrl->ir_timer)) {
ctrl->ir_timer.function = ir_timer_func;
ctrl->ir_timer.expires=jiffies + msecs_to_jiffies(ctrl->ir_timerperiod);
ctrl->ir_timer.data = (unsigned long)ctrl;
add_timer(&ctrl->ir_timer);
}
__gpio_set_value(ctrl->ir_laser_io, 1);
set_bit(IR_LASER, &ctrl->state);
}
break;
default:
break;
}
} else {
switch(index) {
case LEFT_LASER:
if(test_bit(LEFT_LASER, &ctrl->state)) {
__gpio_set_value(ctrl->left_laser_io, 0);
clear_bit(LEFT_LASER, &ctrl->state);
}
break;
case RIGHT_LASER:
if(test_bit(RIGHT_LASER, &ctrl->state)) {
__gpio_set_value(ctrl->right_laser_io, 0);
clear_bit(RIGHT_LASER, &ctrl->state);
}
break;
case IR_LASER:
if(test_bit(IR_LASER, &ctrl->state)) {
__gpio_set_value(ctrl->ir_laser_io, 0);
clear_bit(IR_LASER, &ctrl->state);
}
break;
default:
break;
}
}
ctrl->strobe_irq_count++;
spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
}
static int laser_ctrl_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct laser_ctrl *ctrl;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
memset(ctrl, 0, sizeof(*ctrl));
ctrl->left_laser.gpio = of_get_named_gpio_flags(np, "left_laser", 0,
(enum of_gpio_flags *)(&ctrl->left_laser));
if (!gpio_is_valid(ctrl->left_laser.gpio))
pr_err("%s: left_laser io is invalid.\n", __func__);
ctrl->right_laser.gpio = of_get_named_gpio_flags(np, "right_laser", 0,
(enum of_gpio_flags *)(&ctrl->right_laser));
if (!gpio_is_valid(ctrl->right_laser.gpio))
pr_err("%s: right_laser io is invalid.\n", __func__);
ctrl->ir_laser.gpio = of_get_named_gpio_flags(np, "ir_laser", 0,
(enum of_gpio_flags *)(&ctrl->ir_laser));
if (!gpio_is_valid(ctrl->ir_laser.gpio))
pr_err("%s: ir_laser io is invalid.\n", __func__);
ctrl->strobe.gpio = of_get_named_gpio_flags(np, "strobe", 0,
(enum of_gpio_flags *)(&ctrl->strobe));
if (!gpio_is_valid(ctrl->strobe.gpio))
pr_err("%s: strobe io is invalid.\n", __func__);
/* request gpio */
ctrl->left_laser_io = os_gpio_request(&ctrl->left_laser);
os_gpio_set(&ctrl->left_laser);
ctrl->right_laser_io = os_gpio_request(&ctrl->right_laser);
os_gpio_set(&ctrl->right_laser);
ctrl->ir_laser_io = os_gpio_request(&ctrl->ir_laser);
os_gpio_set(&ctrl->ir_laser);
ctrl->strobe_io = os_gpio_request(&ctrl->strobe);
gpio_direction_input(ctrl->strobe.gpio);
ctrl->strobe_irq = gpio_to_irq(ctrl->strobe.gpio);
/* init timer for closing laser automatically */
ctrl->left_right_timerperiod = LEFT_RIGHT_TIMER_PERIOD_MS;
ctrl->ir_timerperiod = IR_TIMER_PERIOD_MS;
init_timer(&ctrl->left_timer);
init_timer(&ctrl->right_timer);
init_timer(&ctrl->ir_timer);
ctrl->state = 0;
/* request irq */
if (devm_request_irq(&pdev->dev, ctrl->strobe_irq, strobe_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "laser_ctrl", ctrl)) {
pr_err("%s request irq %d failure\n", __func__, ctrl->strobe_irq);
} else {
pr_info("%s request irq success, strobe_irq:%d\n", __func__, ctrl->strobe_irq);
}
/* disable_irq(ctrl->strobe_irq); */
spin_lock_init(&ctrl->lock);
dev_set_drvdata(&pdev->dev, ctrl);
return 0;
}
static int laser_ctrl_remove(struct platform_device *pdev)
{
struct laser_ctrl *ctrl = (struct laser_ctrl*)dev_get_drvdata(&pdev->dev);
os_gpio_release(ctrl->left_laser_io);
os_gpio_release(ctrl->right_laser_io);
os_gpio_release(ctrl->ir_laser_io);
os_gpio_release(ctrl->strobe_io);
del_timer(&ctrl->left_timer);
del_timer(&ctrl->right_timer);
del_timer(&ctrl->ir_timer);
devm_free_irq(&pdev->dev, ctrl->strobe_irq, (void *)ctrl);
dev_set_drvdata(&pdev->dev, NULL);
kfree(ctrl);
return 0;
}
static const struct of_device_id laser_ctrl_match[] = {
{ .compatible = "laser_ctrl", },
{ },
};
MODULE_DEVICE_TABLE(of, laser_ctrl_match);
static struct platform_driver laser_ctrl_driver = {
.driver = {
.name = LASER_CTRL_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = laser_ctrl_match,
},
.probe = laser_ctrl_probe,
.remove = laser_ctrl_remove,
};
static int laser_ctrl_init(void)
{
platform_driver_register(&laser_ctrl_driver);
return 0;
}
static void laser_ctrl_exit(void)
{
platform_driver_unregister(&laser_ctrl_driver);
}
module_init(laser_ctrl_init);
module_exit(laser_ctrl_exit);
MODULE_AUTHOR("zhaoyumin");
MODULE_LICENSE("GPL");
Camera IR laser driver
最新推荐文章于 2024-07-16 09:48:01 发布