基于 platform 平台的驱动框架实现_驱动

实现步进电机的驱动

一套驱动支持多个设备

软件环境:Linux-3.5内核
硬件环境:FriendlyArm Tiny4412开发板

/* bj_drv.c */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>

#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;
    char dir_motor;
    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 
demo_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 demo_open (struct inode *inodp, struct file *filp) {
    filp->private_data = container_of(inodp->i_cdev, struct motor, cdev);
    return 0;
}

static int demo_release (struct inode *inodp, struct file *filp) {
    return 0;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = demo_open,
    .unlocked_ioctl = demo_unlocked_ioctl,
    .release = demo_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("wanghao plus 3");
MODULE_DESCRIPTION("It is a simplest demo for motor driver module");

===================================================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值