免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4544 | 回复: 4

关于device_driver中probe函数的编写 [复制链接]

论坛徽章:
0
发表于 2010-03-15 11:45 |显示全部楼层
本帖最后由 zhanghonghu84 于 2010-03-30 10:24 编辑

小菜鸟最近在写一个SPI接口的AD驱动,用的是AD7888,主芯片是at91sam9260,在文件board-sam9260ek.c中,把结构体改成如下了
static struct spi_board_info ek_spi_devices[] = {
/*
#if !defined(CONFIG_MMC_AT91)
        {        // DataFlash chip
                .modalias        = "mtd_dataflash",
        //        .chip_select        = 1,
            .chip_select        = 0,     //zhh
                .max_speed_hz        = 15 * 1000 * 1000,
                .bus_num        = 0,
        },
#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
        {        // DataFlash card
                .modalias        = "mtd_dataflash",
                .chip_select        = 0,
                .max_speed_hz        = 15 * 1000 * 1000,
                .bus_num        = 0,
        },
#endif
#endif
*/
#if defined(CONFIG_AD788
        {   /* spi ad */
            .modalias   = "ad7888",
            .chip_select    = 0,
            .max_speed_hz   = 15 * 1000 * 1000,
            .bus_num    = 0,
            .mode                = SPI_MODE_0,
        },
#endif


#if defined(CONFIG_MMC_SPI)
        {        /* DataFlash card */
                .modalias        = "mmc_spi",
                .chip_select        = 1,
                .max_speed_hz        = 15 * 1000 * 1000,
                .bus_num        = 0,               
        },
#endif


#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
        {        /* AT73C213 DAC */
                .modalias        = "at73c213",
                .chip_select        = 0,
                .max_speed_hz        = 10 * 1000 * 1000,
                .bus_num        = 1,
                .mode                = SPI_MODE_1,
                .platform_data        = &at73c213_data,
        },
#endif
};

然后参照其他的驱动,自己编写了一个AD7888的驱动,如下
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/sched.h>

#include <linux/platform_device.h>
#include <linux/spi/spi.h>


/*
DONTC ZERO ADD2 ADD1 ADD0 REF PM1 PM0

Bit Mnemonic Comment
7 DONTC Don’t Care. The value written to this bit of the Control Register is a don’t care, i.e., it doesn’t matter if the bit is
    0 or 1.
   
6 ZERO A zero must be written to this bit to ensure correct operation of the AD7888.

5 ADD2 These three address bits are loaded at the end of the present conversion sequence and select which analog input
4 ADD1 channel is converted for the next conversion. The selected input channel is decoded as shown in Table II.
3 ADD0

2 REF Reference Bit. With a 0 in this bit, the on-chip reference is enabled. With a 1 in this bit, the on-chip reference
    is disabled. To obtain best performance from the AD7888, the internal reference should be disabled when
    using an externally applied reference source. (See On-Chip Reference section.)
   
1, 0 PM1, PM0 Power Management Bits. These two bits decode the mode of operation of the AD7888 as shown in Table III.

PM1     PM0     MODE
0       0       Normal Operation. In this mode, the AD7888
            remains in full power mode regardless of the
            status of any of the logic inputs. This mode
            allows the fastest possible throughput rate from
            the AD7888.
0       1       Full Shutdown. In this mode, the AD7888 is
            in full shutdown mode with all circuitry on the
            AD7888, including the on-chip reference, entering
            its power-down mode. The AD7888 retains
            the information in the control Register bits
            while in full shutdown. The part remains in full
            shutdown until these bits are changed.
1       0       Autoshutdown. In this mode, the AD7888
            automatically enters full shutdown mode at the
            end of each conversion. Wake-up time from full
            shutdown is 5 μs and the user should ensure that
            5 μs have elapsed before attempting to perform
            a valid conversion on the part in this mode.
1       1       Autostandby. In this standby mode, portions
            of the AD7888 are powered down but the onchip
            reference voltage remains powered up. The
            REF bit should be 0 to ensure the on-chip reference
            is enabled. This mode is similar to autoshutdown
            but allows the part to power-up
            much faster.

*/
/*
    bit7            0
    bit6            0
    bit5/4/3        地址
    bit2            0 我们采用内部参考电压 参考电压为2.5V
    bit1/0          0/0  为了简便,采用正常模式,
*/
// AD通道定义
#define         AD_ADD1_REG    0x00
#define         AD_ADD2_REG    0x08
#define         AD_ADD3_REG    0x10
#define         AD_ADD4_REG    0x18
#define         AD_ADD5_REG    0x20
#define         AD_ADD6_REG    0x28
#define         AD_ADD7_REG    0x30
#define         AD_ADD8_REG    0x38

