18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Renesas R-Car GyroADC driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Marek Vasut <marek.vasut@gmail.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/clk.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 238c2ecf20Sopenharmony_ci#include <linux/iio/sysfs.h> 248c2ecf20Sopenharmony_ci#include <linux/iio/trigger.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DRIVER_NAME "rcar-gyroadc" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* GyroADC registers. */ 298c2ecf20Sopenharmony_ci#define RCAR_GYROADC_MODE_SELECT 0x00 308c2ecf20Sopenharmony_ci#define RCAR_GYROADC_MODE_SELECT_1_MB88101A 0x0 318c2ecf20Sopenharmony_ci#define RCAR_GYROADC_MODE_SELECT_2_ADCS7476 0x1 328c2ecf20Sopenharmony_ci#define RCAR_GYROADC_MODE_SELECT_3_MAX1162 0x3 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define RCAR_GYROADC_START_STOP 0x04 358c2ecf20Sopenharmony_ci#define RCAR_GYROADC_START_STOP_START BIT(0) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define RCAR_GYROADC_CLOCK_LENGTH 0x08 388c2ecf20Sopenharmony_ci#define RCAR_GYROADC_1_25MS_LENGTH 0x0c 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define RCAR_GYROADC_REALTIME_DATA(ch) (0x10 + ((ch) * 4)) 418c2ecf20Sopenharmony_ci#define RCAR_GYROADC_100MS_ADDED_DATA(ch) (0x30 + ((ch) * 4)) 428c2ecf20Sopenharmony_ci#define RCAR_GYROADC_10MS_AVG_DATA(ch) (0x50 + ((ch) * 4)) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define RCAR_GYROADC_FIFO_STATUS 0x70 458c2ecf20Sopenharmony_ci#define RCAR_GYROADC_FIFO_STATUS_EMPTY(ch) BIT(0 + (4 * (ch))) 468c2ecf20Sopenharmony_ci#define RCAR_GYROADC_FIFO_STATUS_FULL(ch) BIT(1 + (4 * (ch))) 478c2ecf20Sopenharmony_ci#define RCAR_GYROADC_FIFO_STATUS_ERROR(ch) BIT(2 + (4 * (ch))) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define RCAR_GYROADC_INTR 0x74 508c2ecf20Sopenharmony_ci#define RCAR_GYROADC_INTR_INT BIT(0) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define RCAR_GYROADC_INTENR 0x78 538c2ecf20Sopenharmony_ci#define RCAR_GYROADC_INTENR_INTEN BIT(0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define RCAR_GYROADC_SAMPLE_RATE 800 /* Hz */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define RCAR_GYROADC_RUNTIME_PM_DELAY_MS 2000 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cienum rcar_gyroadc_model { 608c2ecf20Sopenharmony_ci RCAR_GYROADC_MODEL_DEFAULT, 618c2ecf20Sopenharmony_ci RCAR_GYROADC_MODEL_R8A7792, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct rcar_gyroadc { 658c2ecf20Sopenharmony_ci struct device *dev; 668c2ecf20Sopenharmony_ci void __iomem *regs; 678c2ecf20Sopenharmony_ci struct clk *clk; 688c2ecf20Sopenharmony_ci struct regulator *vref[8]; 698c2ecf20Sopenharmony_ci unsigned int num_channels; 708c2ecf20Sopenharmony_ci enum rcar_gyroadc_model model; 718c2ecf20Sopenharmony_ci unsigned int mode; 728c2ecf20Sopenharmony_ci unsigned int sample_width; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci const unsigned long clk_mhz = clk_get_rate(priv->clk) / 1000000; 788c2ecf20Sopenharmony_ci const unsigned long clk_mul = 798c2ecf20Sopenharmony_ci (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5; 808c2ecf20Sopenharmony_ci unsigned long clk_len = clk_mhz * clk_mul; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * According to the R-Car Gen2 datasheet Rev. 1.01, Sept 08 2014, 848c2ecf20Sopenharmony_ci * page 77-7, clock length must be even number. If it's odd number, 858c2ecf20Sopenharmony_ci * add one. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ci if (clk_len & 1) 888c2ecf20Sopenharmony_ci clk_len++; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Stop the GyroADC. */ 918c2ecf20Sopenharmony_ci writel(0, priv->regs + RCAR_GYROADC_START_STOP); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Disable IRQ on V2H. */ 948c2ecf20Sopenharmony_ci if (priv->model == RCAR_GYROADC_MODEL_R8A7792) 958c2ecf20Sopenharmony_ci writel(0, priv->regs + RCAR_GYROADC_INTENR); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* Set mode and timing. */ 988c2ecf20Sopenharmony_ci writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT); 998c2ecf20Sopenharmony_ci writel(clk_len, priv->regs + RCAR_GYROADC_CLOCK_LENGTH); 1008c2ecf20Sopenharmony_ci writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH); 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic void rcar_gyroadc_hw_start(struct rcar_gyroadc *priv) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci /* Start sampling. */ 1068c2ecf20Sopenharmony_ci writel(RCAR_GYROADC_START_STOP_START, 1078c2ecf20Sopenharmony_ci priv->regs + RCAR_GYROADC_START_STOP); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Wait for the first conversion to complete. This is longer than 1118c2ecf20Sopenharmony_ci * the 1.25 mS in the datasheet because 1.25 mS is not enough for 1128c2ecf20Sopenharmony_ci * the hardware to deliver the first sample and the hardware does 1138c2ecf20Sopenharmony_ci * then return zeroes instead of valid data. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci mdelay(3); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void rcar_gyroadc_hw_stop(struct rcar_gyroadc *priv) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci /* Stop the GyroADC. */ 1218c2ecf20Sopenharmony_ci writel(0, priv->regs + RCAR_GYROADC_START_STOP); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define RCAR_GYROADC_CHAN(_idx) { \ 1258c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, \ 1268c2ecf20Sopenharmony_ci .indexed = 1, \ 1278c2ecf20Sopenharmony_ci .channel = (_idx), \ 1288c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1298c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE), \ 1308c2ecf20Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic const struct iio_chan_spec rcar_gyroadc_iio_channels_1[] = { 1348c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(0), 1358c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(1), 1368c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(2), 1378c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(3), 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct iio_chan_spec rcar_gyroadc_iio_channels_2[] = { 1418c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(0), 1428c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(1), 1438c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(2), 1448c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(3), 1458c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(4), 1468c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(5), 1478c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(6), 1488c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(7), 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = { 1528c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(0), 1538c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(1), 1548c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(2), 1558c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(3), 1568c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(4), 1578c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(5), 1588c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(6), 1598c2ecf20Sopenharmony_ci RCAR_GYROADC_CHAN(7), 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 1658c2ecf20Sopenharmony_ci int ret; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci if (on) { 1688c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 1698c2ecf20Sopenharmony_ci if (ret < 0) 1708c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 1718c2ecf20Sopenharmony_ci } else { 1728c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 1738c2ecf20Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return ret; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, 1808c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1818c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 1848c2ecf20Sopenharmony_ci struct regulator *consumer; 1858c2ecf20Sopenharmony_ci unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel); 1868c2ecf20Sopenharmony_ci unsigned int vref; 1878c2ecf20Sopenharmony_ci int ret; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * MB88101 is special in that it has only single regulator for 1918c2ecf20Sopenharmony_ci * all four channels. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) 1948c2ecf20Sopenharmony_ci consumer = priv->vref[0]; 1958c2ecf20Sopenharmony_ci else 1968c2ecf20Sopenharmony_ci consumer = priv->vref[chan->channel]; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci switch (mask) { 1998c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 2008c2ecf20Sopenharmony_ci if (chan->type != IIO_VOLTAGE) 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Channel not connected. */ 2048c2ecf20Sopenharmony_ci if (!consumer) 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = iio_device_claim_direct_mode(indio_dev); 2088c2ecf20Sopenharmony_ci if (ret) 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci ret = rcar_gyroadc_set_power(priv, true); 2128c2ecf20Sopenharmony_ci if (ret < 0) { 2138c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 2148c2ecf20Sopenharmony_ci return ret; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci *val = readl(priv->regs + datareg); 2188c2ecf20Sopenharmony_ci *val &= BIT(priv->sample_width) - 1; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = rcar_gyroadc_set_power(priv, false); 2218c2ecf20Sopenharmony_ci iio_device_release_direct_mode(indio_dev); 2228c2ecf20Sopenharmony_ci if (ret < 0) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2268c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 2278c2ecf20Sopenharmony_ci /* Channel not connected. */ 2288c2ecf20Sopenharmony_ci if (!consumer) 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci vref = regulator_get_voltage(consumer); 2328c2ecf20Sopenharmony_ci *val = vref / 1000; 2338c2ecf20Sopenharmony_ci *val2 = 1 << priv->sample_width; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL; 2368c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SAMP_FREQ: 2378c2ecf20Sopenharmony_ci *val = RCAR_GYROADC_SAMPLE_RATE; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return IIO_VAL_INT; 2408c2ecf20Sopenharmony_ci default: 2418c2ecf20Sopenharmony_ci return -EINVAL; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int rcar_gyroadc_reg_access(struct iio_dev *indio_dev, 2468c2ecf20Sopenharmony_ci unsigned int reg, unsigned int writeval, 2478c2ecf20Sopenharmony_ci unsigned int *readval) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 2508c2ecf20Sopenharmony_ci unsigned int maxreg = RCAR_GYROADC_FIFO_STATUS; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (readval == NULL) 2538c2ecf20Sopenharmony_ci return -EINVAL; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (reg % 4) 2568c2ecf20Sopenharmony_ci return -EINVAL; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* Handle the V2H case with extra interrupt block. */ 2598c2ecf20Sopenharmony_ci if (priv->model == RCAR_GYROADC_MODEL_R8A7792) 2608c2ecf20Sopenharmony_ci maxreg = RCAR_GYROADC_INTENR; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (reg > maxreg) 2638c2ecf20Sopenharmony_ci return -EINVAL; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci *readval = readl(priv->regs + reg); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic const struct iio_info rcar_gyroadc_iio_info = { 2718c2ecf20Sopenharmony_ci .read_raw = rcar_gyroadc_read_raw, 2728c2ecf20Sopenharmony_ci .debugfs_reg_access = rcar_gyroadc_reg_access, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic const struct of_device_id rcar_gyroadc_match[] = { 2768c2ecf20Sopenharmony_ci { 2778c2ecf20Sopenharmony_ci /* R-Car compatible GyroADC */ 2788c2ecf20Sopenharmony_ci .compatible = "renesas,rcar-gyroadc", 2798c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODEL_DEFAULT, 2808c2ecf20Sopenharmony_ci }, { 2818c2ecf20Sopenharmony_ci /* R-Car V2H specialty with interrupt registers. */ 2828c2ecf20Sopenharmony_ci .compatible = "renesas,r8a7792-gyroadc", 2838c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODEL_R8A7792, 2848c2ecf20Sopenharmony_ci }, { 2858c2ecf20Sopenharmony_ci /* sentinel */ 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rcar_gyroadc_match); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic const struct of_device_id rcar_gyroadc_child_match[] = { 2928c2ecf20Sopenharmony_ci /* Mode 1 ADCs */ 2938c2ecf20Sopenharmony_ci { 2948c2ecf20Sopenharmony_ci .compatible = "fujitsu,mb88101a", 2958c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_1_MB88101A, 2968c2ecf20Sopenharmony_ci }, 2978c2ecf20Sopenharmony_ci /* Mode 2 ADCs */ 2988c2ecf20Sopenharmony_ci { 2998c2ecf20Sopenharmony_ci .compatible = "ti,adcs7476", 3008c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, 3018c2ecf20Sopenharmony_ci }, { 3028c2ecf20Sopenharmony_ci .compatible = "ti,adc121", 3038c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, 3048c2ecf20Sopenharmony_ci }, { 3058c2ecf20Sopenharmony_ci .compatible = "adi,ad7476", 3068c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, 3078c2ecf20Sopenharmony_ci }, 3088c2ecf20Sopenharmony_ci /* Mode 3 ADCs */ 3098c2ecf20Sopenharmony_ci { 3108c2ecf20Sopenharmony_ci .compatible = "maxim,max1162", 3118c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, 3128c2ecf20Sopenharmony_ci }, { 3138c2ecf20Sopenharmony_ci .compatible = "maxim,max11100", 3148c2ecf20Sopenharmony_ci .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci { /* sentinel */ } 3178c2ecf20Sopenharmony_ci}; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 3228c2ecf20Sopenharmony_ci const struct iio_chan_spec *channels; 3238c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 3248c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 3258c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 3268c2ecf20Sopenharmony_ci struct device_node *child; 3278c2ecf20Sopenharmony_ci struct regulator *vref; 3288c2ecf20Sopenharmony_ci unsigned int reg; 3298c2ecf20Sopenharmony_ci unsigned int adcmode = -1, childmode; 3308c2ecf20Sopenharmony_ci unsigned int sample_width; 3318c2ecf20Sopenharmony_ci unsigned int num_channels; 3328c2ecf20Sopenharmony_ci int ret, first = 1; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci for_each_child_of_node(np, child) { 3358c2ecf20Sopenharmony_ci of_id = of_match_node(rcar_gyroadc_child_match, child); 3368c2ecf20Sopenharmony_ci if (!of_id) { 3378c2ecf20Sopenharmony_ci dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".", 3388c2ecf20Sopenharmony_ci child); 3398c2ecf20Sopenharmony_ci continue; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci childmode = (uintptr_t)of_id->data; 3438c2ecf20Sopenharmony_ci switch (childmode) { 3448c2ecf20Sopenharmony_ci case RCAR_GYROADC_MODE_SELECT_1_MB88101A: 3458c2ecf20Sopenharmony_ci sample_width = 12; 3468c2ecf20Sopenharmony_ci channels = rcar_gyroadc_iio_channels_1; 3478c2ecf20Sopenharmony_ci num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_1); 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci case RCAR_GYROADC_MODE_SELECT_2_ADCS7476: 3508c2ecf20Sopenharmony_ci sample_width = 15; 3518c2ecf20Sopenharmony_ci channels = rcar_gyroadc_iio_channels_2; 3528c2ecf20Sopenharmony_ci num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_2); 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci case RCAR_GYROADC_MODE_SELECT_3_MAX1162: 3558c2ecf20Sopenharmony_ci sample_width = 16; 3568c2ecf20Sopenharmony_ci channels = rcar_gyroadc_iio_channels_3; 3578c2ecf20Sopenharmony_ci num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3); 3588c2ecf20Sopenharmony_ci break; 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci goto err_e_inval; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * MB88101 is special in that it's only a single chip taking 3658c2ecf20Sopenharmony_ci * up all the CHS lines. Thus, the DT binding is also special 3668c2ecf20Sopenharmony_ci * and has no reg property. If we run into such ADC, handle 3678c2ecf20Sopenharmony_ci * it here. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) { 3708c2ecf20Sopenharmony_ci reg = 0; 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci ret = of_property_read_u32(child, "reg", ®); 3738c2ecf20Sopenharmony_ci if (ret) { 3748c2ecf20Sopenharmony_ci dev_err(dev, 3758c2ecf20Sopenharmony_ci "Failed to get child reg property of ADC \"%pOFn\".\n", 3768c2ecf20Sopenharmony_ci child); 3778c2ecf20Sopenharmony_ci goto err_of_node_put; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Channel number is too high. */ 3818c2ecf20Sopenharmony_ci if (reg >= num_channels) { 3828c2ecf20Sopenharmony_ci dev_err(dev, 3838c2ecf20Sopenharmony_ci "Only %i channels supported with %pOFn, but reg = <%i>.\n", 3848c2ecf20Sopenharmony_ci num_channels, child, reg); 3858c2ecf20Sopenharmony_ci goto err_e_inval; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Child node selected different mode than the rest. */ 3908c2ecf20Sopenharmony_ci if (!first && (adcmode != childmode)) { 3918c2ecf20Sopenharmony_ci dev_err(dev, 3928c2ecf20Sopenharmony_ci "Channel %i uses different ADC mode than the rest.\n", 3938c2ecf20Sopenharmony_ci reg); 3948c2ecf20Sopenharmony_ci goto err_e_inval; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Channel is valid, grab the regulator. */ 3988c2ecf20Sopenharmony_ci dev->of_node = child; 3998c2ecf20Sopenharmony_ci vref = devm_regulator_get(dev, "vref"); 4008c2ecf20Sopenharmony_ci dev->of_node = np; 4018c2ecf20Sopenharmony_ci if (IS_ERR(vref)) { 4028c2ecf20Sopenharmony_ci dev_dbg(dev, "Channel %i 'vref' supply not connected.\n", 4038c2ecf20Sopenharmony_ci reg); 4048c2ecf20Sopenharmony_ci ret = PTR_ERR(vref); 4058c2ecf20Sopenharmony_ci goto err_of_node_put; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci priv->vref[reg] = vref; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (!first) 4118c2ecf20Sopenharmony_ci continue; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* First child node which passed sanity tests. */ 4148c2ecf20Sopenharmony_ci adcmode = childmode; 4158c2ecf20Sopenharmony_ci first = 0; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci priv->num_channels = num_channels; 4188c2ecf20Sopenharmony_ci priv->mode = childmode; 4198c2ecf20Sopenharmony_ci priv->sample_width = sample_width; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci indio_dev->channels = channels; 4228c2ecf20Sopenharmony_ci indio_dev->num_channels = num_channels; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci /* 4258c2ecf20Sopenharmony_ci * MB88101 is special and we only have one such device 4268c2ecf20Sopenharmony_ci * attached to the GyroADC at a time, so if we found it, 4278c2ecf20Sopenharmony_ci * we can stop parsing here. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) { 4308c2ecf20Sopenharmony_ci of_node_put(child); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (first) { 4368c2ecf20Sopenharmony_ci dev_err(dev, "No valid ADC channels found, aborting.\n"); 4378c2ecf20Sopenharmony_ci return -EINVAL; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cierr_e_inval: 4438c2ecf20Sopenharmony_ci ret = -EINVAL; 4448c2ecf20Sopenharmony_cierr_of_node_put: 4458c2ecf20Sopenharmony_ci of_node_put(child); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 4528c2ecf20Sopenharmony_ci unsigned int i; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_channels; i++) { 4558c2ecf20Sopenharmony_ci if (!priv->vref[i]) 4568c2ecf20Sopenharmony_ci continue; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci regulator_disable(priv->vref[i]); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 4658c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 4668c2ecf20Sopenharmony_ci unsigned int i; 4678c2ecf20Sopenharmony_ci int ret; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_channels; i++) { 4708c2ecf20Sopenharmony_ci if (!priv->vref[i]) 4718c2ecf20Sopenharmony_ci continue; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ret = regulator_enable(priv->vref[i]); 4748c2ecf20Sopenharmony_ci if (ret) { 4758c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable regulator %i (ret=%i)\n", 4768c2ecf20Sopenharmony_ci i, ret); 4778c2ecf20Sopenharmony_ci goto err; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cierr: 4848c2ecf20Sopenharmony_ci rcar_gyroadc_deinit_supplies(indio_dev); 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int rcar_gyroadc_probe(struct platform_device *pdev) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4918c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv; 4928c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 4938c2ecf20Sopenharmony_ci int ret; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); 4968c2ecf20Sopenharmony_ci if (!indio_dev) 4978c2ecf20Sopenharmony_ci return -ENOMEM; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci priv = iio_priv(indio_dev); 5008c2ecf20Sopenharmony_ci priv->dev = dev; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci priv->regs = devm_platform_ioremap_resource(pdev, 0); 5038c2ecf20Sopenharmony_ci if (IS_ERR(priv->regs)) 5048c2ecf20Sopenharmony_ci return PTR_ERR(priv->regs); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(dev, "fck"); 5078c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) 5088c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->clk), 5098c2ecf20Sopenharmony_ci "Failed to get IF clock\n"); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ret = rcar_gyroadc_parse_subdevs(indio_dev); 5128c2ecf20Sopenharmony_ci if (ret) 5138c2ecf20Sopenharmony_ci return ret; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci ret = rcar_gyroadc_init_supplies(indio_dev); 5168c2ecf20Sopenharmony_ci if (ret) 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci priv->model = (enum rcar_gyroadc_model) 5208c2ecf20Sopenharmony_ci of_device_get_match_data(&pdev->dev); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci indio_dev->name = DRIVER_NAME; 5258c2ecf20Sopenharmony_ci indio_dev->info = &rcar_gyroadc_iio_info; 5268c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 5298c2ecf20Sopenharmony_ci if (ret) { 5308c2ecf20Sopenharmony_ci dev_err(dev, "Could not prepare or enable the IF clock.\n"); 5318c2ecf20Sopenharmony_ci goto err_clk_if_enable; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, RCAR_GYROADC_RUNTIME_PM_DELAY_MS); 5358c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 5368c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 5398c2ecf20Sopenharmony_ci rcar_gyroadc_hw_init(priv); 5408c2ecf20Sopenharmony_ci rcar_gyroadc_hw_start(priv); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ret = iio_device_register(indio_dev); 5438c2ecf20Sopenharmony_ci if (ret) { 5448c2ecf20Sopenharmony_ci dev_err(dev, "Couldn't register IIO device.\n"); 5458c2ecf20Sopenharmony_ci goto err_iio_device_register; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cierr_iio_device_register: 5538c2ecf20Sopenharmony_ci rcar_gyroadc_hw_stop(priv); 5548c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5558c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5568c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 5578c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5588c2ecf20Sopenharmony_cierr_clk_if_enable: 5598c2ecf20Sopenharmony_ci rcar_gyroadc_deinit_supplies(indio_dev); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci return ret; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic int rcar_gyroadc_remove(struct platform_device *pdev) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = platform_get_drvdata(pdev); 5678c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 5688c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci iio_device_unregister(indio_dev); 5718c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 5728c2ecf20Sopenharmony_ci rcar_gyroadc_hw_stop(priv); 5738c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5748c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5758c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 5768c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5778c2ecf20Sopenharmony_ci rcar_gyroadc_deinit_supplies(indio_dev); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci#if defined(CONFIG_PM) 5838c2ecf20Sopenharmony_cistatic int rcar_gyroadc_suspend(struct device *dev) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 5868c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci rcar_gyroadc_hw_stop(priv); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int rcar_gyroadc_resume(struct device *dev) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct iio_dev *indio_dev = dev_get_drvdata(dev); 5968c2ecf20Sopenharmony_ci struct rcar_gyroadc *priv = iio_priv(indio_dev); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci rcar_gyroadc_hw_start(priv); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci#endif 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic const struct dev_pm_ops rcar_gyroadc_pm_ops = { 6058c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL) 6068c2ecf20Sopenharmony_ci}; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic struct platform_driver rcar_gyroadc_driver = { 6098c2ecf20Sopenharmony_ci .probe = rcar_gyroadc_probe, 6108c2ecf20Sopenharmony_ci .remove = rcar_gyroadc_remove, 6118c2ecf20Sopenharmony_ci .driver = { 6128c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 6138c2ecf20Sopenharmony_ci .of_match_table = rcar_gyroadc_match, 6148c2ecf20Sopenharmony_ci .pm = &rcar_gyroadc_pm_ops, 6158c2ecf20Sopenharmony_ci }, 6168c2ecf20Sopenharmony_ci}; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cimodule_platform_driver(rcar_gyroadc_driver); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 6218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Renesas R-Car GyroADC driver"); 6228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 623