1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * AD7606 Parallel Interface ADC driver 4 * 5 * Copyright 2011 - 2024 Analog Devices Inc. 6 * Copyright 2024 BayLibre SAS. 7 */ 8 9 #include <linux/err.h> 10 #include <linux/gpio/consumer.h> 11 #include <linux/io.h> 12 #include <linux/mod_devicetable.h> 13 #include <linux/module.h> 14 #include <linux/platform_device.h> 15 #include <linux/property.h> 16 #include <linux/types.h> 17 18 #include <linux/iio/backend.h> 19 #include <linux/iio/iio.h> 20 21 #include "ad7606.h" 22 #include "ad7606_bus_iface.h" 23 24 static const struct iio_chan_spec ad7606b_bi_channels[] = { 25 AD7606_BI_CHANNEL(0), 26 AD7606_BI_CHANNEL(1), 27 AD7606_BI_CHANNEL(2), 28 AD7606_BI_CHANNEL(3), 29 AD7606_BI_CHANNEL(4), 30 AD7606_BI_CHANNEL(5), 31 AD7606_BI_CHANNEL(6), 32 AD7606_BI_CHANNEL(7), 33 }; 34 35 static const struct iio_chan_spec ad7606b_bi_sw_channels[] = { 36 AD7606_BI_SW_CHANNEL(0), 37 AD7606_BI_SW_CHANNEL(1), 38 AD7606_BI_SW_CHANNEL(2), 39 AD7606_BI_SW_CHANNEL(3), 40 AD7606_BI_SW_CHANNEL(4), 41 AD7606_BI_SW_CHANNEL(5), 42 AD7606_BI_SW_CHANNEL(6), 43 AD7606_BI_SW_CHANNEL(7), 44 }; 45 46 static int ad7606_par_bus_update_scan_mode(struct iio_dev *indio_dev, 47 const unsigned long *scan_mask) 48 { 49 struct ad7606_state *st = iio_priv(indio_dev); 50 unsigned int c, ret; 51 52 for (c = 0; c < indio_dev->num_channels; c++) { 53 if (test_bit(c, scan_mask)) 54 ret = iio_backend_chan_enable(st->back, c); 55 else 56 ret = iio_backend_chan_disable(st->back, c); 57 if (ret) 58 return ret; 59 } 60 61 return 0; 62 } 63 64 static int ad7606_par_bus_setup_iio_backend(struct device *dev, 65 struct iio_dev *indio_dev) 66 { 67 struct ad7606_state *st = iio_priv(indio_dev); 68 unsigned int ret, c; 69 struct iio_backend_data_fmt data = { 70 .sign_extend = true, 71 .enable = true, 72 }; 73 74 st->back = devm_iio_backend_get(dev, NULL); 75 if (IS_ERR(st->back)) 76 return PTR_ERR(st->back); 77 78 /* If the device is iio_backend powered the PWM is mandatory */ 79 if (!st->cnvst_pwm) 80 return dev_err_probe(st->dev, -EINVAL, 81 "A PWM is mandatory when using backend.\n"); 82 83 ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev); 84 if (ret) 85 return ret; 86 87 ret = devm_iio_backend_enable(dev, st->back); 88 if (ret) 89 return ret; 90 91 for (c = 0; c < indio_dev->num_channels; c++) { 92 ret = iio_backend_data_format_set(st->back, c, &data); 93 if (ret) 94 return ret; 95 } 96 97 indio_dev->channels = ad7606b_bi_channels; 98 indio_dev->num_channels = 8; 99 100 return 0; 101 } 102 103 static int ad7606_par_bus_reg_read(struct ad7606_state *st, unsigned int addr) 104 { 105 struct ad7606_platform_data *pdata = st->dev->platform_data; 106 int val, ret; 107 108 ret = pdata->bus_reg_read(st->back, addr, &val); 109 if (ret) 110 return ret; 111 112 return val; 113 } 114 115 static int ad7606_par_bus_reg_write(struct ad7606_state *st, unsigned int addr, 116 unsigned int val) 117 { 118 struct ad7606_platform_data *pdata = st->dev->platform_data; 119 120 return pdata->bus_reg_write(st->back, addr, val); 121 } 122 123 static int ad7606_par_bus_sw_mode_config(struct iio_dev *indio_dev) 124 { 125 indio_dev->channels = ad7606b_bi_sw_channels; 126 127 return 0; 128 } 129 130 static const struct ad7606_bus_ops ad7606_bi_bops = { 131 .iio_backend_config = ad7606_par_bus_setup_iio_backend, 132 .update_scan_mode = ad7606_par_bus_update_scan_mode, 133 .reg_read = ad7606_par_bus_reg_read, 134 .reg_write = ad7606_par_bus_reg_write, 135 .sw_mode_config = ad7606_par_bus_sw_mode_config, 136 }; 137 138 static int ad7606_par16_read_block(struct device *dev, 139 int count, void *buf) 140 { 141 struct iio_dev *indio_dev = dev_get_drvdata(dev); 142 struct ad7606_state *st = iio_priv(indio_dev); 143 144 145 /* 146 * On the parallel interface, the frstdata signal is set to high while 147 * and after reading the sample of the first channel and low for all 148 * other channels. This can be used to check that the incoming data is 149 * correctly aligned. During normal operation the data should never 150 * become unaligned, but some glitch or electrostatic discharge might 151 * cause an extra read or clock cycle. Monitoring the frstdata signal 152 * allows to recover from such failure situations. 153 */ 154 int num = count; 155 u16 *_buf = buf; 156 157 if (st->gpio_frstdata) { 158 insw((unsigned long)st->base_address, _buf, 1); 159 if (!gpiod_get_value(st->gpio_frstdata)) { 160 ad7606_reset(st); 161 return -EIO; 162 } 163 _buf++; 164 num--; 165 } 166 insw((unsigned long)st->base_address, _buf, num); 167 return 0; 168 } 169 170 static const struct ad7606_bus_ops ad7606_par16_bops = { 171 .read_block = ad7606_par16_read_block, 172 }; 173 174 static int ad7606_par8_read_block(struct device *dev, 175 int count, void *buf) 176 { 177 struct iio_dev *indio_dev = dev_get_drvdata(dev); 178 struct ad7606_state *st = iio_priv(indio_dev); 179 /* 180 * On the parallel interface, the frstdata signal is set to high while 181 * and after reading the sample of the first channel and low for all 182 * other channels. This can be used to check that the incoming data is 183 * correctly aligned. During normal operation the data should never 184 * become unaligned, but some glitch or electrostatic discharge might 185 * cause an extra read or clock cycle. Monitoring the frstdata signal 186 * allows to recover from such failure situations. 187 */ 188 int num = count; 189 u16 *_buf = buf; 190 191 if (st->gpio_frstdata) { 192 insb((unsigned long)st->base_address, _buf, 2); 193 if (!gpiod_get_value(st->gpio_frstdata)) { 194 ad7606_reset(st); 195 return -EIO; 196 } 197 _buf++; 198 num--; 199 } 200 insb((unsigned long)st->base_address, _buf, num * 2); 201 202 return 0; 203 } 204 205 static const struct ad7606_bus_ops ad7606_par8_bops = { 206 .read_block = ad7606_par8_read_block, 207 }; 208 209 static int ad7606_par_probe(struct platform_device *pdev) 210 { 211 const struct ad7606_chip_info *chip_info; 212 const struct platform_device_id *id; 213 struct resource *res; 214 void __iomem *addr; 215 resource_size_t remap_size; 216 int irq; 217 218 /* 219 * If a firmware node is available (ACPI or DT), platform_device_id is null 220 * and we must use get_match_data. 221 */ 222 if (dev_fwnode(&pdev->dev)) { 223 chip_info = device_get_match_data(&pdev->dev); 224 if (device_property_present(&pdev->dev, "io-backends")) 225 /* 226 * If a backend is available ,call the core probe with backend 227 * bops, otherwise use the former bops. 228 */ 229 return ad7606_probe(&pdev->dev, 0, NULL, 230 chip_info, 231 &ad7606_bi_bops); 232 } else { 233 id = platform_get_device_id(pdev); 234 chip_info = (const struct ad7606_chip_info *)id->driver_data; 235 } 236 237 irq = platform_get_irq(pdev, 0); 238 if (irq < 0) 239 return irq; 240 241 addr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 242 if (IS_ERR(addr)) 243 return PTR_ERR(addr); 244 245 remap_size = resource_size(res); 246 247 return ad7606_probe(&pdev->dev, irq, addr, chip_info, 248 remap_size > 1 ? &ad7606_par16_bops : 249 &ad7606_par8_bops); 250 } 251 252 static const struct platform_device_id ad7606_driver_ids[] = { 253 { .name = "ad7605-4", .driver_data = (kernel_ulong_t)&ad7605_4_info, }, 254 { .name = "ad7606-4", .driver_data = (kernel_ulong_t)&ad7606_4_info, }, 255 { .name = "ad7606-6", .driver_data = (kernel_ulong_t)&ad7606_6_info, }, 256 { .name = "ad7606-8", .driver_data = (kernel_ulong_t)&ad7606_8_info, }, 257 { .name = "ad7606b", .driver_data = (kernel_ulong_t)&ad7606b_info, }, 258 { .name = "ad7607", .driver_data = (kernel_ulong_t)&ad7607_info, }, 259 { .name = "ad7608", .driver_data = (kernel_ulong_t)&ad7608_info, }, 260 { .name = "ad7609", .driver_data = (kernel_ulong_t)&ad7609_info, }, 261 { } 262 }; 263 MODULE_DEVICE_TABLE(platform, ad7606_driver_ids); 264 265 static const struct of_device_id ad7606_of_match[] = { 266 { .compatible = "adi,ad7605-4", .data = &ad7605_4_info }, 267 { .compatible = "adi,ad7606-4", .data = &ad7606_4_info }, 268 { .compatible = "adi,ad7606-6", .data = &ad7606_6_info }, 269 { .compatible = "adi,ad7606-8", .data = &ad7606_8_info }, 270 { .compatible = "adi,ad7606b", .data = &ad7606b_info }, 271 { .compatible = "adi,ad7607", .data = &ad7607_info }, 272 { .compatible = "adi,ad7608", .data = &ad7608_info }, 273 { .compatible = "adi,ad7609", .data = &ad7609_info }, 274 { } 275 }; 276 MODULE_DEVICE_TABLE(of, ad7606_of_match); 277 278 static struct platform_driver ad7606_driver = { 279 .probe = ad7606_par_probe, 280 .id_table = ad7606_driver_ids, 281 .driver = { 282 .name = "ad7606", 283 .pm = AD7606_PM_OPS, 284 .of_match_table = ad7606_of_match, 285 }, 286 }; 287 module_platform_driver(ad7606_driver); 288 289 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 290 MODULE_DESCRIPTION("Analog Devices AD7606 ADC"); 291 MODULE_LICENSE("GPL v2"); 292 MODULE_IMPORT_NS("IIO_AD7606"); 293 MODULE_IMPORT_NS("IIO_BACKEND"); 294