#define         MAX_AD_CHANNEL  8   // the max channel num
//global
char ad7888_rx_buf[MAX_AD_CHANNEL];
int  ad7888_tx_buf[MAX_AD_CHANNEL];

/*
* NOTE: this is an *AD* driver.  
* Handle SPI chips with the drivers/spi/
*
*/
struct ad7888_data {
        struct spi_device        *spi;
        struct mutex                lock;
};


/*******************************************************************************
* Function Name  : void ad7888_init(void)
* Description    : ad7888 init
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void ad7888_init(void)
{
   
}

/*******************************************************************************
* Function Name  : void ad7888_exit(void)
* Description    : ad7888 exit
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void ad7888_exit(void)
{
   
}

/*******************************************************************************
* Function Name  : static int ad7888_read_reg(struct spi_device *spi, int reg)
* Description    : depend on the channel to read ad7888 ad data
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static int ad7888_read_reg(struct spi_device *spi, int reg)
{
    char buf[2];
    buf[0] = reg;
    buf[1] = 0;
    spi_write_then_read(spi, buf, 1, buf, 2);
    return buf[1] << 8 | buf[0];
}
/*******************************************************************************
* Function Name  : static int ad7888_read_reg(struct spi_device *spi, int reg)
* Description    : depend on the channel to read ad7888 ad data
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static int ad7888_probe(struct spi_device *spi)
{
    struct ad7888_data        *ts = NULL;         
        int         ret;
               
        /* Chip description 暂时不加*/

        //AD7888 上升沿接收数据,下降沿发送数据,选择模式0,16位数据(前4为0),MSB在前        默认可以不写         
        spi->mode = SPI_MODE_0;
        spi->bits_per_word = 8;

        ret = spi_setup(spi);
        if (ret < 0)
                return ret;

   
        ts = kzalloc(sizeof(struct ad7888_data), GFP_KERNEL);
        if (!ts)
        {
            ret = -ENOMEM;

            return ret;
        }               

        mutex_init(&ts->lock);
        ts->spi = spi_dev_get(spi);
        dev_set_drvdata(&spi->dev, ts);
       
        /* Ping the chip ... the status register is pretty portable,
         * unlike probing manufacturer IDs.  We do expect that system
         * firmware didn't write it in the past few milliseconds!
         */
         /*
        ret = spi_w8r16(spi, AD_ADD8_REG);
        if (ret <= 0) {
                dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", ret, ret);
                ret = -ENXIO;
                goto fail;
        }       
        */
    // 注册设备
   
   // ret = device_register(&ts->spi->dev);
//        if (ret)
//                goto fail;
               
        fail:
        dev_dbg(&spi->dev, "probe err %d\n", ret);
        dev_set_drvdata(&spi->dev, NULL);
        mutex_destroy(&ts->lock);
        kfree(ts);

        return ret;
}

static int ad7888_remove(struct spi_device *spi)
{
    struct ad7888_data *ts;

        ts = dev_get_drvdata(&spi->dev);
        if (ts == NULL)
                return -ENODEV;

    dev_set_drvdata(&spi->dev, NULL);
    mutex_destroy(&ts->lock);
     // 注册设备
//   device_unregister(&ts->spi->dev);
   
        kfree(ts);
  
        return 0;   
}

static struct spi_driver ad7888_spi_driver = {
    .probe  = ad7888_probe,
    .remove = ad7888_remove,
    .driver = {
                    .name   = "ad7888",
                    .owner  = THIS_MODULE,                  
                            .bus    = &spi_bus_type,
               
              },
};

static int __init ad7888_spi_init(void)
{   
    ad7888_init();
   
    return spi_register_driver(&ad7888_spi_driver);
}

static void __exit ad7888_spi_exit(void)
{
    ad7888_exit();
    spi_unregister_driver(&ad7888_spi_driver);
}

module_init(ad7888_spi_init);
module_exit(ad7888_spi_exit);

