I.MX6 AD7606-4 device driver registe hacking
/********************************************************************** * 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); }