ckfwq/linux-3.0.4/drivers/char/amr_ledctrl.c

275 lines
6.9 KiB
C
Raw Normal View History

2024-12-30 10:53:50 +08:00
/*
* amr_ledctrl.c - driver for Emi Display in Loongson soc
*
* Copyright (C) 2012 Loongson Corporation
*
* 2013-01-31
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/rcupdate.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/completion.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <gsc3280/gpio.h>
#include <gsc3280/timer.h>
#include "amr_ledctrl.h"
static void amr_stop_led(struct amr_ledsctrl_param *param);
/*----------------------------------------------------------------------------*/
struct gpio amr_leds_gpios[AMR_MAX_PIN_NR] = {
{GSC3280_GPC(15), GPIOF_OUT_INIT_HIGH, "AMR run led"},
{GSC3280_GPC(16), GPIOF_OUT_INIT_HIGH, "AMR alarm led"}
};
/*----------------------------------------------------------------------------*/
struct amr_ledctrl {
struct cdev cdev;
struct class *amrleds_class;
dev_t dev;
bool led_on;
bool timer_run;
unsigned int total_time;
struct gsc3280_hard_timer amr_hard_timer;
struct amr_ledsctrl_param amr_param;
};
struct amr_ledctrl amr_ledctrl_priv;
void amr_hard_timer_fn(unsigned long data)
{
struct amr_ledsctrl_param *param = &amr_ledctrl_priv.amr_param;
if (amr_ledctrl_priv.led_on == true)
amr_ledctrl_priv.total_time += param->on_time;
else
amr_ledctrl_priv.total_time += param->off_time;
if (amr_ledctrl_priv.total_time >= param->run_time)
{
amr_stop_led(param);
return;
}
else
{
if (amr_ledctrl_priv.led_on == true)
{
amr_ledctrl_priv.amr_hard_timer.expires = param->off_time;
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 1);
amr_ledctrl_priv.led_on = false;
}
else
{
amr_ledctrl_priv.amr_hard_timer.expires = param->on_time;
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 0);
amr_ledctrl_priv.led_on = true;
}
gsc3280_mod_timer(&amr_ledctrl_priv.amr_hard_timer);
}
}
static void amr_stop_led(struct amr_ledsctrl_param *param)
{
amr_ledctrl_priv.led_on = false;
gsc3280_timer_stop(&amr_ledctrl_priv.amr_hard_timer);
amr_ledctrl_priv.timer_run = false;
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 1);
}
static int amr_start_led(struct amr_ledsctrl_param *param)
{
amr_ledctrl_priv.timer_run = true;
amr_ledctrl_priv.amr_hard_timer.type = ONCE;
amr_ledctrl_priv.amr_hard_timer.expires = param->on_time;
amr_ledctrl_priv.amr_hard_timer.function = amr_hard_timer_fn;
amr_ledctrl_priv.amr_hard_timer.data = (unsigned long)param;
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 0);
amr_ledctrl_priv.led_on = true;
gsc3280_timer_start(&amr_ledctrl_priv.amr_hard_timer);
amr_ledctrl_priv.total_time = 0;
return 0;
}
/*----------------------------------------------------------------------------*/
/*
*/
static long amrleds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct amr_ledsctrl_param *param = &amr_ledctrl_priv.amr_param;
if (_IOC_TYPE(cmd) != AMR_LED_MAGIC) return -ENOTTY;
if (_IOC_NR(cmd) > EMIDISP_IOC_MAXNR) return -ENOTTY;
/*
if (amr_ledctrl_priv.timer_run == true)
return -EBUSY;
*/
copy_from_user(param, (unsigned char*)arg, sizeof(struct amr_ledsctrl_param));
if (param->led_index >= AMR_MAX_PIN_NR) return -EINVAL;
if (param->run_time < (param->on_time + param->off_time)) {
param->run_time = param->on_time + param->off_time;
}
switch(cmd) {
case AMR_LED_RUN:
if (0 != param->on_time) {
ret = amr_start_led(param);
if (ret)
return ret;
} else
return -EINVAL;
break;
case AMR_LED_STOP:
amr_stop_led(param);
break;
case AMR_LED_ON:
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 0);
amr_ledctrl_priv.led_on = true;
break;
case AMR_LED_OFF:
gpio_set_value(amr_leds_gpios[param->led_index].gpio, 1);
amr_ledctrl_priv.led_on = false;
break;
default:
return -ENOTTY;
}
return 0;
}
static int amrleds_open(struct inode *inode, struct file *filp) {
int ret = 0;
ret = gpio_request_array(amr_leds_gpios, AMR_MAX_PIN_NR);
if (ret < 0)
return ret;
memset(&amr_ledctrl_priv.amr_hard_timer,
0x00, sizeof(amr_ledctrl_priv.amr_hard_timer));
ret = gsc3280_request_hard_timer(&amr_ledctrl_priv.amr_hard_timer);
if (ret)
return ret;
amr_ledctrl_priv.timer_run = false;
return 0;
}
static int amrleds_release(struct inode *inode, struct file *filp)
{
gsc3280_free_hard_timer(&amr_ledctrl_priv.amr_hard_timer);
gpio_free_array(amr_leds_gpios, AMR_MAX_PIN_NR);
amr_stop_led(&amr_ledctrl_priv.amr_param);
return 0;
}
struct file_operations amrleds_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = amrleds_ioctl,
.open = amrleds_open,
.release = amrleds_release,
};
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
static int __init amr_ledctrl_init(void)
{
int err;
int result;
int major;
result = alloc_chrdev_region(&amr_ledctrl_priv.dev, 0, 0, "amrleds");
major = MAJOR(amr_ledctrl_priv.dev);
if (result < 0) {
printk(KERN_WARNING "amr_ledctrl: can't get major %d\n", major);
return result;
}
cdev_init(&amr_ledctrl_priv.cdev, &amrleds_fops);
amr_ledctrl_priv.cdev.owner = THIS_MODULE;
amr_ledctrl_priv.cdev.ops = &amrleds_fops;
err = cdev_add(&amr_ledctrl_priv.cdev, amr_ledctrl_priv.dev, 1);
if (err) {
printk(KERN_NOTICE "Error[%d] cdev_add emidisp\n", err);
return -1;
}
amr_ledctrl_priv.amrleds_class = class_create(THIS_MODULE, "amrleds");
if (IS_ERR(amr_ledctrl_priv.amrleds_class)) {
printk(KERN_ERR "Failed in create amrleds_cdev class\n");
return -1;
}
device_create(amr_ledctrl_priv.amrleds_class, NULL,
amr_ledctrl_priv.dev,
NULL, "amrleds");
return 0;
}
/*----------------------------------------------------------------------------*/
static void __exit amr_ledctrl_exit(void)
{
cdev_del(&amr_ledctrl_priv.cdev);
unregister_chrdev_region(amr_ledctrl_priv.dev, 1);
device_destroy(amr_ledctrl_priv.amrleds_class, amr_ledctrl_priv.dev);
class_destroy(amr_ledctrl_priv.amrleds_class);
}
/*----------------------------------------------------------------------------*/
module_init(amr_ledctrl_init);
module_exit(amr_ledctrl_exit);
/*----------------------------------------------------------------------------*/
MODULE_AUTHOR("ansonn.wang@gmail.com");
MODULE_DESCRIPTION("amr leds driver");
MODULE_LICENSE("GPL");
/*----------------------------------------------------------------------------*/