嵌入式Linux驱动加载问题...

嵌入式Linux驱动

在TI的芯片AM4378开发板上运行linux.
工具链是gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf
板子内核版本4.1.18
主机Ubuntu18.x

添加QEP驱动
步骤如下:
1.在内核文件夹下linux-master/drivers新建文件夹qep
添加驱动文件tieqep.c

/*
 * TI eQEP driver for AM33xx devices
 * sysfs entries
 *   - position = absolute - current position; relative - last latched value
 *   - mode => 0 - absolute; 1 - relative
 *   - period => sampling period for the hardware
 *   - enable => 0 - eQEP disabled, 1 - eQEP enabled
 */

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/input.h>
 
// Include the PWMSS subsystem headers, because this unit controls
// whether our clock source is enabled, and if eQEP is to be
// enabled, we need to start the clock
#include "../pwm/pwm-tipwmss.h"

// eQEP register offsets from its base IO address
#define QPOSCNT    0x0000
#define QPOSINIT   0x0004
#define QPOSMAX    0x0008
#define QPOSCMP    0x000C
#define QPOSILAT   0x0010
#define QPOSSLAT   0x0014
#define QPOSLAT    0x0018
#define QUTMR      0x001C
#define QUPRD      0x0020    
#define QWDTMR     0x0024
#define QWDPRD     0x0026
#define QDECCTL    0x0028
#define QEPCTL     0x002A
#define QCAPCTL    0x002C
#define QPOSCTL    0x002E
#define QEINT      0x0030
#define QFLG       0x0032
#define QCLR       0x0034
#define QFRC       0x0036
#define QEPSTS     0x0038
#define QCTMR      0x003A
#define QCPRD      0x003C
#define QCTMRLAT   0x003E
#define QCPRDLAT   0x0040
#define QREVID     0x005C

// Bits for the QDECTL register
#define QSRC1      (0x0001 << 15)
#define QSRC0      (0x0001 << 14)
#define SOEN       (0x0001 << 13)
#define SPSEL      (0x0001 << 12)
#define XCR        (0x0001 << 11)
#define SWAP       (0x0001 << 10)
#define IGATE      (0x0001 << 9)
#define QAP        (0x0001 << 8)
#define QBP        (0x0001 << 7)
#define QIP        (0x0001 << 6)
#define QSP        (0x0001 << 5)

// Bits for the QEPCTL register
#define FREESOFT1  (0x0001 << 15)
#define FREESOFT0  (0x0001 << 14)
#define PCRM1      (0x0001 << 13)
#define PCRM0      (0x0001 << 12)
#define SEI1       (0x0001 << 11)
#define SEI0       (0x0001 << 10)
#define IEI1       (0x0001 << 9)
#define IEI0       (0x0001 << 8)
#define SWI        (0x0001 << 7)
#define SEL        (0x0001 << 6)
#define IEL1       (0x0001 << 5)
#define IEL0       (0x0001 << 4)
#define PHEN       (0x0001 << 3)
#define QCLM       (0x0001 << 2)
#define UTE        (0x0001 << 1)
#define WDE        (0x0001 << 0)

// Bits for the QEPCTL register
#define QDF        (0x0001 << 5)

// Bits for the QCAPCTL register
#define CEN        (0x0001 << 15)
#define CCPS2      (0x0001 << 6)
#define CCPS0      (0x0001 << 5)
#define CCPS1      (0x0001 << 4)
#define UPPS3      (0x0001 << 3)
#define UPPS2      (0x0001 << 2)
#define UPPS1      (0x0001 << 1)
#define UPPS0      (0x0001 << 0)

// Bits for the QPOSCTL register
#define PCSHDW     (0x0001 << 15)
#define PCLOAD     (0x0001 << 14)
#define PCPOL      (0x0001 << 13)
#define PCE        (0x0001 << 12)
#define PCSPW11    (0x0001 << 11)
#define PCSPW10    (0x0001 << 10)
#define PCSPW9    (0x0001 << 9)
#define PCSPW8    (0x0001 << 8)
#define PCSPW7    (0x0001 << 7)
#define PCSPW6    (0x0001 << 6)
#define PCSPW5    (0x0001 << 5)
#define PCSPW4    (0x0001 << 4)
#define PCSPW3    (0x0001 << 3)
#define PCSPW2    (0x0001 << 2)
#define PCSPW1    (0x0001 << 1)
#define PCSPW0    (0x0001 << 0)

// Bits for the interrupt registers
#define EQEP_INTERRUPT_MASK (0x0FFF)
#define UTOF                (0x0001 << 11)

// Bits to control the clock in the PWMSS subsystem
#define PWMSS_EQEPCLK_EN        BIT(4)
#define PWMSS_EQEPCLK_STOP_REQ  BIT(5)
#define PWMSS_EQEPCLK_EN_ACK    BIT(4)

// Modes for the eQEP unit
//  Absolute - the position entry represents the current position of the encoder.
//             Poll this value and it will be notified every period nanoseconds
//  Relative - the position entry represents the last latched position of the encoder
//             This value is latched every period nanoseconds and the internal counter
//             is subsequenty reset
#define TIEQEP_MODE_ABSOLUTE    0
#define TIEQEP_MODE_RELATIVE    1

// Structure defining the characteristics of the eQEP unit
struct eqep_chip
{
   
    // Platform device for this eQEP unit
    struct platform_device *pdev;
    
    // Pointer to the base of the memory of the eQEP unit
    void __iomem           *mmio_base;
    
    // SYSCLKOUT to the eQEP unit
    u32                     clk_rate;
    
    // IRQ for the eQEP unit
    u16                     irq;
    
    // Mode of the eQEP unit
    u8                      mode;
    
    // work stuct for the notify userspace work
    struct work_struct      notify_work;
    
    // Backup for driver suspension
    u16                     prior_qepctl;
    u16                     prior_qeint;
};

// Notify userspace work
void notify_handler (struct work_struct *work)
{
   
    // Get a reference to the eQEP driver
    struct eqep_chip *eqep = container_of(work, struct eqep_chip, notify_work);
    
    // Notify the userspace
    sysfs_notify(&eqep->pdev->dev.kobj, NULL, "position");
}

// eQEP Interrupt handler
static irqreturn_t eqep_irq_handler(int irq, void *dev_id)
{
   
    // Get the instance information
    struct platform_device *pdev = dev_id;
    struct eqep_chip       *eqep = platform_get_drvdata(pdev);

    // Get the interrupt flags
    u16 iflags = readw(eqep->mmio_base + QFLG) & EQEP_INTERRUPT_MASK;

    // Check the interrupt source(s)
    if(iflags & UTOF)
    {
   
        // Handle the unit timer overflow interrupt by notifying any potential pollers
        schedule_work(&eqep->notify_work);
    }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值