I.MX6 AD7606-4 device driver registe hacking

时间:2021-01-12 09:25:40
/**********************************************************************
 *          I.MX6 AD7606-4 device driver registe hacking
 * 说明:
 *     看一下AD7606的驱动注册上是否存在一些问题。
 *
 *                                2017-8-4 深圳 龙华樟坑村 曾剑锋
 *********************************************************************/

/*                                                                                                  
 * initialize __mach_desc_MX6Q_SABRESD data structure.                                              
 */                                                                                                 
MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")                    
    /* Maintainer: Freescale Semiconductor, Inc. */                                                 
    .boot_params = MX6_PHYS_OFFSET + 0x100,                                                         
    .fixup = fixup_mxc_board,                                                                       
    .map_io = mx6_map_io,                                                                           
    .init_irq = mx6_init_irq,                                                                       
    .init_machine = mx6_sabresd_board_init,    ------------+                                        
    .timer = &mx6_sabresd_timer,                           |                                        
    .reserve = mx6q_sabresd_reserve,                       |                                        
MACHINE_END                                                |                                        
                                                           |                                        
static void __init mx6_sabresd_board_init(void)   <--------+                                        
{                                                                                                   
    ...                                                                                             
                                                                                                    
    /* SPI */                                                                                       
    imx6q_add_ecspi(1, &mx6q_sabresd_spi2_data);   ---------------------------+                     
    spi_device_init();                             ---------------------------*-+                   
                                                                              | |                   
    ...                                                                       | |                   
}                                                                             | |                   
                                                                              | |                   
static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = { <---+ |                   
    .chipselect     = mx6q_sabresd_spi2_cs,                                     |                   
    .num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi2_cs),                         |                   
};                                                                              |                   
                                                                                |                   
static void spi_device_init(void)              <--------------------------------+                   
{                                                                                                   
    spi_register_board_info(imx6_sabresd_spi_nor_device,    -----------------------+                
                ARRAY_SIZE(imx6_sabresd_spi_nor_device));                          |                
}                                                                                  |                
                                                                                   |                
static struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = {  <-------+                
{                                                                                                   
    {                                                                                               
        /* the modalias must be the same as spi device driver name */                               
        .modalias = "ad7606-4", /* Name of spi_driver for this device */                            
        .max_speed_hz = 500000,     /* max spi clock (SCK) speed in HZ */                           
        //.max_speed_hz = 10000000,     /* max spi clock (SCK) speed in HZ */                       
        //.max_speed_hz = 14500000,     /* max spi clock (SCK) speed in HZ */                       
        .bus_num = 1, /* Framework bus number */                                                    
        .chip_select = 0, /* Framework chip select */                                               
        .platform_data = &ad7606_pdata,                            -----------+                     
        // .controller_data = &ad7606_chip_info, /* Blackfin only */          |                     
        .irq = gpio_to_irq(AD7606_GPIO_BUSY),                                 |                     
        .mode = SPI_MODE_0,                                                   |                     
    },                                                                        |                     
};                                                                            |                     
                                                                              |                     
static struct ad7606_platform_data ad7606_pdata = {          <----------------+                     
    .default_os = 0,                                                                                
    .default_range = 5000,                                                                          
    .gpio_convst = AD7606_GPIO_CONVST,                                                              
    .gpio_reset = AD7606_GPIO_RESET,                                                                
    .gpio_range = -1,                                                                               
    .gpio_os0 = AD7606_GPIO_OS0,                                                                    
    .gpio_os1 = AD7606_GPIO_OS1,                                                                    
    .gpio_os2 = AD7606_GPIO_OS2,                                                                    
    .gpio_frstdata = -1,                                                                            
    //.gpio_frstdata = AD7606_GPIO_FRSTDATA,                                                        
    .gpio_stby = AD7606_GPIO_STBY,                                                                  
};                                                                                                  
                                                                                                    
"drivers/staging/iio/adc/ad7606_spi.c"
static const struct spi_device_id ad7606_id[] = {   <---------+                                     
    {"ad7606-8", ID_AD7606_8},                                |                                     
    {"ad7606-6", ID_AD7606_6},                                |                                     
    {"ad7606-4", ID_AD7606_4},                                |                                     
    {}                                                        |                                     
};                                                            |                                     
                                                              |                                     
static struct spi_driver ad7606_driver = {     <------------+ |                                     
    .driver = {                                             | |                                     
        .name = "ad7606",                                   | |                                     
        .bus = &spi_bus_type,                               | |                                     
        .owner = THIS_MODULE,                               | |                                     
        .pm    = AD7606_SPI_PM_OPS,                         | |                                     
    },                                                      | |                                     
    .probe = ad7606_spi_probe,                        ------*-*-------+                             
    .remove = __devexit_p(ad7606_spi_remove),               | |       |                             
    .id_table = ad7606_id,                     -------------*-+       |                             
};                                                          |         |                             
                                                            |         |                             
static int __init ad7606_spi_init(void)                     |         |                             
{                                                           |         |                             
    return spi_register_driver(&ad7606_driver);       ------+         |                             
}                                                                     |                             
module_init(ad7606_spi_init);                                         |                             
                                                                      |                             
static void __exit ad7606_spi_exit(void)                              |                             
{                                                                     |                             
    spi_unregister_driver(&ad7606_driver);                            |                             
}                                                                     |                             
module_exit(ad7606_spi_exit);                                         |                             
                                                                      |                             
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");  |                             
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");                      |                             
MODULE_LICENSE("GPL v2");                                             |                             
MODULE_ALIAS("spi:ad7606_spi");                                       |                             
                                                                      |                             
static int __devinit ad7606_spi_probe(struct spi_device *spi)  <------+                             
{                                                                                                   
    struct iio_dev *indio_dev;                                                                      
                                                                                                    
    indio_dev = ad7606_probe(&spi->dev, spi->irq, NULL,      ---------+                             
               spi_get_device_id(spi)->driver_data,                   |                             
               &ad7606_spi_bops);                                     |                             
                                                                      |                             
    if (IS_ERR(indio_dev))                                            |                             
        return PTR_ERR(indio_dev);                                    |                             
                                                                      |                             
    spi_set_drvdata(spi, indio_dev);                                  |                             
                                                                      |                             
    return 0;                                                         |                             
}                                                                     |                             
                                                                      |                             
struct iio_dev *ad7606_probe(struct device *dev, int irq,     <-------+                             
                  void __iomem *base_address,                                                       
                  unsigned id,                                                                      
                  const struct ad7606_bus_ops *bops)                                                
{                                                                                                   
    struct ad7606_platform_data *pdata = dev->platform_data;                                        
    struct ad7606_state *st;                                                                        
    int ret, regdone = 0;                                                                           
    struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));                                   
                                                                                                    
    if (indio_dev == NULL) {                                                                        
        ret = -ENOMEM;                                                                              
        goto error_ret;                                                                             
    }                                                                                               
                                                                                                    
    st = iio_priv(indio_dev);                                                                       
                                                                                                    
    st->dev = dev;                                                                                  
    st->id = id;                                                                                    
    st->irq = irq;                                                                                  
    st->bops = bops;                                                                                
    st->base_address = base_address;                                                                
    st->range = pdata->default_range == 10000 ? 10000 : 5000;                                       
                                                                                                    
    ret = ad7606_oversampling_get_index(pdata->default_os);                                         
    if (ret < 0) {                                                                                  
        dev_warn(dev, "oversampling %d is not supported\n",                                         
             pdata->default_os);                                                                    
        st->oversampling = 0;                                                                       
    } else {                                                                                        
        st->oversampling = pdata->default_os;                                                       
    }                                                                                               
                                                                                                    
    st->reg = regulator_get(dev, "vcc");                                                            
    if (!IS_ERR(st->reg)) {                                                                         
        ret = regulator_enable(st->reg);                                                            
        if (ret)                                                                                    
            goto error_put_reg;                                                                     
    }                                                                                               
                                                                                                    
    st->pdata = pdata;                                                                              
    st->chip_info = &ad7606_chip_info_tbl[id];                                                      
                                                                                                    
    indio_dev->dev.parent = dev;                                                                    
    indio_dev->info = &ad7606_info;                                                                 
    indio_dev->modes = INDIO_DIRECT_MODE;                                                           
    indio_dev->name = st->chip_info->name;                                                          
    indio_dev->channels = st->chip_info->channels;                                                  
    indio_dev->num_channels = st->chip_info->num_channels;                                          
                                                                                                    
    init_waitqueue_head(&st->wq_data_avail);                                                        
                                                                                                    
    ret = ad7606_request_gpios(st);                                                                 
    if (ret)                                                                                        
        goto error_disable_reg;                                                                     
                                                                                                    
    ret = ad7606_reset(st);                                                                         
    if (ret)                                                                                        
        dev_warn(st->dev, "failed to RESET: no RESET GPIO specified\n");                            
                                                                                                    
    ret = request_irq(st->irq, ad7606_interrupt,                                                    
        IRQF_TRIGGER_FALLING, st->chip_info->name, indio_dev);                                      
    if (ret)                                                                                        
        goto error_free_gpios;                                                                      
                                                                                                    
    ret = ad7606_register_ring_funcs_and_init(indio_dev);                                           
    if (ret)                                                                                        
        goto error_free_irq;                                                                        
                                                                                                    
    ret = iio_device_register(indio_dev);                                                           
    if (ret)                                                                                        
        goto error_free_irq;                                                                        
    regdone = 1;                                                                                    
                                                                                                    
    ret = iio_ring_buffer_register_ex(indio_dev->ring, 0,                                           
                      indio_dev->channels,                                                          
                      indio_dev->num_channels);                                                     
    if (ret)                                                                                        
        goto error_cleanup_ring;                                                                    
                                                                                                    
    return indio_dev;                                                                               
                                                                                                    
error_cleanup_ring:                                                                                 
    ad7606_ring_cleanup(indio_dev);                                                                 
                                                                                                    
error_free_irq:                                                                                     
    free_irq(st->irq, indio_dev);                                                                   
                                                                                                    
error_free_gpios:                                                                                   
    ad7606_free_gpios(st);                                                                          
                                                                                                    
error_disable_reg:                                                                                  
    if (!IS_ERR(st->reg))                                                                           
        regulator_disable(st->reg);                                                                 
error_put_reg:                                                                                      
    if (!IS_ERR(st->reg))                                                                           
        regulator_put(st->reg);                                                                     
    if (regdone)                                                                                    
        iio_device_unregister(indio_dev);                                                           
    else                                                                                            
        iio_free_device(indio_dev);                                                                 
error_ret:                                                                                          
    return ERR_PTR(ret);                                                                            
}