| @@ -0,0 +1,482 @@ |
| | 1 | // SPDX-License-Identifier: GPL-2.0-only |
| | 2 | /* |
| | 3 | * Analog Devices Generic AXI ADC IP core |
| | 4 | * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip |
| | 5 | * |
| | 6 | * Copyright 2012-2020 Analog Devices Inc. |
| | 7 | */ |
| | 8 | |
| | 9 | #include <linux/bitfield.h> |
| | 10 | #include <linux/clk.h> |
| | 11 | #include <linux/io.h> |
| | 12 | #include <linux/delay.h> |
| | 13 | #include <linux/module.h> |
| | 14 | #include <linux/of_device.h> |
| | 15 | #include <linux/platform_device.h> |
| | 16 | #include <linux/slab.h> |
| | 17 | |
| | 18 | #include <linux/iio/iio.h> |
| | 19 | #include <linux/iio/sysfs.h> |
| | 20 | #include <linux/iio/buffer.h> |
| | 21 | #include <linux/iio/buffer-dmaengine.h> |
| | 22 | |
| | 23 | #include <linux/fpga/adi-axi-common.h> |
| | 24 | #include <linux/iio/adc/adi-axi-adc.h> |
| | 25 | |
| | 26 | /** |
| | 27 | * Register definitions: |
| | 28 | * https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map |
| | 29 | */ |
| | 30 | |
| | 31 | /* ADC controls */ |
| | 32 | |
| | 33 | #define ADI_AXI_REG_RSTN 0x0040 |
| | 34 | #define ADI_AXI_REG_RSTN_CE_N BIT(2) |
| | 35 | #define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1) |
| | 36 | #define ADI_AXI_REG_RSTN_RSTN BIT(0) |
| | 37 | |
| | 38 | /* ADC Channel controls */ |
| | 39 | |
| | 40 | #define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40) |
| | 41 | #define ADI_AXI_REG_CHAN_CTRL_LB_OWR BIT(11) |
| | 42 | #define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) |
| | 43 | #define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) |
| | 44 | #define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) |
| | 45 | #define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) |
| | 46 | #define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) |
| | 47 | #define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) |
| | 48 | #define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1) |
| | 49 | #define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0) |
| | 50 | |
| | 51 | #define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \ |
| | 52 | (ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \ |
| | 53 | ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ |
| | 54 | ADI_AXI_REG_CHAN_CTRL_ENABLE) |
| | 55 | |
| | 56 | struct adi_axi_adc_core_info { |
| | 57 | unsigned int version; |
| | 58 | }; |
| | 59 | |
| | 60 | struct adi_axi_adc_state { |
| | 61 | struct mutex lock; |
| | 62 | |
| | 63 | struct adi_axi_adc_client *client; |
| | 64 | void __iomem *regs; |
| | 65 | }; |
| | 66 | |
| | 67 | struct adi_axi_adc_client { |
| | 68 | struct list_head entry; |
| | 69 | struct adi_axi_adc_conv conv; |
| | 70 | struct adi_axi_adc_state *state; |
| | 71 | struct device *dev; |
| | 72 | const struct adi_axi_adc_core_info *info; |
| | 73 | }; |
| | 74 | |
| | 75 | static LIST_HEAD(registered_clients); |
| | 76 | static DEFINE_MUTEX(registered_clients_lock); |
| | 77 | |
| | 78 | static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) |
| | 79 | { |
| | 80 | return container_of(conv, struct adi_axi_adc_client, conv); |
| | 81 | } |
| | 82 | |
| | 83 | void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) |
| | 84 | { |
| | 85 | struct adi_axi_adc_client *cl = conv_to_client(conv); |
| | 86 | |
| | 87 | return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); |
| | 88 | } |
| | 89 | EXPORT_SYMBOL_GPL(adi_axi_adc_conv_priv); |
| | 90 | |
| | 91 | static void adi_axi_adc_write(struct adi_axi_adc_state *st, |
| | 92 | unsigned int reg, |
| | 93 | unsigned int val) |
| | 94 | { |
| | 95 | iowrite32(val, st->regs + reg); |
| | 96 | } |
| | 97 | |
| | 98 | static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, |
| | 99 | unsigned int reg) |
| | 100 | { |
| | 101 | return ioread32(st->regs + reg); |
| | 102 | } |
| | 103 | |
| | 104 | static int adi_axi_adc_config_dma_buffer(struct device *dev, |
| | 105 | struct iio_dev *indio_dev) |
| | 106 | { |
| | 107 | struct iio_buffer *buffer; |
| | 108 | const char *dma_name; |
| | 109 | |
| | 110 | if (!device_property_present(dev, "dmas")) |
| | 111 | return 0; |
| | 112 | |
| | 113 | if (device_property_read_string(dev, "dma-names", &dma_name)) |
| | 114 | dma_name = "rx"; |
| | 115 | |
| | 116 | buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, |
| | 117 | dma_name); |
| | 118 | if (IS_ERR(buffer)) |
| | 119 | return PTR_ERR(buffer); |
| | 120 | |
| | 121 | indio_dev->modes |= INDIO_BUFFER_HARDWARE; |
| | 122 | iio_device_attach_buffer(indio_dev, buffer); |
| | 123 | |
| | 124 | return 0; |
| | 125 | } |
| | 126 | |
| | 127 | static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, |
| | 128 | struct iio_chan_spec const *chan, |
| | 129 | int *val, int *val2, long mask) |
| | 130 | { |
| | 131 | struct adi_axi_adc_state *st = iio_priv(indio_dev); |
| | 132 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 133 | |
| | 134 | if (!conv->read_raw) |
| | 135 | return -EOPNOTSUPP; |
| | 136 | |
| | 137 | return conv->read_raw(conv, chan, val, val2, mask); |
| | 138 | } |
| | 139 | |
| | 140 | static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, |
| | 141 | struct iio_chan_spec const *chan, |
| | 142 | int val, int val2, long mask) |
| | 143 | { |
| | 144 | struct adi_axi_adc_state *st = iio_priv(indio_dev); |
| | 145 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 146 | |
| | 147 | if (!conv->write_raw) |
| | 148 | return -EOPNOTSUPP; |
| | 149 | |
| | 150 | return conv->write_raw(conv, chan, val, val2, mask); |
| | 151 | } |
| | 152 | |
| | 153 | static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, |
| | 154 | const unsigned long *scan_mask) |
| | 155 | { |
| | 156 | struct adi_axi_adc_state *st = iio_priv(indio_dev); |
| | 157 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 158 | unsigned int i, ctrl; |
| | 159 | |
| | 160 | for (i = 0; i < conv->chip_info->num_channels; i++) { |
| | 161 | ctrl = adi_axi_adc_read(st, ADI_AXI_REG_CHAN_CTRL(i)); |
| | 162 | |
| | 163 | if (test_bit(i, scan_mask)) |
| | 164 | ctrl |= ADI_AXI_REG_CHAN_CTRL_ENABLE; |
| | 165 | else |
| | 166 | ctrl &= ~ADI_AXI_REG_CHAN_CTRL_ENABLE; |
| | 167 | |
| | 168 | adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), ctrl); |
| | 169 | } |
| | 170 | |
| | 171 | return 0; |
| | 172 | } |
| | 173 | |
| | 174 | static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, |
| | 175 | size_t sizeof_priv) |
| | 176 | { |
| | 177 | struct adi_axi_adc_client *cl; |
| | 178 | size_t alloc_size; |
| | 179 | |
| | 180 | alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); |
| | 181 | if (sizeof_priv) |
| | 182 | alloc_size += ALIGN(sizeof_priv, IIO_ALIGN); |
| | 183 | |
| | 184 | cl = kzalloc(alloc_size, GFP_KERNEL); |
| | 185 | if (!cl) |
| | 186 | return ERR_PTR(-ENOMEM); |
| | 187 | |
| | 188 | mutex_lock(®istered_clients_lock); |
| | 189 | |
| | 190 | cl->dev = get_device(dev); |
| | 191 | |
| | 192 | list_add_tail(&cl->entry, ®istered_clients); |
| | 193 | |
| | 194 | mutex_unlock(®istered_clients_lock); |
| | 195 | |
| | 196 | return &cl->conv; |
| | 197 | } |
| | 198 | |
| | 199 | static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) |
| | 200 | { |
| | 201 | struct adi_axi_adc_client *cl = conv_to_client(conv); |
| | 202 | |
| | 203 | mutex_lock(®istered_clients_lock); |
| | 204 | |
| | 205 | list_del(&cl->entry); |
| | 206 | put_device(cl->dev); |
| | 207 | |
| | 208 | mutex_unlock(®istered_clients_lock); |
| | 209 | |
| | 210 | kfree(cl); |
| | 211 | } |
| | 212 | |
| | 213 | static void devm_adi_axi_adc_conv_release(struct device *dev, void *res) |
| | 214 | { |
| | 215 | adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res); |
| | 216 | } |
| | 217 | |
| | 218 | struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, |
| | 219 | size_t sizeof_priv) |
| | 220 | { |
| | 221 | struct adi_axi_adc_conv **ptr, *conv; |
| | 222 | |
| | 223 | ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr), |
| | 224 | GFP_KERNEL); |
| | 225 | if (!ptr) |
| | 226 | return ERR_PTR(-ENOMEM); |
| | 227 | |
| | 228 | conv = adi_axi_adc_conv_register(dev, sizeof_priv); |
| | 229 | if (IS_ERR(conv)) { |
| | 230 | devres_free(ptr); |
| | 231 | return ERR_CAST(conv); |
| | 232 | } |
| | 233 | |
| | 234 | *ptr = conv; |
| | 235 | devres_add(dev, ptr); |
| | 236 | |
| | 237 | return conv; |
| | 238 | } |
| | 239 | EXPORT_SYMBOL_GPL(devm_adi_axi_adc_conv_register); |
| | 240 | |
| | 241 | static ssize_t in_voltage_scale_available_show(struct device *dev, |
| | 242 | struct device_attribute *attr, |
| | 243 | char *buf) |
| | 244 | { |
| | 245 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
| | 246 | struct adi_axi_adc_state *st = iio_priv(indio_dev); |
| | 247 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 248 | size_t len = 0; |
| | 249 | int i; |
| | 250 | |
| | 251 | for (i = 0; i < conv->chip_info->num_scales; i++) { |
| | 252 | const unsigned int *s = conv->chip_info->scale_table[i]; |
| | 253 | |
| | 254 | len += scnprintf(buf + len, PAGE_SIZE - len, |
| | 255 | "%u.%06u ", s[0], s[1]); |
| | 256 | } |
| | 257 | buf[len - 1] = '\n'; |
| | 258 | |
| | 259 | return len; |
| | 260 | } |
| | 261 | |
| | 262 | static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); |
| | 263 | |
| | 264 | enum { |
| | 265 | ADI_AXI_ATTR_SCALE_AVAIL, |
| | 266 | }; |
| | 267 | |
| | 268 | #define ADI_AXI_ATTR(_en_, _file_) \ |
| | 269 | [ADI_AXI_ATTR_##_en_] = &iio_dev_attr_##_file_.dev_attr.attr |
| | 270 | |
| | 271 | static struct attribute *adi_axi_adc_attributes[] = { |
| | 272 | ADI_AXI_ATTR(SCALE_AVAIL, in_voltage_scale_available), |
| | 273 | NULL |
| | 274 | }; |
| | 275 | |
| | 276 | static umode_t axi_adc_attr_is_visible(struct kobject *kobj, |
| | 277 | struct attribute *attr, int n) |
| | 278 | { |
| | 279 | struct device *dev = container_of(kobj, struct device, kobj); |
| | 280 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
| | 281 | struct adi_axi_adc_state *st = iio_priv(indio_dev); |
| | 282 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 283 | |
| | 284 | switch (n) { |
| | 285 | case ADI_AXI_ATTR_SCALE_AVAIL: |
| | 286 | if (!conv->chip_info->num_scales) |
| | 287 | return 0; |
| | 288 | return attr->mode; |
| | 289 | default: |
| | 290 | return attr->mode; |
| | 291 | } |
| | 292 | } |
| | 293 | |
| | 294 | static const struct attribute_group adi_axi_adc_attribute_group = { |
| | 295 | .attrs = adi_axi_adc_attributes, |
| | 296 | .is_visible = axi_adc_attr_is_visible, |
| | 297 | }; |
| | 298 | |
| | 299 | static const struct iio_info adi_axi_adc_info = { |
| | 300 | .read_raw = &adi_axi_adc_read_raw, |
| | 301 | .write_raw = &adi_axi_adc_write_raw, |
| | 302 | .attrs = &adi_axi_adc_attribute_group, |
| | 303 | .update_scan_mode = &adi_axi_adc_update_scan_mode, |
| | 304 | }; |
| | 305 | |
| | 306 | static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { |
| | 307 | .version = ADI_AXI_PCORE_VER(10, 0, 'a'), |
| | 308 | }; |
| | 309 | |
| | 310 | static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) |
| | 311 | { |
| | 312 | const struct adi_axi_adc_core_info *info; |
| | 313 | struct adi_axi_adc_client *cl; |
| | 314 | struct device_node *cln; |
| | 315 | |
| | 316 | info = of_device_get_match_data(dev); |
| | 317 | if (!info) |
| | 318 | return ERR_PTR(-ENODEV); |
| | 319 | |
| | 320 | cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); |
| | 321 | if (!cln) { |
| | 322 | dev_err(dev, "No 'adi,adc-dev' node defined\n"); |
| | 323 | return ERR_PTR(-ENODEV); |
| | 324 | } |
| | 325 | |
| | 326 | mutex_lock(®istered_clients_lock); |
| | 327 | |
| | 328 | list_for_each_entry(cl, ®istered_clients, entry) { |
| | 329 | if (!cl->dev) |
| | 330 | continue; |
| | 331 | |
| | 332 | if (cl->dev->of_node != cln) |
| | 333 | continue; |
| | 334 | |
| | 335 | if (!try_module_get(dev->driver->owner)) { |
| | 336 | mutex_unlock(®istered_clients_lock); |
| | 337 | return ERR_PTR(-ENODEV); |
| | 338 | } |
| | 339 | |
| | 340 | get_device(dev); |
| | 341 | cl->info = info; |
| | 342 | mutex_unlock(®istered_clients_lock); |
| | 343 | return cl; |
| | 344 | } |
| | 345 | |
| | 346 | mutex_unlock(®istered_clients_lock); |
| | 347 | |
| | 348 | return ERR_PTR(-EPROBE_DEFER); |
| | 349 | } |
| | 350 | |
| | 351 | static int adi_axi_adc_setup_channels(struct device *dev, |
| | 352 | struct adi_axi_adc_state *st) |
| | 353 | { |
| | 354 | struct adi_axi_adc_conv *conv = &st->client->conv; |
| | 355 | int i, ret; |
| | 356 | |
| | 357 | if (conv->preenable_setup) { |
| | 358 | ret = conv->preenable_setup(conv); |
| | 359 | if (ret) |
| | 360 | return ret; |
| | 361 | } |
| | 362 | |
| | 363 | for (i = 0; i < conv->chip_info->num_channels; i++) { |
| | 364 | adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), |
| | 365 | ADI_AXI_REG_CHAN_CTRL_DEFAULTS); |
| | 366 | } |
| | 367 | |
| | 368 | return 0; |
| | 369 | } |
| | 370 | |
| | 371 | static void axi_adc_reset(struct adi_axi_adc_state *st) |
| | 372 | { |
| | 373 | adi_axi_adc_write(st, ADI_AXI_REG_RSTN, 0); |
| | 374 | mdelay(10); |
| | 375 | adi_axi_adc_write(st, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN); |
| | 376 | mdelay(10); |
| | 377 | adi_axi_adc_write(st, ADI_AXI_REG_RSTN, |
| | 378 | ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); |
| | 379 | } |
| | 380 | |
| | 381 | static void adi_axi_adc_cleanup(void *data) |
| | 382 | { |
| | 383 | struct adi_axi_adc_client *cl = data; |
| | 384 | |
| | 385 | put_device(cl->dev); |
| | 386 | module_put(cl->dev->driver->owner); |
| | 387 | } |
| | 388 | |
| | 389 | static int adi_axi_adc_probe(struct platform_device *pdev) |
| | 390 | { |
| | 391 | struct adi_axi_adc_conv *conv; |
| | 392 | struct iio_dev *indio_dev; |
| | 393 | struct adi_axi_adc_client *cl; |
| | 394 | struct adi_axi_adc_state *st; |
| | 395 | unsigned int ver; |
| | 396 | int ret; |
| | 397 | |
| | 398 | cl = adi_axi_adc_attach_client(&pdev->dev); |
| | 399 | if (IS_ERR(cl)) |
| | 400 | return PTR_ERR(cl); |
| | 401 | |
| | 402 | ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); |
| | 403 | if (ret) |
| | 404 | return ret; |
| | 405 | |
| | 406 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); |
| | 407 | if (indio_dev == NULL) |
| | 408 | return -ENOMEM; |
| | 409 | |
| | 410 | st = iio_priv(indio_dev); |
| | 411 | st->client = cl; |
| | 412 | cl->state = st; |
| | 413 | mutex_init(&st->lock); |
| | 414 | |
| | 415 | st->regs = devm_platform_ioremap_resource(pdev, 0); |
| | 416 | if (IS_ERR(st->regs)) |
| | 417 | return PTR_ERR(st->regs); |
| | 418 | |
| | 419 | conv = &st->client->conv; |
| | 420 | |
| | 421 | axi_adc_reset(st); |
| | 422 | |
| | 423 | ver = adi_axi_adc_read(st, ADI_AXI_REG_VERSION); |
| | 424 | |
| | 425 | if (cl->info->version > ver) { |
| | 426 | dev_err(&pdev->dev, |
| | 427 | "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", |
| | 428 | ADI_AXI_PCORE_VER_MAJOR(cl->info->version), |
| | 429 | ADI_AXI_PCORE_VER_MINOR(cl->info->version), |
| | 430 | ADI_AXI_PCORE_VER_PATCH(cl->info->version), |
| | 431 | ADI_AXI_PCORE_VER_MAJOR(ver), |
| | 432 | ADI_AXI_PCORE_VER_MINOR(ver), |
| | 433 | ADI_AXI_PCORE_VER_PATCH(ver)); |
| | 434 | return -ENODEV; |
| | 435 | } |
| | 436 | |
| | 437 | indio_dev->info = &adi_axi_adc_info; |
| | 438 | indio_dev->dev.parent = &pdev->dev; |
| | 439 | indio_dev->name = "adi-axi-adc"; |
| | 440 | indio_dev->modes = INDIO_DIRECT_MODE; |
| | 441 | indio_dev->num_channels = conv->chip_info->num_channels; |
| | 442 | indio_dev->channels = conv->chip_info->channels; |
| | 443 | |
| | 444 | ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); |
| | 445 | if (ret) |
| | 446 | return ret; |
| | 447 | |
| | 448 | ret = adi_axi_adc_setup_channels(&pdev->dev, st); |
| | 449 | if (ret) |
| | 450 | return ret; |
| | 451 | |
| | 452 | ret = devm_iio_device_register(&pdev->dev, indio_dev); |
| | 453 | if (ret) |
| | 454 | return ret; |
| | 455 | |
| | 456 | dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", |
| | 457 | ADI_AXI_PCORE_VER_MAJOR(ver), |
| | 458 | ADI_AXI_PCORE_VER_MINOR(ver), |
| | 459 | ADI_AXI_PCORE_VER_PATCH(ver)); |
| | 460 | |
| | 461 | return 0; |
| | 462 | } |
| | 463 | |
| | 464 | /* Match table for of_platform binding */ |
| | 465 | static const struct of_device_id adi_axi_adc_of_match[] = { |
| | 466 | { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, |
| | 467 | { /* end of list */ } |
| | 468 | }; |
| | 469 | MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match); |
| | 470 | |
| | 471 | static struct platform_driver adi_axi_adc_driver = { |
| | 472 | .driver = { |
| | 473 | .name = KBUILD_MODNAME, |
| | 474 | .of_match_table = adi_axi_adc_of_match, |
| | 475 | }, |
| | 476 | .probe = adi_axi_adc_probe, |
| | 477 | }; |
| | 478 | module_platform_driver(adi_axi_adc_driver); |
| | 479 | |
| | 480 | MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); |
| | 481 | MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); |
| | 482 | MODULE_LICENSE("GPL v2"); |