mirror of
https://github.com/raspberrypi/linux.git
synced 2026-01-02 07:43:34 +00:00
Merge tag 'char-misc-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc and other driver updates from Greg KH:
"Here is the large set of char/misc and other small driver subsystem
changes for 6.1-rc1. Loads of different things in here:
- IIO driver updates, additions, and changes. Probably the largest
part of the diffstat
- habanalabs driver update with support for new hardware and
features, the second largest part of the diff.
- fpga subsystem driver updates and additions
- mhi subsystem updates
- Coresight driver updates
- gnss subsystem updates
- extcon driver updates
- icc subsystem updates
- fsi subsystem updates
- nvmem subsystem and driver updates
- misc driver updates
- speakup driver additions for new features
- lots of tiny driver updates and cleanups
All of these have been in the linux-next tree for a while with no
reported issues"
* tag 'char-misc-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (411 commits)
w1: Split memcpy() of struct cn_msg flexible array
spmi: pmic-arb: increase SPMI transaction timeout delay
spmi: pmic-arb: block access for invalid PMIC arbiter v5 SPMI writes
spmi: pmic-arb: correct duplicate APID to PPID mapping logic
spmi: pmic-arb: add support to dispatch interrupt based on IRQ status
spmi: pmic-arb: check apid against limits before calling irq handler
spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq
spmi: pmic-arb: handle spurious interrupt
spmi: pmic-arb: add a print in cleanup_irq
drivers: spmi: Directly use ida_alloc()/free()
MAINTAINERS: add TI ECAP driver info
counter: ti-ecap-capture: capture driver support for ECAP
Documentation: ABI: sysfs-bus-counter: add frequency & num_overflows items
dt-bindings: counter: add ti,am62-ecap-capture.yaml
counter: Introduce the COUNTER_COMP_ARRAY component type
counter: Consolidate Counter extension sysfs attribute creation
counter: Introduce the Count capture component
counter: 104-quad-8: Add Signal polarity component
counter: Introduce the Signal polarity component
counter: interrupt-cnt: Implement watch_validate callback
...
This commit is contained in:
@@ -653,6 +653,20 @@ config MAX1118
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max1118.
|
||||
|
||||
config MAX11205
|
||||
tristate "Maxim max11205 ADC driver"
|
||||
depends on SPI
|
||||
select AD_SIGMA_DELTA
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
|
||||
help
|
||||
Say yes here to build support for Maxim max11205 16-bit, single-channel
|
||||
ultra-low power delta-sigma ADC.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called max11205.
|
||||
|
||||
config MAX1241
|
||||
tristate "Maxim max1241 ADC driver"
|
||||
depends on SPI_MASTER
|
||||
@@ -718,6 +732,8 @@ config MCP3422
|
||||
config MCP3911
|
||||
tristate "Microchip Technology MCP3911 driver"
|
||||
depends on SPI
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to build support for Microchip Technology's MCP3911
|
||||
analog to digital converter.
|
||||
@@ -919,6 +935,21 @@ config ROCKCHIP_SARADC
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rockchip_saradc.
|
||||
|
||||
config RICHTEK_RTQ6056
|
||||
tristate "Richtek RTQ6056 Current and Power Monitor ADC"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
select IIO_BUFFER
|
||||
select IIO_TRIGGERED_BUFFER
|
||||
help
|
||||
Say yes here to enable RQT6056 ADC support.
|
||||
RTQ6056 is a high accuracy current-sense monitor with I2C and SMBus
|
||||
compatible interface, and the device provides full information for
|
||||
system by reading out the load current and power.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called rtq6056.
|
||||
|
||||
config RZG2L_ADC
|
||||
tristate "Renesas RZ/G2L ADC driver"
|
||||
depends on ARCH_RZG2L || COMPILE_TEST
|
||||
@@ -1022,22 +1053,6 @@ config STMPE_ADC
|
||||
Say yes here to build support for ST Microelectronics STMPE
|
||||
built-in ADC block (stmpe811).
|
||||
|
||||
config STX104
|
||||
tristate "Apex Embedded Systems STX104 driver"
|
||||
depends on PC104 && X86
|
||||
select ISA_BUS_API
|
||||
select GPIOLIB
|
||||
help
|
||||
Say yes here to build support for the Apex Embedded Systems STX104
|
||||
integrated analog PC/104 card.
|
||||
|
||||
This driver supports the 16 channels of single-ended (8 channels of
|
||||
differential) analog inputs, 2 channels of analog output, 4 digital
|
||||
inputs, and 4 digital outputs provided by the STX104.
|
||||
|
||||
The base port addresses for the devices may be configured via the base
|
||||
array module parameter.
|
||||
|
||||
config SUN4I_GPADC
|
||||
tristate "Support for the Allwinner SoCs GPADC"
|
||||
depends on IIO
|
||||
|
||||
@@ -61,6 +61,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o ltc2497-core.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
obj-$(CONFIG_MAX11100) += max11100.o
|
||||
obj-$(CONFIG_MAX1118) += max1118.o
|
||||
obj-$(CONFIG_MAX11205) += max11205.o
|
||||
obj-$(CONFIG_MAX1241) += max1241.o
|
||||
obj-$(CONFIG_MAX1363) += max1363.o
|
||||
obj-$(CONFIG_MAX9611) += max9611.o
|
||||
@@ -85,10 +86,10 @@ obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
|
||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||
obj-$(CONFIG_RICHTEK_RTQ6056) += rtq6056.o
|
||||
obj-$(CONFIG_RZG2L_ADC) += rzg2l_adc.o
|
||||
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||
obj-$(CONFIG_STX104) += stx104.o
|
||||
obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
|
||||
obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
|
||||
obj-$(CONFIG_STM32_ADC) += stm32-adc.o
|
||||
|
||||
@@ -925,8 +925,8 @@ static int ab8500_gpadc_read_raw(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int ab8500_gpadc_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -938,7 +938,7 @@ static int ab8500_gpadc_of_xlate(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
static const struct iio_info ab8500_gpadc_info = {
|
||||
.of_xlate = ab8500_gpadc_of_xlate,
|
||||
.fwnode_xlate = ab8500_gpadc_fwnode_xlate,
|
||||
.read_raw = ab8500_gpadc_read_raw,
|
||||
};
|
||||
|
||||
@@ -968,7 +968,7 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
|
||||
/**
|
||||
* ab8500_gpadc_parse_channel() - process devicetree channel configuration
|
||||
* @dev: pointer to containing device
|
||||
* @np: device tree node for the channel to configure
|
||||
* @fwnode: fw node for the channel to configure
|
||||
* @ch: channel info to fill in
|
||||
* @iio_chan: IIO channel specification to fill in
|
||||
*
|
||||
@@ -976,15 +976,15 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
|
||||
* and define usage for things like AUX GPADC inputs more precisely.
|
||||
*/
|
||||
static int ab8500_gpadc_parse_channel(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct fwnode_handle *fwnode,
|
||||
struct ab8500_gpadc_chan_info *ch,
|
||||
struct iio_chan_spec *iio_chan)
|
||||
{
|
||||
const char *name = np->name;
|
||||
const char *name = fwnode_get_name(fwnode);
|
||||
u32 chan;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(np, "reg", &chan);
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &chan);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid channel number %s\n", name);
|
||||
return ret;
|
||||
@@ -1021,22 +1021,20 @@ static int ab8500_gpadc_parse_channel(struct device *dev,
|
||||
/**
|
||||
* ab8500_gpadc_parse_channels() - Parse the GPADC channels from DT
|
||||
* @gpadc: the GPADC to configure the channels for
|
||||
* @np: device tree node containing the channel configurations
|
||||
* @chans: the IIO channels we parsed
|
||||
* @nchans: the number of IIO channels we parsed
|
||||
*/
|
||||
static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc,
|
||||
struct device_node *np,
|
||||
struct iio_chan_spec **chans_parsed,
|
||||
unsigned int *nchans_parsed)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct fwnode_handle *child;
|
||||
struct ab8500_gpadc_chan_info *ch;
|
||||
struct iio_chan_spec *iio_chans;
|
||||
unsigned int nchans;
|
||||
int i;
|
||||
|
||||
nchans = of_get_available_child_count(np);
|
||||
nchans = device_get_child_node_count(gpadc->dev);
|
||||
if (!nchans) {
|
||||
dev_err(gpadc->dev, "no channel children\n");
|
||||
return -ENODEV;
|
||||
@@ -1054,7 +1052,7 @@ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc,
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
for_each_available_child_of_node(np, child) {
|
||||
device_for_each_child_node(gpadc->dev, child) {
|
||||
struct iio_chan_spec *iio_chan;
|
||||
int ret;
|
||||
|
||||
@@ -1064,7 +1062,7 @@ static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc,
|
||||
ret = ab8500_gpadc_parse_channel(gpadc->dev, child, ch,
|
||||
iio_chan);
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
i++;
|
||||
@@ -1081,7 +1079,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
struct ab8500_gpadc *gpadc;
|
||||
struct iio_dev *indio_dev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct iio_chan_spec *iio_chans;
|
||||
unsigned int n_iio_chans;
|
||||
int ret;
|
||||
@@ -1096,7 +1093,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
gpadc->dev = dev;
|
||||
gpadc->ab8500 = dev_get_drvdata(dev->parent);
|
||||
|
||||
ret = ab8500_gpadc_parse_channels(gpadc, np, &iio_chans, &n_iio_chans);
|
||||
ret = ab8500_gpadc_parse_channels(gpadc, &iio_chans, &n_iio_chans);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -936,11 +936,6 @@ static void ad7124_reg_disable(void *r)
|
||||
regulator_disable(r);
|
||||
}
|
||||
|
||||
static void ad7124_clk_disable(void *c)
|
||||
{
|
||||
clk_disable_unprepare(c);
|
||||
}
|
||||
|
||||
static int ad7124_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad7124_chip_info *info;
|
||||
@@ -993,18 +988,10 @@ static int ad7124_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
st->mclk = devm_clk_get(&spi->dev, "mclk");
|
||||
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return PTR_ERR(st->mclk);
|
||||
|
||||
ret = clk_prepare_enable(st->mclk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7124_clk_disable, st->mclk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ad7124_soft_reset(st);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -539,13 +539,6 @@ static void ad7768_regulator_disable(void *data)
|
||||
regulator_disable(st->vref);
|
||||
}
|
||||
|
||||
static void ad7768_clk_disable(void *data)
|
||||
{
|
||||
struct ad7768_state *st = data;
|
||||
|
||||
clk_disable_unprepare(st->mclk);
|
||||
}
|
||||
|
||||
static int ad7768_set_channel_label(struct iio_dev *indio_dev,
|
||||
int num_channels)
|
||||
{
|
||||
@@ -600,18 +593,10 @@ static int ad7768_probe(struct spi_device *spi)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->mclk = devm_clk_get(&spi->dev, "mclk");
|
||||
st->mclk = devm_clk_get_enabled(&spi->dev, "mclk");
|
||||
if (IS_ERR(st->mclk))
|
||||
return PTR_ERR(st->mclk);
|
||||
|
||||
ret = clk_prepare_enable(st->mclk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad7768_clk_disable, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->mclk_freq = clk_get_rate(st->mclk);
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@@ -93,6 +94,7 @@ enum ad7923_id {
|
||||
.sign = 'u', \
|
||||
.realbits = (bits), \
|
||||
.storagebits = 16, \
|
||||
.shift = 12 - (bits), \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
@@ -268,7 +270,8 @@ static int ad7923_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
if (chan->address == EXTRACT(ret, 12, 4))
|
||||
*val = EXTRACT(ret, 0, 12);
|
||||
*val = EXTRACT(ret, chan->scan_type.shift,
|
||||
chan->scan_type.realbits);
|
||||
else
|
||||
return -EIO;
|
||||
|
||||
@@ -298,6 +301,7 @@ static void ad7923_regulator_disable(void *data)
|
||||
|
||||
static int ad7923_probe(struct spi_device *spi)
|
||||
{
|
||||
u32 ad7923_range = AD7923_RANGE;
|
||||
struct ad7923_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
const struct ad7923_chip_info *info;
|
||||
@@ -309,8 +313,11 @@ static int ad7923_probe(struct spi_device *spi)
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
if (device_property_read_bool(&spi->dev, "adi,range-double"))
|
||||
ad7923_range = 0;
|
||||
|
||||
st->spi = spi;
|
||||
st->settings = AD7923_CODING | AD7923_RANGE |
|
||||
st->settings = AD7923_CODING | ad7923_range |
|
||||
AD7923_PM_MODE_WRITE(AD7923_PM_MODE_OPS);
|
||||
|
||||
info = &ad7923_chip_info[spi_get_device_id(spi)->driver_data];
|
||||
|
||||
@@ -378,13 +378,6 @@ static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv)
|
||||
return ad9467_outputmode_set(st->spi, st->output_mode);
|
||||
}
|
||||
|
||||
static void ad9467_clk_disable(void *data)
|
||||
{
|
||||
struct ad9467_state *st = data;
|
||||
|
||||
clk_disable_unprepare(st->clk);
|
||||
}
|
||||
|
||||
static int ad9467_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ad9467_chip_info *info;
|
||||
@@ -404,18 +397,10 @@ static int ad9467_probe(struct spi_device *spi)
|
||||
st = adi_axi_adc_conv_priv(conv);
|
||||
st->spi = spi;
|
||||
|
||||
st->clk = devm_clk_get(&spi->dev, "adc-clk");
|
||||
st->clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
|
||||
if (IS_ERR(st->clk))
|
||||
return PTR_ERR(st->clk);
|
||||
|
||||
ret = clk_prepare_enable(st->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ad9467_clk_disable, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(st->pwrdown_gpio))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -202,7 +202,7 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct imx8qxp_adc *adc = iio_priv(indio_dev);
|
||||
struct device *dev = adc->dev;
|
||||
|
||||
u32 ctrl, vref_uv;
|
||||
u32 ctrl;
|
||||
long ret;
|
||||
|
||||
switch (mask) {
|
||||
@@ -245,8 +245,10 @@ static int imx8qxp_adc_read_raw(struct iio_dev *indio_dev,
|
||||
return IIO_VAL_INT;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
vref_uv = regulator_get_voltage(adc->vref);
|
||||
*val = vref_uv / 1000;
|
||||
ret = regulator_get_voltage(adc->vref);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*val = ret / 1000;
|
||||
*val2 = 12;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
|
||||
@@ -719,12 +719,12 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int ingenic_adc_of_xlate(struct iio_dev *iio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int ingenic_adc_fwnode_xlate(struct iio_dev *iio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!iiospec->args_count)
|
||||
if (!iiospec->nargs)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < iio_dev->num_channels; ++i)
|
||||
@@ -734,16 +734,11 @@ static int ingenic_adc_of_xlate(struct iio_dev *iio_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ingenic_adc_clk_cleanup(void *data)
|
||||
{
|
||||
clk_unprepare(data);
|
||||
}
|
||||
|
||||
static const struct iio_info ingenic_adc_info = {
|
||||
.write_raw = ingenic_adc_write_raw,
|
||||
.read_raw = ingenic_adc_read_raw,
|
||||
.read_avail = ingenic_adc_read_avail,
|
||||
.of_xlate = ingenic_adc_of_xlate,
|
||||
.fwnode_xlate = ingenic_adc_fwnode_xlate,
|
||||
};
|
||||
|
||||
static int ingenic_adc_buffer_enable(struct iio_dev *iio_dev)
|
||||
@@ -858,13 +853,13 @@ static int ingenic_adc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->clk = devm_clk_get(dev, "adc");
|
||||
adc->clk = devm_clk_get_prepared(dev, "adc");
|
||||
if (IS_ERR(adc->clk)) {
|
||||
dev_err(dev, "Unable to get clock\n");
|
||||
return PTR_ERR(adc->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
ret = clk_enable(adc->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
return ret;
|
||||
@@ -893,12 +888,6 @@ static int ingenic_adc_probe(struct platform_device *pdev)
|
||||
usleep_range(2000, 3000); /* Must wait at least 2ms. */
|
||||
clk_disable(adc->clk);
|
||||
|
||||
ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to add action\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
iio_dev->name = "jz-adc";
|
||||
iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
|
||||
iio_dev->setup_ops = &ingenic_buffer_setup_ops;
|
||||
|
||||
@@ -121,11 +121,6 @@ static void lpc18xx_clear_cr_reg(void *data)
|
||||
writel(0, adc->base + LPC18XX_ADC_CR);
|
||||
}
|
||||
|
||||
static void lpc18xx_clk_disable(void *clk)
|
||||
{
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static void lpc18xx_regulator_disable(void *vref)
|
||||
{
|
||||
regulator_disable(vref);
|
||||
@@ -151,7 +146,7 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(adc->base))
|
||||
return PTR_ERR(adc->base);
|
||||
|
||||
adc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
adc->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(adc->clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(adc->clk),
|
||||
"error getting clock\n");
|
||||
@@ -177,17 +172,6 @@ static int lpc18xx_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(adc->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, lpc18xx_clk_disable,
|
||||
adc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rate = clk_get_rate(adc->clk);
|
||||
clkdiv = DIV_ROUND_UP(rate, LPC18XX_ADC_CLK_TARGET);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "ltc2497.h"
|
||||
|
||||
@@ -74,6 +75,7 @@ static int ltc2496_probe(struct spi_device *spi)
|
||||
spi_set_drvdata(spi, indio_dev);
|
||||
st->spi = spi;
|
||||
st->common_ddata.result_and_measure = ltc2496_result_and_measure;
|
||||
st->common_ddata.chip_info = device_get_match_data(dev);
|
||||
|
||||
return ltc2497core_probe(dev, indio_dev);
|
||||
}
|
||||
@@ -85,8 +87,13 @@ static void ltc2496_remove(struct spi_device *spi)
|
||||
ltc2497core_remove(indio_dev);
|
||||
}
|
||||
|
||||
static const struct ltc2497_chip_info ltc2496_info = {
|
||||
.resolution = 16,
|
||||
.name = NULL,
|
||||
};
|
||||
|
||||
static const struct of_device_id ltc2496_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2496", },
|
||||
{ .compatible = "lltc,ltc2496", .data = <c2496_info, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2496_of_match);
|
||||
|
||||
@@ -95,7 +95,7 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
|
||||
*val = ret / 1000;
|
||||
*val2 = 17;
|
||||
*val2 = ddata->chip_info->resolution + 1;
|
||||
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
|
||||
@@ -169,7 +169,15 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
|
||||
struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
indio_dev->name = dev_name(dev);
|
||||
/*
|
||||
* Keep using dev_name() for the iio_dev's name on some of the parts,
|
||||
* since updating it would result in a ABI breakage.
|
||||
*/
|
||||
if (ddata->chip_info->name)
|
||||
indio_dev->name = ddata->chip_info->name;
|
||||
else
|
||||
indio_dev->name = dev_name(dev);
|
||||
|
||||
indio_dev->info = <c2497core_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = ltc2497core_channel;
|
||||
|
||||
@@ -12,18 +12,31 @@
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "ltc2497.h"
|
||||
|
||||
enum ltc2497_chip_type {
|
||||
TYPE_LTC2497,
|
||||
TYPE_LTC2499,
|
||||
};
|
||||
|
||||
struct ltc2497_driverdata {
|
||||
/* this must be the first member */
|
||||
struct ltc2497core_driverdata common_ddata;
|
||||
struct i2c_client *client;
|
||||
u32 recv_size;
|
||||
u32 sub_lsb;
|
||||
/*
|
||||
* DMA (thus cache coherency maintenance) may require the
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
__be32 buf __aligned(IIO_DMA_MINALIGN);
|
||||
union {
|
||||
__be32 d32;
|
||||
u8 d8[3];
|
||||
} data __aligned(IIO_DMA_MINALIGN);
|
||||
};
|
||||
|
||||
static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
|
||||
@@ -34,13 +47,43 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
|
||||
int ret;
|
||||
|
||||
if (val) {
|
||||
ret = i2c_master_recv(st->client, (char *)&st->buf, 3);
|
||||
if (st->recv_size == 3)
|
||||
ret = i2c_master_recv(st->client, (char *)&st->data.d8,
|
||||
st->recv_size);
|
||||
else
|
||||
ret = i2c_master_recv(st->client, (char *)&st->data.d32,
|
||||
st->recv_size);
|
||||
if (ret < 0) {
|
||||
dev_err(&st->client->dev, "i2c_master_recv failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
*val = (be32_to_cpu(st->buf) >> 14) - (1 << 17);
|
||||
/*
|
||||
* The data format is 16/24 bit 2s complement, but with an upper sign bit on the
|
||||
* resolution + 1 position, which is set for positive values only. Given this
|
||||
* bit's value, subtracting BIT(resolution + 1) from the ADC's result is
|
||||
* equivalent to a sign extension.
|
||||
*/
|
||||
if (st->recv_size == 3) {
|
||||
*val = (get_unaligned_be24(st->data.d8) >> st->sub_lsb)
|
||||
- BIT(ddata->chip_info->resolution + 1);
|
||||
} else {
|
||||
*val = (be32_to_cpu(st->data.d32) >> st->sub_lsb)
|
||||
- BIT(ddata->chip_info->resolution + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The part started a new conversion at the end of the above i2c
|
||||
* transfer, so if the address didn't change since the last call
|
||||
* everything is fine and we can return early.
|
||||
* If not (which should only happen when some sort of bulk
|
||||
* conversion is implemented) we have to program the new
|
||||
* address. Note that this probably fails as the conversion that
|
||||
* was triggered above is like not complete yet and the two
|
||||
* operations have to be done in a single transfer.
|
||||
*/
|
||||
if (ddata->addr_prev == address)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte(st->client,
|
||||
@@ -54,9 +97,11 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
|
||||
static int ltc2497_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
const struct ltc2497_chip_info *chip_info;
|
||||
struct iio_dev *indio_dev;
|
||||
struct ltc2497_driverdata *st;
|
||||
struct device *dev = &client->dev;
|
||||
u32 resolution;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_WRITE_BYTE))
|
||||
@@ -71,6 +116,15 @@ static int ltc2497_probe(struct i2c_client *client,
|
||||
st->client = client;
|
||||
st->common_ddata.result_and_measure = ltc2497_result_and_measure;
|
||||
|
||||
chip_info = device_get_match_data(dev);
|
||||
if (!chip_info)
|
||||
chip_info = (const struct ltc2497_chip_info *)id->driver_data;
|
||||
st->common_ddata.chip_info = chip_info;
|
||||
|
||||
resolution = chip_info->resolution;
|
||||
st->sub_lsb = 31 - (resolution + 1);
|
||||
st->recv_size = BITS_TO_BYTES(resolution) + 1;
|
||||
|
||||
return ltc2497core_probe(dev, indio_dev);
|
||||
}
|
||||
|
||||
@@ -81,14 +135,27 @@ static void ltc2497_remove(struct i2c_client *client)
|
||||
ltc2497core_remove(indio_dev);
|
||||
}
|
||||
|
||||
static const struct ltc2497_chip_info ltc2497_info[] = {
|
||||
[TYPE_LTC2497] = {
|
||||
.resolution = 16,
|
||||
.name = NULL,
|
||||
},
|
||||
[TYPE_LTC2499] = {
|
||||
.resolution = 24,
|
||||
.name = "ltc2499",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ltc2497_id[] = {
|
||||
{ "ltc2497", 0 },
|
||||
{ "ltc2497", (kernel_ulong_t)<c2497_info[TYPE_LTC2497] },
|
||||
{ "ltc2499", (kernel_ulong_t)<c2497_info[TYPE_LTC2499] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc2497_id);
|
||||
|
||||
static const struct of_device_id ltc2497_of_match[] = {
|
||||
{ .compatible = "lltc,ltc2497", },
|
||||
{ .compatible = "lltc,ltc2497", .data = <c2497_info[TYPE_LTC2497] },
|
||||
{ .compatible = "lltc,ltc2499", .data = <c2497_info[TYPE_LTC2499] },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ltc2497_of_match);
|
||||
|
||||
@@ -4,9 +4,15 @@
|
||||
#define LTC2497_CONFIG_DEFAULT LTC2497_ENABLE
|
||||
#define LTC2497_CONVERSION_TIME_MS 150ULL
|
||||
|
||||
struct ltc2497_chip_info {
|
||||
u32 resolution;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct ltc2497core_driverdata {
|
||||
struct regulator *ref;
|
||||
ktime_t time_prev;
|
||||
const struct ltc2497_chip_info *chip_info;
|
||||
u8 addr_prev;
|
||||
int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
|
||||
u8 address, int *val);
|
||||
|
||||
183
drivers/iio/adc/max11205.c
Normal file
183
drivers/iio/adc/max11205.c
Normal file
@@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Maxim MAX11205 16-Bit Delta-Sigma ADC
|
||||
*
|
||||
* Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1240-max11205.pdf
|
||||
* Copyright (C) 2022 Analog Devices, Inc.
|
||||
* Author: Ramona Bolboaca <ramona.bolboaca@analog.com>
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/adc/ad_sigma_delta.h>
|
||||
|
||||
#define MAX11205_BIT_SCALE 15
|
||||
#define MAX11205A_OUT_DATA_RATE 116
|
||||
#define MAX11205B_OUT_DATA_RATE 13
|
||||
|
||||
enum max11205_chip_type {
|
||||
TYPE_MAX11205A,
|
||||
TYPE_MAX11205B,
|
||||
};
|
||||
|
||||
struct max11205_chip_info {
|
||||
unsigned int out_data_rate;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct max11205_state {
|
||||
const struct max11205_chip_info *chip_info;
|
||||
struct regulator *vref;
|
||||
struct ad_sigma_delta sd;
|
||||
};
|
||||
|
||||
static const struct ad_sigma_delta_info max11205_sigma_delta_info = {
|
||||
.has_registers = false,
|
||||
};
|
||||
|
||||
static int max11205_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
struct max11205_state *st = iio_priv(indio_dev);
|
||||
int reg_mv;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return ad_sigma_delta_single_conversion(indio_dev, chan, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
reg_mv = regulator_get_voltage(st->vref);
|
||||
if (reg_mv < 0)
|
||||
return reg_mv;
|
||||
reg_mv /= 1000;
|
||||
*val = reg_mv;
|
||||
*val2 = MAX11205_BIT_SCALE;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*val = st->chip_info->out_data_rate;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct iio_info max11205_iio_info = {
|
||||
.read_raw = max11205_read_raw,
|
||||
.validate_trigger = ad_sd_validate_trigger,
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec max11205_channels[] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_BE,
|
||||
},
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct max11205_chip_info max11205_chip_info[] = {
|
||||
[TYPE_MAX11205A] = {
|
||||
.out_data_rate = MAX11205A_OUT_DATA_RATE,
|
||||
.name = "max11205a",
|
||||
},
|
||||
[TYPE_MAX11205B] = {
|
||||
.out_data_rate = MAX11205B_OUT_DATA_RATE,
|
||||
.name = "max11205b",
|
||||
},
|
||||
};
|
||||
|
||||
static void max11205_reg_disable(void *reg)
|
||||
{
|
||||
regulator_disable(reg);
|
||||
}
|
||||
|
||||
static int max11205_probe(struct spi_device *spi)
|
||||
{
|
||||
struct max11205_state *st;
|
||||
struct iio_dev *indio_dev;
|
||||
int ret;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
ad_sd_init(&st->sd, indio_dev, spi, &max11205_sigma_delta_info);
|
||||
|
||||
st->chip_info = device_get_match_data(&spi->dev);
|
||||
if (!st->chip_info)
|
||||
st->chip_info =
|
||||
(const struct max11205_chip_info *)spi_get_device_id(spi)->driver_data;
|
||||
|
||||
indio_dev->name = st->chip_info->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = max11205_channels;
|
||||
indio_dev->num_channels = 1;
|
||||
indio_dev->info = &max11205_iio_info;
|
||||
|
||||
st->vref = devm_regulator_get(&spi->dev, "vref");
|
||||
if (IS_ERR(st->vref))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->vref),
|
||||
"Failed to get vref regulator\n");
|
||||
|
||||
ret = regulator_enable(st->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, max11205_reg_disable, st->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_ad_sd_setup_buffer_and_trigger(&spi->dev, indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(&spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct spi_device_id max11205_spi_ids[] = {
|
||||
{ "max11205a", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205A] },
|
||||
{ "max11205b", (kernel_ulong_t)&max11205_chip_info[TYPE_MAX11205B] },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, max11205_spi_ids);
|
||||
|
||||
static const struct of_device_id max11205_dt_ids[] = {
|
||||
{
|
||||
.compatible = "maxim,max11205a",
|
||||
.data = &max11205_chip_info[TYPE_MAX11205A],
|
||||
},
|
||||
{
|
||||
.compatible = "maxim,max11205b",
|
||||
.data = &max11205_chip_info[TYPE_MAX11205B],
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max11205_dt_ids);
|
||||
|
||||
static struct spi_driver max11205_spi_driver = {
|
||||
.driver = {
|
||||
.name = "max11205",
|
||||
.of_match_table = max11205_dt_ids,
|
||||
},
|
||||
.probe = max11205_probe,
|
||||
.id_table = max11205_spi_ids,
|
||||
};
|
||||
module_spi_driver(max11205_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Ramona Bolboaca <ramona.bolboaca@analog.com>");
|
||||
MODULE_DESCRIPTION("MAX11205 ADC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(IIO_AD_SIGMA_DELTA);
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/events.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/driver.h>
|
||||
#include <linux/iio/kfifo_buf.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
@@ -1595,11 +1594,6 @@ static int max1363_probe(struct i2c_client *client,
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_iio_map_array_register(&client->dev, indio_dev,
|
||||
client->dev.platform_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
st = iio_priv(indio_dev);
|
||||
|
||||
mutex_init(&st->lock);
|
||||
|
||||
@@ -5,16 +5,25 @@
|
||||
* Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
|
||||
* Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define MCP3911_REG_CHANNEL0 0x00
|
||||
#define MCP3911_REG_CHANNEL1 0x03
|
||||
#define MCP3911_REG_MOD 0x06
|
||||
@@ -22,6 +31,8 @@
|
||||
#define MCP3911_REG_GAIN 0x09
|
||||
|
||||
#define MCP3911_REG_STATUSCOM 0x0a
|
||||
#define MCP3911_STATUSCOM_DRHIZ BIT(12)
|
||||
#define MCP3911_STATUSCOM_READ GENMASK(7, 6)
|
||||
#define MCP3911_STATUSCOM_CH1_24WIDTH BIT(4)
|
||||
#define MCP3911_STATUSCOM_CH0_24WIDTH BIT(3)
|
||||
#define MCP3911_STATUSCOM_EN_OFFCAL BIT(2)
|
||||
@@ -30,6 +41,7 @@
|
||||
#define MCP3911_REG_CONFIG 0x0c
|
||||
#define MCP3911_CONFIG_CLKEXT BIT(1)
|
||||
#define MCP3911_CONFIG_VREFEXT BIT(2)
|
||||
#define MCP3911_CONFIG_OSR GENMASK(13, 11)
|
||||
|
||||
#define MCP3911_REG_OFFCAL_CH0 0x0e
|
||||
#define MCP3911_REG_GAINCAL_CH0 0x11
|
||||
@@ -48,12 +60,22 @@
|
||||
|
||||
#define MCP3911_NUM_CHANNELS 2
|
||||
|
||||
static const int mcp3911_osr_table[] = { 32, 64, 128, 256, 512, 1024, 2048, 4096 };
|
||||
|
||||
struct mcp3911 {
|
||||
struct spi_device *spi;
|
||||
struct mutex lock;
|
||||
struct regulator *vref;
|
||||
struct clk *clki;
|
||||
u32 dev_addr;
|
||||
struct iio_trigger *trig;
|
||||
struct {
|
||||
u32 channels[MCP3911_NUM_CHANNELS];
|
||||
s64 ts __aligned(8);
|
||||
} scan;
|
||||
|
||||
u8 tx_buf __aligned(IIO_DMA_MINALIGN);
|
||||
u8 rx_buf[MCP3911_NUM_CHANNELS * 3];
|
||||
};
|
||||
|
||||
static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
|
||||
@@ -98,6 +120,36 @@ static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
|
||||
return mcp3911_write(adc, reg, val, len);
|
||||
}
|
||||
|
||||
static int mcp3911_write_raw_get_fmt(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return IIO_VAL_INT_PLUS_NANO;
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp3911_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long info)
|
||||
{
|
||||
switch (info) {
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*type = IIO_VAL_INT;
|
||||
*vals = mcp3911_osr_table;
|
||||
*length = ARRAY_SIZE(mcp3911_osr_table);
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int mcp3911_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *channel, int *val,
|
||||
int *val2, long mask)
|
||||
@@ -126,6 +178,15 @@ static int mcp3911_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, val, 2);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
*val = FIELD_GET(MCP3911_CONFIG_OSR, *val);
|
||||
*val = 32 << *val;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
if (adc->vref) {
|
||||
@@ -185,6 +246,17 @@ static int mcp3911_write_raw(struct iio_dev *indio_dev,
|
||||
MCP3911_STATUSCOM_EN_OFFCAL,
|
||||
MCP3911_STATUSCOM_EN_OFFCAL, 2);
|
||||
break;
|
||||
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
for (int i = 0; i < sizeof(mcp3911_osr_table); i++) {
|
||||
if (val == mcp3911_osr_table[i]) {
|
||||
val = FIELD_PREP(MCP3911_CONFIG_OSR, i);
|
||||
ret = mcp3911_update(adc, MCP3911_REG_CONFIG, MCP3911_CONFIG_OSR,
|
||||
val, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -196,25 +268,80 @@ out:
|
||||
.type = IIO_VOLTAGE, \
|
||||
.indexed = 1, \
|
||||
.channel = idx, \
|
||||
.scan_index = idx, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | \
|
||||
BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_shared_by_type_available = \
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
|
||||
.scan_type = { \
|
||||
.sign = 's', \
|
||||
.realbits = 24, \
|
||||
.storagebits = 32, \
|
||||
.endianness = IIO_BE, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static const struct iio_chan_spec mcp3911_channels[] = {
|
||||
MCP3911_CHAN(0),
|
||||
MCP3911_CHAN(1),
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
};
|
||||
|
||||
static irqreturn_t mcp3911_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct mcp3911 *adc = iio_priv(indio_dev);
|
||||
struct spi_transfer xfer[] = {
|
||||
{
|
||||
.tx_buf = &adc->tx_buf,
|
||||
.len = 1,
|
||||
}, {
|
||||
.rx_buf = adc->rx_buf,
|
||||
.len = sizeof(adc->rx_buf),
|
||||
},
|
||||
};
|
||||
int scan_index;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&adc->lock);
|
||||
adc->tx_buf = MCP3911_REG_READ(MCP3911_CHANNEL(0), adc->dev_addr);
|
||||
ret = spi_sync_transfer(adc->spi, xfer, ARRAY_SIZE(xfer));
|
||||
if (ret < 0) {
|
||||
dev_warn(&adc->spi->dev,
|
||||
"failed to get conversion data\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for_each_set_bit(scan_index, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
const struct iio_chan_spec *scan_chan = &indio_dev->channels[scan_index];
|
||||
|
||||
adc->scan.channels[i] = get_unaligned_be24(&adc->rx_buf[scan_chan->channel * 3]);
|
||||
i++;
|
||||
}
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &adc->scan,
|
||||
iio_get_time_ns(indio_dev));
|
||||
out:
|
||||
mutex_unlock(&adc->lock);
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct iio_info mcp3911_info = {
|
||||
.read_raw = mcp3911_read_raw,
|
||||
.write_raw = mcp3911_write_raw,
|
||||
.read_avail = mcp3911_read_avail,
|
||||
.write_raw_get_fmt = mcp3911_write_raw_get_fmt,
|
||||
};
|
||||
|
||||
static int mcp3911_config(struct mcp3911 *adc)
|
||||
{
|
||||
struct device *dev = &adc->spi->dev;
|
||||
u32 configreg;
|
||||
u32 regval;
|
||||
int ret;
|
||||
|
||||
ret = device_property_read_u32(dev, "microchip,device-addr", &adc->dev_addr);
|
||||
@@ -233,31 +360,67 @@ static int mcp3911_config(struct mcp3911 *adc)
|
||||
}
|
||||
dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
|
||||
|
||||
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &configreg, 2);
|
||||
ret = mcp3911_read(adc, MCP3911_REG_CONFIG, ®val, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regval &= ~MCP3911_CONFIG_VREFEXT;
|
||||
if (adc->vref) {
|
||||
dev_dbg(&adc->spi->dev, "use external voltage reference\n");
|
||||
configreg |= MCP3911_CONFIG_VREFEXT;
|
||||
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 1);
|
||||
} else {
|
||||
dev_dbg(&adc->spi->dev,
|
||||
"use internal voltage reference (1.2V)\n");
|
||||
configreg &= ~MCP3911_CONFIG_VREFEXT;
|
||||
regval |= FIELD_PREP(MCP3911_CONFIG_VREFEXT, 0);
|
||||
}
|
||||
|
||||
regval &= ~MCP3911_CONFIG_CLKEXT;
|
||||
if (adc->clki) {
|
||||
dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
|
||||
configreg |= MCP3911_CONFIG_CLKEXT;
|
||||
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 1);
|
||||
} else {
|
||||
dev_dbg(&adc->spi->dev,
|
||||
"use crystal oscillator as clocksource\n");
|
||||
configreg &= ~MCP3911_CONFIG_CLKEXT;
|
||||
regval |= FIELD_PREP(MCP3911_CONFIG_CLKEXT, 0);
|
||||
}
|
||||
|
||||
return mcp3911_write(adc, MCP3911_REG_CONFIG, configreg, 2);
|
||||
ret = mcp3911_write(adc, MCP3911_REG_CONFIG, regval, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mcp3911_read(adc, MCP3911_REG_STATUSCOM, ®val, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Address counter incremented, cycle through register types */
|
||||
regval &= ~MCP3911_STATUSCOM_READ;
|
||||
regval |= FIELD_PREP(MCP3911_STATUSCOM_READ, 0x02);
|
||||
|
||||
return mcp3911_write(adc, MCP3911_REG_STATUSCOM, regval, 2);
|
||||
}
|
||||
|
||||
static void mcp3911_cleanup_regulator(void *vref)
|
||||
{
|
||||
regulator_disable(vref);
|
||||
}
|
||||
|
||||
static int mcp3911_set_trigger_state(struct iio_trigger *trig, bool enable)
|
||||
{
|
||||
struct mcp3911 *adc = iio_trigger_get_drvdata(trig);
|
||||
|
||||
if (enable)
|
||||
enable_irq(adc->spi->irq);
|
||||
else
|
||||
disable_irq(adc->spi->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops mcp3911_trigger_ops = {
|
||||
.validate_device = iio_trigger_validate_own_device,
|
||||
.set_trigger_state = mcp3911_set_trigger_state,
|
||||
};
|
||||
|
||||
static int mcp3911_probe(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
@@ -286,9 +449,14 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
ret = regulator_enable(adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev,
|
||||
mcp3911_cleanup_regulator, adc->vref);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc->clki = devm_clk_get(&adc->spi->dev, NULL);
|
||||
adc->clki = devm_clk_get_enabled(&adc->spi->dev, NULL);
|
||||
if (IS_ERR(adc->clki)) {
|
||||
if (PTR_ERR(adc->clki) == -ENOENT) {
|
||||
adc->clki = NULL;
|
||||
@@ -296,21 +464,22 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
dev_err(&adc->spi->dev,
|
||||
"failed to get adc clk (%ld)\n",
|
||||
PTR_ERR(adc->clki));
|
||||
ret = PTR_ERR(adc->clki);
|
||||
goto reg_disable;
|
||||
}
|
||||
} else {
|
||||
ret = clk_prepare_enable(adc->clki);
|
||||
if (ret < 0) {
|
||||
dev_err(&adc->spi->dev,
|
||||
"Failed to enable clki: %d\n", ret);
|
||||
goto reg_disable;
|
||||
return PTR_ERR(adc->clki);
|
||||
}
|
||||
}
|
||||
|
||||
ret = mcp3911_config(adc);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
return ret;
|
||||
|
||||
if (device_property_read_bool(&adc->spi->dev, "microchip,data-ready-hiz"))
|
||||
ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
|
||||
0, 2);
|
||||
else
|
||||
ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM, MCP3911_STATUSCOM_DRHIZ,
|
||||
MCP3911_STATUSCOM_DRHIZ, 2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
@@ -322,31 +491,38 @@ static int mcp3911_probe(struct spi_device *spi)
|
||||
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (spi->irq > 0) {
|
||||
adc->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
|
||||
indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!adc->trig)
|
||||
return PTR_ERR(adc->trig);
|
||||
|
||||
adc->trig->ops = &mcp3911_trigger_ops;
|
||||
iio_trigger_set_drvdata(adc->trig, adc);
|
||||
ret = devm_iio_trigger_register(&spi->dev, adc->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* The device generates interrupts as long as it is powered up.
|
||||
* Some platforms might not allow the option to power it down so
|
||||
* don't enable the interrupt to avoid extra load on the system.
|
||||
*/
|
||||
ret = devm_request_irq(&spi->dev, spi->irq,
|
||||
&iio_trigger_generic_data_rdy_poll, IRQF_NO_AUTOEN | IRQF_ONESHOT,
|
||||
indio_dev->name, adc->trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
|
||||
NULL,
|
||||
mcp3911_trigger_handler, NULL);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
|
||||
clk_disable:
|
||||
clk_disable_unprepare(adc->clki);
|
||||
reg_disable:
|
||||
if (adc->vref)
|
||||
regulator_disable(adc->vref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcp3911_remove(struct spi_device *spi)
|
||||
{
|
||||
struct iio_dev *indio_dev = spi_get_drvdata(spi);
|
||||
struct mcp3911 *adc = iio_priv(indio_dev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
|
||||
clk_disable_unprepare(adc->clki);
|
||||
if (adc->vref)
|
||||
regulator_disable(adc->vref);
|
||||
return devm_iio_device_register(&adc->spi->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id mcp3911_dt_ids[] = {
|
||||
@@ -367,7 +543,6 @@ static struct spi_driver mcp3911_driver = {
|
||||
.of_match_table = mcp3911_dt_ids,
|
||||
},
|
||||
.probe = mcp3911_probe,
|
||||
.remove = mcp3911_remove,
|
||||
.id_table = mcp3911_id,
|
||||
};
|
||||
module_spi_driver(mcp3911_driver);
|
||||
|
||||
@@ -353,7 +353,7 @@ static int mt6360_adc_probe(struct platform_device *pdev)
|
||||
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id __maybe_unused mt6360_adc_of_id[] = {
|
||||
static const struct of_device_id mt6360_adc_of_id[] = {
|
||||
{ .compatible = "mediatek,mt6360-adc", },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
@@ -694,8 +694,8 @@ static int pm8xxx_read_raw(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int pm8xxx_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
struct pm8xxx_xoadc *adc = iio_priv(indio_dev);
|
||||
u8 pre_scale_mux;
|
||||
@@ -706,10 +706,10 @@ static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
|
||||
* First cell is prescaler or premux, second cell is analog
|
||||
* mux.
|
||||
*/
|
||||
if (iiospec->args_count != 2) {
|
||||
dev_err(&indio_dev->dev, "wrong number of arguments for %pOFn need 2 got %d\n",
|
||||
iiospec->np,
|
||||
iiospec->args_count);
|
||||
if (iiospec->nargs != 2) {
|
||||
dev_err(&indio_dev->dev, "wrong number of arguments for %pfwP need 2 got %d\n",
|
||||
iiospec->fwnode,
|
||||
iiospec->nargs);
|
||||
return -EINVAL;
|
||||
}
|
||||
pre_scale_mux = (u8)iiospec->args[0];
|
||||
@@ -727,34 +727,34 @@ static int pm8xxx_of_xlate(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
static const struct iio_info pm8xxx_xoadc_info = {
|
||||
.of_xlate = pm8xxx_of_xlate,
|
||||
.fwnode_xlate = pm8xxx_fwnode_xlate,
|
||||
.read_raw = pm8xxx_read_raw,
|
||||
};
|
||||
|
||||
static int pm8xxx_xoadc_parse_channel(struct device *dev,
|
||||
struct device_node *np,
|
||||
struct fwnode_handle *fwnode,
|
||||
const struct xoadc_channel *hw_channels,
|
||||
struct iio_chan_spec *iio_chan,
|
||||
struct pm8xxx_chan_info *ch)
|
||||
{
|
||||
const char *name = np->name;
|
||||
const char *name = fwnode_get_name(fwnode);
|
||||
const struct xoadc_channel *hwchan;
|
||||
u32 pre_scale_mux, amux_channel;
|
||||
u32 pre_scale_mux, amux_channel, reg[2];
|
||||
u32 rsv, dec;
|
||||
int ret;
|
||||
int chid;
|
||||
|
||||
ret = of_property_read_u32_index(np, "reg", 0, &pre_scale_mux);
|
||||
ret = fwnode_property_read_u32_array(fwnode, "reg", reg,
|
||||
ARRAY_SIZE(reg));
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid pre scale/mux number %s\n", name);
|
||||
return ret;
|
||||
}
|
||||
ret = of_property_read_u32_index(np, "reg", 1, &amux_channel);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid amux channel number %s\n", name);
|
||||
dev_err(dev, "invalid pre scale/mux or amux channel number %s\n",
|
||||
name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pre_scale_mux = reg[0];
|
||||
amux_channel = reg[1];
|
||||
|
||||
/* Find the right channel setting */
|
||||
chid = 0;
|
||||
hwchan = &hw_channels[0];
|
||||
@@ -778,7 +778,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
|
||||
/* Everyone seems to use default ("type 2") decimation */
|
||||
ch->decimation = VADC_DEF_DECIMATION;
|
||||
|
||||
if (!of_property_read_u32(np, "qcom,ratiometric", &rsv)) {
|
||||
if (!fwnode_property_read_u32(fwnode, "qcom,ratiometric", &rsv)) {
|
||||
ch->calibration = VADC_CALIB_RATIOMETRIC;
|
||||
if (rsv > XOADC_RSV_MAX) {
|
||||
dev_err(dev, "%s too large RSV value %d\n", name, rsv);
|
||||
@@ -791,7 +791,7 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
|
||||
}
|
||||
|
||||
/* Optional decimation, if omitted we use the default */
|
||||
ret = of_property_read_u32(np, "qcom,decimation", &dec);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &dec);
|
||||
if (!ret) {
|
||||
ret = qcom_vadc_decimation_from_dt(dec);
|
||||
if (ret < 0) {
|
||||
@@ -820,15 +820,14 @@ static int pm8xxx_xoadc_parse_channel(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc,
|
||||
struct device_node *np)
|
||||
static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct fwnode_handle *child;
|
||||
struct pm8xxx_chan_info *ch;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
adc->nchans = of_get_available_child_count(np);
|
||||
adc->nchans = device_get_child_node_count(adc->dev);
|
||||
if (!adc->nchans) {
|
||||
dev_err(adc->dev, "no channel children\n");
|
||||
return -ENODEV;
|
||||
@@ -846,14 +845,14 @@ static int pm8xxx_xoadc_parse_channels(struct pm8xxx_xoadc *adc,
|
||||
return -ENOMEM;
|
||||
|
||||
i = 0;
|
||||
for_each_available_child_of_node(np, child) {
|
||||
device_for_each_child_node(adc->dev, child) {
|
||||
ch = &adc->chans[i];
|
||||
ret = pm8xxx_xoadc_parse_channel(adc->dev, child,
|
||||
adc->variant->channels,
|
||||
&adc->iio_chans[i],
|
||||
ch);
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
i++;
|
||||
@@ -884,12 +883,11 @@ static int pm8xxx_xoadc_probe(struct platform_device *pdev)
|
||||
const struct xoadc_variant *variant;
|
||||
struct pm8xxx_xoadc *adc;
|
||||
struct iio_dev *indio_dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct regmap *map;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
variant = of_device_get_match_data(dev);
|
||||
variant = device_get_match_data(dev);
|
||||
if (!variant)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -904,7 +902,7 @@ static int pm8xxx_xoadc_probe(struct platform_device *pdev)
|
||||
init_completion(&adc->complete);
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
ret = pm8xxx_xoadc_parse_channels(adc, np);
|
||||
ret = pm8xxx_xoadc_parse_channels(adc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -403,8 +403,8 @@ static irqreturn_t adc5_isr(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int adc5_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int adc5_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
int i;
|
||||
@@ -416,8 +416,8 @@ static int adc5_of_xlate(struct iio_dev *indio_dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int adc7_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int adc7_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
struct adc5_chip *adc = iio_priv(indio_dev);
|
||||
int i, v_channel;
|
||||
@@ -481,12 +481,12 @@ static int adc7_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
static const struct iio_info adc5_info = {
|
||||
.read_raw = adc5_read_raw,
|
||||
.of_xlate = adc5_of_xlate,
|
||||
.fwnode_xlate = adc5_fwnode_xlate,
|
||||
};
|
||||
|
||||
static const struct iio_info adc7_info = {
|
||||
.read_raw = adc7_read_raw,
|
||||
.of_xlate = adc7_of_xlate,
|
||||
.fwnode_xlate = adc7_fwnode_xlate,
|
||||
};
|
||||
|
||||
struct adc5_channels {
|
||||
@@ -526,6 +526,8 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0,
|
||||
SCALE_HW_CALIB_PMIC_THERM)
|
||||
[ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 0,
|
||||
@@ -549,6 +551,12 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = {
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 0,
|
||||
SCALE_HW_CALIB_PM5_SMB_TEMP)
|
||||
[ADC5_GPIO1_100K_PU] = ADC5_CHAN_TEMP("gpio1_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_GPIO3_100K_PU] = ADC5_CHAN_TEMP("gpio3_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
[ADC5_GPIO4_100K_PU] = ADC5_CHAN_TEMP("gpio4_100k_pu", 0,
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
};
|
||||
|
||||
static const struct adc5_channels adc7_chans_pmic[ADC5_MAX_CHANNEL] = {
|
||||
@@ -589,6 +597,8 @@ static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VREF_VADC] = ADC5_CHAN_VOLT("vref_vadc", 0,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1,
|
||||
SCALE_HW_CALIB_DEFAULT)
|
||||
[ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1,
|
||||
@@ -611,18 +621,18 @@ static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = {
|
||||
SCALE_HW_CALIB_THERM_100K_PULLUP)
|
||||
};
|
||||
|
||||
static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
static int adc5_get_fw_channel_data(struct adc5_chip *adc,
|
||||
struct adc5_channel_prop *prop,
|
||||
struct device_node *node,
|
||||
struct fwnode_handle *fwnode,
|
||||
const struct adc5_data *data)
|
||||
{
|
||||
const char *name = node->name, *channel_name;
|
||||
const char *name = fwnode_get_name(fwnode), *channel_name;
|
||||
u32 chan, value, varr[2];
|
||||
u32 sid = 0;
|
||||
int ret;
|
||||
struct device *dev = adc->dev;
|
||||
|
||||
ret = of_property_read_u32(node, "reg", &chan);
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &chan);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid channel number %s\n", name);
|
||||
return ret;
|
||||
@@ -647,15 +657,13 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
prop->channel = chan;
|
||||
prop->sid = sid;
|
||||
|
||||
channel_name = of_get_property(node,
|
||||
"label", NULL) ? : node->name;
|
||||
if (!channel_name) {
|
||||
dev_err(dev, "Invalid channel name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = fwnode_property_read_string(fwnode, "label", &channel_name);
|
||||
if (ret)
|
||||
channel_name = name;
|
||||
|
||||
prop->datasheet_name = channel_name;
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,decimation", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
|
||||
if (!ret) {
|
||||
ret = qcom_adc5_decimation_from_dt(value, data->decimation);
|
||||
if (ret < 0) {
|
||||
@@ -668,7 +676,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
prop->decimation = ADC5_DECIMATION_DEFAULT;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
|
||||
ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2);
|
||||
if (!ret) {
|
||||
ret = qcom_adc5_prescaling_from_dt(varr[0], varr[1]);
|
||||
if (ret < 0) {
|
||||
@@ -682,7 +690,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
adc->data->adc_chans[prop->channel].prescale_index;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
|
||||
if (!ret) {
|
||||
u8 dig_version[2];
|
||||
|
||||
@@ -713,7 +721,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,avg-samples", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value);
|
||||
if (!ret) {
|
||||
ret = qcom_adc5_avg_samples_from_dt(value);
|
||||
if (ret < 0) {
|
||||
@@ -726,7 +734,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
|
||||
prop->avg_samples = VADC_DEF_AVG_SAMPLES;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "qcom,ratiometric"))
|
||||
if (fwnode_property_read_bool(fwnode, "qcom,ratiometric"))
|
||||
prop->cal_method = ADC5_RATIOMETRIC_CAL;
|
||||
else
|
||||
prop->cal_method = ADC5_ABSOLUTE_CAL;
|
||||
@@ -801,16 +809,16 @@ static const struct of_device_id adc5_match_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, adc5_match_table);
|
||||
|
||||
static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
|
||||
static int adc5_get_fw_data(struct adc5_chip *adc)
|
||||
{
|
||||
const struct adc5_channels *adc_chan;
|
||||
struct iio_chan_spec *iio_chan;
|
||||
struct adc5_channel_prop prop, *chan_props;
|
||||
struct device_node *child;
|
||||
struct fwnode_handle *child;
|
||||
unsigned int index = 0;
|
||||
int ret;
|
||||
|
||||
adc->nchannels = of_get_available_child_count(node);
|
||||
adc->nchannels = device_get_child_node_count(adc->dev);
|
||||
if (!adc->nchannels)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -826,14 +834,14 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
|
||||
|
||||
chan_props = adc->chan_props;
|
||||
iio_chan = adc->iio_chans;
|
||||
adc->data = of_device_get_match_data(adc->dev);
|
||||
adc->data = device_get_match_data(adc->dev);
|
||||
if (!adc->data)
|
||||
adc->data = &adc5_data_pmic;
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
ret = adc5_get_dt_channel_data(adc, &prop, child, adc->data);
|
||||
device_for_each_child_node(adc->dev, child) {
|
||||
ret = adc5_get_fw_channel_data(adc, &prop, child, adc->data);
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -858,7 +866,6 @@ static int adc5_get_dt_data(struct adc5_chip *adc, struct device_node *node)
|
||||
|
||||
static int adc5_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct adc5_chip *adc;
|
||||
@@ -870,7 +877,7 @@ static int adc5_probe(struct platform_device *pdev)
|
||||
if (!regmap)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_property_read_u32(node, "reg", ®);
|
||||
ret = device_property_read_u32(dev, "reg", ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -886,7 +893,7 @@ static int adc5_probe(struct platform_device *pdev)
|
||||
init_completion(&adc->complete);
|
||||
mutex_init(&adc->lock);
|
||||
|
||||
ret = adc5_get_dt_data(adc, node);
|
||||
ret = adc5_get_fw_data(adc);
|
||||
if (ret) {
|
||||
dev_err(dev, "adc get dt data failed\n");
|
||||
return ret;
|
||||
|
||||
@@ -13,8 +13,9 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/log2.h>
|
||||
@@ -481,8 +482,8 @@ static int vadc_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vadc_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int vadc_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
struct vadc_priv *vadc = iio_priv(indio_dev);
|
||||
unsigned int i;
|
||||
@@ -496,7 +497,7 @@ static int vadc_of_xlate(struct iio_dev *indio_dev,
|
||||
|
||||
static const struct iio_info vadc_info = {
|
||||
.read_raw = vadc_read_raw,
|
||||
.of_xlate = vadc_of_xlate,
|
||||
.fwnode_xlate = vadc_fwnode_xlate,
|
||||
};
|
||||
|
||||
struct vadc_channels {
|
||||
@@ -647,15 +648,15 @@ static const struct vadc_channels vadc_chans[] = {
|
||||
VADC_CHAN_NO_SCALE(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0)
|
||||
};
|
||||
|
||||
static int vadc_get_dt_channel_data(struct device *dev,
|
||||
static int vadc_get_fw_channel_data(struct device *dev,
|
||||
struct vadc_channel_prop *prop,
|
||||
struct device_node *node)
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
const char *name = node->name;
|
||||
const char *name = fwnode_get_name(fwnode);
|
||||
u32 chan, value, varr[2];
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(node, "reg", &chan);
|
||||
ret = fwnode_property_read_u32(fwnode, "reg", &chan);
|
||||
if (ret) {
|
||||
dev_err(dev, "invalid channel number %s\n", name);
|
||||
return ret;
|
||||
@@ -669,7 +670,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
/* the channel has DT description */
|
||||
prop->channel = chan;
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,decimation", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,decimation", &value);
|
||||
if (!ret) {
|
||||
ret = qcom_vadc_decimation_from_dt(value);
|
||||
if (ret < 0) {
|
||||
@@ -682,7 +683,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
prop->decimation = VADC_DEF_DECIMATION;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
|
||||
ret = fwnode_property_read_u32_array(fwnode, "qcom,pre-scaling", varr, 2);
|
||||
if (!ret) {
|
||||
ret = vadc_prescaling_from_dt(varr[0], varr[1]);
|
||||
if (ret < 0) {
|
||||
@@ -695,7 +696,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
prop->prescale = vadc_chans[prop->channel].prescale_index;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
|
||||
if (!ret) {
|
||||
ret = vadc_hw_settle_time_from_dt(value);
|
||||
if (ret < 0) {
|
||||
@@ -708,7 +709,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "qcom,avg-samples", &value);
|
||||
ret = fwnode_property_read_u32(fwnode, "qcom,avg-samples", &value);
|
||||
if (!ret) {
|
||||
ret = vadc_avg_samples_from_dt(value);
|
||||
if (ret < 0) {
|
||||
@@ -721,7 +722,7 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
prop->avg_samples = VADC_DEF_AVG_SAMPLES;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "qcom,ratiometric"))
|
||||
if (fwnode_property_read_bool(fwnode, "qcom,ratiometric"))
|
||||
prop->calibration = VADC_CALIB_RATIOMETRIC;
|
||||
else
|
||||
prop->calibration = VADC_CALIB_ABSOLUTE;
|
||||
@@ -731,16 +732,16 @@ static int vadc_get_dt_channel_data(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
|
||||
static int vadc_get_fw_data(struct vadc_priv *vadc)
|
||||
{
|
||||
const struct vadc_channels *vadc_chan;
|
||||
struct iio_chan_spec *iio_chan;
|
||||
struct vadc_channel_prop prop;
|
||||
struct device_node *child;
|
||||
struct fwnode_handle *child;
|
||||
unsigned int index = 0;
|
||||
int ret;
|
||||
|
||||
vadc->nchannels = of_get_available_child_count(node);
|
||||
vadc->nchannels = device_get_child_node_count(vadc->dev);
|
||||
if (!vadc->nchannels)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -756,10 +757,10 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
|
||||
|
||||
iio_chan = vadc->iio_chans;
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
|
||||
device_for_each_child_node(vadc->dev, child) {
|
||||
ret = vadc_get_fw_channel_data(vadc->dev, &prop, child);
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
fwnode_handle_put(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -848,7 +849,6 @@ static int vadc_check_revision(struct vadc_priv *vadc)
|
||||
|
||||
static int vadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct iio_dev *indio_dev;
|
||||
struct vadc_priv *vadc;
|
||||
@@ -860,7 +860,7 @@ static int vadc_probe(struct platform_device *pdev)
|
||||
if (!regmap)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_property_read_u32(node, "reg", ®);
|
||||
ret = device_property_read_u32(dev, "reg", ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -880,7 +880,7 @@ static int vadc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = vadc_get_dt_data(vadc, node);
|
||||
ret = vadc_get_fw_data(vadc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
||||
661
drivers/iio/adc/rtq6056.c
Normal file
661
drivers/iio/adc/rtq6056.c
Normal file
@@ -0,0 +1,661 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Richtek Technology Corp.
|
||||
*
|
||||
* ChiYuan Huang <cy_huang@richtek.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/util_macros.h>
|
||||
|
||||
#include <linux/iio/buffer.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/sysfs.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
|
||||
#define RTQ6056_REG_CONFIG 0x00
|
||||
#define RTQ6056_REG_SHUNTVOLT 0x01
|
||||
#define RTQ6056_REG_BUSVOLT 0x02
|
||||
#define RTQ6056_REG_POWER 0x03
|
||||
#define RTQ6056_REG_CURRENT 0x04
|
||||
#define RTQ6056_REG_CALIBRATION 0x05
|
||||
#define RTQ6056_REG_MASKENABLE 0x06
|
||||
#define RTQ6056_REG_ALERTLIMIT 0x07
|
||||
#define RTQ6056_REG_MANUFACTID 0xFE
|
||||
#define RTQ6056_REG_DIEID 0xFF
|
||||
|
||||
#define RTQ6056_VENDOR_ID 0x1214
|
||||
#define RTQ6056_DEFAULT_CONFIG 0x4127
|
||||
#define RTQ6056_CONT_ALLON 7
|
||||
|
||||
enum {
|
||||
RTQ6056_CH_VSHUNT = 0,
|
||||
RTQ6056_CH_VBUS,
|
||||
RTQ6056_CH_POWER,
|
||||
RTQ6056_CH_CURRENT,
|
||||
RTQ6056_MAX_CHANNEL
|
||||
};
|
||||
|
||||
enum {
|
||||
F_OPMODE = 0,
|
||||
F_VSHUNTCT,
|
||||
F_VBUSCT,
|
||||
F_AVG,
|
||||
F_RESET,
|
||||
F_MAX_FIELDS
|
||||
};
|
||||
|
||||
struct rtq6056_priv {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *rm_fields[F_MAX_FIELDS];
|
||||
u32 shunt_resistor_uohm;
|
||||
int vshuntct_us;
|
||||
int vbusct_us;
|
||||
int avg_sample;
|
||||
};
|
||||
|
||||
static const struct reg_field rtq6056_reg_fields[F_MAX_FIELDS] = {
|
||||
[F_OPMODE] = REG_FIELD(RTQ6056_REG_CONFIG, 0, 2),
|
||||
[F_VSHUNTCT] = REG_FIELD(RTQ6056_REG_CONFIG, 3, 5),
|
||||
[F_VBUSCT] = REG_FIELD(RTQ6056_REG_CONFIG, 6, 8),
|
||||
[F_AVG] = REG_FIELD(RTQ6056_REG_CONFIG, 9, 11),
|
||||
[F_RESET] = REG_FIELD(RTQ6056_REG_CONFIG, 15, 15),
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec rtq6056_channels[RTQ6056_MAX_CHANNEL + 1] = {
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 0,
|
||||
.address = RTQ6056_REG_SHUNTVOLT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = IIO_VOLTAGE,
|
||||
.indexed = 1,
|
||||
.channel = 1,
|
||||
.address = RTQ6056_REG_BUSVOLT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = IIO_POWER,
|
||||
.indexed = 1,
|
||||
.channel = 2,
|
||||
.address = RTQ6056_REG_POWER,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 2,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = IIO_CURRENT,
|
||||
.indexed = 1,
|
||||
.channel = 3,
|
||||
.address = RTQ6056_REG_CURRENT,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SAMP_FREQ),
|
||||
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
.scan_index = 3,
|
||||
.scan_type = {
|
||||
.sign = 's',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_CPU,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(RTQ6056_MAX_CHANNEL),
|
||||
};
|
||||
|
||||
static int rtq6056_adc_read_channel(struct rtq6056_priv *priv,
|
||||
struct iio_chan_spec const *ch,
|
||||
int *val)
|
||||
{
|
||||
struct device *dev = priv->dev;
|
||||
unsigned int addr = ch->address;
|
||||
unsigned int regval;
|
||||
int ret;
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
ret = regmap_read(priv->regmap, addr, ®val);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Power and VBUS is unsigned 16-bit, others are signed 16-bit */
|
||||
if (addr == RTQ6056_REG_BUSVOLT || addr == RTQ6056_REG_POWER)
|
||||
*val = regval;
|
||||
else
|
||||
*val = sign_extend32(regval, 16);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int rtq6056_adc_read_scale(struct iio_chan_spec const *ch, int *val,
|
||||
int *val2)
|
||||
{
|
||||
switch (ch->address) {
|
||||
case RTQ6056_REG_SHUNTVOLT:
|
||||
/* VSHUNT lsb 2.5uV */
|
||||
*val = 2500;
|
||||
*val2 = 1000000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case RTQ6056_REG_BUSVOLT:
|
||||
/* VBUS lsb 1.25mV */
|
||||
*val = 1250;
|
||||
*val2 = 1000;
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
case RTQ6056_REG_POWER:
|
||||
/* Power lsb 25mW */
|
||||
*val = 25;
|
||||
return IIO_VAL_INT;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sample frequency for channel VSHUNT and VBUS. The indices correspond
|
||||
* with the bit value expected by the chip. And it can be found at
|
||||
* https://www.richtek.com/assets/product_file/RTQ6056/DSQ6056-00.pdf
|
||||
*/
|
||||
static const int rtq6056_samp_freq_list[] = {
|
||||
7194, 4926, 3717, 1904, 964, 485, 243, 122,
|
||||
};
|
||||
|
||||
static int rtq6056_adc_set_samp_freq(struct rtq6056_priv *priv,
|
||||
struct iio_chan_spec const *ch, int val)
|
||||
{
|
||||
struct regmap_field *rm_field;
|
||||
unsigned int selector;
|
||||
int *ct, ret;
|
||||
|
||||
if (val > 7194 || val < 122)
|
||||
return -EINVAL;
|
||||
|
||||
if (ch->address == RTQ6056_REG_SHUNTVOLT) {
|
||||
rm_field = priv->rm_fields[F_VSHUNTCT];
|
||||
ct = &priv->vshuntct_us;
|
||||
} else if (ch->address == RTQ6056_REG_BUSVOLT) {
|
||||
rm_field = priv->rm_fields[F_VBUSCT];
|
||||
ct = &priv->vbusct_us;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
selector = find_closest_descending(val, rtq6056_samp_freq_list,
|
||||
ARRAY_SIZE(rtq6056_samp_freq_list));
|
||||
|
||||
ret = regmap_field_write(rm_field, selector);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*ct = 1000000 / rtq6056_samp_freq_list[selector];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Available averaging rate for rtq6056. The indices correspond with the bit
|
||||
* value expected by the chip. And it can be found at
|
||||
* https://www.richtek.com/assets/product_file/RTQ6056/DSQ6056-00.pdf
|
||||
*/
|
||||
static const int rtq6056_avg_sample_list[] = {
|
||||
1, 4, 16, 64, 128, 256, 512, 1024,
|
||||
};
|
||||
|
||||
static int rtq6056_adc_set_average(struct rtq6056_priv *priv, int val)
|
||||
{
|
||||
unsigned int selector;
|
||||
int ret;
|
||||
|
||||
if (val > 1024 || val < 1)
|
||||
return -EINVAL;
|
||||
|
||||
selector = find_closest(val, rtq6056_avg_sample_list,
|
||||
ARRAY_SIZE(rtq6056_avg_sample_list));
|
||||
|
||||
ret = regmap_field_write(priv->rm_fields[F_AVG], selector);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->avg_sample = rtq6056_avg_sample_list[selector];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtq6056_adc_get_sample_freq(struct rtq6056_priv *priv,
|
||||
struct iio_chan_spec const *ch, int *val)
|
||||
{
|
||||
int sample_time;
|
||||
|
||||
if (ch->address == RTQ6056_REG_SHUNTVOLT)
|
||||
sample_time = priv->vshuntct_us;
|
||||
else if (ch->address == RTQ6056_REG_BUSVOLT)
|
||||
sample_time = priv->vbusct_us;
|
||||
else {
|
||||
sample_time = priv->vshuntct_us + priv->vbusct_us;
|
||||
sample_time *= priv->avg_sample;
|
||||
}
|
||||
|
||||
*val = 1000000 / sample_time;
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int rtq6056_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val,
|
||||
int *val2, long mask)
|
||||
{
|
||||
struct rtq6056_priv *priv = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
return rtq6056_adc_read_channel(priv, chan, val);
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
return rtq6056_adc_read_scale(chan, val, val2);
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*val = priv->avg_sample;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
return rtq6056_adc_get_sample_freq(priv, chan, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rtq6056_adc_read_avail(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
const int **vals, int *type, int *length,
|
||||
long mask)
|
||||
{
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
*vals = rtq6056_samp_freq_list;
|
||||
*type = IIO_VAL_INT;
|
||||
*length = ARRAY_SIZE(rtq6056_samp_freq_list);
|
||||
return IIO_AVAIL_LIST;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
*vals = rtq6056_avg_sample_list;
|
||||
*type = IIO_VAL_INT;
|
||||
*length = ARRAY_SIZE(rtq6056_avg_sample_list);
|
||||
return IIO_AVAIL_LIST;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int rtq6056_adc_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val,
|
||||
int val2, long mask)
|
||||
{
|
||||
struct rtq6056_priv *priv = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
ret = rtq6056_adc_set_samp_freq(priv, chan, val);
|
||||
break;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
ret = rtq6056_adc_set_average(priv, val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *rtq6056_channel_labels[RTQ6056_MAX_CHANNEL] = {
|
||||
[RTQ6056_CH_VSHUNT] = "Vshunt",
|
||||
[RTQ6056_CH_VBUS] = "Vbus",
|
||||
[RTQ6056_CH_POWER] = "Power",
|
||||
[RTQ6056_CH_CURRENT] = "Current",
|
||||
};
|
||||
|
||||
static int rtq6056_adc_read_label(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
char *label)
|
||||
{
|
||||
return sysfs_emit(label, "%s\n", rtq6056_channel_labels[chan->channel]);
|
||||
}
|
||||
|
||||
static int rtq6056_set_shunt_resistor(struct rtq6056_priv *priv,
|
||||
int resistor_uohm)
|
||||
{
|
||||
unsigned int calib_val;
|
||||
int ret;
|
||||
|
||||
if (resistor_uohm <= 0) {
|
||||
dev_err(priv->dev, "Invalid resistor [%d]\n", resistor_uohm);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* calibration = 5120000 / (Rshunt (uOhm) * current lsb (1mA)) */
|
||||
calib_val = 5120000 / resistor_uohm;
|
||||
ret = regmap_write(priv->regmap, RTQ6056_REG_CALIBRATION, calib_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->shunt_resistor_uohm = resistor_uohm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t shunt_resistor_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct rtq6056_priv *priv = iio_priv(dev_to_iio_dev(dev));
|
||||
int vals[2] = { priv->shunt_resistor_uohm, 1000000 };
|
||||
|
||||
return iio_format_value(buf, IIO_VAL_FRACTIONAL, 1, vals);
|
||||
}
|
||||
|
||||
static ssize_t shunt_resistor_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
||||
struct rtq6056_priv *priv = iio_priv(indio_dev);
|
||||
int val, val_fract, ret;
|
||||
|
||||
ret = iio_device_claim_direct_mode(indio_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_str_to_fixpoint(buf, 100000, &val, &val_fract);
|
||||
if (ret)
|
||||
goto out_store;
|
||||
|
||||
ret = rtq6056_set_shunt_resistor(priv, val * 1000000 + val_fract);
|
||||
|
||||
out_store:
|
||||
iio_device_release_direct_mode(indio_dev);
|
||||
|
||||
return ret ?: len;
|
||||
}
|
||||
|
||||
static IIO_DEVICE_ATTR_RW(shunt_resistor, 0);
|
||||
|
||||
static struct attribute *rtq6056_attributes[] = {
|
||||
&iio_dev_attr_shunt_resistor.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group rtq6056_attribute_group = {
|
||||
.attrs = rtq6056_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info rtq6056_info = {
|
||||
.attrs = &rtq6056_attribute_group,
|
||||
.read_raw = rtq6056_adc_read_raw,
|
||||
.read_avail = rtq6056_adc_read_avail,
|
||||
.write_raw = rtq6056_adc_write_raw,
|
||||
.read_label = rtq6056_adc_read_label,
|
||||
};
|
||||
|
||||
static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct rtq6056_priv *priv = iio_priv(indio_dev);
|
||||
struct device *dev = priv->dev;
|
||||
struct {
|
||||
u16 vals[RTQ6056_MAX_CHANNEL];
|
||||
s64 timestamp __aligned(8);
|
||||
} data;
|
||||
unsigned int raw;
|
||||
int i = 0, bit, ret;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) {
|
||||
unsigned int addr = rtq6056_channels[bit].address;
|
||||
|
||||
ret = regmap_read(priv->regmap, addr, &raw);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
data.vals[i++] = raw;
|
||||
}
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev));
|
||||
|
||||
out:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void rtq6056_enter_shutdown_state(void *dev)
|
||||
{
|
||||
struct rtq6056_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
/* Enter shutdown state */
|
||||
regmap_field_write(priv->rm_fields[F_OPMODE], 0);
|
||||
}
|
||||
|
||||
static bool rtq6056_is_readable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case RTQ6056_REG_CONFIG ... RTQ6056_REG_ALERTLIMIT:
|
||||
case RTQ6056_REG_MANUFACTID ... RTQ6056_REG_DIEID:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool rtq6056_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case RTQ6056_REG_CONFIG:
|
||||
case RTQ6056_REG_CALIBRATION ... RTQ6056_REG_ALERTLIMIT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config rtq6056_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
.max_register = RTQ6056_REG_DIEID,
|
||||
.readable_reg = rtq6056_is_readable_reg,
|
||||
.writeable_reg = rtq6056_is_writeable_reg,
|
||||
};
|
||||
|
||||
static int rtq6056_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct rtq6056_priv *priv;
|
||||
struct device *dev = &i2c->dev;
|
||||
struct regmap *regmap;
|
||||
unsigned int vendor_id, shunt_resistor_uohm;
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = iio_priv(indio_dev);
|
||||
priv->dev = dev;
|
||||
priv->vshuntct_us = priv->vbusct_us = 1037;
|
||||
priv->avg_sample = 1;
|
||||
i2c_set_clientdata(i2c, priv);
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &rtq6056_regmap_config);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"Failed to init regmap\n");
|
||||
|
||||
priv->regmap = regmap;
|
||||
|
||||
ret = regmap_read(regmap, RTQ6056_REG_MANUFACTID, &vendor_id);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to get manufacturer info\n");
|
||||
|
||||
if (vendor_id != RTQ6056_VENDOR_ID)
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"Invalid vendor id 0x%04x\n", vendor_id);
|
||||
|
||||
ret = devm_regmap_field_bulk_alloc(dev, regmap, priv->rm_fields,
|
||||
rtq6056_reg_fields, F_MAX_FIELDS);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to init regmap field\n");
|
||||
|
||||
/*
|
||||
* By default, configure average sample as 1, bus and shunt conversion
|
||||
* time as 1037 microsecond, and operating mode to all on.
|
||||
*/
|
||||
ret = regmap_write(regmap, RTQ6056_REG_CONFIG, RTQ6056_DEFAULT_CONFIG);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to enable continuous sensing\n");
|
||||
|
||||
ret = devm_add_action_or_reset(dev, rtq6056_enter_shutdown_state, dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n");
|
||||
|
||||
/* By default, use 2000 micro-Ohm resistor */
|
||||
shunt_resistor_uohm = 2000;
|
||||
device_property_read_u32(dev, "shunt-resistor-micro-ohms",
|
||||
&shunt_resistor_uohm);
|
||||
|
||||
ret = rtq6056_set_shunt_resistor(priv, shunt_resistor_uohm);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to init shunt resistor\n");
|
||||
|
||||
indio_dev->name = "rtq6056";
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
indio_dev->channels = rtq6056_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(rtq6056_channels);
|
||||
indio_dev->info = &rtq6056_info;
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
|
||||
rtq6056_buffer_trigger_handler,
|
||||
NULL);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to allocate iio trigger buffer\n");
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static int rtq6056_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct rtq6056_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
/* Configure to shutdown mode */
|
||||
return regmap_field_write(priv->rm_fields[F_OPMODE], 0);
|
||||
}
|
||||
|
||||
static int rtq6056_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct rtq6056_priv *priv = dev_get_drvdata(dev);
|
||||
int sample_rdy_time_us, ret;
|
||||
|
||||
ret = regmap_field_write(priv->rm_fields[F_OPMODE], RTQ6056_CONT_ALLON);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sample_rdy_time_us = priv->vbusct_us + priv->vshuntct_us;
|
||||
sample_rdy_time_us *= priv->avg_sample;
|
||||
|
||||
usleep_range(sample_rdy_time_us, sample_rdy_time_us + 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_RUNTIME_DEV_PM_OPS(rtq6056_pm_ops, rtq6056_runtime_suspend,
|
||||
rtq6056_runtime_resume, NULL);
|
||||
|
||||
static const struct of_device_id rtq6056_device_match[] = {
|
||||
{ .compatible = "richtek,rtq6056" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rtq6056_device_match);
|
||||
|
||||
static struct i2c_driver rtq6056_driver = {
|
||||
.driver = {
|
||||
.name = "rtq6056",
|
||||
.of_match_table = rtq6056_device_match,
|
||||
.pm = pm_ptr(&rtq6056_pm_ops),
|
||||
},
|
||||
.probe_new = rtq6056_probe,
|
||||
};
|
||||
module_i2c_driver(rtq6056_driver);
|
||||
|
||||
MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
|
||||
MODULE_DESCRIPTION("Richtek RTQ6056 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -9,6 +9,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
@@ -62,6 +63,7 @@ struct stm32_adc_priv;
|
||||
* @regs: common registers for all instances
|
||||
* @clk_sel: clock selection routine
|
||||
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
|
||||
* @ipid: adc identification number
|
||||
* @has_syscfg: SYSCFG capability flags
|
||||
* @num_irqs: number of interrupt lines
|
||||
* @num_adcs: maximum number of ADC instances in the common registers
|
||||
@@ -70,6 +72,7 @@ struct stm32_adc_priv_cfg {
|
||||
const struct stm32_adc_common_regs *regs;
|
||||
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
|
||||
u32 max_clk_rate_hz;
|
||||
u32 ipid;
|
||||
unsigned int has_syscfg;
|
||||
unsigned int num_irqs;
|
||||
unsigned int num_adcs;
|
||||
@@ -78,6 +81,7 @@ struct stm32_adc_priv_cfg {
|
||||
/**
|
||||
* struct stm32_adc_priv - stm32 ADC core private data
|
||||
* @irq: irq(s) for ADC block
|
||||
* @nb_adc_max: actual maximum number of instance per ADC block
|
||||
* @domain: irq domain reference
|
||||
* @aclk: clock reference for the analog circuitry
|
||||
* @bclk: bus clock common for all ADCs, depends on part used
|
||||
@@ -95,6 +99,7 @@ struct stm32_adc_priv_cfg {
|
||||
*/
|
||||
struct stm32_adc_priv {
|
||||
int irq[STM32_ADC_MAX_ADCS];
|
||||
unsigned int nb_adc_max;
|
||||
struct irq_domain *domain;
|
||||
struct clk *aclk;
|
||||
struct clk *bclk;
|
||||
@@ -354,7 +359,7 @@ static void stm32_adc_irq_handler(struct irq_desc *desc)
|
||||
* before invoking the interrupt handler (e.g. call ISR only for
|
||||
* IRQ-enabled ADCs).
|
||||
*/
|
||||
for (i = 0; i < priv->cfg->num_adcs; i++) {
|
||||
for (i = 0; i < priv->nb_adc_max; i++) {
|
||||
if ((status & priv->cfg->regs->eoc_msk[i] &&
|
||||
stm32_adc_eoc_enabled(priv, i)) ||
|
||||
(status & priv->cfg->regs->ovr_msk[i]))
|
||||
@@ -424,7 +429,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
|
||||
int hwirq;
|
||||
unsigned int i;
|
||||
|
||||
for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++)
|
||||
for (hwirq = 0; hwirq < priv->nb_adc_max; hwirq++)
|
||||
irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
|
||||
irq_domain_remove(priv->domain);
|
||||
|
||||
@@ -642,6 +647,49 @@ static int stm32_adc_core_switches_probe(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_probe_identification(struct platform_device *pdev,
|
||||
struct stm32_adc_priv *priv)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device_node *child;
|
||||
const char *compat;
|
||||
int ret, count = 0;
|
||||
u32 id, val;
|
||||
|
||||
if (!priv->cfg->ipid)
|
||||
return 0;
|
||||
|
||||
id = FIELD_GET(STM32MP1_IPIDR_MASK,
|
||||
readl_relaxed(priv->common.base + STM32MP1_ADC_IPDR));
|
||||
if (id != priv->cfg->ipid) {
|
||||
dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
ret = of_property_read_string(child, "compatible", &compat);
|
||||
if (ret)
|
||||
continue;
|
||||
/* Count child nodes with stm32 adc compatible */
|
||||
if (strstr(compat, "st,stm32") && strstr(compat, "adc"))
|
||||
count++;
|
||||
}
|
||||
|
||||
val = readl_relaxed(priv->common.base + STM32MP1_ADC_HWCFGR0);
|
||||
priv->nb_adc_max = FIELD_GET(STM32MP1_ADCNUM_MASK, val);
|
||||
if (count > priv->nb_adc_max) {
|
||||
dev_err(&pdev->dev, "Unexpected child number: %d", count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val = readl_relaxed(priv->common.base + STM32MP1_ADC_VERR);
|
||||
dev_dbg(&pdev->dev, "ADC version: %lu.%lu\n",
|
||||
FIELD_GET(STM32MP1_MAJREV_MASK, val),
|
||||
FIELD_GET(STM32MP1_MINREV_MASK, val));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_adc_priv *priv;
|
||||
@@ -661,6 +709,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
|
||||
priv->cfg = (const struct stm32_adc_priv_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
priv->nb_adc_max = priv->cfg->num_adcs;
|
||||
spin_lock_init(&priv->common.lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -703,6 +752,10 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_pm_stop;
|
||||
|
||||
ret = stm32_adc_probe_identification(pdev, priv);
|
||||
if (ret < 0)
|
||||
goto err_hw_stop;
|
||||
|
||||
ret = regulator_get_voltage(priv->vref);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret);
|
||||
@@ -811,8 +864,8 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
|
||||
.clk_sel = stm32h7_adc_clk_sel,
|
||||
.max_clk_rate_hz = 36000000,
|
||||
.has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD,
|
||||
.ipid = STM32MP15_IPIDR_NUMBER,
|
||||
.num_irqs = 2,
|
||||
.num_adcs = 2,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_adc_of_match[] = {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* | 0x300 | Master & Slave common regs |
|
||||
* --------------------------------------------------------
|
||||
*/
|
||||
/* Maximum ADC instances number per ADC block for all supported SoCs */
|
||||
#define STM32_ADC_MAX_ADCS 3
|
||||
#define STM32_ADC_OFFSET 0x100
|
||||
#define STM32_ADCX_COMN_OFFSET 0x300
|
||||
@@ -105,6 +106,12 @@
|
||||
/* STM32MP1 - ADC2 instance option register */
|
||||
#define STM32MP1_ADC2_OR 0xD0
|
||||
|
||||
/* STM32MP1 - Identification registers */
|
||||
#define STM32MP1_ADC_HWCFGR0 0x3F0
|
||||
#define STM32MP1_ADC_VERR 0x3F4
|
||||
#define STM32MP1_ADC_IPDR 0x3F8
|
||||
#define STM32MP1_ADC_SIDR 0x3FC
|
||||
|
||||
/* STM32H7 - common registers for all ADC instances */
|
||||
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
|
||||
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
|
||||
@@ -181,6 +188,30 @@ enum stm32h7_adc_dmngt {
|
||||
/* STM32MP1_ADC2_OR - bit fields */
|
||||
#define STM32MP1_VDDCOREEN BIT(0)
|
||||
|
||||
/* STM32MP1_ADC_HWCFGR0 - bit fields */
|
||||
#define STM32MP1_ADCNUM_SHIFT 0
|
||||
#define STM32MP1_ADCNUM_MASK GENMASK(3, 0)
|
||||
#define STM32MP1_MULPIPE_SHIFT 4
|
||||
#define STM32MP1_MULPIPE_MASK GENMASK(7, 4)
|
||||
#define STM32MP1_OPBITS_SHIFT 8
|
||||
#define STM32MP1_OPBITS_MASK GENMASK(11, 8)
|
||||
#define STM32MP1_IDLEVALUE_SHIFT 12
|
||||
#define STM32MP1_IDLEVALUE_MASK GENMASK(15, 12)
|
||||
|
||||
/* STM32MP1_ADC_VERR - bit fields */
|
||||
#define STM32MP1_MINREV_SHIFT 0
|
||||
#define STM32MP1_MINREV_MASK GENMASK(3, 0)
|
||||
#define STM32MP1_MAJREV_SHIFT 4
|
||||
#define STM32MP1_MAJREV_MASK GENMASK(7, 4)
|
||||
|
||||
/* STM32MP1_ADC_IPDR - bit fields */
|
||||
#define STM32MP1_IPIDR_MASK GENMASK(31, 0)
|
||||
|
||||
/* STM32MP1_ADC_SIDR - bit fields */
|
||||
#define STM32MP1_SIDR_MASK GENMASK(31, 0)
|
||||
|
||||
#define STM32MP15_IPIDR_NUMBER 0x00110005
|
||||
|
||||
/**
|
||||
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
|
||||
* @base: control registers base cpu addr
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/nvmem-consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "stm32-adc-core.h"
|
||||
|
||||
@@ -241,6 +241,7 @@ struct stm32_adc_cfg {
|
||||
* @chan_name: channel name array
|
||||
* @num_diff: number of differential channels
|
||||
* @int_ch: internal channel indexes array
|
||||
* @nsmps: number of channels with optional sample time
|
||||
*/
|
||||
struct stm32_adc {
|
||||
struct stm32_adc_common *common;
|
||||
@@ -267,6 +268,7 @@ struct stm32_adc {
|
||||
char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
|
||||
u32 num_diff;
|
||||
int int_ch[STM32_ADC_INT_CH_NB];
|
||||
int nsmps;
|
||||
};
|
||||
|
||||
struct stm32_adc_diff_channel {
|
||||
@@ -1520,8 +1522,8 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
|
||||
const struct of_phandle_args *iiospec)
|
||||
static int stm32_adc_fwnode_xlate(struct iio_dev *indio_dev,
|
||||
const struct fwnode_reference_args *iiospec)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -1575,7 +1577,7 @@ static const struct iio_info stm32_adc_iio_info = {
|
||||
.hwfifo_set_watermark = stm32_adc_set_watermark,
|
||||
.update_scan_mode = stm32_adc_update_scan_mode,
|
||||
.debugfs_reg_access = stm32_adc_debugfs_reg_access,
|
||||
.of_xlate = stm32_adc_of_xlate,
|
||||
.fwnode_xlate = stm32_adc_fwnode_xlate,
|
||||
};
|
||||
|
||||
static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc)
|
||||
@@ -1772,14 +1774,14 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
|
||||
{},
|
||||
};
|
||||
|
||||
static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev)
|
||||
static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct device *dev = &indio_dev->dev;
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
unsigned int i;
|
||||
u32 res;
|
||||
|
||||
if (of_property_read_u32(node, "assigned-resolution-bits", &res))
|
||||
if (device_property_read_u32(dev, "assigned-resolution-bits", &res))
|
||||
res = adc->cfg->adc_info->resolutions[0];
|
||||
|
||||
for (i = 0; i < adc->cfg->adc_info->num_res; i++)
|
||||
@@ -1863,11 +1865,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
|
||||
|
||||
static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct device *dev = &indio_dev->dev;
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
int num_channels = 0, ret;
|
||||
|
||||
ret = of_property_count_u32_elems(node, "st,adc-channels");
|
||||
ret = device_property_count_u32(dev, "st,adc-channels");
|
||||
if (ret > adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Bad st,adc-channels?\n");
|
||||
return -EINVAL;
|
||||
@@ -1875,8 +1877,15 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm
|
||||
num_channels += ret;
|
||||
}
|
||||
|
||||
ret = of_property_count_elems_of_size(node, "st,adc-diff-channels",
|
||||
sizeof(struct stm32_adc_diff_channel));
|
||||
/*
|
||||
* each st,adc-diff-channels is a group of 2 u32 so we divide @ret
|
||||
* to get the *real* number of channels.
|
||||
*/
|
||||
ret = device_property_count_u32(dev, "st,adc-diff-channels");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32));
|
||||
if (ret > adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
|
||||
return -EINVAL;
|
||||
@@ -1886,8 +1895,8 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm
|
||||
}
|
||||
|
||||
/* Optional sample time is provided either for each, or all channels */
|
||||
ret = of_property_count_u32_elems(node, "st,min-sample-time-nsecs");
|
||||
if (ret > 1 && ret != num_channels) {
|
||||
adc->nsmps = device_property_count_u32(dev, "st,min-sample-time-nsecs");
|
||||
if (adc->nsmps > 1 && adc->nsmps != num_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -1897,21 +1906,20 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm
|
||||
|
||||
static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
|
||||
struct stm32_adc *adc,
|
||||
struct iio_chan_spec *channels)
|
||||
struct iio_chan_spec *channels,
|
||||
int nchans)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
|
||||
struct device *dev = &indio_dev->dev;
|
||||
u32 num_diff = adc->num_diff;
|
||||
int size = num_diff * sizeof(*diff) / sizeof(u32);
|
||||
int scan_index = 0, val, ret, i;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
u32 smp = 0;
|
||||
int scan_index = 0, ret, i, c;
|
||||
u32 smp = 0, smps[STM32_ADC_CH_MAX], chans[STM32_ADC_CH_MAX];
|
||||
|
||||
if (num_diff) {
|
||||
ret = of_property_read_u32_array(node, "st,adc-diff-channels",
|
||||
(u32 *)diff, size);
|
||||
ret = device_property_read_u32_array(dev, "st,adc-diff-channels",
|
||||
(u32 *)diff, size);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret);
|
||||
return ret;
|
||||
@@ -1932,32 +1940,47 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
|
||||
}
|
||||
}
|
||||
|
||||
of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) {
|
||||
if (val >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
|
||||
ret = device_property_read_u32_array(dev, "st,adc-channels", chans,
|
||||
nchans);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (c = 0; c < nchans; c++) {
|
||||
if (chans[c] >= adc_info->max_channels) {
|
||||
dev_err(&indio_dev->dev, "Invalid channel %d\n",
|
||||
chans[c]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Channel can't be configured both as single-ended & diff */
|
||||
for (i = 0; i < num_diff; i++) {
|
||||
if (val == diff[i].vinp) {
|
||||
dev_err(&indio_dev->dev, "channel %d misconfigured\n", val);
|
||||
if (chans[c] == diff[i].vinp) {
|
||||
dev_err(&indio_dev->dev, "channel %d misconfigured\n", chans[c]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
|
||||
0, scan_index, false);
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
|
||||
chans[c], 0, scan_index, false);
|
||||
scan_index++;
|
||||
}
|
||||
|
||||
if (adc->nsmps > 0) {
|
||||
ret = device_property_read_u32_array(dev, "st,min-sample-time-nsecs",
|
||||
smps, adc->nsmps);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < scan_index; i++) {
|
||||
/*
|
||||
* Using of_property_read_u32_index(), smp value will only be
|
||||
* modified if valid u32 value can be decoded. This allows to
|
||||
* get either no value, 1 shared value for all indexes, or one
|
||||
* value per channel.
|
||||
* This check is used with the above logic so that smp value
|
||||
* will only be modified if valid u32 value can be decoded. This
|
||||
* allows to get either no value, 1 shared value for all indexes,
|
||||
* or one value per channel. The point is to have the same
|
||||
* behavior as 'of_property_read_u32_index()'.
|
||||
*/
|
||||
of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp);
|
||||
if (i < adc->nsmps)
|
||||
smp = smps[i];
|
||||
|
||||
/* Prepare sampling time settings */
|
||||
stm32_adc_smpr_init(adc, channels[i].channel, smp);
|
||||
@@ -2005,22 +2028,21 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
|
||||
struct stm32_adc *adc,
|
||||
struct iio_chan_spec *channels)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct device_node *child;
|
||||
struct fwnode_handle *child;
|
||||
const char *name;
|
||||
int val, scan_index = 0, ret;
|
||||
bool differential;
|
||||
u32 vin[2];
|
||||
|
||||
for_each_available_child_of_node(node, child) {
|
||||
ret = of_property_read_u32(child, "reg", &val);
|
||||
device_for_each_child_node(&indio_dev->dev, child) {
|
||||
ret = fwnode_property_read_u32(child, "reg", &val);
|
||||
if (ret) {
|
||||
dev_err(&indio_dev->dev, "Missing channel index %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = of_property_read_string(child, "label", &name);
|
||||
ret = fwnode_property_read_string(child, "label", &name);
|
||||
/* label is optional */
|
||||
if (!ret) {
|
||||
if (strlen(name) >= STM32_ADC_CH_SZ) {
|
||||
@@ -2047,7 +2069,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
|
||||
}
|
||||
|
||||
differential = false;
|
||||
ret = of_property_read_u32_array(child, "diff-channels", vin, 2);
|
||||
ret = fwnode_property_read_u32_array(child, "diff-channels", vin, 2);
|
||||
/* diff-channels is optional */
|
||||
if (!ret) {
|
||||
differential = true;
|
||||
@@ -2064,7 +2086,7 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
|
||||
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
|
||||
vin[1], scan_index, differential);
|
||||
|
||||
ret = of_property_read_u32(child, "st,min-sample-time-ns", &val);
|
||||
ret = fwnode_property_read_u32(child, "st,min-sample-time-ns", &val);
|
||||
/* st,min-sample-time-ns is optional */
|
||||
if (!ret) {
|
||||
stm32_adc_smpr_init(adc, channels[scan_index].channel, val);
|
||||
@@ -2082,14 +2104,13 @@ static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
|
||||
return scan_index;
|
||||
|
||||
err:
|
||||
of_node_put(child);
|
||||
fwnode_handle_put(child);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
{
|
||||
struct device_node *node = indio_dev->dev.of_node;
|
||||
struct stm32_adc *adc = iio_priv(indio_dev);
|
||||
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
|
||||
struct iio_chan_spec *channels;
|
||||
@@ -2099,7 +2120,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
|
||||
adc->int_ch[i] = STM32_ADC_INT_CH_NONE;
|
||||
|
||||
num_channels = of_get_available_child_count(node);
|
||||
num_channels = device_get_child_node_count(&indio_dev->dev);
|
||||
/* If no channels have been found, fallback to channels legacy properties. */
|
||||
if (!num_channels) {
|
||||
legacy = true;
|
||||
@@ -2130,7 +2151,8 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev, bool timestamping)
|
||||
return -ENOMEM;
|
||||
|
||||
if (legacy)
|
||||
ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels);
|
||||
ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels,
|
||||
num_channels);
|
||||
else
|
||||
ret = stm32_adc_generic_chan_init(indio_dev, adc, channels);
|
||||
if (ret < 0)
|
||||
@@ -2212,9 +2234,6 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
bool timestamping = false;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
return -ENODEV;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
@@ -2223,17 +2242,16 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
adc->common = dev_get_drvdata(pdev->dev.parent);
|
||||
spin_lock_init(&adc->lock);
|
||||
init_completion(&adc->completion);
|
||||
adc->cfg = (const struct stm32_adc_cfg *)
|
||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
||||
adc->cfg = device_get_match_data(dev);
|
||||
|
||||
indio_dev->name = dev_name(&pdev->dev);
|
||||
indio_dev->dev.of_node = pdev->dev.of_node;
|
||||
device_set_node(&indio_dev->dev, dev_fwnode(&pdev->dev));
|
||||
indio_dev->info = &stm32_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED;
|
||||
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, "reg", &adc->offset);
|
||||
ret = device_property_read_u32(dev, "reg", &adc->offset);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "missing reg property\n");
|
||||
return -EINVAL;
|
||||
@@ -2262,7 +2280,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
ret = stm32_adc_of_get_resolution(indio_dev);
|
||||
ret = stm32_adc_fw_get_resolution(indio_dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -2279,7 +2297,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
|
||||
timestamping = true;
|
||||
}
|
||||
|
||||
ret = stm32_adc_chan_of_init(indio_dev, timestamping);
|
||||
ret = stm32_adc_chan_fw_init(indio_dev, timestamping);
|
||||
if (ret < 0)
|
||||
goto err_dma_disable;
|
||||
|
||||
|
||||
@@ -1,402 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* IIO driver for the Apex Embedded Systems STX104
|
||||
* Copyright (C) 2016 William Breathitt Gray
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/types.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/isa.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define STX104_OUT_CHAN(chan) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = chan, \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.output = 1 \
|
||||
}
|
||||
#define STX104_IN_CHAN(chan, diff) { \
|
||||
.type = IIO_VOLTAGE, \
|
||||
.channel = chan, \
|
||||
.channel2 = chan, \
|
||||
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
|
||||
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
.indexed = 1, \
|
||||
.differential = diff \
|
||||
}
|
||||
|
||||
#define STX104_NUM_OUT_CHAN 2
|
||||
|
||||
#define STX104_EXTENT 16
|
||||
|
||||
static unsigned int base[max_num_isa_dev(STX104_EXTENT)];
|
||||
static unsigned int num_stx104;
|
||||
module_param_hw_array(base, uint, ioport, &num_stx104, 0);
|
||||
MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
|
||||
|
||||
/**
|
||||
* struct stx104_reg - device register structure
|
||||
* @ssr_ad: Software Strobe Register and ADC Data
|
||||
* @achan: ADC Channel
|
||||
* @dio: Digital I/O
|
||||
* @dac: DAC Channels
|
||||
* @cir_asr: Clear Interrupts and ADC Status
|
||||
* @acr: ADC Control
|
||||
* @pccr_fsh: Pacer Clock Control and FIFO Status MSB
|
||||
* @acfg: ADC Configuration
|
||||
*/
|
||||
struct stx104_reg {
|
||||
u16 ssr_ad;
|
||||
u8 achan;
|
||||
u8 dio;
|
||||
u16 dac[2];
|
||||
u8 cir_asr;
|
||||
u8 acr;
|
||||
u8 pccr_fsh;
|
||||
u8 acfg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stx104_iio - IIO device private data structure
|
||||
* @chan_out_states: channels' output states
|
||||
* @reg: I/O address offset for the device registers
|
||||
*/
|
||||
struct stx104_iio {
|
||||
unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
|
||||
struct stx104_reg __iomem *reg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stx104_gpio - GPIO device private data structure
|
||||
* @chip: instance of the gpio_chip
|
||||
* @lock: synchronization lock to prevent I/O race conditions
|
||||
* @base: base port address of the GPIO device
|
||||
* @out_state: output bits state
|
||||
*/
|
||||
struct stx104_gpio {
|
||||
struct gpio_chip chip;
|
||||
spinlock_t lock;
|
||||
u8 __iomem *base;
|
||||
unsigned int out_state;
|
||||
};
|
||||
|
||||
static int stx104_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
|
||||
{
|
||||
struct stx104_iio *const priv = iio_priv(indio_dev);
|
||||
struct stx104_reg __iomem *const reg = priv->reg;
|
||||
unsigned int adc_config;
|
||||
int adbu;
|
||||
int gain;
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
/* get gain configuration */
|
||||
adc_config = ioread8(®->acfg);
|
||||
gain = adc_config & 0x3;
|
||||
|
||||
*val = 1 << gain;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->output) {
|
||||
*val = priv->chan_out_states[chan->channel];
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
/* select ADC channel */
|
||||
iowrite8(chan->channel | (chan->channel << 4), ®->achan);
|
||||
|
||||
/* trigger ADC sample capture by writing to the 8-bit
|
||||
* Software Strobe Register and wait for completion
|
||||
*/
|
||||
iowrite8(0, ®->ssr_ad);
|
||||
while (ioread8(®->cir_asr) & BIT(7));
|
||||
|
||||
*val = ioread16(®->ssr_ad);
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_OFFSET:
|
||||
/* get ADC bipolar/unipolar configuration */
|
||||
adc_config = ioread8(®->acfg);
|
||||
adbu = !(adc_config & BIT(2));
|
||||
|
||||
*val = -32768 * adbu;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
/* get ADC bipolar/unipolar and gain configuration */
|
||||
adc_config = ioread8(®->acfg);
|
||||
adbu = !(adc_config & BIT(2));
|
||||
gain = adc_config & 0x3;
|
||||
|
||||
*val = 5;
|
||||
*val2 = 15 - adbu + gain;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int stx104_write_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan, int val, int val2, long mask)
|
||||
{
|
||||
struct stx104_iio *const priv = iio_priv(indio_dev);
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_HARDWAREGAIN:
|
||||
/* Only four gain states (x1, x2, x4, x8) */
|
||||
switch (val) {
|
||||
case 1:
|
||||
iowrite8(0, &priv->reg->acfg);
|
||||
break;
|
||||
case 2:
|
||||
iowrite8(1, &priv->reg->acfg);
|
||||
break;
|
||||
case 4:
|
||||
iowrite8(2, &priv->reg->acfg);
|
||||
break;
|
||||
case 8:
|
||||
iowrite8(3, &priv->reg->acfg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (chan->output) {
|
||||
/* DAC can only accept up to a 16-bit value */
|
||||
if ((unsigned int)val > 65535)
|
||||
return -EINVAL;
|
||||
|
||||
priv->chan_out_states[chan->channel] = val;
|
||||
iowrite16(val, &priv->reg->dac[chan->channel]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct iio_info stx104_info = {
|
||||
.read_raw = stx104_read_raw,
|
||||
.write_raw = stx104_write_raw
|
||||
};
|
||||
|
||||
/* single-ended input channels configuration */
|
||||
static const struct iio_chan_spec stx104_channels_sing[] = {
|
||||
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
|
||||
STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
|
||||
STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
|
||||
STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
|
||||
STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
|
||||
STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
|
||||
STX104_IN_CHAN(15, 0)
|
||||
};
|
||||
/* differential input channels configuration */
|
||||
static const struct iio_chan_spec stx104_channels_diff[] = {
|
||||
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
|
||||
STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
|
||||
STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
|
||||
STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
|
||||
};
|
||||
|
||||
static int stx104_gpio_get_direction(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
/* GPIO 0-3 are input only, while the rest are output only */
|
||||
if (offset < 4)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
if (offset >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
if (offset < 4)
|
||||
return -EINVAL;
|
||||
|
||||
chip->set(chip, offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
|
||||
if (offset >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
return !!(ioread8(stx104gpio->base) & BIT(offset));
|
||||
}
|
||||
|
||||
static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
|
||||
*bits = ioread8(stx104gpio->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
const unsigned int mask = BIT(offset) >> 4;
|
||||
unsigned long flags;
|
||||
|
||||
if (offset < 4)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&stx104gpio->lock, flags);
|
||||
|
||||
if (value)
|
||||
stx104gpio->out_state |= mask;
|
||||
else
|
||||
stx104gpio->out_state &= ~mask;
|
||||
|
||||
iowrite8(stx104gpio->out_state, stx104gpio->base);
|
||||
|
||||
spin_unlock_irqrestore(&stx104gpio->lock, flags);
|
||||
}
|
||||
|
||||
#define STX104_NGPIO 8
|
||||
static const char *stx104_names[STX104_NGPIO] = {
|
||||
"DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
|
||||
};
|
||||
|
||||
static void stx104_gpio_set_multiple(struct gpio_chip *chip,
|
||||
unsigned long *mask, unsigned long *bits)
|
||||
{
|
||||
struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
|
||||
unsigned long flags;
|
||||
|
||||
/* verify masked GPIO are output */
|
||||
if (!(*mask & 0xF0))
|
||||
return;
|
||||
|
||||
*mask >>= 4;
|
||||
*bits >>= 4;
|
||||
|
||||
spin_lock_irqsave(&stx104gpio->lock, flags);
|
||||
|
||||
stx104gpio->out_state &= ~*mask;
|
||||
stx104gpio->out_state |= *mask & *bits;
|
||||
iowrite8(stx104gpio->out_state, stx104gpio->base);
|
||||
|
||||
spin_unlock_irqrestore(&stx104gpio->lock, flags);
|
||||
}
|
||||
|
||||
static int stx104_probe(struct device *dev, unsigned int id)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
struct stx104_iio *priv;
|
||||
struct stx104_gpio *stx104gpio;
|
||||
int err;
|
||||
|
||||
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL);
|
||||
if (!stx104gpio)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!devm_request_region(dev, base[id], STX104_EXTENT,
|
||||
dev_name(dev))) {
|
||||
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
|
||||
base[id], base[id] + STX104_EXTENT);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
priv = iio_priv(indio_dev);
|
||||
priv->reg = devm_ioport_map(dev, base[id], STX104_EXTENT);
|
||||
if (!priv->reg)
|
||||
return -ENOMEM;
|
||||
|
||||
indio_dev->info = &stx104_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
/* determine if differential inputs */
|
||||
if (ioread8(&priv->reg->cir_asr) & BIT(5)) {
|
||||
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
|
||||
indio_dev->channels = stx104_channels_diff;
|
||||
} else {
|
||||
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
|
||||
indio_dev->channels = stx104_channels_sing;
|
||||
}
|
||||
|
||||
indio_dev->name = dev_name(dev);
|
||||
|
||||
/* configure device for software trigger operation */
|
||||
iowrite8(0, &priv->reg->acr);
|
||||
|
||||
/* initialize gain setting to x1 */
|
||||
iowrite8(0, &priv->reg->acfg);
|
||||
|
||||
/* initialize DAC output to 0V */
|
||||
iowrite16(0, &priv->reg->dac[0]);
|
||||
iowrite16(0, &priv->reg->dac[1]);
|
||||
|
||||
stx104gpio->chip.label = dev_name(dev);
|
||||
stx104gpio->chip.parent = dev;
|
||||
stx104gpio->chip.owner = THIS_MODULE;
|
||||
stx104gpio->chip.base = -1;
|
||||
stx104gpio->chip.ngpio = STX104_NGPIO;
|
||||
stx104gpio->chip.names = stx104_names;
|
||||
stx104gpio->chip.get_direction = stx104_gpio_get_direction;
|
||||
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
|
||||
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
|
||||
stx104gpio->chip.get = stx104_gpio_get;
|
||||
stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
|
||||
stx104gpio->chip.set = stx104_gpio_set;
|
||||
stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
|
||||
stx104gpio->base = &priv->reg->dio;
|
||||
stx104gpio->out_state = 0x0;
|
||||
|
||||
spin_lock_init(&stx104gpio->lock);
|
||||
|
||||
err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
|
||||
if (err) {
|
||||
dev_err(dev, "GPIO registering failed (%d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
|
||||
static struct isa_driver stx104_driver = {
|
||||
.probe = stx104_probe,
|
||||
.driver = {
|
||||
.name = "stx104"
|
||||
},
|
||||
};
|
||||
|
||||
module_isa_driver(stx104_driver, num_stx104);
|
||||
|
||||
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
|
||||
MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -797,13 +797,6 @@ static void ads131e08_regulator_disable(void *data)
|
||||
regulator_disable(st->vref_reg);
|
||||
}
|
||||
|
||||
static void ads131e08_clk_disable(void *data)
|
||||
{
|
||||
struct ads131e08_state *st = data;
|
||||
|
||||
clk_disable_unprepare(st->adc_clk);
|
||||
}
|
||||
|
||||
static int ads131e08_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct ads131e08_info *info;
|
||||
@@ -896,21 +889,11 @@ static int ads131e08_probe(struct spi_device *spi)
|
||||
st->vref_reg = NULL;
|
||||
}
|
||||
|
||||
st->adc_clk = devm_clk_get(&spi->dev, "adc-clk");
|
||||
st->adc_clk = devm_clk_get_enabled(&spi->dev, "adc-clk");
|
||||
if (IS_ERR(st->adc_clk))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(st->adc_clk),
|
||||
"failed to get the ADC clock\n");
|
||||
|
||||
ret = clk_prepare_enable(st->adc_clk);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "failed to prepare/enable the ADC clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(&spi->dev, ads131e08_clk_disable, st);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
adc_clk_hz = clk_get_rate(st->adc_clk);
|
||||
if (!adc_clk_hz) {
|
||||
dev_err(&spi->dev, "failed to get the ADC clock rate\n");
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@@ -139,6 +141,7 @@ enum tsc2046_state {
|
||||
struct tsc2046_adc_priv {
|
||||
struct spi_device *spi;
|
||||
const struct tsc2046_adc_dcfg *dcfg;
|
||||
struct regulator *vref_reg;
|
||||
|
||||
struct iio_trigger *trig;
|
||||
struct hrtimer trig_timer;
|
||||
@@ -173,6 +176,7 @@ struct tsc2046_adc_priv {
|
||||
u32 scan_interval_us;
|
||||
u32 time_per_scan_us;
|
||||
u32 time_per_bit_ns;
|
||||
unsigned int vref_mv;
|
||||
|
||||
struct tsc2046_adc_ch_cfg ch_cfg[TI_TSC2046_MAX_CHAN];
|
||||
};
|
||||
@@ -252,7 +256,9 @@ static u8 tsc2046_adc_get_cmd(struct tsc2046_adc_priv *priv, int ch_idx,
|
||||
case TI_TSC2046_ADDR_AUX:
|
||||
case TI_TSC2046_ADDR_VBAT:
|
||||
case TI_TSC2046_ADDR_TEMP0:
|
||||
pd |= TI_TSC2046_SER | TI_TSC2046_PD1_VREF_ON;
|
||||
pd |= TI_TSC2046_SER;
|
||||
if (!priv->vref_reg)
|
||||
pd |= TI_TSC2046_PD1_VREF_ON;
|
||||
}
|
||||
|
||||
return TI_TSC2046_START | FIELD_PREP(TI_TSC2046_ADDR, ch_idx) | pd;
|
||||
@@ -468,7 +474,7 @@ static int tsc2046_adc_read_raw(struct iio_dev *indio_dev,
|
||||
* So, it is better to use external voltage-divider driver
|
||||
* instead, which is calculating complete chain.
|
||||
*/
|
||||
*val = TI_TSC2046_INT_VREF;
|
||||
*val = priv->vref_mv;
|
||||
*val2 = chan->scan_type.realbits;
|
||||
return IIO_VAL_FRACTIONAL_LOG2;
|
||||
}
|
||||
@@ -740,6 +746,49 @@ static void tsc2046_adc_parse_fwnode(struct tsc2046_adc_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static void tsc2046_adc_regulator_disable(void *data)
|
||||
{
|
||||
struct tsc2046_adc_priv *priv = data;
|
||||
|
||||
regulator_disable(priv->vref_reg);
|
||||
}
|
||||
|
||||
static int tsc2046_adc_configure_regulator(struct tsc2046_adc_priv *priv)
|
||||
{
|
||||
struct device *dev = &priv->spi->dev;
|
||||
int ret;
|
||||
|
||||
priv->vref_reg = devm_regulator_get_optional(dev, "vref");
|
||||
if (IS_ERR(priv->vref_reg)) {
|
||||
/* If regulator exists but can't be get, return an error */
|
||||
if (PTR_ERR(priv->vref_reg) != -ENODEV)
|
||||
return PTR_ERR(priv->vref_reg);
|
||||
priv->vref_reg = NULL;
|
||||
}
|
||||
if (!priv->vref_reg) {
|
||||
/* Use internal reference */
|
||||
priv->vref_mv = TI_TSC2046_INT_VREF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = regulator_enable(priv->vref_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, tsc2046_adc_regulator_disable,
|
||||
priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_get_voltage(priv->vref_reg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->vref_mv = ret / MILLI;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsc2046_adc_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct tsc2046_adc_dcfg *dcfg;
|
||||
@@ -756,6 +805,11 @@ static int tsc2046_adc_probe(struct spi_device *spi)
|
||||
}
|
||||
|
||||
dcfg = device_get_match_data(dev);
|
||||
if (!dcfg) {
|
||||
const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
|
||||
dcfg = (const struct tsc2046_adc_dcfg *)id->driver_data;
|
||||
}
|
||||
if (!dcfg)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -781,6 +835,10 @@ static int tsc2046_adc_probe(struct spi_device *spi)
|
||||
indio_dev->num_channels = dcfg->num_channels;
|
||||
indio_dev->info = &tsc2046_adc_info;
|
||||
|
||||
ret = tsc2046_adc_configure_regulator(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tsc2046_adc_parse_fwnode(priv);
|
||||
|
||||
ret = tsc2046_adc_setup_spi_msg(priv);
|
||||
@@ -833,11 +891,18 @@ static const struct of_device_id ads7950_of_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ads7950_of_table);
|
||||
|
||||
static const struct spi_device_id tsc2046_adc_spi_ids[] = {
|
||||
{ "tsc2046e-adc", (unsigned long)&tsc2046_adc_dcfg_tsc2046e },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(spi, tsc2046_adc_spi_ids);
|
||||
|
||||
static struct spi_driver tsc2046_adc_driver = {
|
||||
.driver = {
|
||||
.name = "tsc2046",
|
||||
.of_match_table = ads7950_of_table,
|
||||
},
|
||||
.id_table = tsc2046_adc_spi_ids,
|
||||
.probe = tsc2046_adc_probe,
|
||||
};
|
||||
module_spi_driver(tsc2046_adc_driver);
|
||||
|
||||
@@ -1351,11 +1351,6 @@ static const struct of_device_id ams_of_match_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ams_of_match_table);
|
||||
|
||||
static void ams_clk_disable_unprepare(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
static int ams_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev;
|
||||
@@ -1380,18 +1375,10 @@ static int ams_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(ams->base))
|
||||
return PTR_ERR(ams->base);
|
||||
|
||||
ams->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
ams->clk = devm_clk_get_enabled(&pdev->dev, NULL);
|
||||
if (IS_ERR(ams->clk))
|
||||
return PTR_ERR(ams->clk);
|
||||
|
||||
ret = clk_prepare_enable(ams->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(&pdev->dev, ams_clk_disable_unprepare, ams->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = devm_delayed_work_autocancel(&pdev->dev, &ams->ams_unmask_work,
|
||||
ams_unmask_worker);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -1296,13 +1296,6 @@ static const char * const xadc_type_names[] = {
|
||||
[XADC_TYPE_US] = "xilinx-system-monitor",
|
||||
};
|
||||
|
||||
static void xadc_clk_disable_unprepare(void *data)
|
||||
{
|
||||
struct clk *clk = data;
|
||||
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
static void xadc_cancel_delayed_work(void *data)
|
||||
{
|
||||
struct delayed_work *work = data;
|
||||
@@ -1374,19 +1367,10 @@ static int xadc_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
xadc->clk = devm_clk_get(dev, NULL);
|
||||
xadc->clk = devm_clk_get_enabled(dev, NULL);
|
||||
if (IS_ERR(xadc->clk))
|
||||
return PTR_ERR(xadc->clk);
|
||||
|
||||
ret = clk_prepare_enable(xadc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_add_action_or_reset(dev,
|
||||
xadc_clk_disable_unprepare, xadc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Make sure not to exceed the maximum samplerate since otherwise the
|
||||
* resulting interrupt storm will soft-lock the system.
|
||||
|
||||
Reference in New Issue
Block a user