Camera IR laser driver

#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");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值