基于 platform 平台的驱动框架实现
实现步进电机的驱动
一套驱动支持多个设备
软件环境:Linux-3.5内核
硬件环境:FriendlyArm Tiny4412 开发板 / Exynos 4412 SOC / ARM cortex A9
Makefile
obj-m := window_dev.o door_dev.o bj_drv.o
MYKERNEL := /home/flyme/soc/linux-3.5-millet/
all: bjioctl.h
make -C $(MYKERNEL) M=`pwd` modules
sudo cp bj_drv.ko window_dev.ko door_dev.ko /fsroot
clean:
make -C $(MYKERNEL) M=`pwd` clean
bjioctl.h
#ifndef _BJ_H_
#define _BJ_H_
#define BJMAC 'J'
#define BJCW _IOW(BJMAC, 0, int)
#define BJCCW _IOW(BJMAC, 1, int)
#define BJSTOP _IOW(BJMAC, 2, int)
#endif // _BJ_H_
door_dev.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void door_release (struct device* pdev) {
}
static struct resource devsrc[] = {
{
.start = EXYNOS4_GPB(4),
.end = EXYNOS4_GPB(7),
.flags = IORESOURCE_MEM,
.name = "door_base",
},
};
static struct platform_device door_dev = {
.resource = devsrc,
.id = 1,
.num_resources = ARRAY_SIZE(devsrc),
.name = "door_motor",
.dev = {
.release = door_release,
},
};
module_driver(door_dev, platform_device_register, platform_device_unregister);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("door motor 3.0");
MODULE_DESCRIPTION("It is a motor device module for door");
window_dev.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void window_release (struct device* pdev) {
}
static struct resource devsrc[] = {
{
.start = EXYNOS4_GPJ0(3),
.end = EXYNOS4_GPJ0(6),
.flags = IORESOURCE_MEM,
.name = "window_base",
},
};
static struct platform_device window_dev = {
.resource = devsrc,
.id = 0,
.num_resources = ARRAY_SIZE(devsrc),
.name = "window_motor",
.dev = {
.release = window_release,
},
};
module_driver(window_dev, platform_device_register, platform_device_unregister);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("window motor 3.0");
MODULE_DESCRIPTION("It is a motor device module for window");
bj_drv.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "bjioctl.h"
#define STEP ARRAY_SIZE(beat_code)
#define DEVCNT 2
/*
#define BJBASE 0x11400000 // GPJ0base
#define BJCON 0x0240 // GPJ0con
#define BJDAT 0x0244 // GPJ0dat
*/
enum { OFF, ON };
static unsigned char beat_code[] = { // 步进电机节拍对应的 IO 控制代码
0x09, 0x03, 0x06, 0x0C
};
/*
static unsigned char beat_code[] = { // 步进电机节拍对应的 IO 控制代码
0x09, 0x01, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x08
};
*/
static int msec = 5;
static int enperied = 1;
static int major = 50;
struct motor {
u32 start;
u32 end;
int minor;
long beats;
struct cdev cdev;
struct class *class;
struct timer_list timer;
};
struct motor motor[DEVCNT];
/*
static u32 start = 0;
static u32 end = 0;
static int devnum = 0;
static struct cdev cdev;
static struct class *class = NULL;
static struct timer_list timer;
*/
static void set_mytimer(int minor, u32 sec);
static void service_timer(unsigned long data);
static void motor_start(int minor, signed long angle);
static void motor_stop(int minor);
static int motor_turn(int minor);
static void service_timer(unsigned long data) {
int minor = (int)data;
if (enperied)
mod_timer(&motor[minor].timer, jiffies + msec*HZ/1000);
if (motor_turn(minor))
enperied = 0;
}
static void set_mytimer(int minor, u32 sec) {
setup_timer(&motor[minor].timer, service_timer, (unsigned long)minor);
motor[minor].timer.expires = jiffies + sec*HZ/1000;
add_timer(&motor[minor].timer);
}
static long
my_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int minor = ((struct motor *)filp->private_data)->minor;
if (arg < 0)
return -EINVAL;
if (_IOC_TYPE(cmd) == BJMAC) {
switch (_IOC_NR(cmd)) {
default:
return -EINVAL;
case 0:
motor_start(minor, arg);
break;
case 1:
motor_start(minor, -1 * arg);
break;
case 2:
motor_stop(minor);
break;
}
}
return 0;
}
static int my_open (struct inode *inodp, struct file *filp) {
filp->private_data = container_of(inodp->i_cdev, struct motor, cdev);
return 0;
}
static int my_release (struct inode *inodp, struct file *filp) {
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.unlocked_ioctl = my_unlocked_ioctl,
.release = my_release,
};
static int bj_probe(struct platform_device *pdev)
{
int ret;
int i = 0;
int devnum = 0;
struct resource *pres;
struct device *device = NULL;
struct class *class = NULL;
motor[pdev->id].minor = pdev->id;
printk("--- driver %d device ---\n", pdev->id);
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
motor[pdev->id].start = pres->start;
motor[pdev->id].end = pres->end;
class = class_create(THIS_MODULE, pdev->name);
if (IS_ERR(class))
return PTR_ERR(class);
printk("--- class create %s ---\n", pdev->name);
for (i = pres->start; i <= pres->end; i++) {
if ((ret = gpio_request(i, "motor")) < 0)
goto error0;
gpio_direction_output(i, OFF);
}
printk("--- %d gpio request ---\n", pres->start);
devnum = MKDEV(major, pdev->id);
printk("--- devnum is %d ---\n", devnum);
ret = register_chrdev_region(devnum, 1, pdev->name);
if (ret < 0) {
ret = -EINVAL;
goto error0;
}
printk("--- register %d ---\n", devnum);
cdev_init(&motor[pdev->id].cdev, &fops);
if ((ret = cdev_add(&motor[pdev->id].cdev, devnum, 1)) < 0)
goto error1;
printk("--- cdev add %d ---\n", devnum);
device = device_create(class, NULL, devnum, NULL, pdev->name);
if (IS_ERR(device)) {
ret = PTR_ERR(device);
goto error2;
}
motor[pdev->id].class = class;
printk("--- device create %s ok! ---\n", pdev->name);
return 0;
error2:
cdev_del(&motor[pdev->id].cdev);
error1:
unregister_chrdev_region(devnum, 1);
error0:
class_destroy(class);
for ( ; i >= pres->start; i--)
gpio_free(i);
return ret;
}
static int bj_remove(struct platform_device *pdev)
{
int i = 0;
int devnum = 0;
struct resource *pres;
struct class *class = motor[pdev->id].class;
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
devnum = MKDEV(major, pdev->id);
device_destroy(class, devnum);
cdev_del(&motor[pdev->id].cdev);
for (i = pres->start; i <= pres->end; i++)
gpio_free(i);
cdev_del(&motor[pdev->id].cdev);
unregister_chrdev_region(devnum, 1);
class_destroy(class);
printk("--- cdev %s die! ---\n", pdev->name);
return 0;
}
static struct platform_device_id millet_tables[] = {
{ "door_motor", },
{ "window_motor", },
};
static struct platform_driver bj_drv = {
.id_table = millet_tables,
.driver= {
.name = "bj_motor",
},
.probe = bj_probe,
.remove = bj_remove,
};
module_platform_driver(bj_drv);
static void motor_start(int minor, signed long angle) {
motor[minor].beats = (angle * 4076 / 2) / 360; // 实测为 4076 拍转动一圈
set_mytimer(minor, msec);
enperied = 1;
}
static void motor_stop(int minor) {
motor[minor].beats = 0;
del_timer_sync(&motor[minor].timer);
enperied = 1;
}
static int motor_turn(int minor)
{
int i = 0, j = 0;
int ret = 0;
static unsigned char index[DEVCNT] = {0};
long beats[DEVCNT] = {0};
beats[minor] = motor[minor].beats;
if (beats[minor] != 0) {
if (beats[minor] > 0) {
index[minor]++;
index[minor] = index[minor] & (STEP - 1); // (STEP==4)?0x3:0x7
motor[minor].beats--;
} else {
index[minor]--;
index[minor] = index[minor] & (STEP - 1);
motor[minor].beats++;
}
for (i = motor[minor].start, j = 0; i <= motor[minor].end; i++, j++) {
if (beat_code[index[minor]] & (0x1 << j))
gpio_set_value(i, ON);
else
gpio_set_value(i, OFF);
}
ret = 0;
} else
ret = 1;
return ret;
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wanghaomaker");
MODULE_VERSION("bj motor 3.0");
MODULE_DESCRIPTION("It is a motor driver module");