编译进去启动后,在/sys里面
#ls /sys/bus/spi/devices/spi1.0/
/sys/bus/spi/devices/spi1.0/bus/        /sys/bus/spi/devices/spi1.0/subsystem/
/sys/bus/spi/devices/spi1.0/driver/     /sys/bus/spi/devices/spi1.0/uevent
/sys/bus/spi/devices/spi1.0/modalias

# cat /sys/bus/spi/devices/spi1.0/modalias
ad7888

# ls /sys/bus/spi/drivers/
ad7888   mmc_spi  spidev
#


device和driver都找到了,但是我不知道probe函数怎么写,
以下是spi相关的
/**
* struct spi_driver - Host side "protocol" driver
* @probe: Binds this driver to the spi device.  Drivers can verify
*        that the device is actually present, and may need to configure
*        characteristics (such as bits_per_word) which weren't needed for
*        the initial configuration done during system setup.
* @remove: Unbinds this driver from the spi device
* @shutdown: Standard shutdown callback used during system state
*        transitions such as powerdown/halt and kexec
* @suspend: Standard suspend callback used during system state transitions
* @resume: Standard resume callback used during system state transitions
* @driver: SPI device drivers should initialize the name and owner
*        field of this structure.
*
* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link.  It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages).  These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
*/
struct spi_driver {
        int                        (*probe)(struct spi_device *spi);
        int                        (*remove)(struct spi_device *spi);
        void                        (*shutdown)(struct spi_device *spi);
        int                        (*suspend)(struct spi_device *spi, pm_message_t mesg);
        int                        (*resume)(struct spi_device *spi);
        struct device_driver        driver;
};


按照注释
@probe: Binds this driver to the spi device.  Drivers can verify
*        that the device is actually present, and may need to configure
*        characteristics (such as bits_per_word) which weren't needed for
*        the initial configuration done during system setup.
它主要有2个作用,把这个驱动绑定到具体的SPI设备上,并能探测到存在的SPI设备,可能会配置一些在系统启动配置不了的参数。

以下是我写的probe函数
/*******************************************************************************
* Function Name  : static int ad7888_read_reg(struct spi_device *spi, int reg)
* Description    : depend on the channel to read ad7888 ad data
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static int ad7888_probe(struct spi_device *spi)
{
    struct ad7888_data        *ts = NULL;         
        int         ret;
               
        /* Chip description 暂时不加*/

        //AD7888 上升沿接收数据,下降沿发送数据,选择模式0,16位数据(前4为0),MSB在前        默认可以不写         
        spi->mode = SPI_MODE_0;
        spi->bits_per_word = 8;

        ret = spi_setup(spi);
        if (ret < 0)
                return ret;

   
        ts = kzalloc(sizeof(struct ad7888_data), GFP_KERNEL);
        if (!ts)
        {
            ret = -ENOMEM;

            return ret;
        }               

        mutex_init(&ts->lock);
        ts->spi = spi_dev_get(spi);
        dev_set_drvdata(&spi->dev, ts);
       
        /* Ping the chip ... the status register is pretty portable,
         * unlike probing manufacturer IDs.  We do expect that system
         * firmware didn't write it in the past few milliseconds!
         */
         /*
        ret = spi_w8r16(spi, AD_ADD8_REG);
        if (ret <= 0) {
                dev_dbg(&spi->dev, "rdsr --> %d (%02x)\n", ret, ret);
                ret = -ENXIO;
                goto fail;
        }       
        */
    // 注册设备
   
   // ret = device_register(&ts->spi->dev);
//        if (ret)
//                goto fail;

               
        fail:
        dev_dbg(&spi->dev, "probe err %d\n", ret);
        dev_set_drvdata(&spi->dev, NULL);
        mutex_destroy(&ts->lock);
        kfree(ts);

        return ret;
}


各位指教一二,看probe函数还要哪些?

论坛徽章:
0
发表于 2010-03-15 13:57 |显示全部楼层
各位提点建议吧,还是我没有表达清楚呢?
若没有表达清楚,各位兄弟也提些建议,呵呵,第一次在CU上发帖,多包涵

论坛徽章:
5
摩羯座
日期:2014-07-22 09:03:552015元宵节徽章
日期:2015-03-06 15:50:392015亚冠之大阪钢巴
日期:2015-06-12 16:01:352015年中国系统架构师大会
日期:2015-06-29 16:11:2815-16赛季CBA联赛之四川
日期:2018-12-17 14:10:21
发表于 2010-03-15 15:17 |显示全部楼层
可以参考一下kernelsource 的drivers/spi/spi_s3c24xx.c

