1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * AD7606 Parallel Interface ADC driver 4 * 5 * Copyright 2011 Analog Devices Inc. 6 */ 7 8 #include <linux/mod_devicetable.h> 9 #include <linux/module.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/platform_device.h> 12 #include <linux/types.h> 13 #include <linux/err.h> 14 #include <linux/io.h> 15 16 #include <linux/iio/iio.h> 17 #include "ad7606.h" 18 19 static int ad7606_par16_read_block(struct device *dev, 20 int count, void *buf) 21 { 22 struct iio_dev *indio_dev = dev_get_drvdata(dev); 23 struct ad7606_state *st = iio_priv(indio_dev); 24 25 26 /* 27 * On the parallel interface, the frstdata signal is set to high while 28 * and after reading the sample of the first channel and low for all 29 * other channels. This can be used to check that the incoming data is 30 * correctly aligned. During normal operation the data should never 31 * become unaligned, but some glitch or electrostatic discharge might 32 * cause an extra read or clock cycle. Monitoring the frstdata signal 33 * allows to recover from such failure situations. 34 */ 35 int num = count; 36 u16 *_buf = buf; 37 38 if (st->gpio_frstdata) { 39 insw((unsigned long)st->base_address, _buf, 1); 40 if (!gpiod_get_value(st->gpio_frstdata)) { 41 ad7606_reset(st); 42 return -EIO; 43 } 44 _buf++; 45 num--; 46 } 47 insw((unsigned long)st->base_address, _buf, num); 48 return 0; 49 } 50 51 static const struct ad7606_bus_ops ad7606_par16_bops = { 52 .read_block = ad7606_par16_read_block, 53 }; 54 55 static int ad7606_par8_read_block(struct device *dev, 56 int count, void *buf) 57 { 58 struct iio_dev *indio_dev = dev_get_drvdata(dev); 59 struct ad7606_state *st = iio_priv(indio_dev); 60 /* 61 * On the parallel interface, the frstdata signal is set to high while 62 * and after reading the sample of the first channel and low for all 63 * other channels. This can be used to check that the incoming data is 64 * correctly aligned. During normal operation the data should never 65 * become unaligned, but some glitch or electrostatic discharge might 66 * cause an extra read or clock cycle. Monitoring the frstdata signal 67 * allows to recover from such failure situations. 68 */ 69 int num = count; 70 u16 *_buf = buf; 71 72 if (st->gpio_frstdata) { 73 insb((unsigned long)st->base_address, _buf, 2); 74 if (!gpiod_get_value(st->gpio_frstdata)) { 75 ad7606_reset(st); 76 return -EIO; 77 } 78 _buf++; 79 num--; 80 } 81 insb((unsigned long)st->base_address, _buf, num * 2); 82 83 return 0; 84 } 85 86 static const struct ad7606_bus_ops ad7606_par8_bops = { 87 .read_block = ad7606_par8_read_block, 88 }; 89 90 static int ad7606_par_probe(struct platform_device *pdev) 91 { 92 const struct platform_device_id *id = platform_get_device_id(pdev); 93 struct resource *res; 94 void __iomem *addr; 95 resource_size_t remap_size; 96 int irq; 97 98 irq = platform_get_irq(pdev, 0); 99 if (irq < 0) 100 return irq; 101 102 addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 103 if (IS_ERR(addr)) 104 return PTR_ERR(addr); 105 106 remap_size = resource_size(res); 107 108 return ad7606_probe(&pdev->dev, irq, addr, 109 id->name, id->driver_data, 110 remap_size > 1 ? &ad7606_par16_bops : 111 &ad7606_par8_bops); 112 } 113 114 static const struct platform_device_id ad7606_driver_ids[] = { 115 { .name = "ad7605-4", .driver_data = ID_AD7605_4, }, 116 { .name = "ad7606-4", .driver_data = ID_AD7606_4, }, 117 { .name = "ad7606-6", .driver_data = ID_AD7606_6, }, 118 { .name = "ad7606-8", .driver_data = ID_AD7606_8, }, 119 { } 120 }; 121 MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); 122 123 static const struct of_device_id ad7606_of_match[] = { 124 { .compatible = "adi,ad7605-4" }, 125 { .compatible = "adi,ad7606-4" }, 126 { .compatible = "adi,ad7606-6" }, 127 { .compatible = "adi,ad7606-8" }, 128 { }, 129 }; 130 MODULE_DEVICE_TABLE(of, ad7606_of_match); 131 132 static struct platform_driver ad7606_driver = { 133 .probe = ad7606_par_probe, 134 .id_table = ad7606_driver_ids, 135 .driver = { 136 .name = "ad7606", 137 .pm = AD7606_PM_OPS, 138 .of_match_table = ad7606_of_match, 139 }, 140 }; 141 module_platform_driver(ad7606_driver); 142 143 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 144 MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); 145 MODULE_LICENSE("GPL v2"); 146 MODULE_IMPORT_NS(IIO_AD7606); 147