Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Marek Vašut | 2355 | 99.16% | 2 | 28.57% |
Arnd Bergmann | 8 | 0.34% | 1 | 14.29% |
Geert Uytterhoeven | 7 | 0.29% | 2 | 28.57% |
Rob Herring | 3 | 0.13% | 1 | 14.29% |
Kuninori Morimoto | 2 | 0.08% | 1 | 14.29% |
Total | 2375 | 7 |
// SPDX-License-Identifier: GPL-2.0+ /* * Renesas R-Car GyroADC driver * * Copyright 2016 Marek Vasut <marek.vasut@gmail.com> */ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/clk.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/regulator/consumer.h> #include <linux/of_platform.h> #include <linux/err.h> #include <linux/pm_runtime.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> #define DRIVER_NAME "rcar-gyroadc" /* GyroADC registers. */ #define RCAR_GYROADC_MODE_SELECT 0x00 #define RCAR_GYROADC_MODE_SELECT_1_MB88101A 0x0 #define RCAR_GYROADC_MODE_SELECT_2_ADCS7476 0x1 #define RCAR_GYROADC_MODE_SELECT_3_MAX1162 0x3 #define RCAR_GYROADC_START_STOP 0x04 #define RCAR_GYROADC_START_STOP_START BIT(0) #define RCAR_GYROADC_CLOCK_LENGTH 0x08 #define RCAR_GYROADC_1_25MS_LENGTH 0x0c #define RCAR_GYROADC_REALTIME_DATA(ch) (0x10 + ((ch) * 4)) #define RCAR_GYROADC_100MS_ADDED_DATA(ch) (0x30 + ((ch) * 4)) #define RCAR_GYROADC_10MS_AVG_DATA(ch) (0x50 + ((ch) * 4)) #define RCAR_GYROADC_FIFO_STATUS 0x70 #define RCAR_GYROADC_FIFO_STATUS_EMPTY(ch) BIT(0 + (4 * (ch))) #define RCAR_GYROADC_FIFO_STATUS_FULL(ch) BIT(1 + (4 * (ch))) #define RCAR_GYROADC_FIFO_STATUS_ERROR(ch) BIT(2 + (4 * (ch))) #define RCAR_GYROADC_INTR 0x74 #define RCAR_GYROADC_INTR_INT BIT(0) #define RCAR_GYROADC_INTENR 0x78 #define RCAR_GYROADC_INTENR_INTEN BIT(0) #define RCAR_GYROADC_SAMPLE_RATE 800 /* Hz */ #define RCAR_GYROADC_RUNTIME_PM_DELAY_MS 2000 enum rcar_gyroadc_model { RCAR_GYROADC_MODEL_DEFAULT, RCAR_GYROADC_MODEL_R8A7792, }; struct rcar_gyroadc { struct device *dev; void __iomem *regs; struct clk *clk; struct regulator *vref[8]; unsigned int num_channels; enum rcar_gyroadc_model model; unsigned int mode; unsigned int sample_width; }; static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv) { const unsigned long clk_mhz = clk_get_rate(priv->clk) / 1000000; const unsigned long clk_mul = (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5; unsigned long clk_len = clk_mhz * clk_mul; /* * According to the R-Car Gen2 datasheet Rev. 1.01, Sept 08 2014, * page 77-7, clock length must be even number. If it's odd number, * add one. */ if (clk_len & 1) clk_len++; /* Stop the GyroADC. */ writel(0, priv->regs + RCAR_GYROADC_START_STOP); /* Disable IRQ on V2H. */ if (priv->model == RCAR_GYROADC_MODEL_R8A7792) writel(0, priv->regs + RCAR_GYROADC_INTENR); /* Set mode and timing. */ writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT); writel(clk_len, priv->regs + RCAR_GYROADC_CLOCK_LENGTH); writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH); } static void rcar_gyroadc_hw_start(struct rcar_gyroadc *priv) { /* Start sampling. */ writel(RCAR_GYROADC_START_STOP_START, priv->regs + RCAR_GYROADC_START_STOP); /* * Wait for the first conversion to complete. This is longer than * the 1.25 mS in the datasheet because 1.25 mS is not enough for * the hardware to deliver the first sample and the hardware does * then return zeroes instead of valid data. */ mdelay(3); } static void rcar_gyroadc_hw_stop(struct rcar_gyroadc *priv) { /* Stop the GyroADC. */ writel(0, priv->regs + RCAR_GYROADC_START_STOP); } #define RCAR_GYROADC_CHAN(_idx) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .channel = (_idx), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ } static const struct iio_chan_spec rcar_gyroadc_iio_channels_1[] = { RCAR_GYROADC_CHAN(0), RCAR_GYROADC_CHAN(1), RCAR_GYROADC_CHAN(2), RCAR_GYROADC_CHAN(3), }; static const struct iio_chan_spec rcar_gyroadc_iio_channels_2[] = { RCAR_GYROADC_CHAN(0), RCAR_GYROADC_CHAN(1), RCAR_GYROADC_CHAN(2), RCAR_GYROADC_CHAN(3), RCAR_GYROADC_CHAN(4), RCAR_GYROADC_CHAN(5), RCAR_GYROADC_CHAN(6), RCAR_GYROADC_CHAN(7), }; static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = { RCAR_GYROADC_CHAN(0), RCAR_GYROADC_CHAN(1), RCAR_GYROADC_CHAN(2), RCAR_GYROADC_CHAN(3), RCAR_GYROADC_CHAN(4), RCAR_GYROADC_CHAN(5), RCAR_GYROADC_CHAN(6), RCAR_GYROADC_CHAN(7), }; static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on) { struct device *dev = priv->dev; int ret; if (on) { ret = pm_runtime_get_sync(dev); if (ret < 0) pm_runtime_put_noidle(dev); } else { pm_runtime_mark_last_busy(dev); ret = pm_runtime_put_autosuspend(dev); } return ret; } static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { struct rcar_gyroadc *priv = iio_priv(indio_dev); struct regulator *consumer; unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel); unsigned int vref; int ret; /* * MB88101 is special in that it has only single regulator for * all four channels. */ if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) consumer = priv->vref[0]; else consumer = priv->vref[chan->channel]; switch (mask) { case IIO_CHAN_INFO_RAW: if (chan->type != IIO_VOLTAGE) return -EINVAL; /* Channel not connected. */ if (!consumer) return -EINVAL; ret = iio_device_claim_direct_mode(indio_dev); if (ret) return ret; ret = rcar_gyroadc_set_power(priv, true); if (ret < 0) { iio_device_release_direct_mode(indio_dev); return ret; } *val = readl(priv->regs + datareg); *val &= BIT(priv->sample_width) - 1; ret = rcar_gyroadc_set_power(priv, false); iio_device_release_direct_mode(indio_dev); if (ret < 0) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* Channel not connected. */ if (!consumer) return -EINVAL; vref = regulator_get_voltage(consumer); *val = vref / 1000; *val2 = 1 << priv->sample_width; return IIO_VAL_FRACTIONAL; case IIO_CHAN_INFO_SAMP_FREQ: *val = RCAR_GYROADC_SAMPLE_RATE; return IIO_VAL_INT; default: return -EINVAL; } } static int rcar_gyroadc_reg_access(struct iio_dev *indio_dev, unsigned int reg, unsigned int writeval, unsigned int *readval) { struct rcar_gyroadc *priv = iio_priv(indio_dev); unsigned int maxreg = RCAR_GYROADC_FIFO_STATUS; if (readval == NULL) return -EINVAL; if (reg % 4) return -EINVAL; /* Handle the V2H case with extra interrupt block. */ if (priv->model == RCAR_GYROADC_MODEL_R8A7792) maxreg = RCAR_GYROADC_INTENR; if (reg > maxreg) return -EINVAL; *readval = readl(priv->regs + reg); return 0; } static const struct iio_info rcar_gyroadc_iio_info = { .read_raw = rcar_gyroadc_read_raw, .debugfs_reg_access = rcar_gyroadc_reg_access, }; static const struct of_device_id rcar_gyroadc_match[] = { { /* R-Car compatible GyroADC */ .compatible = "renesas,rcar-gyroadc", .data = (void *)RCAR_GYROADC_MODEL_DEFAULT, }, { /* R-Car V2H specialty with interrupt registers. */ .compatible = "renesas,r8a7792-gyroadc", .data = (void *)RCAR_GYROADC_MODEL_R8A7792, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, rcar_gyroadc_match); static const struct of_device_id rcar_gyroadc_child_match[] = { /* Mode 1 ADCs */ { .compatible = "fujitsu,mb88101a", .data = (void *)RCAR_GYROADC_MODE_SELECT_1_MB88101A, }, /* Mode 2 ADCs */ { .compatible = "ti,adcs7476", .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, }, { .compatible = "ti,adc121", .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, }, { .compatible = "adi,ad7476", .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476, }, /* Mode 3 ADCs */ { .compatible = "maxim,max1162", .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, }, { .compatible = "maxim,max11100", .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162, }, { /* sentinel */ } }; static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev) { const struct of_device_id *of_id; const struct iio_chan_spec *channels; struct rcar_gyroadc *priv = iio_priv(indio_dev); struct device *dev = priv->dev; struct device_node *np = dev->of_node; struct device_node *child; struct regulator *vref; unsigned int reg; unsigned int adcmode = -1, childmode; unsigned int sample_width; unsigned int num_channels; int ret, first = 1; for_each_child_of_node(np, child) { of_id = of_match_node(rcar_gyroadc_child_match, child); if (!of_id) { dev_err(dev, "Ignoring unsupported ADC \"%pOFn\".", child); continue; } childmode = (uintptr_t)of_id->data; switch (childmode) { case RCAR_GYROADC_MODE_SELECT_1_MB88101A: sample_width = 12; channels = rcar_gyroadc_iio_channels_1; num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_1); break; case RCAR_GYROADC_MODE_SELECT_2_ADCS7476: sample_width = 15; channels = rcar_gyroadc_iio_channels_2; num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_2); break; case RCAR_GYROADC_MODE_SELECT_3_MAX1162: sample_width = 16; channels = rcar_gyroadc_iio_channels_3; num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3); break; default: return -EINVAL; } /* * MB88101 is special in that it's only a single chip taking * up all the CHS lines. Thus, the DT binding is also special * and has no reg property. If we run into such ADC, handle * it here. */ if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) { reg = 0; } else { ret = of_property_read_u32(child, "reg", ®); if (ret) { dev_err(dev, "Failed to get child reg property of ADC \"%pOFn\".\n", child); return ret; } /* Channel number is too high. */ if (reg >= num_channels) { dev_err(dev, "Only %i channels supported with %pOFn, but reg = <%i>.\n", num_channels, child, reg); return ret; } } /* Child node selected different mode than the rest. */ if (!first && (adcmode != childmode)) { dev_err(dev, "Channel %i uses different ADC mode than the rest.\n", reg); return ret; } /* Channel is valid, grab the regulator. */ dev->of_node = child; vref = devm_regulator_get(dev, "vref"); dev->of_node = np; if (IS_ERR(vref)) { dev_dbg(dev, "Channel %i 'vref' supply not connected.\n", reg); return PTR_ERR(vref); } priv->vref[reg] = vref; if (!first) continue; /* First child node which passed sanity tests. */ adcmode = childmode; first = 0; priv->num_channels = num_channels; priv->mode = childmode; priv->sample_width = sample_width; indio_dev->channels = channels; indio_dev->num_channels = num_channels; /* * MB88101 is special and we only have one such device * attached to the GyroADC at a time, so if we found it, * we can stop parsing here. */ if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) break; } if (first) { dev_err(dev, "No valid ADC channels found, aborting.\n"); return -EINVAL; } return 0; } static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev) { struct rcar_gyroadc *priv = iio_priv(indio_dev); unsigned int i; for (i = 0; i < priv->num_channels; i++) { if (!priv->vref[i]) continue; regulator_disable(priv->vref[i]); } } static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev) { struct rcar_gyroadc *priv = iio_priv(indio_dev); struct device *dev = priv->dev; unsigned int i; int ret; for (i = 0; i < priv->num_channels; i++) { if (!priv->vref[i]) continue; ret = regulator_enable(priv->vref[i]); if (ret) { dev_err(dev, "Failed to enable regulator %i (ret=%i)\n", i, ret); goto err; } } return 0; err: rcar_gyroadc_deinit_supplies(indio_dev); return ret; } static int rcar_gyroadc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rcar_gyroadc *priv; struct iio_dev *indio_dev; struct resource *mem; int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); if (!indio_dev) { dev_err(dev, "Failed to allocate IIO device.\n"); return -ENOMEM; } priv = iio_priv(indio_dev); priv->dev = dev; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->regs = devm_ioremap_resource(dev, mem); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); priv->clk = devm_clk_get(dev, "fck"); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret); return ret; } ret = rcar_gyroadc_parse_subdevs(indio_dev); if (ret) return ret; ret = rcar_gyroadc_init_supplies(indio_dev); if (ret) return ret; priv->model = (enum rcar_gyroadc_model) of_device_get_match_data(&pdev->dev); platform_set_drvdata(pdev, indio_dev); indio_dev->name = DRIVER_NAME; indio_dev->dev.parent = dev; indio_dev->dev.of_node = pdev->dev.of_node; indio_dev->info = &rcar_gyroadc_iio_info; indio_dev->modes = INDIO_DIRECT_MODE; ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(dev, "Could not prepare or enable the IF clock.\n"); goto err_clk_if_enable; } pm_runtime_set_autosuspend_delay(dev, RCAR_GYROADC_RUNTIME_PM_DELAY_MS); pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); pm_runtime_get_sync(dev); rcar_gyroadc_hw_init(priv); rcar_gyroadc_hw_start(priv); ret = iio_device_register(indio_dev); if (ret) { dev_err(dev, "Couldn't register IIO device.\n"); goto err_iio_device_register; } pm_runtime_put_sync(dev); return 0; err_iio_device_register: rcar_gyroadc_hw_stop(priv); pm_runtime_put_sync(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); clk_disable_unprepare(priv->clk); err_clk_if_enable: rcar_gyroadc_deinit_supplies(indio_dev); return ret; } static int rcar_gyroadc_remove(struct platform_device *pdev) { struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct rcar_gyroadc *priv = iio_priv(indio_dev); struct device *dev = priv->dev; iio_device_unregister(indio_dev); pm_runtime_get_sync(dev); rcar_gyroadc_hw_stop(priv); pm_runtime_put_sync(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); clk_disable_unprepare(priv->clk); rcar_gyroadc_deinit_supplies(indio_dev); return 0; } #if defined(CONFIG_PM) static int rcar_gyroadc_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct rcar_gyroadc *priv = iio_priv(indio_dev); rcar_gyroadc_hw_stop(priv); return 0; } static int rcar_gyroadc_resume(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct rcar_gyroadc *priv = iio_priv(indio_dev); rcar_gyroadc_hw_start(priv); return 0; } #endif static const struct dev_pm_ops rcar_gyroadc_pm_ops = { SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL) }; static struct platform_driver rcar_gyroadc_driver = { .probe = rcar_gyroadc_probe, .remove = rcar_gyroadc_remove, .driver = { .name = DRIVER_NAME, .of_match_table = rcar_gyroadc_match, .pm = &rcar_gyroadc_pm_ops, }, }; module_platform_driver(rcar_gyroadc_driver); MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); MODULE_DESCRIPTION("Renesas R-Car GyroADC driver"); MODULE_LICENSE("GPL");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1