论坛徽章:
0
发表于 2010-03-15 15:43 |显示全部楼层
谢谢版主的答复。
SPI主控制的我这边源码里有,
主要问题是在于具体设备的驱动的probe写法,各位大虾指点下

论坛徽章:
0
发表于 2010-03-15 15:49 |显示全部楼层
撇开具体的设备,抽象一点,照我的理解,:
以这个SPI设备为例,
系统初始化时,
(1)向内核注册这些板级信息体
spi_register_board_info(devices, nr_devices);
(2)然后是platform_device注册
platform_device_register(&at91sam9260_spi1_device);

因为用的是atmel的SPI控制器,所以有如下代码
static struct platform_driver atmel_spi_driver = {
        .driver                = {
                .name        = "atmel_spi",
                .owner        = THIS_MODULE,
        },
        .suspend        = atmel_spi_suspend,
        .resume                = atmel_spi_resume,
        .remove                = __exit_p(atmel_spi_remove),
};

static int __init atmel_spi_init(void)
{
        return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
}
module_init(atmel_spi_init);

static void __exit atmel_spi_exit(void)
{
        platform_driver_unregister(&atmel_spi_driver);
}
这里主要是针对主控制器的,它的probe函数
static int __init atmel_spi_probe(struct platform_device *pdev)
{
        ------------------省略-----------------------
        ret = spi_register_master(master);
        if (ret)
                goto out_reset_hw;

        return 0;

out_reset_hw:
        spi_writel(as, CR, SPI_BIT(SWRST));
        clk_disable(clk);
        free_irq(irq, master);
out_unmap_regs:
        iounmap(as->regs);
out_free_buffer:
        dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
                        as->buffer_dma);
out_free:
        clk_put(clk);
        spi_master_put(master);
        return ret;
}
看下它的调用过程
atmel_spi_probe----->spi_register_master----->scan_boardinfo---->spi_new_device,相应的注释如下:
****************************************************************************
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
* Context: can sleep
*
* SPI master controllers connect to their drivers using some non-SPI bus,
* such as the platform bus.  The final stage of probe() in that code
* includes calling spi_register_master() to hook up to this SPI bus glue.
*
* SPI controllers use board specific (often SOC specific) bus numbers,
* and board-specific addressing for SPI devices combines those numbers
* with chip select numbers.  Since SPI does not directly support dynamic
* device identification, boards need configuration tables telling which
* chip is at which address.
*
* This must be called from context that can sleep.  It returns zero on
* success, else a negative error code (dropping the master's refcount).
* After a successful return, the caller is responsible for calling
* spi_unregister_master().
*/
int spi_register_master(struct spi_master *master)
***************************************************************************
/* FIXME someone should add support for a __setup("spi", ...) that
* creates board info from kernel command lines
*/
static void scan_boardinfo(struct spi_master *master)
{
        struct boardinfo        *bi;

        mutex_lock(&board_lock);
        list_for_each_entry(bi, &board_list, list) {
                struct spi_board_info        *chip = bi->board_info;
                unsigned                n;

                for (n = bi->n_board_info; n > 0; n--, chip++) {
                        if (chip->bus_num != master->bus_num)
                                continue;
                        /* NOTE: this relies on spi_new_device to
                         * issue diagnostics when given bogus inputs
                         */
                        (void) spi_new_device(master, chip);
                }
        }
        mutex_unlock(&board_lock);
}
****************************************************************************
/**
* spi_new_device - instantiate one new SPI device
* @master: Controller to which device is connected
* @chip: Describes the SPI device
* Context: can sleep
*
* On typical mainboards, this is purely internal; and it's not needed
* after board init creates the hard-wired devices.  Some development
* platforms may not be able to use spi_register_board_info though, and
* this is exported so that for example a USB or parport based adapter
* driver could add devices (which it would learn about out-of-band).
*
* Returns the new device, or NULL.
*/
struct spi_device *spi_new_device(struct spi_master *master,
                                  struct spi_board_info *chip)
{
        struct spi_device        *proxy;
        int                        status;

        /* NOTE:  caller did any chip->bus_num checks necessary.
         *
         * Also, unless we change the return value convention to use
         * error-or-pointer (not NULL-or-pointer), troubleshootability
         * suggests syslogged diagnostics are best here (ugh).
         */

        proxy = spi_alloc_device(master);
        if (!proxy)
                return NULL;

        WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));

        proxy->chip_select = chip->chip_select;
        proxy->max_speed_hz = chip->max_speed_hz;
        proxy->mode = chip->mode;
        proxy->irq = chip->irq;
        strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
        proxy->dev.platform_data = (void *) chip->platform_data;
        proxy->controller_data = chip->controller_data;
        proxy->controller_state = NULL;

        status = spi_add_device(proxy);
        if (status < 0) {
                spi_dev_put(proxy);
                return NULL;
        }

        return proxy;
}
******************************************************************************
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
*
* Companion function to spi_alloc_device.  Devices allocated with
* spi_alloc_device can be added onto the spi bus with this function.
*
* Returns 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
        static DEFINE_MUTEX(spi_add_lock);
        struct device *dev = spi->master->dev.parent;
        int status;

        /* Chipselects are numbered 0..max; validate. */
        if (spi->chip_select >= spi->master->num_chipselect) {
                dev_err(dev, "cs%d >= max %d\n",
                        spi->chip_select,
                        spi->master->num_chipselect);
                return -EINVAL;
        }

        /* Set the bus ID string */
        snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
                        "%s.%u", spi->master->dev.bus_id,
                        spi->chip_select);


        /* We need to make sure there's no other device with this
         * chipselect **BEFORE** we call setup(), else we'll trash
         * its configuration.  Lock against concurrent add() calls.
         */
        mutex_lock(&spi_add_lock);

        if (bus_find_device_by_name(&spi_bus_type, NULL, spi->dev.bus_id)
                        != NULL) {
                dev_err(dev, "chipselect %d already in use\n",
                                spi->chip_select);
                status = -EBUSY;
                goto done;
        }

        /* Drivers may modify this initial i/o setup, but will
         * normally rely on the device being setup.  Devices
         * using SPI_CS_HIGH can't coexist well otherwise...
         */
        status = spi->master->setup(spi);
        if (status < 0) {
                dev_err(dev, "can't %s %s, status %d\n",
                                "setup", spi->dev.bus_id, status);
                goto done;
        }

        /* Device may be bound to an active driver when this returns */
        status = device_add(&spi->dev);
        if (status < 0)
                dev_err(dev, "can't %s %s, status %d\n",
                                "add", spi->dev.bus_id, status);
        else
                dev_dbg(dev, "registered child %s\n", spi->dev.bus_id);

