18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD5592R Digital <-> Analog converters driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2014-2016 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * Author: Paul Cercueil <paul.cercueil@analog.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/mutex.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/property.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <dt-bindings/iio/adi,ad5592r.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "ad5592r-base.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic int ad5592r_gpio_get(struct gpio_chip *chip, unsigned offset) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct ad5592r_state *st = gpiochip_get_data(chip); 278c2ecf20Sopenharmony_ci int ret = 0; 288c2ecf20Sopenharmony_ci u8 val; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci mutex_lock(&st->gpio_lock); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (st->gpio_out & BIT(offset)) 338c2ecf20Sopenharmony_ci val = st->gpio_val; 348c2ecf20Sopenharmony_ci else 358c2ecf20Sopenharmony_ci ret = st->ops->gpio_read(st, &val); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci mutex_unlock(&st->gpio_lock); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (ret < 0) 408c2ecf20Sopenharmony_ci return ret; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return !!(val & BIT(offset)); 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void ad5592r_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct ad5592r_state *st = gpiochip_get_data(chip); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci mutex_lock(&st->gpio_lock); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (value) 528c2ecf20Sopenharmony_ci st->gpio_val |= BIT(offset); 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci st->gpio_val &= ~BIT(offset); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci mutex_unlock(&st->gpio_lock); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int ad5592r_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct ad5592r_state *st = gpiochip_get_data(chip); 648c2ecf20Sopenharmony_ci int ret; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mutex_lock(&st->gpio_lock); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci st->gpio_out &= ~BIT(offset); 698c2ecf20Sopenharmony_ci st->gpio_in |= BIT(offset); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); 728c2ecf20Sopenharmony_ci if (ret < 0) 738c2ecf20Sopenharmony_ci goto err_unlock; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cierr_unlock: 788c2ecf20Sopenharmony_ci mutex_unlock(&st->gpio_lock); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return ret; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int ad5592r_gpio_direction_output(struct gpio_chip *chip, 848c2ecf20Sopenharmony_ci unsigned offset, int value) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct ad5592r_state *st = gpiochip_get_data(chip); 878c2ecf20Sopenharmony_ci int ret; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci mutex_lock(&st->gpio_lock); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (value) 928c2ecf20Sopenharmony_ci st->gpio_val |= BIT(offset); 938c2ecf20Sopenharmony_ci else 948c2ecf20Sopenharmony_ci st->gpio_val &= ~BIT(offset); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci st->gpio_in &= ~BIT(offset); 978c2ecf20Sopenharmony_ci st->gpio_out |= BIT(offset); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); 1008c2ecf20Sopenharmony_ci if (ret < 0) 1018c2ecf20Sopenharmony_ci goto err_unlock; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); 1048c2ecf20Sopenharmony_ci if (ret < 0) 1058c2ecf20Sopenharmony_ci goto err_unlock; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cierr_unlock: 1108c2ecf20Sopenharmony_ci mutex_unlock(&st->gpio_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return ret; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int ad5592r_gpio_request(struct gpio_chip *chip, unsigned offset) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct ad5592r_state *st = gpiochip_get_data(chip); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (!(st->gpio_map & BIT(offset))) { 1208c2ecf20Sopenharmony_ci dev_err(st->dev, "GPIO %d is reserved by alternate function\n", 1218c2ecf20Sopenharmony_ci offset); 1228c2ecf20Sopenharmony_ci return -ENODEV; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int ad5592r_gpio_init(struct ad5592r_state *st) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci if (!st->gpio_map) 1318c2ecf20Sopenharmony_ci return 0; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci st->gpiochip.label = dev_name(st->dev); 1348c2ecf20Sopenharmony_ci st->gpiochip.base = -1; 1358c2ecf20Sopenharmony_ci st->gpiochip.ngpio = 8; 1368c2ecf20Sopenharmony_ci st->gpiochip.parent = st->dev; 1378c2ecf20Sopenharmony_ci st->gpiochip.can_sleep = true; 1388c2ecf20Sopenharmony_ci st->gpiochip.direction_input = ad5592r_gpio_direction_input; 1398c2ecf20Sopenharmony_ci st->gpiochip.direction_output = ad5592r_gpio_direction_output; 1408c2ecf20Sopenharmony_ci st->gpiochip.get = ad5592r_gpio_get; 1418c2ecf20Sopenharmony_ci st->gpiochip.set = ad5592r_gpio_set; 1428c2ecf20Sopenharmony_ci st->gpiochip.request = ad5592r_gpio_request; 1438c2ecf20Sopenharmony_ci st->gpiochip.owner = THIS_MODULE; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mutex_init(&st->gpio_lock); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return gpiochip_add_data(&st->gpiochip, st); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic void ad5592r_gpio_cleanup(struct ad5592r_state *st) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci if (st->gpio_map) 1538c2ecf20Sopenharmony_ci gpiochip_remove(&st->gpiochip); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int ad5592r_reset(struct ad5592r_state *st) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct gpio_desc *gpio; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci gpio = devm_gpiod_get_optional(st->dev, "reset", GPIOD_OUT_LOW); 1618c2ecf20Sopenharmony_ci if (IS_ERR(gpio)) 1628c2ecf20Sopenharmony_ci return PTR_ERR(gpio); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (gpio) { 1658c2ecf20Sopenharmony_ci udelay(1); 1668c2ecf20Sopenharmony_ci gpiod_set_value(gpio, 1); 1678c2ecf20Sopenharmony_ci } else { 1688c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 1698c2ecf20Sopenharmony_ci /* Writing this magic value resets the device */ 1708c2ecf20Sopenharmony_ci st->ops->reg_write(st, AD5592R_REG_RESET, 0xdac); 1718c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci udelay(250); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int ad5592r_get_vref(struct ad5592r_state *st) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci int ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (st->reg) { 1848c2ecf20Sopenharmony_ci ret = regulator_get_voltage(st->reg); 1858c2ecf20Sopenharmony_ci if (ret < 0) 1868c2ecf20Sopenharmony_ci return ret; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return ret / 1000; 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci return 2500; 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int ad5592r_set_channel_modes(struct ad5592r_state *st) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci const struct ad5592r_rw_ops *ops = st->ops; 1978c2ecf20Sopenharmony_ci int ret; 1988c2ecf20Sopenharmony_ci unsigned i; 1998c2ecf20Sopenharmony_ci u8 pulldown = 0, tristate = 0, dac = 0, adc = 0; 2008c2ecf20Sopenharmony_ci u16 read_back; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci for (i = 0; i < st->num_channels; i++) { 2038c2ecf20Sopenharmony_ci switch (st->channel_modes[i]) { 2048c2ecf20Sopenharmony_ci case CH_MODE_DAC: 2058c2ecf20Sopenharmony_ci dac |= BIT(i); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci case CH_MODE_ADC: 2098c2ecf20Sopenharmony_ci adc |= BIT(i); 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci case CH_MODE_DAC_AND_ADC: 2138c2ecf20Sopenharmony_ci dac |= BIT(i); 2148c2ecf20Sopenharmony_ci adc |= BIT(i); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci case CH_MODE_GPIO: 2188c2ecf20Sopenharmony_ci st->gpio_map |= BIT(i); 2198c2ecf20Sopenharmony_ci st->gpio_in |= BIT(i); /* Default to input */ 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci case CH_MODE_UNUSED: 2238c2ecf20Sopenharmony_ci default: 2248c2ecf20Sopenharmony_ci switch (st->channel_offstate[i]) { 2258c2ecf20Sopenharmony_ci case CH_OFFSTATE_OUT_TRISTATE: 2268c2ecf20Sopenharmony_ci tristate |= BIT(i); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci case CH_OFFSTATE_OUT_LOW: 2308c2ecf20Sopenharmony_ci st->gpio_out |= BIT(i); 2318c2ecf20Sopenharmony_ci break; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci case CH_OFFSTATE_OUT_HIGH: 2348c2ecf20Sopenharmony_ci st->gpio_out |= BIT(i); 2358c2ecf20Sopenharmony_ci st->gpio_val |= BIT(i); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci case CH_OFFSTATE_PULLDOWN: 2398c2ecf20Sopenharmony_ci default: 2408c2ecf20Sopenharmony_ci pulldown |= BIT(i); 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Pull down unused pins to GND */ 2498c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_PULLDOWN, pulldown); 2508c2ecf20Sopenharmony_ci if (ret) 2518c2ecf20Sopenharmony_ci goto err_unlock; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_TRISTATE, tristate); 2548c2ecf20Sopenharmony_ci if (ret) 2558c2ecf20Sopenharmony_ci goto err_unlock; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Configure pins that we use */ 2588c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_DAC_EN, dac); 2598c2ecf20Sopenharmony_ci if (ret) 2608c2ecf20Sopenharmony_ci goto err_unlock; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_ADC_EN, adc); 2638c2ecf20Sopenharmony_ci if (ret) 2648c2ecf20Sopenharmony_ci goto err_unlock; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_GPIO_SET, st->gpio_val); 2678c2ecf20Sopenharmony_ci if (ret) 2688c2ecf20Sopenharmony_ci goto err_unlock; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_GPIO_OUT_EN, st->gpio_out); 2718c2ecf20Sopenharmony_ci if (ret) 2728c2ecf20Sopenharmony_ci goto err_unlock; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_GPIO_IN_EN, st->gpio_in); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci goto err_unlock; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Verify that we can read back at least one register */ 2798c2ecf20Sopenharmony_ci ret = ops->reg_read(st, AD5592R_REG_ADC_EN, &read_back); 2808c2ecf20Sopenharmony_ci if (!ret && (read_back & 0xff) != adc) 2818c2ecf20Sopenharmony_ci ret = -EIO; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cierr_unlock: 2848c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int ad5592r_reset_channel_modes(struct ad5592r_state *st) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci int i; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(st->channel_modes); i++) 2938c2ecf20Sopenharmony_ci st->channel_modes[i] = CH_MODE_UNUSED; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return ad5592r_set_channel_modes(st); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int ad5592r_write_raw(struct iio_dev *iio_dev, 2998c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, int val, int val2, long mask) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct ad5592r_state *st = iio_priv(iio_dev); 3028c2ecf20Sopenharmony_ci int ret; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci switch (mask) { 3058c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (val >= (1 << chan->scan_type.realbits) || val < 0) 3088c2ecf20Sopenharmony_ci return -EINVAL; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (!chan->output) 3118c2ecf20Sopenharmony_ci return -EINVAL; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 3148c2ecf20Sopenharmony_ci ret = st->ops->write_dac(st, chan->channel, val); 3158c2ecf20Sopenharmony_ci if (!ret) 3168c2ecf20Sopenharmony_ci st->cached_dac[chan->channel] = val; 3178c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3188c2ecf20Sopenharmony_ci return ret; 3198c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 3208c2ecf20Sopenharmony_ci if (chan->type == IIO_VOLTAGE) { 3218c2ecf20Sopenharmony_ci bool gain; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (val == st->scale_avail[0][0] && 3248c2ecf20Sopenharmony_ci val2 == st->scale_avail[0][1]) 3258c2ecf20Sopenharmony_ci gain = false; 3268c2ecf20Sopenharmony_ci else if (val == st->scale_avail[1][0] && 3278c2ecf20Sopenharmony_ci val2 == st->scale_avail[1][1]) 3288c2ecf20Sopenharmony_ci gain = true; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ret = st->ops->reg_read(st, AD5592R_REG_CTRL, 3358c2ecf20Sopenharmony_ci &st->cached_gp_ctrl); 3368c2ecf20Sopenharmony_ci if (ret < 0) { 3378c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (chan->output) { 3428c2ecf20Sopenharmony_ci if (gain) 3438c2ecf20Sopenharmony_ci st->cached_gp_ctrl |= 3448c2ecf20Sopenharmony_ci AD5592R_REG_CTRL_DAC_RANGE; 3458c2ecf20Sopenharmony_ci else 3468c2ecf20Sopenharmony_ci st->cached_gp_ctrl &= 3478c2ecf20Sopenharmony_ci ~AD5592R_REG_CTRL_DAC_RANGE; 3488c2ecf20Sopenharmony_ci } else { 3498c2ecf20Sopenharmony_ci if (gain) 3508c2ecf20Sopenharmony_ci st->cached_gp_ctrl |= 3518c2ecf20Sopenharmony_ci AD5592R_REG_CTRL_ADC_RANGE; 3528c2ecf20Sopenharmony_ci else 3538c2ecf20Sopenharmony_ci st->cached_gp_ctrl &= 3548c2ecf20Sopenharmony_ci ~AD5592R_REG_CTRL_ADC_RANGE; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci ret = st->ops->reg_write(st, AD5592R_REG_CTRL, 3588c2ecf20Sopenharmony_ci st->cached_gp_ctrl); 3598c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci default: 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int ad5592r_read_raw(struct iio_dev *iio_dev, 3728c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 3738c2ecf20Sopenharmony_ci int *val, int *val2, long m) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct ad5592r_state *st = iio_priv(iio_dev); 3768c2ecf20Sopenharmony_ci u16 read_val; 3778c2ecf20Sopenharmony_ci int ret, mult; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci switch (m) { 3808c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 3818c2ecf20Sopenharmony_ci if (!chan->output) { 3828c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 3838c2ecf20Sopenharmony_ci ret = st->ops->read_adc(st, chan->channel, &read_val); 3848c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 3858c2ecf20Sopenharmony_ci if (ret) 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if ((read_val >> 12 & 0x7) != (chan->channel & 0x7)) { 3898c2ecf20Sopenharmony_ci dev_err(st->dev, "Error while reading channel %u\n", 3908c2ecf20Sopenharmony_ci chan->channel); 3918c2ecf20Sopenharmony_ci return -EIO; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci read_val &= GENMASK(11, 0); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci } else { 3978c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 3988c2ecf20Sopenharmony_ci read_val = st->cached_dac[chan->channel]; 3998c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci dev_dbg(st->dev, "Channel %u read: 0x%04hX\n", 4038c2ecf20Sopenharmony_ci chan->channel, read_val); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci *val = (int) read_val; 4068c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4078c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 4088c2ecf20Sopenharmony_ci *val = ad5592r_get_vref(st); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (chan->type == IIO_TEMP) { 4118c2ecf20Sopenharmony_ci s64 tmp = *val * (3767897513LL / 25LL); 4128c2ecf20Sopenharmony_ci *val = div_s64_rem(tmp, 1000000000LL, val2); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (chan->output) 4208c2ecf20Sopenharmony_ci mult = !!(st->cached_gp_ctrl & 4218c2ecf20Sopenharmony_ci AD5592R_REG_CTRL_DAC_RANGE); 4228c2ecf20Sopenharmony_ci else 4238c2ecf20Sopenharmony_ci mult = !!(st->cached_gp_ctrl & 4248c2ecf20Sopenharmony_ci AD5592R_REG_CTRL_ADC_RANGE); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci *val *= ++mult; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci *val2 = chan->scan_type.realbits; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 4338c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_OFFSET: 4348c2ecf20Sopenharmony_ci ret = ad5592r_get_vref(st); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci mutex_lock(&st->lock); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (st->cached_gp_ctrl & AD5592R_REG_CTRL_ADC_RANGE) 4398c2ecf20Sopenharmony_ci *val = (-34365 * 25) / ret; 4408c2ecf20Sopenharmony_ci else 4418c2ecf20Sopenharmony_ci *val = (-75365 * 25) / ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci mutex_unlock(&st->lock); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci return IIO_VAL_INT; 4468c2ecf20Sopenharmony_ci default: 4478c2ecf20Sopenharmony_ci return -EINVAL; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic int ad5592r_write_raw_get_fmt(struct iio_dev *indio_dev, 4528c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, long mask) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci switch (mask) { 4558c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 4568c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_NANO; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci default: 4598c2ecf20Sopenharmony_ci return IIO_VAL_INT_PLUS_MICRO; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return -EINVAL; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic const struct iio_info ad5592r_info = { 4668c2ecf20Sopenharmony_ci .read_raw = ad5592r_read_raw, 4678c2ecf20Sopenharmony_ci .write_raw = ad5592r_write_raw, 4688c2ecf20Sopenharmony_ci .write_raw_get_fmt = ad5592r_write_raw_get_fmt, 4698c2ecf20Sopenharmony_ci}; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic ssize_t ad5592r_show_scale_available(struct iio_dev *iio_dev, 4728c2ecf20Sopenharmony_ci uintptr_t private, 4738c2ecf20Sopenharmony_ci const struct iio_chan_spec *chan, 4748c2ecf20Sopenharmony_ci char *buf) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct ad5592r_state *st = iio_priv(iio_dev); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return sprintf(buf, "%d.%09u %d.%09u\n", 4798c2ecf20Sopenharmony_ci st->scale_avail[0][0], st->scale_avail[0][1], 4808c2ecf20Sopenharmony_ci st->scale_avail[1][0], st->scale_avail[1][1]); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic const struct iio_chan_spec_ext_info ad5592r_ext_info[] = { 4848c2ecf20Sopenharmony_ci { 4858c2ecf20Sopenharmony_ci .name = "scale_available", 4868c2ecf20Sopenharmony_ci .read = ad5592r_show_scale_available, 4878c2ecf20Sopenharmony_ci .shared = IIO_SHARED_BY_TYPE, 4888c2ecf20Sopenharmony_ci }, 4898c2ecf20Sopenharmony_ci {}, 4908c2ecf20Sopenharmony_ci}; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic void ad5592r_setup_channel(struct iio_dev *iio_dev, 4938c2ecf20Sopenharmony_ci struct iio_chan_spec *chan, bool output, unsigned id) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci chan->type = IIO_VOLTAGE; 4968c2ecf20Sopenharmony_ci chan->indexed = 1; 4978c2ecf20Sopenharmony_ci chan->output = output; 4988c2ecf20Sopenharmony_ci chan->channel = id; 4998c2ecf20Sopenharmony_ci chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); 5008c2ecf20Sopenharmony_ci chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); 5018c2ecf20Sopenharmony_ci chan->scan_type.sign = 'u'; 5028c2ecf20Sopenharmony_ci chan->scan_type.realbits = 12; 5038c2ecf20Sopenharmony_ci chan->scan_type.storagebits = 16; 5048c2ecf20Sopenharmony_ci chan->ext_info = ad5592r_ext_info; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int ad5592r_alloc_channels(struct iio_dev *iio_dev) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct ad5592r_state *st = iio_priv(iio_dev); 5108c2ecf20Sopenharmony_ci unsigned i, curr_channel = 0, 5118c2ecf20Sopenharmony_ci num_channels = st->num_channels; 5128c2ecf20Sopenharmony_ci struct iio_chan_spec *channels; 5138c2ecf20Sopenharmony_ci struct fwnode_handle *child; 5148c2ecf20Sopenharmony_ci u32 reg, tmp; 5158c2ecf20Sopenharmony_ci int ret; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci device_for_each_child_node(st->dev, child) { 5188c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(child, "reg", ®); 5198c2ecf20Sopenharmony_ci if (ret || reg >= ARRAY_SIZE(st->channel_modes)) 5208c2ecf20Sopenharmony_ci continue; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(child, "adi,mode", &tmp); 5238c2ecf20Sopenharmony_ci if (!ret) 5248c2ecf20Sopenharmony_ci st->channel_modes[reg] = tmp; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(child, "adi,off-state", &tmp); 5278c2ecf20Sopenharmony_ci if (!ret) 5288c2ecf20Sopenharmony_ci st->channel_offstate[reg] = tmp; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci channels = devm_kcalloc(st->dev, 5328c2ecf20Sopenharmony_ci 1 + 2 * num_channels, sizeof(*channels), 5338c2ecf20Sopenharmony_ci GFP_KERNEL); 5348c2ecf20Sopenharmony_ci if (!channels) 5358c2ecf20Sopenharmony_ci return -ENOMEM; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci for (i = 0; i < num_channels; i++) { 5388c2ecf20Sopenharmony_ci switch (st->channel_modes[i]) { 5398c2ecf20Sopenharmony_ci case CH_MODE_DAC: 5408c2ecf20Sopenharmony_ci ad5592r_setup_channel(iio_dev, &channels[curr_channel], 5418c2ecf20Sopenharmony_ci true, i); 5428c2ecf20Sopenharmony_ci curr_channel++; 5438c2ecf20Sopenharmony_ci break; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci case CH_MODE_ADC: 5468c2ecf20Sopenharmony_ci ad5592r_setup_channel(iio_dev, &channels[curr_channel], 5478c2ecf20Sopenharmony_ci false, i); 5488c2ecf20Sopenharmony_ci curr_channel++; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci case CH_MODE_DAC_AND_ADC: 5528c2ecf20Sopenharmony_ci ad5592r_setup_channel(iio_dev, &channels[curr_channel], 5538c2ecf20Sopenharmony_ci true, i); 5548c2ecf20Sopenharmony_ci curr_channel++; 5558c2ecf20Sopenharmony_ci ad5592r_setup_channel(iio_dev, &channels[curr_channel], 5568c2ecf20Sopenharmony_ci false, i); 5578c2ecf20Sopenharmony_ci curr_channel++; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci default: 5618c2ecf20Sopenharmony_ci continue; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci channels[curr_channel].type = IIO_TEMP; 5668c2ecf20Sopenharmony_ci channels[curr_channel].channel = 8; 5678c2ecf20Sopenharmony_ci channels[curr_channel].info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 5688c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE) | 5698c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_OFFSET); 5708c2ecf20Sopenharmony_ci curr_channel++; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci iio_dev->num_channels = curr_channel; 5738c2ecf20Sopenharmony_ci iio_dev->channels = channels; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return 0; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic void ad5592r_init_scales(struct ad5592r_state *st, int vref_mV) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci s64 tmp = (s64)vref_mV * 1000000000LL >> 12; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci st->scale_avail[0][0] = 5838c2ecf20Sopenharmony_ci div_s64_rem(tmp, 1000000000LL, &st->scale_avail[0][1]); 5848c2ecf20Sopenharmony_ci st->scale_avail[1][0] = 5858c2ecf20Sopenharmony_ci div_s64_rem(tmp * 2, 1000000000LL, &st->scale_avail[1][1]); 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ciint ad5592r_probe(struct device *dev, const char *name, 5898c2ecf20Sopenharmony_ci const struct ad5592r_rw_ops *ops) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci struct iio_dev *iio_dev; 5928c2ecf20Sopenharmony_ci struct ad5592r_state *st; 5938c2ecf20Sopenharmony_ci int ret; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci iio_dev = devm_iio_device_alloc(dev, sizeof(*st)); 5968c2ecf20Sopenharmony_ci if (!iio_dev) 5978c2ecf20Sopenharmony_ci return -ENOMEM; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci st = iio_priv(iio_dev); 6008c2ecf20Sopenharmony_ci st->dev = dev; 6018c2ecf20Sopenharmony_ci st->ops = ops; 6028c2ecf20Sopenharmony_ci st->num_channels = 8; 6038c2ecf20Sopenharmony_ci dev_set_drvdata(dev, iio_dev); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci st->reg = devm_regulator_get_optional(dev, "vref"); 6068c2ecf20Sopenharmony_ci if (IS_ERR(st->reg)) { 6078c2ecf20Sopenharmony_ci if ((PTR_ERR(st->reg) != -ENODEV) && dev->of_node) 6088c2ecf20Sopenharmony_ci return PTR_ERR(st->reg); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci st->reg = NULL; 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci ret = regulator_enable(st->reg); 6138c2ecf20Sopenharmony_ci if (ret) 6148c2ecf20Sopenharmony_ci return ret; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci iio_dev->name = name; 6188c2ecf20Sopenharmony_ci iio_dev->info = &ad5592r_info; 6198c2ecf20Sopenharmony_ci iio_dev->modes = INDIO_DIRECT_MODE; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci mutex_init(&st->lock); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ad5592r_init_scales(st, ad5592r_get_vref(st)); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci ret = ad5592r_reset(st); 6268c2ecf20Sopenharmony_ci if (ret) 6278c2ecf20Sopenharmony_ci goto error_disable_reg; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci ret = ops->reg_write(st, AD5592R_REG_PD, 6308c2ecf20Sopenharmony_ci (st->reg == NULL) ? AD5592R_REG_PD_EN_REF : 0); 6318c2ecf20Sopenharmony_ci if (ret) 6328c2ecf20Sopenharmony_ci goto error_disable_reg; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci ret = ad5592r_alloc_channels(iio_dev); 6358c2ecf20Sopenharmony_ci if (ret) 6368c2ecf20Sopenharmony_ci goto error_disable_reg; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci ret = ad5592r_set_channel_modes(st); 6398c2ecf20Sopenharmony_ci if (ret) 6408c2ecf20Sopenharmony_ci goto error_reset_ch_modes; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci ret = iio_device_register(iio_dev); 6438c2ecf20Sopenharmony_ci if (ret) 6448c2ecf20Sopenharmony_ci goto error_reset_ch_modes; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = ad5592r_gpio_init(st); 6478c2ecf20Sopenharmony_ci if (ret) 6488c2ecf20Sopenharmony_ci goto error_dev_unregister; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cierror_dev_unregister: 6538c2ecf20Sopenharmony_ci iio_device_unregister(iio_dev); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cierror_reset_ch_modes: 6568c2ecf20Sopenharmony_ci ad5592r_reset_channel_modes(st); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cierror_disable_reg: 6598c2ecf20Sopenharmony_ci if (st->reg) 6608c2ecf20Sopenharmony_ci regulator_disable(st->reg); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return ret; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ad5592r_probe); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ciint ad5592r_remove(struct device *dev) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct iio_dev *iio_dev = dev_get_drvdata(dev); 6698c2ecf20Sopenharmony_ci struct ad5592r_state *st = iio_priv(iio_dev); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci iio_device_unregister(iio_dev); 6728c2ecf20Sopenharmony_ci ad5592r_reset_channel_modes(st); 6738c2ecf20Sopenharmony_ci ad5592r_gpio_cleanup(st); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (st->reg) 6768c2ecf20Sopenharmony_ci regulator_disable(st->reg); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return 0; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ad5592r_remove); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Cercueil <paul.cercueil@analog.com>"); 6838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD5592R multi-channel converters"); 6848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 685