done:
        mutex_unlock(&spi_add_lock);
        return status;
}
*******************************************************************************

有如下几个疑问:
(1)设备已经增加到平台设备里面了,平台设备和平台驱动都已经注册,并且在这个主控制器的probe函数里面已经把具体的device设备加进去了,那么我写spi 设备驱动时,比如这里的AD7888,只需要注册driver就行了,不知道我理解的是否对不?但是我对比了其他具体的设备驱动,发现那些设备又注册了一次设备。

(2)按照这样写驱动的话,一些读写及控制函数怎么加进去,我看了一些其他的驱动,
比如一个eeprom驱动
/*
* NOTE: this is an *EEPROM* driver.  The vagaries of product naming
* mean that some AT25 products are EEPROMs, and others are FLASH.
* Handle FLASH chips with the drivers/mtd/devices/m25p80.c driver,
* not this one!
*/
struct at25_data {
        struct spi_device        *spi;
        struct mutex                lock;
        struct spi_eeprom        chip;
        struct bin_attribute        bin;
        unsigned                addrlen;
};
就把读写函数都放在struct bin_attribute        bin;

一个SPI扩展IO芯片MAX7301是这样定义结构体的:
/*
* Some registers must be read back to modify.
* To save time we cache them here in memory
*/
struct max7301 {
        struct mutex        lock;
        u8                port_config[8];        /* field 0 is unused */
        u32                out_level;        /* cached output levels */
        struct gpio_chip chip;
        struct spi_device *spi;
};

把控制都放在struct gpio_chip chip;里面了。

而DS1305呢
/* register RTC ... from here on, ds1305->ctrl needs locking */
        rtc = rtc_device_register("ds1305", &spi->dev,
                        &ds1305_ops, THIS_MODULE);
这个比较好理解,就放在ds1305_ops里面了。

于是我打算把这个读写函数放在
struct ad7888_data {
        struct spi_device        *spi;
        struct mutex                lock;
};
这个结构体,

我对驱动理解很肤浅,各位提提建议
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP