Commit 82aec3ed authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-4.16a' of...

Merge tag 'iio-for-4.16a' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

First set of new device support, cleanups and features for IIO in the 4.16 cycle

New device support
* IDT Z0PT2201 ambient light and UVB sensor
  - new driver and DT bindings.
* MAX30102 (pulse oximetery sensor)
  - support for MAX30105 sensor (smoke detector)  Just goes to show
    how two supposedly totally different applications can use very similar
    devices.
* UVIS25 UV sensor
  - new driver and DT bindings.

Major new features
* at91-sama5d2-adc
  - DMA support including bindings + a fix for an issue with acking the
    interrupt to prevent false overrun reports.
* ina2xx
  - allow control of shunt voltage PGA and bus voltage range to give better
    accuracy in some cases.
* stm32-adc
  - support differential channels (precursor patch reworked how channel names
    were created to enable this).

Cleanups / minor fixes / features
* core
  - mark a deliberate switch fallthrough.
  - macro to populate struct iio_map array elements.
* docs
  - typo fix.
* MAINTAINERS
  - add some missing entries for IIO ABI files.

* ad7152
  - tidy up unlocking paths.
* ad7746
  - tidy up unlocking paths.
* ak8975
  - add an ACPI id found on a prototype board.
* aspeed-adc
  - deassert reset in probe to ensure device is usable.
* bfin-trigger
  - platform_get_irq return value fixing.
* bmc150
  - OF device ID table for i2c (spi to be done).
* cros_ec
  - unused variable cleanup.
* da208
  - ACPI binding seen on Linx 820 tablet.
* ina2xx
  - shift down raw value to drop status flags from value (likely to have
    been hidden in the noise).
  - tidy up a special case that wasn't needed.
* inv_mpu6050
  - i2c_unregister_device knows about null values so don't check it twice.
* kxsd9
  - fix missing MODULE_LICENSE and MODULE_DESCRIPTION.
* max30102
  - missing new lines in dev_err.
  - inconsistent punctuation in error messages.
  - fix LED mode mask number of bits.
  - check return value of power mode functions to handle errors.
  - introduce an intensity channel macro to reduce duplication.
  - fix minor issue where device wasn't necessarily enabled during
    a get temperature.
  - use indicies for LED channels.
  - move the mode seetting to buffer_postenable - precursor to new device
    support.
  - prepare to allow copying of varying numbers of measurement.
* meson-saradc
  - drop irrelevant clock and update bindings.
* mma8452
  - a couple of renames for readability reasons.
* qcom_vadc
  - fix missing MODULE_LICENSE and MODULE_DESCRIPTION.
* st_accel
  - drop an unused variable.
* sx9500
  - add an ACPI id found on a prototype board.
parents dfe571ac 8d05ffd2
......@@ -1290,7 +1290,7 @@ KernelVersion: 3.4
Contact: linux-iio@vger.kernel.org
Description:
Unit-less light intensity. Modifiers both and ir indicate
that measurements contains visible and infrared light
that measurements contain visible and infrared light
components or just infrared light, respectively. Modifier uv indicates
that measurements contain ultraviolet light components.
......
......@@ -15,7 +15,6 @@ Required properties:
- "clkin" for the reference clock (typically XTAL)
- "core" for the SAR ADC core clock
optional clocks:
- "sana" for the analog clock
- "adc_clk" for the ADC (sampling) clock
- "adc_sel" for the ADC (sampling) clock mux
- vref-supply: the regulator supply for the ADC reference voltage
......
......@@ -8,6 +8,7 @@ Required properties:
- reg: memory window mapping address and length
- clocks: Input clock used to derive the sample clock. Expected to be the
SoC's APB clock.
- resets: Reset controller phandle
- #io-channel-cells: Must be set to <1> to indicate channels are selected
by index.
......@@ -15,6 +16,7 @@ Example:
adc@1e6e9000 {
compatible = "aspeed,ast2400-adc";
reg = <0x1e6e9000 0xb0>;
clocks = <&clk_apb>;
clocks = <&syscon ASPEED_CLK_APB>;
resets = <&syscon ASPEED_RESET_ADC>;
#io-channel-cells = <1>;
};
......@@ -17,6 +17,11 @@ Required properties:
This property uses the IRQ edge types values: IRQ_TYPE_EDGE_RISING ,
IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH
Optional properties:
- dmas: Phandle to dma channel for the ADC.
- dma-names: Must be "rx" when dmas property is being used.
See ../../dma/dma.txt for details.
Example:
adc: adc@fc030000 {
......@@ -31,4 +36,6 @@ adc: adc@fc030000 {
vddana-supply = <&vdd_3v3_lp_reg>;
vref-supply = <&vdd_3v3_lp_reg>;
atmel,trigger-edge-type = <IRQ_TYPE_EDGE_BOTH>;
dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | AT91_XDMAC_DT_PERID(25))>;
dma-names = "rx";
}
......@@ -62,6 +62,15 @@ Required properties:
- st,adc-channels: List of single-ended channels muxed for this ADC.
It can have up to 16 channels on stm32f4 or 20 channels on stm32h7, numbered
from 0 to 15 or 19 (resp. for in0..in15 or in0..in19).
- st,adc-diff-channels: List of differential channels muxed for this ADC.
Depending on part used, some channels can be configured as differential
instead of single-ended (e.g. stm32h7). List here positive and negative
inputs pairs as <vinp vinn>, <vinp vinn>,... vinp and vinn are numbered
from 0 to 19 on stm32h7)
Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is required.
Both properties can be used together. Some channels can be used as
single-ended and some other ones as differential (mixed). But channels
can't be configured both as single-ended and differential (invalid).
- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
Documentation/devicetree/bindings/iio/iio-bindings.txt
......@@ -111,3 +120,18 @@ Example:
...
other adc child nodes follow...
};
Example to setup:
- channel 1 as single-ended
- channels 2 & 3 as differential (with resp. 6 & 7 negative inputs)
adc: adc@40022000 {
compatible = "st,stm32h7-adc-core";
...
adc1: adc@0 {
compatible = "st,stm32h7-adc";
...
st,adc-channels = <1>;
st,adc-diff-channels = <2 6>, <3 7>;
};
};
Maxim MAX30102 heart rate and pulse oximeter sensor
Maxim MAX30105 optical particle-sensing module
* https://datasheets.maximintegrated.com/en/ds/MAX30102.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX30105.pdf
Required properties:
- compatible: must be "maxim,max30102"
- compatible: must be "maxim,max30102" or "maxim,max30105"
- reg: the I2C address of the sensor
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: the sole interrupt generated by the device
......@@ -12,8 +14,10 @@ Required properties:
interrupt client node bindings.
Optional properties:
- maxim,red-led-current-microamp: configuration for RED LED current
- maxim,red-led-current-microamp: configuration for red LED current
- maxim,ir-led-current-microamp: configuration for IR LED current
- maxim,green-led-current-microamp: configuration for green LED current
(max30105 only)
Note that each step is approximately 200 microamps, ranging from 0 uA to
50800 uA.
......
* ST UVIS25 uv sensor
Required properties:
- compatible: should be "st,uvis25"
- reg: i2c address of the sensor / spi cs line
Optional properties:
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ. It should be configured with
flags IRQ_TYPE_LEVEL_HIGH, IRQ_TYPE_EDGE_RISING, IRQ_TYPE_LEVEL_LOW or
IRQ_TYPE_EDGE_FALLING.
Refer to interrupt-controller/interrupts.txt for generic interrupt
client node bindings.
Example:
uvis25@47 {
compatible = "st,uvis25";
reg = <0x47>;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
......@@ -262,6 +262,7 @@ ACCES 104-QUAD-8 IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-counter-104-quad-8
F: drivers/iio/counter/104-quad-8.c
ACCES PCI-IDIO-16 GPIO DRIVER
......@@ -845,6 +846,8 @@ M: Michael Hennerich <Michael.Hennerich@analog.com>
W: http://wiki.analog.com/
W: http://ez.analog.com/community/linux-device-drivers
S: Supported
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-ad9523
F: Documentation/ABI/testing/sysfs-bus-iio-frequency-adf4350
F: drivers/iio/*/ad*
F: drivers/iio/adc/ltc2497*
X: drivers/iio/*/adjd*
......@@ -4126,6 +4129,7 @@ DEVANTECH SRF ULTRASONIC RANGER IIO DRIVER
M: Andreas Klinger <ak@it-klinger.de>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
F: drivers/iio/proximity/srf*.c
DEVICE COREDUMP (DEV_COREDUMP)
......@@ -6829,6 +6833,8 @@ R: Peter Meerwald-Stadler <pmeerw@pmeerw.net>
L: linux-iio@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git
S: Maintained
F: Documentation/ABI/testing/configfs-iio*
F: Documentation/ABI/testing/sysfs-bus-iio*
F: Documentation/devicetree/bindings/iio/
F: drivers/iio/
F: drivers/staging/iio/
......
......@@ -81,9 +81,21 @@ static const struct i2c_device_id bmc150_accel_id[] = {
MODULE_DEVICE_TABLE(i2c, bmc150_accel_id);
static const struct of_device_id bmc150_accel_of_match[] = {
{ .compatible = "bosch,bmc150_accel" },
{ .compatible = "bosch,bmi055_accel" },
{ .compatible = "bosch,bma255" },
{ .compatible = "bosch,bma250e" },
{ .compatible = "bosch,bma222e" },
{ .compatible = "bosch,bma280" },
{ },
};
MODULE_DEVICE_TABLE(of, bmc150_accel_of_match);
static struct i2c_driver bmc150_accel_driver = {
.driver = {
.name = "bmc150_accel_i2c",
.of_match_table = bmc150_accel_of_match,
.acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match),
.pm = &bmc150_accel_pm_ops,
},
......
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/byteorder/generic.h>
......@@ -25,7 +26,7 @@
#define DA280_MODE_ENABLE 0x1e
#define DA280_MODE_DISABLE 0x9e
enum { da226, da280 };
enum da280_chipset { da226, da280 };
/*
* a value of + or -4096 corresponds to + or - 1G
......@@ -91,12 +92,24 @@ static const struct iio_info da280_info = {
.read_raw = da280_read_raw,
};
static enum da280_chipset da280_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return -EINVAL;
return (enum da280_chipset) id->driver_data;
}
static int da280_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct da280_data *data;
enum da280_chipset chip;
ret = i2c_smbus_read_byte_data(client, DA280_REG_CHIP_ID);
if (ret != DA280_CHIP_ID)
......@@ -114,7 +127,14 @@ static int da280_probe(struct i2c_client *client,
indio_dev->info = &da280_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = da280_channels;
if (id->driver_data == da226) {
if (ACPI_HANDLE(&client->dev)) {
chip = da280_match_acpi_device(&client->dev);
} else {
chip = id->driver_data;
}
if (chip == da226) {
indio_dev->name = "da226";
indio_dev->num_channels = 2;
} else {
......@@ -158,6 +178,12 @@ static int da280_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(da280_pm_ops, da280_suspend, da280_resume);
static const struct acpi_device_id da280_acpi_match[] = {
{"MIRAACC", da280},
{},
};
MODULE_DEVICE_TABLE(acpi, da280_acpi_match);
static const struct i2c_device_id da280_i2c_id[] = {
{ "da226", da226 },
{ "da280", da280 },
......@@ -168,6 +194,7 @@ MODULE_DEVICE_TABLE(i2c, da280_i2c_id);
static struct i2c_driver da280_driver = {
.driver = {
.name = "da280",
.acpi_match_table = ACPI_PTR(da280_acpi_match),
.pm = &da280_pm_ops,
},
.probe = da280_probe,
......
......@@ -63,3 +63,6 @@ static struct i2c_driver kxsd9_i2c_driver = {
.id_table = kxsd9_i2c_id,
};
module_i2c_driver(kxsd9_i2c_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("KXSD9 accelerometer I2C interface");
......@@ -135,7 +135,7 @@ struct mma8452_event_regs {
u8 ev_count;
};
static const struct mma8452_event_regs ev_regs_accel_falling = {
static const struct mma8452_event_regs ff_mt_ev_regs = {
.ev_cfg = MMA8452_FF_MT_CFG,
.ev_cfg_ele = MMA8452_FF_MT_CFG_ELE,
.ev_cfg_chan_shift = MMA8452_FF_MT_CHAN_SHIFT,
......@@ -145,7 +145,7 @@ static const struct mma8452_event_regs ev_regs_accel_falling = {
.ev_count = MMA8452_FF_MT_COUNT
};
static const struct mma8452_event_regs ev_regs_accel_rising = {
static const struct mma8452_event_regs trans_ev_regs = {
.ev_cfg = MMA8452_TRANSIENT_CFG,
.ev_cfg_ele = MMA8452_TRANSIENT_CFG_ELE,
.ev_cfg_chan_shift = MMA8452_TRANSIENT_CHAN_SHIFT,
......@@ -284,7 +284,7 @@ static const int mma8452_samp_freq[8][2] = {
};
/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
static const unsigned int mma8452_transient_time_step_us[4][8] = {
static const unsigned int mma8452_time_step_us[4][8] = {
{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */
{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */
{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/
......@@ -777,12 +777,12 @@ static int mma8452_get_event_regs(struct mma8452_data *data,
& MMA8452_INT_TRANS) &&
(data->chip_info->enabled_events
& MMA8452_INT_TRANS))
*ev_reg = &ev_regs_accel_rising;
*ev_reg = &trans_ev_regs;
else
*ev_reg = &ev_regs_accel_falling;
*ev_reg = &ff_mt_ev_regs;
return 0;
case IIO_EV_DIR_FALLING:
*ev_reg = &ev_regs_accel_falling;
*ev_reg = &ff_mt_ev_regs;
return 0;
default:
return -EINVAL;
......@@ -826,7 +826,7 @@ static int mma8452_read_event_value(struct iio_dev *indio_dev,
if (power_mode < 0)
return power_mode;
us = ret * mma8452_transient_time_step_us[power_mode][
us = ret * mma8452_time_step_us[power_mode][
mma8452_get_odr_index(data)];
*val = us / USEC_PER_SEC;
*val2 = us % USEC_PER_SEC;
......@@ -883,7 +883,7 @@ static int mma8452_write_event_value(struct iio_dev *indio_dev,
return ret;
steps = (val * USEC_PER_SEC + val2) /
mma8452_transient_time_step_us[ret][
mma8452_time_step_us[ret][
mma8452_get_odr_index(data)];
if (steps < 0 || steps > 0xff)
......
......@@ -920,8 +920,6 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
int st_accel_common_probe(struct iio_dev *indio_dev)
{
struct st_sensor_data *adata = iio_priv(indio_dev);
struct st_sensors_platform_data *pdata =
(struct st_sensors_platform_data *)adata->dev->platform_data;
int irq = adata->get_irq_data_ready(indio_dev);
int err;
......@@ -948,9 +946,6 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
&adata->sensor_settings->fs.fs_avl[0];
adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
if (!pdata)
pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
if (err < 0)
goto st_accel_power_off;
......
......@@ -158,6 +158,7 @@ config AT91_SAMA5D2_ADC
tristate "Atmel AT91 SAMA5D2 ADC"
depends on ARCH_AT91 || COMPILE_TEST
depends on HAS_IOMEM
depends on HAS_DMA
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Atmel SAMA5D2 ADC which is
......
......@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/types.h>
......@@ -53,11 +54,12 @@ struct aspeed_adc_model_data {
};
struct aspeed_adc_data {
struct device *dev;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *clk_prescaler;
struct clk_hw *clk_scaler;
struct device *dev;
void __iomem *base;
spinlock_t clk_lock;
struct clk_hw *clk_prescaler;
struct clk_hw *clk_scaler;
struct reset_control *rst;
};
#define ASPEED_CHAN(_idx, _data_reg_addr) { \
......@@ -217,6 +219,15 @@ static int aspeed_adc_probe(struct platform_device *pdev)
goto scaler_error;
}
data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(data->rst)) {
dev_err(&pdev->dev,
"invalid or missing reset controller device tree entry");
ret = PTR_ERR(data->rst);
goto reset_error;
}
reset_control_deassert(data->rst);
model_data = of_device_get_match_data(&pdev->dev);
if (model_data->wait_init_sequence) {
......@@ -263,9 +274,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
data->base + ASPEED_REG_ENGINE_CONTROL);
clk_disable_unprepare(data->clk_scaler->clk);
reset_error:
reset_control_assert(data->rst);
clk_enable_error:
clk_hw_unregister_divider(data->clk_scaler);
scaler_error:
clk_hw_unregister_divider(data->clk_prescaler);
return ret;
......@@ -280,6 +292,7 @@ static int aspeed_adc_remove(struct platform_device *pdev)
writel(ASPEED_OPERATION_MODE_POWER_DOWN,
data->base + ASPEED_REG_ENGINE_CONTROL);
clk_disable_unprepare(data->clk_scaler->clk);
reset_control_assert(data->rst);
clk_hw_unregister_divider(data->clk_scaler);
clk_hw_unregister_divider(data->clk_prescaler);
......
......@@ -16,6 +16,8 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
......@@ -100,6 +102,8 @@
#define AT91_SAMA5D2_LCDR 0x20
/* Interrupt Enable Register */
#define AT91_SAMA5D2_IER 0x24
/* Interrupt Enable Register - general overrun error */
#define AT91_SAMA5D2_IER_GOVRE BIT(25)
/* Interrupt Disable Register */
#define AT91_SAMA5D2_IDR 0x28
/* Interrupt Mask Register */
......@@ -167,13 +171,19 @@
/*
* Maximum number of bytes to hold conversion from all channels
* plus the timestamp
* without the timestamp.
*/
#define AT91_BUFFER_MAX_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \
AT91_SAMA5D2_DIFF_CHAN_CNT) * 2 + 8)
#define AT91_BUFFER_MAX_CONVERSION_BYTES ((AT91_SAMA5D2_SINGLE_CHAN_CNT + \
AT91_SAMA5D2_DIFF_CHAN_CNT) * 2)
/* This total must also include the timestamp */
#define AT91_BUFFER_MAX_BYTES (AT91_BUFFER_MAX_CONVERSION_BYTES + 8)
#define AT91_BUFFER_MAX_HWORDS (AT91_BUFFER_MAX_BYTES / 2)
#define AT91_HWFIFO_MAX_SIZE_STR "128"
#define AT91_HWFIFO_MAX_SIZE 128
#define AT91_SAMA5D2_CHAN_SINGLE(num, addr) \
{ \
.type = IIO_VOLTAGE, \
......@@ -228,6 +238,28 @@ struct at91_adc_trigger {
bool hw_trig;
};
/**
* at91_adc_dma - at91-sama5d2 dma information struct
* @dma_chan: the dma channel acquired
* @rx_buf: dma coherent allocated area
* @rx_dma_buf: dma handler for the buffer
* @phys_addr: physical address of the ADC base register
* @buf_idx: index inside the dma buffer where reading was last done
* @rx_buf_sz: size of buffer used by DMA operation
* @watermark: number of conversions to copy before DMA triggers irq
* @dma_ts: hold the start timestamp of dma operation
*/
struct at91_adc_dma {
struct dma_chan *dma_chan;
u8 *rx_buf;
dma_addr_t rx_dma_buf;
phys_addr_t phys_addr;
int buf_idx;
int rx_buf_sz;
int watermark;
s64 dma_ts;
};
struct at91_adc_state {
void __iomem *base;
int irq;
......@@ -242,6 +274,7 @@ struct at91_adc_state {
u32 conversion_value;
struct at91_adc_soc_info soc_info;
wait_queue_head_t wq_data_available;
struct at91_adc_dma dma_st;
u16 buffer[AT91_BUFFER_MAX_HWORDS];
/*
* lock to prevent concurrent 'single conversion' requests through
......@@ -322,11 +355,17 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
if (state) {
at91_adc_writel(st, AT91_SAMA5D2_CHER,
BIT(chan->channel));
at91_adc_writel(st, AT91_SAMA5D2_IER,
BIT(chan->channel));
/* enable irq only if not using DMA */
if (!st->dma_st.dma_chan) {
at91_adc_writel(st, AT91_SAMA5D2_IER,
BIT(chan->channel));
}
} else {
at91_adc_writel(st, AT91_SAMA5D2_IDR,
BIT(chan->channel));
/* disable irq only if not using DMA */
if (!st->dma_st.dma_chan) {
at91_adc_writel(st, AT91_SAMA5D2_IDR,
BIT(chan->channel));
}
at91_adc_writel(st, AT91_SAMA5D2_CHDR,
BIT(chan->channel));
}
......@@ -340,6 +379,10 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig)
struct iio_dev *indio = iio_trigger_get_drvdata(trig);
struct at91_adc_state *st = iio_priv(indio);
/* if we are using DMA, we must not reenable irq after each trigger */
if (st->dma_st.dma_chan)
return 0;
enable_irq(st->irq);
/* Needed to ACK the DRDY interruption */
......@@ -350,6 +393,153 @@ static int at91_adc_reenable_trigger(struct iio_trigger *trig)
static const struct iio_trigger_ops at91_adc_trigger_ops = {
.set_trigger_state = &at91_adc_configure_trigger,
.try_reenable = &at91_adc_reenable_trigger,
.validate_device = iio_trigger_validate_own_device,
};
static int at91_adc_dma_size_done(struct at91_adc_state *st)
{
struct dma_tx_state state;
enum dma_status status;
int i, size;
status = dmaengine_tx_status(st->dma_st.dma_chan,
st->dma_st.dma_chan->cookie,
&state);
if (status != DMA_IN_PROGRESS)
return 0;
/* Transferred length is size in bytes from end of buffer */
i = st->dma_st.rx_buf_sz - state.residue;
/* Return available bytes */
if (i >= st->dma_st.buf_idx)
size = i - st->dma_st.buf_idx;
else
size = st->dma_st.rx_buf_sz + i - st->dma_st.buf_idx;
return size;
}
static void at91_dma_buffer_done(void *data)
{
struct iio_dev *indio_dev = data;
iio_trigger_poll_chained(indio_dev->trig);
}
static int at91_adc_dma_start(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
struct dma_async_tx_descriptor *desc;
dma_cookie_t cookie;
int ret;
u8 bit;
if (!st->dma_st.dma_chan)
return 0;
/* we start a new DMA, so set buffer index to start */
st->dma_st.buf_idx = 0;
/*
* compute buffer size w.r.t. watermark and enabled channels.
* scan_bytes is aligned so we need an exact size for DMA
*/
st->dma_st.rx_buf_sz = 0;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
struct iio_chan_spec const *chan = indio_dev->channels + bit;
st->dma_st.rx_buf_sz += chan->scan_type.storagebits / 8;
}
st->dma_st.rx_buf_sz *= st->dma_st.watermark;
/* Prepare a DMA cyclic transaction */
desc = dmaengine_prep_dma_cyclic(st->dma_st.dma_chan,
st->dma_st.rx_dma_buf,
st->dma_st.rx_buf_sz,
st->dma_st.rx_buf_sz / 2,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(&indio_dev->dev, "cannot prepare DMA cyclic\n");
return -EBUSY;
}
desc->callback = at91_dma_buffer_done;
desc->callback_param = indio_dev;
cookie = dmaengine_submit(desc);
ret = dma_submit_error(cookie);
if (ret) {
dev_err(&indio_dev->dev, "cannot submit DMA cyclic\n");
dmaengine_terminate_async(st->dma_st.dma_chan);
return ret;
}
/* enable general overrun error signaling */
at91_adc_writel(st, AT91_SAMA5D2_IER, AT91_SAMA5D2_IER_GOVRE);
/* Issue pending DMA requests */
dma_async_issue_pending(st->dma_st.dma_chan);
/* consider current time as DMA start time for timestamps */
st->dma_st.dma_ts = iio_get_time_ns(indio_dev);
dev_dbg(&indio_dev->dev, "DMA cyclic started\n");
return 0;
}
static int at91_adc_buffer_postenable(struct iio_dev *indio_dev)
{
int ret;
ret = at91_adc_dma_start(indio_dev);
if (ret) {
dev_err(&indio_dev->dev, "buffer postenable failed\n");
return ret;
}
return iio_triggered_buffer_postenable(indio_dev);
}
static int at91_adc_buffer_predisable(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
int ret;
u8 bit;
ret = iio_triggered_buffer_predisable(indio_dev);
if (ret < 0)
dev_err(&indio_dev->dev, "buffer predisable failed\n");
if (!st->dma_st.dma_chan)
return ret;
/* if we are using DMA we must clear registers and end DMA */
dmaengine_terminate_sync(st->dma_st.dma_chan);
/*
* For each enabled channel we must read the last converted value
* to clear EOC status and not get a possible interrupt later.
* This value is being read by DMA from LCDR anyway
*/
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
struct iio_chan_spec const *chan = indio_dev->channels + bit;
if (st->dma_st.dma_chan)
at91_adc_readl(st, chan->address);
}
/* read overflow register to clear possible overflow status */
at91_adc_readl(st, AT91_SAMA5D2_OVER);
return ret;
}
static const struct iio_buffer_setup_ops at91_buffer_setup_ops = {
.postenable = &at91_adc_buffer_postenable,
.predisable = &at91_adc_buffer_predisable,
};
static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio,
......@@ -388,24 +578,77 @@ static int at91_adc_trigger_init(struct iio_dev *indio)
return 0;
}
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev,
struct iio_poll_func *pf)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio = pf->indio_dev;
struct at91_adc_state *st = iio_priv(indio);
struct at91_adc_state *st = iio_priv(indio_dev);
int i = 0;
u8 bit;
for_each_set_bit(bit, indio->active_scan_mask, indio->num_channels) {
struct iio_chan_spec const *chan = indio->channels + bit;
for_each_set_bit(bit, indio_dev->active_scan_mask,
indio_dev->num_channels) {
struct iio_chan_spec const *chan = indio_dev->channels + bit;
st->buffer[i] = at91_adc_readl(st, chan->address);
i++;
}
iio_push_to_buffers_with_timestamp(indio_dev, st->buffer,
pf->timestamp);
}
iio_push_to_buffers_with_timestamp(indio, st->buffer, pf->timestamp);
static void at91_adc_trigger_handler_dma(struct iio_dev *indio_dev)
{
struct at91_adc_state *st = iio_priv(indio_dev);
int transferred_len = at91_adc_dma_size_done(st);
s64 ns = iio_get_time_ns(indio_dev);
s64 interval;
int sample_index = 0, sample_count, sample_size;
u32 status = at91_adc_readl(st, AT91_SAMA5D2_ISR);
/* if we reached this point, we cannot sample faster */
if (status & AT91_SAMA5D2_IER_GOVRE)
pr_info_ratelimited("%s: conversion overrun detected\n",
indio_dev->name);
iio_trigger_notify_done(indio->trig);
sample_size = div_s64(st->dma_st.rx_buf_sz, st->dma_st.watermark);
sample_count = div_s64(transferred_len, sample_size);
/*
* interval between samples is total time since last transfer handling
* divided by the number of samples (total size divided by sample size)
*/
interval = div_s64((ns - st->dma_st.dma_ts), sample_count);
while (transferred_len >= sample_size) {
iio_push_to_buffers_with_timestamp(indio_dev,
(st->dma_st.rx_buf + st->dma_st.buf_idx),
(st->dma_st.dma_ts + interval * sample_index));
/* adjust remaining length */
transferred_len -= sample_size;
/* adjust buffer index */
st->dma_st.buf_idx += sample_size;
/* in case of reaching end of buffer, reset index */
if (st->dma_st.buf_idx >= st->dma_st.rx_buf_sz)
st->dma_st.buf_idx = 0;
sample_index++;
}
/* adjust saved time for next transfer handling */
st->dma_st.dma_ts = iio_get_time_ns(indio_dev);
}
static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(indio_dev);
if (st->dma_st.dma_chan)
at91_adc_trigger_handler_dma(indio_dev);
else
at91_adc_trigger_handler_nodma(indio_dev, pf);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
......@@ -414,7 +657,7 @@ static int at91_adc_buffer_init(struct iio_dev *indio)
{
return devm_iio_triggered_buffer_setup(&indio->dev, indio,
&iio_pollfunc_store_time,
&at91_adc_trigger_handler, NULL);
&at91_adc_trigger_handler, &at91_buffer_setup_ops);
}
static unsigned at91_adc_startup_time(unsigned startup_time_min,
......@@ -485,10 +728,13 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
if (!(status & imr))
return IRQ_NONE;
if (iio_buffer_enabled(indio)) {
if (iio_buffer_enabled(indio) && !st->dma_st.dma_chan) {
disable_irq_nosync(irq);
iio_trigger_poll(indio->trig);
} else {
} else if (iio_buffer_enabled(indio) && st->dma_st.dma_chan) {
disable_irq_nosync(irq);
WARN(true, "Unexpected irq occurred\n");
} else if (!iio_buffer_enabled(indio)) {
st->conversion_value = at91_adc_readl(st, st->chan->address);
st->conversion_done = true;
wake_up_interruptible(&st->wq_data_available);
......@@ -510,7 +756,6 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&st->lock);
st->chan = chan;
......@@ -541,6 +786,9 @@ static int at91_adc_read_raw(struct iio_dev *indio_dev,
at91_adc_writel(st, AT91_SAMA5D2_IDR, BIT(chan->channel));
at91_adc_writel(st, AT91_SAMA5D2_CHDR, BIT(chan->channel));
/* Needed to ACK the DRDY interruption */
at91_adc_readl(st, AT91_SAMA5D2_LCDR);
mutex_unlock(&st->lock);
iio_device_release_direct_mode(indio_dev);
......@@ -580,9 +828,123 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev,
return 0;
}
static void at91_adc_dma_init(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
struct dma_slave_config config = {0};
/*
* We make the buffer double the size of the fifo,
* such that DMA uses one half of the buffer (full fifo size)
* and the software uses the other half to read/write.
*/
unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE *
AT91_BUFFER_MAX_CONVERSION_BYTES * 2,
PAGE_SIZE);
if (st->dma_st.dma_chan)
return;
st->dma_st.dma_chan = dma_request_slave_channel(&pdev->dev, "rx");
if (!st->dma_st.dma_chan) {
dev_info(&pdev->dev, "can't get DMA channel\n");
goto dma_exit;
}
st->dma_st.rx_buf = dma_alloc_coherent(st->dma_st.dma_chan->device->dev,
pages * PAGE_SIZE,
&st->dma_st.rx_dma_buf,
GFP_KERNEL);
if (!st->dma_st.rx_buf) {
dev_info(&pdev->dev, "can't allocate coherent DMA area\n");
goto dma_chan_disable;
}
/* Configure DMA channel to read data register */
config.direction = DMA_DEV_TO_MEM;
config.src_addr = (phys_addr_t)(st->dma_st.phys_addr
+ AT91_SAMA5D2_LCDR);
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
config.src_maxburst = 1;
config.dst_maxburst = 1;
if (dmaengine_slave_config(st->dma_st.dma_chan, &config)) {
dev_info(&pdev->dev, "can't configure DMA slave\n");
goto dma_free_area;
}
dev_info(&pdev->dev, "using %s for rx DMA transfers\n",
dma_chan_name(st->dma_st.dma_chan));
return;
dma_free_area:
dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_chan_disable:
dma_release_channel(st->dma_st.dma_chan);
st->dma_st.dma_chan = 0;
dma_exit:
dev_info(&pdev->dev, "continuing without DMA support\n");
}
static void at91_adc_dma_disable(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct at91_adc_state *st = iio_priv(indio_dev);
unsigned int pages = DIV_ROUND_UP(AT91_HWFIFO_MAX_SIZE *
AT91_BUFFER_MAX_CONVERSION_BYTES * 2,
PAGE_SIZE);
/* if we are not using DMA, just return */
if (!st->dma_st.dma_chan)
return;
/* wait for all transactions to be terminated first*/
dmaengine_terminate_sync(st->dma_st.dma_chan);
dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE,
st->dma_st.rx_buf, st->dma_st.rx_dma_buf);
dma_release_channel(st->dma_st.dma_chan);
st->dma_st.dma_chan = 0;
dev_info(&pdev->dev, "continuing without DMA support\n");
}
static int at91_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
{
struct at91_adc_state *st = iio_priv(indio_dev);
if (val > AT91_HWFIFO_MAX_SIZE)
return -EINVAL;
if (!st->selected_trig->hw_trig) {
dev_dbg(&indio_dev->dev, "we need hw trigger for DMA\n");
return 0;
}
dev_dbg(&indio_dev->dev, "new watermark is %u\n", val);
st->dma_st.watermark = val;
/*
* The logic here is: if we have watermark 1, it means we do
* each conversion with it's own IRQ, thus we don't need DMA.
* If the watermark is higher, we do DMA to do all the transfers in bulk
*/
if (val == 1)
at91_adc_dma_disable(to_platform_device(&indio_dev->dev));
else if (val > 1)
at91_adc_dma_init(to_platform_device(&indio_dev->dev));
return 0;
}
static const struct iio_info at91_adc_info = {
.read_raw = &at91_adc_read_raw,
.write_raw = &at91_adc_write_raw,
.hwfifo_set_watermark = &at91_adc_set_watermark,
};
static void at91_adc_hw_init(struct at91_adc_state *st)
......@@ -599,6 +961,42 @@ static void at91_adc_hw_init(struct at91_adc_state *st)
at91_adc_setup_samp_freq(st, st->soc_info.min_sample_rate);
}
static ssize_t at91_adc_get_fifo_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev =
platform_get_drvdata(to_platform_device(dev));
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", !!st->dma_st.dma_chan);
}
static ssize_t at91_adc_get_watermark(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iio_dev *indio_dev =
platform_get_drvdata(to_platform_device(dev));
struct at91_adc_state *st = iio_priv(indio_dev);
return scnprintf(buf, PAGE_SIZE, "%d\n", st->dma_st.watermark);
}
static IIO_DEVICE_ATTR(hwfifo_enabled, 0444,
at91_adc_get_fifo_state, NULL, 0);
static IIO_DEVICE_ATTR(hwfifo_watermark, 0444,
at91_adc_get_watermark, NULL, 0);
static IIO_CONST_ATTR(hwfifo_watermark_min, "2");
static IIO_CONST_ATTR(hwfifo_watermark_max, AT91_HWFIFO_MAX_SIZE_STR);
static const struct attribute *at91_adc_fifo_attributes[] = {
&iio_const_attr_hwfifo_watermark_min.dev_attr.attr,
&iio_const_attr_hwfifo_watermark_max.dev_attr.attr,
&iio_dev_attr_hwfifo_watermark.dev_attr.attr,
&iio_dev_attr_hwfifo_enabled.dev_attr.attr,
NULL,
};
static int at91_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
......@@ -674,6 +1072,9 @@ static int at91_adc_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
/* if we plan to use DMA, we need the physical address of the regs */
st->dma_st.phys_addr = res->start;
st->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(st->base))
return PTR_ERR(st->base);
......@@ -737,11 +1138,22 @@ static int at91_adc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "couldn't setup the triggers.\n");
goto per_clk_disable_unprepare;
}
/*
* Initially the iio buffer has a length of 2 and
* a watermark of 1
*/
st->dma_st.watermark = 1;
iio_buffer_set_attrs(indio_dev->buffer,
at91_adc_fifo_attributes);
}
if (dma_coerce_mask_and_coherent(&indio_dev->dev, DMA_BIT_MASK(32)))
dev_info(&pdev->dev, "cannot set DMA mask to 32-bit\n");
ret = iio_device_register(indio_dev);
if (ret < 0)
goto per_clk_disable_unprepare;
goto dma_disable;
if (st->selected_trig->hw_trig)
dev_info(&pdev->dev, "setting up trigger as %s\n",
......@@ -752,6 +1164,8 @@ static int at91_adc_probe(struct platform_device *pdev)
return 0;
dma_disable:
at91_adc_dma_disable(pdev);
per_clk_disable_unprepare:
clk_disable_unprepare(st->per_clk);
vref_disable:
......@@ -768,6 +1182,8 @@ static int at91_adc_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev);
at91_adc_dma_disable(pdev);
clk_disable_unprepare(st->per_clk);
regulator_disable(st->vref);
......
......@@ -92,22 +92,14 @@ static const struct iio_chan_spec axp288_adc_channels[] = {
},
};
#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
_consumer_channel) \
{ \
.adc_channel_label = _adc_channel_label, \
.consumer_dev_name = _consumer_dev_name, \
.consumer_channel = _consumer_channel, \
}
/* for consumer drivers */
static struct iio_map axp288_adc_default_maps[] = {
AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
IIO_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
IIO_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
IIO_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
IIO_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
IIO_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
IIO_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
{},
};
......
......@@ -44,13 +44,14 @@
#define INA226_MASK_ENABLE 0x06
#define INA226_CVRF BIT(3)
#define INA219_CNVR BIT(1)
#define INA2XX_MAX_REGISTERS 8
/* settings - depend on use case */
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
#define INA219_CONFIG_DEFAULT 0x399F /* PGA=1/8, BRNG=32V */
#define INA219_DEFAULT_IT 532
#define INA219_DEFAULT_BRNG 1 /* 32V */
#define INA219_DEFAULT_PGA 125 /* 1000/8 */
#define INA226_CONFIG_DEFAULT 0x4327
#define INA226_DEFAULT_AVG 4
#define INA226_DEFAULT_IT 1110
......@@ -63,6 +64,14 @@
*/
#define INA2XX_MODE_MASK GENMASK(3, 0)
/* Gain for VShunt: 1/8 (default), 1/4, 1/2, 1 */
#define INA219_PGA_MASK GENMASK(12, 11)
#define INA219_SHIFT_PGA(val) ((val) << 11)
/* VBus range: 32V (default), 16V */
#define INA219_BRNG_MASK BIT(13)
#define INA219_SHIFT_BRNG(val) ((val) << 13)
/* Averaging for VBus/VShunt/Power */
#define INA226_AVG_MASK GENMASK(11, 9)
#define INA226_SHIFT_AVG(val) ((val) << 9)
......@@ -79,6 +88,11 @@
#define INA226_ITS_MASK GENMASK(5, 3)
#define INA226_SHIFT_ITS(val) ((val) << 3)
/* INA219 Bus voltage register, low bits are flags */
#define INA219_OVF BIT(0)
#define INA219_CNVR BIT(1)
#define INA219_BUS_VOLTAGE_SHIFT 3
/* Cosmetic macro giving the sampling period for a full P=UxI cycle */
#define SAMPLING_PERIOD(c) ((c->int_time_vbus + c->int_time_vshunt) \
* c->avg)
......@@ -111,8 +125,8 @@ enum ina2xx_ids { ina219, ina226 };
struct ina2xx_config {
u16 config_default;
int calibration_factor;
int shunt_div;
int bus_voltage_shift;
int shunt_voltage_lsb; /* nV */
int bus_voltage_shift; /* position of lsb */
int bus_voltage_lsb; /* uV */
int power_lsb; /* uW */
enum ina2xx_ids chip_id;
......@@ -127,6 +141,8 @@ struct ina2xx_chip_info {
int avg;
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
int range_vbus; /* Bus voltage maximum in V */
int pga_gain_vshunt; /* Shunt voltage PGA gain */
bool allow_async_readout;
};
......@@ -134,8 +150,8 @@ static const struct ina2xx_config ina2xx_config[] = {
[ina219] = {
.config_default = INA219_CONFIG_DEFAULT,
.calibration_factor = 40960000,
.shunt_div = 100,
.bus_voltage_shift = 3,
.shunt_voltage_lsb = 10000,
.bus_voltage_shift = INA219_BUS_VOLTAGE_SHIFT,
.bus_voltage_lsb = 4000,
.power_lsb = 20000,
.chip_id = ina219,
......@@ -143,7 +159,7 @@ static const struct ina2xx_config ina2xx_config[] = {
[ina226] = {
.config_default = INA226_CONFIG_DEFAULT,
.calibration_factor = 5120000,
.shunt_div = 400,
.shunt_voltage_lsb = 2500,
.bus_voltage_shift = 0,
.bus_voltage_lsb = 1250,
.power_lsb = 25000,
......@@ -170,6 +186,9 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
else
*val = regval;
if (chan->address == INA2XX_BUS_VOLTAGE)
*val >>= chip->config->bus_voltage_shift;
return IIO_VAL_INT;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
......@@ -197,15 +216,15 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
/* processed (mV) = raw/shunt_div */
*val2 = chip->config->shunt_div;
*val = 1;
/* processed (mV) = raw * lsb(nV) / 1000000 */
*val = chip->config->shunt_voltage_lsb;
*val2 = 1000000;
return IIO_VAL_FRACTIONAL;
case INA2XX_BUS_VOLTAGE:
/* processed (mV) = raw*lsb (uV) / (1000 << shift) */
/* processed (mV) = raw * lsb (uV) / 1000 */
*val = chip->config->bus_voltage_lsb;
*val2 = 1000 << chip->config->bus_voltage_shift;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case INA2XX_POWER:
......@@ -219,6 +238,18 @@ static int ina2xx_read_raw(struct iio_dev *indio_dev,
*val = 1;
return IIO_VAL_INT;
}
case IIO_CHAN_INFO_HARDWAREGAIN:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
*val = chip->pga_gain_vshunt;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
case INA2XX_BUS_VOLTAGE:
*val = chip->range_vbus == 32 ? 1 : 2;
return IIO_VAL_INT;
}
}
return -EINVAL;
......@@ -353,6 +384,74 @@ static int ina219_set_int_time_vshunt(struct ina2xx_chip_info *chip,
return 0;
}
static const int ina219_vbus_range_tab[] = { 1, 2 };
static int ina219_set_vbus_range_denom(struct ina2xx_chip_info *chip,
unsigned int range,
unsigned int *config)
{
if (range == 1)
chip->range_vbus = 32;
else if (range == 2)
chip->range_vbus = 16;
else
return -EINVAL;
*config &= ~INA219_BRNG_MASK;
*config |= INA219_SHIFT_BRNG(range == 1 ? 1 : 0) & INA219_BRNG_MASK;
return 0;
}
static const int ina219_vshunt_gain_tab[] = { 125, 250, 500, 1000 };
static const int ina219_vshunt_gain_frac[] = {
125, 1000, 250, 1000, 500, 1000, 1000, 1000 };
static int ina219_set_vshunt_pga_gain(struct ina2xx_chip_info *chip,
unsigned int gain,
unsigned int *config)
{
int bits;
if (gain < 125 || gain > 1000)
return -EINVAL;
bits = find_closest(gain, ina219_vshunt_gain_tab,
ARRAY_SIZE(ina219_vshunt_gain_tab));
chip->pga_gain_vshunt = ina219_vshunt_gain_tab[bits];
bits = 3 - bits;
*config &= ~INA219_PGA_MASK;
*config |= INA219_SHIFT_PGA(bits) & INA219_PGA_MASK;
return 0;
}
static int ina2xx_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_HARDWAREGAIN:
switch (chan->address) {
case INA2XX_SHUNT_VOLTAGE:
*type = IIO_VAL_FRACTIONAL;
*length = sizeof(ina219_vshunt_gain_frac) / sizeof(int);
*vals = ina219_vshunt_gain_frac;
return IIO_AVAIL_LIST;
case INA2XX_BUS_VOLTAGE:
*type = IIO_VAL_INT;
*length = sizeof(ina219_vbus_range_tab) / sizeof(int);
*vals = ina219_vbus_range_tab;
return IIO_AVAIL_LIST;
}
}
return -EINVAL;
}
static int ina2xx_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
......@@ -395,6 +494,14 @@ static int ina2xx_write_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_HARDWAREGAIN:
if (chan->address == INA2XX_SHUNT_VOLTAGE)
ret = ina219_set_vshunt_pga_gain(chip, val * 1000 +
val2 / 1000, &tmp);
else
ret = ina219_set_vbus_range_denom(chip, val, &tmp);
break;
default:
ret = -EINVAL;
}
......@@ -532,19 +639,23 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
* Sampling Freq is a consequence of the integration times of
* the Voltage channels.
*/
#define INA219_CHAN_VOLTAGE(_index, _address) { \
#define INA219_CHAN_VOLTAGE(_index, _address, _shift) { \
.type = IIO_VOLTAGE, \
.address = (_address), \
.indexed = 1, \
.channel = (_index), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_INT_TIME), \
BIT(IIO_CHAN_INFO_INT_TIME) | \
BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.info_mask_separate_available = \
BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
.info_mask_shared_by_dir = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.scan_index = (_index), \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.shift = _shift, \
.realbits = 16 - _shift, \
.storagebits = 16, \
.endianness = IIO_LE, \
} \
......@@ -579,8 +690,8 @@ static const struct iio_chan_spec ina226_channels[] = {
};
static const struct iio_chan_spec ina219_channels[] = {
INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE),
INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE),
INA219_CHAN_VOLTAGE(0, INA2XX_SHUNT_VOLTAGE, 0),
INA219_CHAN_VOLTAGE(1, INA2XX_BUS_VOLTAGE, INA219_BUS_VOLTAGE_SHIFT),
INA219_CHAN(IIO_POWER, 2, INA2XX_POWER),
INA219_CHAN(IIO_CURRENT, 3, INA2XX_CURRENT),
IIO_CHAN_SOFT_TIMESTAMP(4),
......@@ -746,7 +857,6 @@ static IIO_CONST_ATTR_NAMED(ina226_integration_time_available,
integration_time_available,
"0.000140 0.000204 0.000332 0.000588 0.001100 0.002116 0.004156 0.008244");
static IIO_DEVICE_ATTR(in_allow_async_readout, S_IRUGO | S_IWUSR,
ina2xx_allow_async_readout_show,
ina2xx_allow_async_readout_store, 0);
......@@ -780,6 +890,7 @@ static const struct attribute_group ina226_attribute_group = {
static const struct iio_info ina219_info = {
.attrs = &ina219_attribute_group,
.read_raw = ina2xx_read_raw,
.read_avail = ina2xx_read_avail,
.write_raw = ina2xx_write_raw,
.debugfs_reg_access = ina2xx_debug_reg,
};
......@@ -860,6 +971,8 @@ static int ina2xx_probe(struct i2c_client *client,
chip->avg = 1;
ina219_set_int_time_vbus(chip, INA219_DEFAULT_IT, &val);
ina219_set_int_time_vshunt(chip, INA219_DEFAULT_IT, &val);
ina219_set_vbus_range_denom(chip, INA219_DEFAULT_BRNG, &val);
ina219_set_vshunt_pga_gain(chip, INA219_DEFAULT_PGA, &val);
}
ret = ina2xx_init(chip, val);
......
......@@ -231,7 +231,6 @@ struct meson_sar_adc_priv {
const struct meson_sar_adc_data *data;
struct clk *clkin;
struct clk *core_clk;
struct clk *sana_clk;
struct clk *adc_sel_clk;
struct clk *adc_clk;
struct clk_gate clk_gate;
......@@ -708,12 +707,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
goto err_core_clk;
}
ret = clk_prepare_enable(priv->sana_clk);
if (ret) {
dev_err(indio_dev->dev.parent, "failed to enable sana clk\n");
goto err_sana_clk;
}
regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval);
......@@ -741,8 +734,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
MESON_SAR_ADC_REG3_ADC_EN, 0);
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
clk_disable_unprepare(priv->sana_clk);
err_sana_clk:
clk_disable_unprepare(priv->core_clk);
err_core_clk:
regulator_disable(priv->vref);
......@@ -768,7 +759,6 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
clk_disable_unprepare(priv->sana_clk);
clk_disable_unprepare(priv->core_clk);
regulator_disable(priv->vref);
......@@ -961,16 +951,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
return PTR_ERR(priv->core_clk);
}
priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
if (IS_ERR(priv->sana_clk)) {
if (PTR_ERR(priv->sana_clk) == -ENOENT) {
priv->sana_clk = NULL;
} else {
dev_err(&pdev->dev, "failed to get sana clk\n");
return PTR_ERR(priv->sana_clk);
}
}
priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
if (IS_ERR(priv->adc_clk)) {
if (PTR_ERR(priv->adc_clk) == -ENOENT) {
......
......@@ -5,6 +5,7 @@
#include <linux/math64.h>
#include <linux/log2.h>
#include <linux/err.h>
#include <linux/module.h>
#include "qcom-vadc-common.h"
......@@ -229,3 +230,6 @@ int qcom_vadc_decimation_from_dt(u32 value)
return __ffs64(value / VADC_DECIMATION_MIN);
}
EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm ADC common functionality");
......@@ -92,6 +92,7 @@
#define STM32H7_ADC_SQR3 0x38
#define STM32H7_ADC_SQR4 0x3C
#define STM32H7_ADC_DR 0x40
#define STM32H7_ADC_DIFSEL 0xC0
#define STM32H7_ADC_CALFACT 0xC4
#define STM32H7_ADC_CALFACT2 0xC8
......@@ -153,6 +154,8 @@ enum stm32h7_adc_dmngt {
/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
#define STM32H7_BOOST_CLKRATE 20000000UL
#define STM32_ADC_CH_MAX 20 /* max number of channels */
#define STM32_ADC_CH_SZ 10 /* max channel name size */
#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
#define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */
#define STM32_ADC_TIMEOUT_US 100000
......@@ -297,9 +300,11 @@ struct stm32_adc_cfg {
* @rx_buf: dma rx buffer cpu address
* @rx_dma_buf: dma rx buffer bus address
* @rx_buf_sz: dma rx buffer size
* @difsel bitmask to set single-ended/differential channel
* @pcsel bitmask to preselect channels on some devices
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
* @cal: optional calibration data on some devices
* @chan_name: channel name array
*/
struct stm32_adc {
struct stm32_adc_common *common;
......@@ -318,72 +323,37 @@ struct stm32_adc {
u8 *rx_buf;
dma_addr_t rx_dma_buf;
unsigned int rx_buf_sz;
u32 difsel;
u32 pcsel;
u32 smpr_val[2];
struct stm32_adc_calib cal;
char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
};
/**
* struct stm32_adc_chan_spec - specification of stm32 adc channel
* @type: IIO channel type
* @channel: channel number (single ended)
* @name: channel name (single ended)
*/
struct stm32_adc_chan_spec {
enum iio_chan_type type;
int channel;
const char *name;
struct stm32_adc_diff_channel {
u32 vinp;
u32 vinn;
};
/**
* struct stm32_adc_info - stm32 ADC, per instance config data
* @channels: Reference to stm32 channels spec
* @max_channels: Number of channels
* @resolutions: available resolutions
* @num_res: number of available resolutions
*/
struct stm32_adc_info {
const struct stm32_adc_chan_spec *channels;
int max_channels;
const unsigned int *resolutions;
const unsigned int num_res;
};
/*
* Input definitions common for all instances:
* stm32f4 can have up to 16 channels
* stm32h7 can have up to 20 channels
*/
static const struct stm32_adc_chan_spec stm32_adc_channels[] = {
{ IIO_VOLTAGE, 0, "in0" },
{ IIO_VOLTAGE, 1, "in1" },
{ IIO_VOLTAGE, 2, "in2" },
{ IIO_VOLTAGE, 3, "in3" },
{ IIO_VOLTAGE, 4, "in4" },
{ IIO_VOLTAGE, 5, "in5" },
{ IIO_VOLTAGE, 6, "in6" },
{ IIO_VOLTAGE, 7, "in7" },
{ IIO_VOLTAGE, 8, "in8" },
{ IIO_VOLTAGE, 9, "in9" },
{ IIO_VOLTAGE, 10, "in10" },
{ IIO_VOLTAGE, 11, "in11" },
{ IIO_VOLTAGE, 12, "in12" },
{ IIO_VOLTAGE, 13, "in13" },
{ IIO_VOLTAGE, 14, "in14" },
{ IIO_VOLTAGE, 15, "in15" },
{ IIO_VOLTAGE, 16, "in16" },
{ IIO_VOLTAGE, 17, "in17" },
{ IIO_VOLTAGE, 18, "in18" },
{ IIO_VOLTAGE, 19, "in19" },
};
static const unsigned int stm32f4_adc_resolutions[] = {
/* sorted values so the index matches RES[1:0] in STM32F4_ADC_CR1 */
12, 10, 8, 6,
};
/* stm32f4 can have up to 16 channels */
static const struct stm32_adc_info stm32f4_adc_info = {
.channels = stm32_adc_channels,
.max_channels = 16,
.resolutions = stm32f4_adc_resolutions,
.num_res = ARRAY_SIZE(stm32f4_adc_resolutions),
......@@ -394,9 +364,9 @@ static const unsigned int stm32h7_adc_resolutions[] = {
16, 14, 12, 10, 8,
};
/* stm32h7 can have up to 20 channels */
static const struct stm32_adc_info stm32h7_adc_info = {
.channels = stm32_adc_channels,
.max_channels = 20,
.max_channels = STM32_ADC_CH_MAX,
.resolutions = stm32h7_adc_resolutions,
.num_res = ARRAY_SIZE(stm32h7_adc_resolutions),
};
......@@ -983,15 +953,19 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
* stm32h7_adc_prepare() - Leave power down mode to enable ADC.
* @adc: stm32 adc instance
* Leave power down mode.
* Configure channels as single ended or differential before enabling ADC.
* Enable ADC.
* Restore calibration data.
* Pre-select channels that may be used in PCSEL (required by input MUX / IO).
* Pre-select channels that may be used in PCSEL (required by input MUX / IO):
* - Only one input is selected for single ended (e.g. 'vinp')
* - Two inputs are selected for differential channels (e.g. 'vinp' & 'vinn')
*/
static int stm32h7_adc_prepare(struct stm32_adc *adc)
{
int ret;
stm32h7_adc_exit_pwr_down(adc);
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(adc);
if (ret)
......@@ -1263,10 +1237,23 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
return ret;
case IIO_CHAN_INFO_SCALE:
*val = adc->common->vref_mv;
*val2 = chan->scan_type.realbits;
if (chan->differential) {
*val = adc->common->vref_mv * 2;
*val2 = chan->scan_type.realbits;
} else {
*val = adc->common->vref_mv;
*val2 = chan->scan_type.realbits;
}
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
if (chan->differential)
/* ADC_full_scale / 2 */
*val = -((1 << chan->scan_type.realbits) / 2);
else
*val = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
......@@ -1628,29 +1615,40 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
}
static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
struct iio_chan_spec *chan,
const struct stm32_adc_chan_spec *channel,
int scan_index, u32 smp)
struct iio_chan_spec *chan, u32 vinp,
u32 vinn, int scan_index, bool differential)
{
struct stm32_adc *adc = iio_priv(indio_dev);
chan->type = channel->type;
chan->channel = channel->channel;
chan->datasheet_name = channel->name;
char *name = adc->chan_name[vinp];
chan->type = IIO_VOLTAGE;
chan->channel = vinp;
if (differential) {
chan->differential = 1;
chan->channel2 = vinn;
snprintf(name, STM32_ADC_CH_SZ, "in%d-in%d", vinp, vinn);
} else {
snprintf(name, STM32_ADC_CH_SZ, "in%d", vinp);
}
chan->datasheet_name = name;
chan->scan_index = scan_index;
chan->indexed = 1;
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET);
chan->scan_type.sign = 'u';
chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res];
chan->scan_type.storagebits = 16;
chan->ext_info = stm32_adc_ext_info;
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, chan->channel, smp);
/* pre-build selected channels mask */
adc->pcsel |= BIT(chan->channel);
if (differential) {
/* pre-build diff channels mask */
adc->difsel |= BIT(chan->channel);
/* Also add negative input to pre-selected channels */
adc->pcsel |= BIT(chan->channel2);
}
}
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
......@@ -1658,17 +1656,40 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
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 stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
struct property *prop;
const __be32 *cur;
struct iio_chan_spec *channels;
int scan_index = 0, num_channels, ret;
int scan_index = 0, num_channels = 0, num_diff = 0, ret, i;
u32 val, smp = 0;
num_channels = of_property_count_u32_elems(node, "st,adc-channels");
if (num_channels < 0 ||
num_channels > adc_info->max_channels) {
ret = of_property_count_u32_elems(node, "st,adc-channels");
if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-channels?\n");
return num_channels < 0 ? num_channels : -EINVAL;
return -EINVAL;
} else if (ret > 0) {
num_channels += ret;
}
ret = of_property_count_elems_of_size(node, "st,adc-diff-channels",
sizeof(*diff));
if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
return -EINVAL;
} else if (ret > 0) {
int size = ret * sizeof(*diff) / sizeof(u32);
num_diff = ret;
num_channels += ret;
ret = of_property_read_u32_array(node, "st,adc-diff-channels",
(u32 *)diff, size);
if (ret)
return ret;
}
if (!num_channels) {
dev_err(&indio_dev->dev, "No channels configured\n");
return -ENODATA;
}
/* Optional sample time is provided either for each, or all channels */
......@@ -1689,6 +1710,33 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
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 miss-configured\n", val);
return -EINVAL;
}
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
0, scan_index, false);
scan_index++;
}
for (i = 0; i < num_diff; i++) {
if (diff[i].vinp >= adc_info->max_channels ||
diff[i].vinn >= adc_info->max_channels) {
dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
diff[i].vinp, diff[i].vinn);
return -EINVAL;
}
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
diff[i].vinp, diff[i].vinn, scan_index,
true);
scan_index++;
}
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
......@@ -1696,12 +1744,9 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
* value per channel.
*/
of_property_read_u32_index(node, "st,min-sample-time-nsecs",
scan_index, &smp);
stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
&adc_info->channels[val],
scan_index, smp);
scan_index++;
i, &smp);
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, channels[i].channel, smp);
}
indio_dev->num_channels = scan_index;
......
......@@ -191,7 +191,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *ec_device;
struct iio_dev *indio_dev;
struct cros_ec_sensors_state *state;
struct iio_chan_spec *channel;
......@@ -201,7 +200,6 @@ static int cros_ec_sensors_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "No CROS EC device found.\n");
return -EINVAL;
}
ec_device = ec_dev->ec_dev;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
if (!indio_dev)
......
......@@ -3,6 +3,9 @@
*
* Copyright (C) 2017 Matt Ranostay <matt@ranostay.consulting>
*
* Support for MAX30105 optical particle sensor
* Copyright (C) 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
......@@ -13,6 +16,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 7-bit I2C chip address: 0x57
* TODO: proximity power saving feature
*/
......@@ -32,6 +36,18 @@
#define MAX30102_REGMAP_NAME "max30102_regmap"
#define MAX30102_DRV_NAME "max30102"
#define MAX30102_PART_NUMBER 0x15
enum max30102_chip_id {
max30102,
max30105,
};
enum max3012_led_idx {
MAX30102_LED_RED,
MAX30102_LED_IR,
MAX30105_LED_GREEN,
};
#define MAX30102_REG_INT_STATUS 0x00
#define MAX30102_REG_INT_STATUS_PWR_RDY BIT(0)
......@@ -52,7 +68,7 @@
#define MAX30102_REG_FIFO_OVR_CTR 0x05
#define MAX30102_REG_FIFO_RD_PTR 0x06
#define MAX30102_REG_FIFO_DATA 0x07
#define MAX30102_REG_FIFO_DATA_ENTRY_LEN 6
#define MAX30102_REG_FIFO_DATA_BYTES 3
#define MAX30102_REG_FIFO_CONFIG 0x08
#define MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES BIT(1)
......@@ -60,11 +76,18 @@
#define MAX30102_REG_FIFO_CONFIG_AFULL BIT(0)
#define MAX30102_REG_MODE_CONFIG 0x09
#define MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN BIT(0)
#define MAX30102_REG_MODE_CONFIG_MODE_HR_EN BIT(1)
#define MAX30102_REG_MODE_CONFIG_MODE_MASK 0x03
#define MAX30102_REG_MODE_CONFIG_MODE_NONE 0x00
#define MAX30102_REG_MODE_CONFIG_MODE_HR 0x02 /* red LED */
#define MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2 0x03 /* red + IR LED */
#define MAX30102_REG_MODE_CONFIG_MODE_MULTI 0x07 /* multi-LED mode */
#define MAX30102_REG_MODE_CONFIG_MODE_MASK GENMASK(2, 0)
#define MAX30102_REG_MODE_CONFIG_PWR BIT(7)
#define MAX30102_REG_MODE_CONTROL_SLOT21 0x11 /* multi-LED control */
#define MAX30102_REG_MODE_CONTROL_SLOT43 0x12
#define MAX30102_REG_MODE_CONTROL_SLOT_MASK (GENMASK(6, 4) | GENMASK(2, 0))
#define MAX30102_REG_MODE_CONTROL_SLOT_SHIFT 4
#define MAX30102_REG_SPO2_CONFIG 0x0a
#define MAX30102_REG_SPO2_CONFIG_PULSE_411_US 0x03
#define MAX30102_REG_SPO2_CONFIG_SR_400HZ 0x03
......@@ -75,6 +98,7 @@
#define MAX30102_REG_RED_LED_CONFIG 0x0c
#define MAX30102_REG_IR_LED_CONFIG 0x0d
#define MAX30105_REG_GREEN_LED_CONFIG 0x0e
#define MAX30102_REG_TEMP_CONFIG 0x21
#define MAX30102_REG_TEMP_CONFIG_TEMP_EN BIT(0)
......@@ -82,14 +106,18 @@
#define MAX30102_REG_TEMP_INTEGER 0x1f
#define MAX30102_REG_TEMP_FRACTION 0x20
#define MAX30102_REG_REV_ID 0xfe
#define MAX30102_REG_PART_ID 0xff
struct max30102_data {
struct i2c_client *client;
struct iio_dev *indio_dev;
struct mutex lock;
struct regmap *regmap;
enum max30102_chip_id chip_id;
u8 buffer[8];
__be32 processed_buffer[2]; /* 2 x 18-bit (padded to 32-bits) */
u8 buffer[12];
__be32 processed_buffer[3]; /* 3 x 18-bit (padded to 32-bits) */
};
static const struct regmap_config max30102_regmap_config = {
......@@ -99,37 +127,47 @@ static const struct regmap_config max30102_regmap_config = {
.val_bits = 8,
};
static const unsigned long max30102_scan_masks[] = {0x3, 0};
static const unsigned long max30102_scan_masks[] = {
BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
0
};
static const unsigned long max30105_scan_masks[] = {
BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR),
BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
BIT(MAX30105_LED_GREEN),
0
};
#define MAX30102_INTENSITY_CHANNEL(_si, _mod) { \
.type = IIO_INTENSITY, \
.channel2 = _mod, \
.modified = 1, \
.scan_index = _si, \
.scan_type = { \
.sign = 'u', \
.shift = 8, \
.realbits = 18, \
.storagebits = 32, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec max30102_channels[] = {
MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
{
.type = IIO_INTENSITY,
.channel2 = IIO_MOD_LIGHT_RED,
.modified = 1,
.scan_index = 0,
.scan_type = {
.sign = 'u',
.shift = 8,
.realbits = 18,
.storagebits = 32,
.endianness = IIO_BE,
},
},
{
.type = IIO_INTENSITY,
.channel2 = IIO_MOD_LIGHT_IR,
.modified = 1,
.scan_index = 1,
.scan_type = {
.sign = 'u',
.shift = 8,
.realbits = 18,
.storagebits = 32,
.endianness = IIO_BE,
},
.type = IIO_TEMP,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = -1,
},
};
static const struct iio_chan_spec max30105_channels[] = {
MAX30102_INTENSITY_CHANNEL(MAX30102_LED_RED, IIO_MOD_LIGHT_RED),
MAX30102_INTENSITY_CHANNEL(MAX30102_LED_IR, IIO_MOD_LIGHT_IR),
MAX30102_INTENSITY_CHANNEL(MAX30105_LED_GREEN, IIO_MOD_LIGHT_GREEN),
{
.type = IIO_TEMP,
.info_mask_separate =
......@@ -138,25 +176,69 @@ static const struct iio_chan_spec max30102_channels[] = {
},
};
static int max30102_set_powermode(struct max30102_data *data, bool state)
static int max30102_set_power(struct max30102_data *data, bool en)
{
return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
MAX30102_REG_MODE_CONFIG_PWR,
state ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
en ? 0 : MAX30102_REG_MODE_CONFIG_PWR);
}
static int max30102_set_powermode(struct max30102_data *data, u8 mode, bool en)
{
u8 reg = mode;
if (!en)
reg |= MAX30102_REG_MODE_CONFIG_PWR;
return regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
MAX30102_REG_MODE_CONFIG_PWR |
MAX30102_REG_MODE_CONFIG_MODE_MASK, reg);
}
#define MAX30102_MODE_CONTROL_LED_SLOTS(slot2, slot1) \
((slot2 << MAX30102_REG_MODE_CONTROL_SLOT_SHIFT) | slot1)
static int max30102_buffer_postenable(struct iio_dev *indio_dev)
{
struct max30102_data *data = iio_priv(indio_dev);
int ret;
u8 reg;
return max30102_set_powermode(data, true);
switch (*indio_dev->active_scan_mask) {
case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR):
reg = MAX30102_REG_MODE_CONFIG_MODE_HR_SPO2;
break;
case BIT(MAX30102_LED_RED) | BIT(MAX30102_LED_IR) |
BIT(MAX30105_LED_GREEN):
ret = regmap_update_bits(data->regmap,
MAX30102_REG_MODE_CONTROL_SLOT21,
MAX30102_REG_MODE_CONTROL_SLOT_MASK,
MAX30102_MODE_CONTROL_LED_SLOTS(2, 1));
if (ret)
return ret;
ret = regmap_update_bits(data->regmap,
MAX30102_REG_MODE_CONTROL_SLOT43,
MAX30102_REG_MODE_CONTROL_SLOT_MASK,
MAX30102_MODE_CONTROL_LED_SLOTS(0, 3));
if (ret)
return ret;
reg = MAX30102_REG_MODE_CONFIG_MODE_MULTI;
break;
default:
return -EINVAL;
}
return max30102_set_powermode(data, reg, true);
}
static int max30102_buffer_predisable(struct iio_dev *indio_dev)
{
struct max30102_data *data = iio_priv(indio_dev);
return max30102_set_powermode(data, false);
return max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
false);
}
static const struct iio_buffer_setup_ops max30102_buffer_setup_ops = {
......@@ -180,32 +262,51 @@ static inline int max30102_fifo_count(struct max30102_data *data)
return 0;
}
static int max30102_read_measurement(struct max30102_data *data)
#define MAX30102_COPY_DATA(i) \
memcpy(&data->processed_buffer[(i)], \
&buffer[(i) * MAX30102_REG_FIFO_DATA_BYTES], \
MAX30102_REG_FIFO_DATA_BYTES)
static int max30102_read_measurement(struct max30102_data *data,
unsigned int measurements)
{
int ret;
u8 *buffer = (u8 *) &data->buffer;
ret = i2c_smbus_read_i2c_block_data(data->client,
MAX30102_REG_FIFO_DATA,
MAX30102_REG_FIFO_DATA_ENTRY_LEN,
measurements *
MAX30102_REG_FIFO_DATA_BYTES,
buffer);
memcpy(&data->processed_buffer[0], &buffer[0], 3);
memcpy(&data->processed_buffer[1], &buffer[3], 3);
switch (measurements) {
case 3:
MAX30102_COPY_DATA(2);
case 2: /* fall-through */
MAX30102_COPY_DATA(1);
case 1: /* fall-through */
MAX30102_COPY_DATA(0);
break;
default:
return -EINVAL;
}
return (ret == MAX30102_REG_FIFO_DATA_ENTRY_LEN) ? 0 : -EINVAL;
return (ret == measurements * MAX30102_REG_FIFO_DATA_BYTES) ?
0 : -EINVAL;
}
static irqreturn_t max30102_interrupt_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct max30102_data *data = iio_priv(indio_dev);
unsigned int measurements = bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
int ret, cnt = 0;
mutex_lock(&data->lock);
while (cnt || (cnt = max30102_fifo_count(data)) > 0) {
ret = max30102_read_measurement(data);
ret = max30102_read_measurement(data, measurements);
if (ret)
break;
......@@ -251,6 +352,29 @@ static int max30102_led_init(struct max30102_data *data)
if (ret)
return ret;
if (data->chip_id == max30105) {
ret = of_property_read_u32(np,
"maxim,green-led-current-microamp", &val);
if (ret) {
dev_info(dev, "no green-led-current-microamp set\n");
/* Default to 7 mA green LED */
val = 7000;
}
ret = max30102_get_current_idx(val, &reg);
if (ret) {
dev_err(dev, "invalid green LED current setting %d\n",
val);
return ret;
}
ret = regmap_write(data->regmap, MAX30105_REG_GREEN_LED_CONFIG,
reg);
if (ret)
return ret;
}
ret = of_property_read_u32(np, "maxim,ir-led-current-microamp", &val);
if (ret) {
dev_info(dev, "no ir-led-current-microamp set\n");
......@@ -261,7 +385,7 @@ static int max30102_led_init(struct max30102_data *data)
ret = max30102_get_current_idx(val, &reg);
if (ret) {
dev_err(dev, "invalid IR LED current setting %d", val);
dev_err(dev, "invalid IR LED current setting %d\n", val);
return ret;
}
......@@ -277,7 +401,7 @@ static int max30102_chip_init(struct max30102_data *data)
if (ret)
return ret;
/* enable 18-bit HR + SPO2 readings at 400Hz */
/* configure 18-bit HR + SpO2 readings at 400Hz */
ret = regmap_write(data->regmap, MAX30102_REG_SPO2_CONFIG,
(MAX30102_REG_SPO2_CONFIG_ADC_4096_STEPS
<< MAX30102_REG_SPO2_CONFIG_ADC_MASK_SHIFT) |
......@@ -287,14 +411,6 @@ static int max30102_chip_init(struct max30102_data *data)
if (ret)
return ret;
/* enable SPO2 mode */
ret = regmap_update_bits(data->regmap, MAX30102_REG_MODE_CONFIG,
MAX30102_REG_MODE_CONFIG_MODE_MASK,
MAX30102_REG_MODE_CONFIG_MODE_HR_EN |
MAX30102_REG_MODE_CONFIG_MODE_SPO2_EN);
if (ret)
return ret;
/* average 4 samples + generate FIFO interrupt */
ret = regmap_write(data->regmap, MAX30102_REG_FIFO_CONFIG,
(MAX30102_REG_FIFO_CONFIG_AVG_4SAMPLES
......@@ -329,20 +445,31 @@ static int max30102_read_temp(struct max30102_data *data, int *val)
return 0;
}
static int max30102_get_temp(struct max30102_data *data, int *val)
static int max30102_get_temp(struct max30102_data *data, int *val, bool en)
{
int ret;
if (en) {
ret = max30102_set_power(data, true);
if (ret)
return ret;
}
/* start acquisition */
ret = regmap_update_bits(data->regmap, MAX30102_REG_TEMP_CONFIG,
MAX30102_REG_TEMP_CONFIG_TEMP_EN,
MAX30102_REG_TEMP_CONFIG_TEMP_EN);
if (ret)
return ret;
goto out;
msleep(35);
ret = max30102_read_temp(data, val);
return max30102_read_temp(data, val);
out:
if (en)
max30102_set_power(data, false);
return ret;
}
static int max30102_read_raw(struct iio_dev *indio_dev,
......@@ -355,20 +482,19 @@ static int max30102_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
/*
* Temperature reading can only be acquired while engine
* is running
* Temperature reading can only be acquired when not in
* shutdown; leave shutdown briefly when buffer not running
*/
mutex_lock(&indio_dev->mlock);
if (!iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else {
ret = max30102_get_temp(data, val);
if (!ret)
ret = IIO_VAL_INT;
}
ret = max30102_get_temp(data, val, true);
else
ret = max30102_get_temp(data, val, false);
mutex_unlock(&indio_dev->mlock);
if (ret)
return ret;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
*val = 1; /* 0.0625 */
......@@ -391,6 +517,7 @@ static int max30102_probe(struct i2c_client *client,
struct iio_buffer *buffer;
struct iio_dev *indio_dev;
int ret;
unsigned int reg;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
......@@ -403,10 +530,7 @@ static int max30102_probe(struct i2c_client *client,
iio_device_attach_buffer(indio_dev, buffer);
indio_dev->name = MAX30102_DRV_NAME;
indio_dev->channels = max30102_channels;
indio_dev->info = &max30102_info;
indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
indio_dev->available_scan_masks = max30102_scan_masks;
indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
indio_dev->setup_ops = &max30102_buffer_setup_ops;
indio_dev->dev.parent = &client->dev;
......@@ -414,16 +538,50 @@ static int max30102_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
data->indio_dev = indio_dev;
data->client = client;
data->chip_id = id->driver_data;
mutex_init(&data->lock);
i2c_set_clientdata(client, indio_dev);
switch (data->chip_id) {
case max30105:
indio_dev->channels = max30105_channels;
indio_dev->num_channels = ARRAY_SIZE(max30105_channels);
indio_dev->available_scan_masks = max30105_scan_masks;
break;
case max30102:
indio_dev->channels = max30102_channels;
indio_dev->num_channels = ARRAY_SIZE(max30102_channels);
indio_dev->available_scan_masks = max30102_scan_masks;
break;
default:
return -ENODEV;
}
data->regmap = devm_regmap_init_i2c(client, &max30102_regmap_config);
if (IS_ERR(data->regmap)) {
dev_err(&client->dev, "regmap initialization failed.\n");
dev_err(&client->dev, "regmap initialization failed\n");
return PTR_ERR(data->regmap);
}
max30102_set_powermode(data, false);
/* check part ID */
ret = regmap_read(data->regmap, MAX30102_REG_PART_ID, &reg);
if (ret)
return ret;
if (reg != MAX30102_PART_NUMBER)
return -ENODEV;
/* show revision ID */
ret = regmap_read(data->regmap, MAX30102_REG_REV_ID, &reg);
if (ret)
return ret;
dev_dbg(&client->dev, "max3010x revision %02x\n", reg);
/* clear mode setting, chip shutdown */
ret = max30102_set_powermode(data, MAX30102_REG_MODE_CONFIG_MODE_NONE,
false);
if (ret)
return ret;
ret = max30102_chip_init(data);
if (ret)
......@@ -452,19 +610,21 @@ static int max30102_remove(struct i2c_client *client)
struct max30102_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
max30102_set_powermode(data, false);
max30102_set_power(data, false);
return 0;
}
static const struct i2c_device_id max30102_id[] = {
{ "max30102", 0 },
{ "max30102", max30102 },
{ "max30105", max30105 },
{}
};
MODULE_DEVICE_TABLE(i2c, max30102_id);
static const struct of_device_id max30102_dt_ids[] = {
{ .compatible = "maxim,max30102" },
{ .compatible = "maxim,max30105" },
{ }
};
MODULE_DEVICE_TABLE(of, max30102_dt_ids);
......@@ -481,5 +641,5 @@ static struct i2c_driver max30102_driver = {
module_i2c_driver(max30102_driver);
MODULE_AUTHOR("Matt Ranostay <matt@ranostay.consulting>");
MODULE_DESCRIPTION("MAX30102 heart rate and pulse oximeter sensor");
MODULE_DESCRIPTION("MAX30102 heart rate/pulse oximeter and MAX30105 particle sensor driver");
MODULE_LICENSE("GPL");
......@@ -196,8 +196,7 @@ void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
{
struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
if (st->mux_client)
i2c_unregister_device(st->mux_client);
i2c_unregister_device(st->mux_client);
}
#else
......
......@@ -588,6 +588,7 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
return snprintf(buf, len, "%d", vals[0]);
case IIO_VAL_INT_PLUS_MICRO_DB:
scale_db = true;
/* fall through */
case IIO_VAL_INT_PLUS_MICRO:
if (vals[1] < 0)
return snprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
......
......@@ -334,6 +334,30 @@ config STK3310
Choosing M will build the driver as a module. If so, the module
will be called stk3310.
config ST_UVIS25
tristate "STMicroelectronics UVIS25 sensor driver"
depends on (I2C || SPI)
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select ST_UVIS25_I2C if (I2C)
select ST_UVIS25_SPI if (SPI_MASTER)
help
Say yes here to build support for STMicroelectronics UVIS25
uv sensor
To compile this driver as a module, choose M here: the module
will be called st_uvis25.
config ST_UVIS25_I2C
tristate
depends on ST_UVIS25
select REGMAP_I2C
config ST_UVIS25_SPI
tristate
depends on ST_UVIS25
select REGMAP_SPI
config TCS3414
tristate "TAOS TCS3414 digital color sensor"
depends on I2C
......@@ -425,4 +449,14 @@ config VL6180
To compile this driver as a module, choose M here: the
module will be called vl6180.
config ZOPT2201
tristate "ZOPT2201 ALS and UV B sensor"
depends on I2C
help
Say Y here if you want to build a driver for the IDT
ZOPT2201 ambient light and UV B sensor.
To compile this driver as a module, choose M here: the
module will be called zopt2201.
endmenu
......@@ -33,6 +33,9 @@ obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_ST_UVIS25) += st_uvis25_core.o
obj-$(CONFIG_ST_UVIS25_I2C) += st_uvis25_i2c.o
obj-$(CONFIG_ST_UVIS25_SPI) += st_uvis25_spi.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL2583) += tsl2583.o
......@@ -41,3 +44,4 @@ obj-$(CONFIG_US5182D) += us5182d.o
obj-$(CONFIG_VCNL4000) += vcnl4000.o
obj-$(CONFIG_VEML6070) += veml6070.o
obj-$(CONFIG_VL6180) += vl6180.o
obj-$(CONFIG_ZOPT2201) += zopt2201.o
......@@ -181,7 +181,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *ec_device;
struct iio_dev *indio_dev;
struct cros_ec_light_prox_state *state;
struct iio_chan_spec *channel;
......@@ -191,7 +190,6 @@ static int cros_ec_light_prox_probe(struct platform_device *pdev)
dev_warn(dev, "No CROS EC device found.\n");
return -EINVAL;
}
ec_device = ec_dev->ec_dev;
indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
if (!indio_dev)
......
/*
* STMicroelectronics uvis25 sensor driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#ifndef ST_UVIS25_H
#define ST_UVIS25_H
#define ST_UVIS25_DEV_NAME "uvis25"
#include <linux/iio/iio.h>
/**
* struct st_uvis25_hw - ST UVIS25 sensor instance
* @regmap: Register map of the device.
* @trig: The trigger in use by the driver.
* @enabled: Status of the sensor (false->off, true->on).
* @irq: Device interrupt line (I2C or SPI).
*/
struct st_uvis25_hw {
struct regmap *regmap;
struct iio_trigger *trig;
bool enabled;
int irq;
};
extern const struct dev_pm_ops st_uvis25_pm_ops;
int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap);
#endif /* ST_UVIS25_H */
/*
* STMicroelectronics uvis25 sensor driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/iio/sysfs.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/buffer.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define ST_UVIS25_REG_WHOAMI_ADDR 0x0f
#define ST_UVIS25_REG_WHOAMI_VAL 0xca
#define ST_UVIS25_REG_CTRL1_ADDR 0x20
#define ST_UVIS25_REG_ODR_MASK BIT(0)
#define ST_UVIS25_REG_BDU_MASK BIT(1)
#define ST_UVIS25_REG_CTRL2_ADDR 0x21
#define ST_UVIS25_REG_BOOT_MASK BIT(7)
#define ST_UVIS25_REG_CTRL3_ADDR 0x22
#define ST_UVIS25_REG_HL_MASK BIT(7)
#define ST_UVIS25_REG_STATUS_ADDR 0x27
#define ST_UVIS25_REG_UV_DA_MASK BIT(0)
#define ST_UVIS25_REG_OUT_ADDR 0x28
static const struct iio_chan_spec st_uvis25_channels[] = {
{
.type = IIO_UVINDEX,
.address = ST_UVIS25_REG_OUT_ADDR,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = 0,
.scan_type = {
.sign = 'u',
.realbits = 8,
.storagebits = 8,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int st_uvis25_check_whoami(struct st_uvis25_hw *hw)
{
int err, data;
err = regmap_read(hw->regmap, ST_UVIS25_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(regmap_get_device(hw->regmap),
"failed to read whoami register\n");
return err;
}
if (data != ST_UVIS25_REG_WHOAMI_VAL) {
dev_err(regmap_get_device(hw->regmap),
"wrong whoami {%02x vs %02x}\n",
data, ST_UVIS25_REG_WHOAMI_VAL);
return -ENODEV;
}
return 0;
}
static int st_uvis25_set_enable(struct st_uvis25_hw *hw, bool enable)
{
int err;
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, enable);
if (err < 0)
return err;
hw->enabled = enable;
return 0;
}
static int st_uvis25_read_oneshot(struct st_uvis25_hw *hw, u8 addr, int *val)
{
int err;
err = st_uvis25_set_enable(hw, true);
if (err < 0)
return err;
msleep(1500);
/*
* in order to avoid possible race conditions with interrupt
* generation, disable the sensor first and then poll output
* register. That sequence guarantees the interrupt will be reset
* when irq line is unmasked
*/
err = st_uvis25_set_enable(hw, false);
if (err < 0)
return err;
err = regmap_read(hw->regmap, addr, val);
return err < 0 ? err : IIO_VAL_INT;
}
static int st_uvis25_read_raw(struct iio_dev *iio_dev,
struct iio_chan_spec const *ch,
int *val, int *val2, long mask)
{
int ret;
ret = iio_device_claim_direct_mode(iio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED: {
struct st_uvis25_hw *hw = iio_priv(iio_dev);
/*
* mask irq line during oneshot read since the sensor
* does not export the capability to disable data-ready line
* in the register map and it is enabled by default.
* If the line is unmasked during read_raw() it will be set
* active and never reset since the trigger is disabled
*/
if (hw->irq > 0)
disable_irq(hw->irq);
ret = st_uvis25_read_oneshot(hw, ch->address, val);
if (hw->irq > 0)
enable_irq(hw->irq);
break;
}
default:
ret = -EINVAL;
break;
}
iio_device_release_direct_mode(iio_dev);
return ret;
}
static irqreturn_t st_uvis25_trigger_handler_thread(int irq, void *private)
{
struct st_uvis25_hw *hw = private;
int err, status;
err = regmap_read(hw->regmap, ST_UVIS25_REG_STATUS_ADDR, &status);
if (err < 0)
return IRQ_HANDLED;
if (!(status & ST_UVIS25_REG_UV_DA_MASK))
return IRQ_NONE;
iio_trigger_poll_chained(hw->trig);
return IRQ_HANDLED;
}
static int st_uvis25_allocate_trigger(struct iio_dev *iio_dev)
{
struct st_uvis25_hw *hw = iio_priv(iio_dev);
struct device *dev = regmap_get_device(hw->regmap);
bool irq_active_low = false;
unsigned long irq_type;
int err;
irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
switch (irq_type) {
case IRQF_TRIGGER_HIGH:
case IRQF_TRIGGER_RISING:
break;
case IRQF_TRIGGER_LOW:
case IRQF_TRIGGER_FALLING:
irq_active_low = true;
break;
default:
dev_info(dev, "mode %lx unsupported\n", irq_type);
return -EINVAL;
}
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL3_ADDR,
ST_UVIS25_REG_HL_MASK, irq_active_low);
if (err < 0)
return err;
err = devm_request_threaded_irq(dev, hw->irq, NULL,
st_uvis25_trigger_handler_thread,
irq_type | IRQF_ONESHOT,
iio_dev->name, hw);
if (err) {
dev_err(dev, "failed to request trigger irq %d\n",
hw->irq);
return err;
}
hw->trig = devm_iio_trigger_alloc(dev, "%s-trigger",
iio_dev->name);
if (!hw->trig)
return -ENOMEM;
iio_trigger_set_drvdata(hw->trig, iio_dev);
hw->trig->dev.parent = dev;
return devm_iio_trigger_register(dev, hw->trig);
}
static int st_uvis25_buffer_preenable(struct iio_dev *iio_dev)
{
return st_uvis25_set_enable(iio_priv(iio_dev), true);
}
static int st_uvis25_buffer_postdisable(struct iio_dev *iio_dev)
{
return st_uvis25_set_enable(iio_priv(iio_dev), false);
}
static const struct iio_buffer_setup_ops st_uvis25_buffer_ops = {
.preenable = st_uvis25_buffer_preenable,
.postenable = iio_triggered_buffer_postenable,
.predisable = iio_triggered_buffer_predisable,
.postdisable = st_uvis25_buffer_postdisable,
};
static irqreturn_t st_uvis25_buffer_handler_thread(int irq, void *p)
{
u8 buffer[ALIGN(sizeof(u8), sizeof(s64)) + sizeof(s64)];
struct iio_poll_func *pf = p;
struct iio_dev *iio_dev = pf->indio_dev;
struct st_uvis25_hw *hw = iio_priv(iio_dev);
int err;
err = regmap_read(hw->regmap, ST_UVIS25_REG_OUT_ADDR, (int *)buffer);
if (err < 0)
goto out;
iio_push_to_buffers_with_timestamp(iio_dev, buffer,
iio_get_time_ns(iio_dev));
out:
iio_trigger_notify_done(hw->trig);
return IRQ_HANDLED;
}
static int st_uvis25_allocate_buffer(struct iio_dev *iio_dev)
{
struct st_uvis25_hw *hw = iio_priv(iio_dev);
return devm_iio_triggered_buffer_setup(regmap_get_device(hw->regmap),
iio_dev, NULL,
st_uvis25_buffer_handler_thread,
&st_uvis25_buffer_ops);
}
static const struct iio_info st_uvis25_info = {
.read_raw = st_uvis25_read_raw,
};
static int st_uvis25_init_sensor(struct st_uvis25_hw *hw)
{
int err;
err = regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL2_ADDR,
ST_UVIS25_REG_BOOT_MASK, 1);
if (err < 0)
return err;
msleep(2000);
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_BDU_MASK, 1);
}
int st_uvis25_probe(struct device *dev, int irq, struct regmap *regmap)
{
struct st_uvis25_hw *hw;
struct iio_dev *iio_dev;
int err;
iio_dev = devm_iio_device_alloc(dev, sizeof(*hw));
if (!iio_dev)
return -ENOMEM;
dev_set_drvdata(dev, (void *)iio_dev);
hw = iio_priv(iio_dev);
hw->irq = irq;
hw->regmap = regmap;
err = st_uvis25_check_whoami(hw);
if (err < 0)
return err;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->dev.parent = dev;
iio_dev->channels = st_uvis25_channels;
iio_dev->num_channels = ARRAY_SIZE(st_uvis25_channels);
iio_dev->name = ST_UVIS25_DEV_NAME;
iio_dev->info = &st_uvis25_info;
err = st_uvis25_init_sensor(hw);
if (err < 0)
return err;
if (hw->irq > 0) {
err = st_uvis25_allocate_buffer(iio_dev);
if (err < 0)
return err;
err = st_uvis25_allocate_trigger(iio_dev);
if (err)
return err;
}
return devm_iio_device_register(dev, iio_dev);
}
EXPORT_SYMBOL(st_uvis25_probe);
static int __maybe_unused st_uvis25_suspend(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, 0);
}
static int __maybe_unused st_uvis25_resume(struct device *dev)
{
struct iio_dev *iio_dev = dev_get_drvdata(dev);
struct st_uvis25_hw *hw = iio_priv(iio_dev);
if (hw->enabled)
return regmap_update_bits(hw->regmap, ST_UVIS25_REG_CTRL1_ADDR,
ST_UVIS25_REG_ODR_MASK, 1);
return 0;
}
const struct dev_pm_ops st_uvis25_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(st_uvis25_suspend, st_uvis25_resume)
};
EXPORT_SYMBOL(st_uvis25_pm_ops);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 sensor driver");
MODULE_LICENSE("GPL v2");
/*
* STMicroelectronics uvis25 i2c driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define UVIS25_I2C_AUTO_INCREMENT BIT(7)
const struct regmap_config st_uvis25_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.write_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
.read_flag_mask = UVIS25_I2C_AUTO_INCREMENT,
};
static int st_uvis25_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
regmap = devm_regmap_init_i2c(client, &st_uvis25_i2c_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_uvis25_probe(&client->dev, client->irq, regmap);
}
static const struct of_device_id st_uvis25_i2c_of_match[] = {
{ .compatible = "st,uvis25", },
{},
};
MODULE_DEVICE_TABLE(of, st_uvis25_i2c_of_match);
static const struct i2c_device_id st_uvis25_i2c_id_table[] = {
{ ST_UVIS25_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(i2c, st_uvis25_i2c_id_table);
static struct i2c_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_i2c",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_i2c_of_match),
},
.probe = st_uvis25_i2c_probe,
.id_table = st_uvis25_i2c_id_table,
};
module_i2c_driver(st_uvis25_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 i2c driver");
MODULE_LICENSE("GPL v2");
/*
* STMicroelectronics uvis25 spi driver
*
* Copyright 2017 STMicroelectronics Inc.
*
* Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>
*
* Licensed under the GPL-2.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "st_uvis25.h"
#define UVIS25_SENSORS_SPI_READ BIT(7)
#define UVIS25_SPI_AUTO_INCREMENT BIT(6)
const struct regmap_config st_uvis25_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.read_flag_mask = UVIS25_SENSORS_SPI_READ | UVIS25_SPI_AUTO_INCREMENT,
.write_flag_mask = UVIS25_SPI_AUTO_INCREMENT,
};
static int st_uvis25_spi_probe(struct spi_device *spi)
{
struct regmap *regmap;
regmap = devm_regmap_init_spi(spi, &st_uvis25_spi_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return st_uvis25_probe(&spi->dev, spi->irq, regmap);
}
static const struct of_device_id st_uvis25_spi_of_match[] = {
{ .compatible = "st,uvis25", },
{},
};
MODULE_DEVICE_TABLE(of, st_uvis25_spi_of_match);
static const struct spi_device_id st_uvis25_spi_id_table[] = {
{ ST_UVIS25_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_uvis25_spi_id_table);
static struct spi_driver st_uvis25_driver = {
.driver = {
.name = "st_uvis25_spi",
.pm = &st_uvis25_pm_ops,
.of_match_table = of_match_ptr(st_uvis25_spi_of_match),
},
.probe = st_uvis25_spi_probe,
.id_table = st_uvis25_spi_id_table,
};
module_spi_driver(st_uvis25_driver);
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi83@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics uvis25 spi driver");
MODULE_LICENSE("GPL v2");
/*
* zopt2201.c - Support for IDT ZOPT2201 ambient light and UV B sensor
*
* Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* Datasheet: https://www.idt.com/document/dst/zopt2201-datasheet
* 7-bit I2C slave addresses 0x53 (default) or 0x52 (programmed)
*
* TODO: interrupt support, ALS/UVB raw mode
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define ZOPT2201_DRV_NAME "zopt2201"
/* Registers */
#define ZOPT2201_MAIN_CTRL 0x00
#define ZOPT2201_LS_MEAS_RATE 0x04
#define ZOPT2201_LS_GAIN 0x05
#define ZOPT2201_PART_ID 0x06
#define ZOPT2201_MAIN_STATUS 0x07
#define ZOPT2201_ALS_DATA 0x0d /* LSB first, 13 to 20 bits */
#define ZOPT2201_UVB_DATA 0x10 /* LSB first, 13 to 20 bits */
#define ZOPT2201_UV_COMP_DATA 0x13 /* LSB first, 13 to 20 bits */
#define ZOPT2201_COMP_DATA 0x16 /* LSB first, 13 to 20 bits */
#define ZOPT2201_INT_CFG 0x19
#define ZOPT2201_INT_PST 0x1a
#define ZOPT2201_MAIN_CTRL_LS_MODE BIT(3) /* 0 .. ALS, 1 .. UV B */
#define ZOPT2201_MAIN_CTRL_LS_EN BIT(1)
/* Values for ZOPT2201_LS_MEAS_RATE resolution / bit width */
#define ZOPT2201_MEAS_RES_20BIT 0 /* takes 400 ms */
#define ZOPT2201_MEAS_RES_19BIT 1 /* takes 200 ms */
#define ZOPT2201_MEAS_RES_18BIT 2 /* takes 100 ms, default */
#define ZOPT2201_MEAS_RES_17BIT 3 /* takes 50 ms */
#define ZOPT2201_MEAS_RES_16BIT 4 /* takes 25 ms */
#define ZOPT2201_MEAS_RES_13BIT 5 /* takes 3.125 ms */
#define ZOPT2201_MEAS_RES_SHIFT 4
/* Values for ZOPT2201_LS_MEAS_RATE measurement rate */
#define ZOPT2201_MEAS_FREQ_25MS 0
#define ZOPT2201_MEAS_FREQ_50MS 1
#define ZOPT2201_MEAS_FREQ_100MS 2 /* default */
#define ZOPT2201_MEAS_FREQ_200MS 3
#define ZOPT2201_MEAS_FREQ_500MS 4
#define ZOPT2201_MEAS_FREQ_1000MS 5
#define ZOPT2201_MEAS_FREQ_2000MS 6
/* Values for ZOPT2201_LS_GAIN */
#define ZOPT2201_LS_GAIN_1 0
#define ZOPT2201_LS_GAIN_3 1
#define ZOPT2201_LS_GAIN_6 2
#define ZOPT2201_LS_GAIN_9 3
#define ZOPT2201_LS_GAIN_18 4
/* Values for ZOPT2201_MAIN_STATUS */
#define ZOPT2201_MAIN_STATUS_POWERON BIT(5)
#define ZOPT2201_MAIN_STATUS_INT BIT(4)
#define ZOPT2201_MAIN_STATUS_DRDY BIT(3)
#define ZOPT2201_PART_NUMBER 0xb2
struct zopt2201_data {
struct i2c_client *client;
struct mutex lock;
u8 gain;
u8 res;
u8 rate;
};
static const struct {
unsigned int gain; /* gain factor */
unsigned int scale; /* micro lux per count */
} zopt2201_gain_als[] = {
{ 1, 19200000 },
{ 3, 6400000 },
{ 6, 3200000 },
{ 9, 2133333 },
{ 18, 1066666 },
};
static const struct {
unsigned int gain; /* gain factor */
unsigned int scale; /* micro W/m2 per count */
} zopt2201_gain_uvb[] = {
{ 1, 460800 },
{ 3, 153600 },
{ 6, 76800 },
{ 9, 51200 },
{ 18, 25600 },
};
static const struct {
unsigned int bits; /* sensor resolution in bits */
unsigned long us; /* measurement time in micro seconds */
} zopt2201_resolution[] = {
{ 20, 400000 },
{ 19, 200000 },
{ 18, 100000 },
{ 17, 50000 },
{ 16, 25000 },
{ 13, 3125 },
};
static const struct {
unsigned int scale, uscale; /* scale factor as integer + micro */
u8 gain; /* gain register value */
u8 res; /* resolution register value */
} zopt2201_scale_als[] = {
{ 19, 200000, 0, 5 },
{ 6, 400000, 1, 5 },
{ 3, 200000, 2, 5 },
{ 2, 400000, 0, 4 },
{ 2, 133333, 3, 5 },
{ 1, 200000, 0, 3 },
{ 1, 66666, 4, 5 },
{ 0, 800000, 1, 4 },
{ 0, 600000, 0, 2 },
{ 0, 400000, 2, 4 },
{ 0, 300000, 0, 1 },
{ 0, 266666, 3, 4 },
{ 0, 200000, 2, 3 },
{ 0, 150000, 0, 0 },
{ 0, 133333, 4, 4 },
{ 0, 100000, 2, 2 },
{ 0, 66666, 4, 3 },
{ 0, 50000, 2, 1 },
{ 0, 33333, 4, 2 },
{ 0, 25000, 2, 0 },
{ 0, 16666, 4, 1 },
{ 0, 8333, 4, 0 },
};
static const struct {
unsigned int scale, uscale; /* scale factor as integer + micro */
u8 gain; /* gain register value */
u8 res; /* resolution register value */
} zopt2201_scale_uvb[] = {
{ 0, 460800, 0, 5 },
{ 0, 153600, 1, 5 },
{ 0, 76800, 2, 5 },
{ 0, 57600, 0, 4 },
{ 0, 51200, 3, 5 },
{ 0, 28800, 0, 3 },
{ 0, 25600, 4, 5 },
{ 0, 19200, 1, 4 },
{ 0, 14400, 0, 2 },
{ 0, 9600, 2, 4 },
{ 0, 7200, 0, 1 },
{ 0, 6400, 3, 4 },
{ 0, 4800, 2, 3 },
{ 0, 3600, 0, 0 },
{ 0, 3200, 4, 4 },
{ 0, 2400, 2, 2 },
{ 0, 1600, 4, 3 },
{ 0, 1200, 2, 1 },
{ 0, 800, 4, 2 },
{ 0, 600, 2, 0 },
{ 0, 400, 4, 1 },
{ 0, 200, 4, 0 },
};
static int zopt2201_enable_mode(struct zopt2201_data *data, bool uvb_mode)
{
u8 out = ZOPT2201_MAIN_CTRL_LS_EN;
if (uvb_mode)
out |= ZOPT2201_MAIN_CTRL_LS_MODE;
return i2c_smbus_write_byte_data(data->client, ZOPT2201_MAIN_CTRL, out);
}
static int zopt2201_read(struct zopt2201_data *data, u8 reg)
{
struct i2c_client *client = data->client;
int tries = 10;
u8 buf[3];
int ret;
mutex_lock(&data->lock);
ret = zopt2201_enable_mode(data, reg == ZOPT2201_UVB_DATA);
if (ret < 0)
goto fail;
while (tries--) {
unsigned long t = zopt2201_resolution[data->res].us;
if (t <= 20000)
usleep_range(t, t + 1000);
else
msleep(t / 1000);
ret = i2c_smbus_read_byte_data(client, ZOPT2201_MAIN_STATUS);
if (ret < 0)
goto fail;
if (ret & ZOPT2201_MAIN_STATUS_DRDY)
break;
}
if (tries < 0) {
ret = -ETIMEDOUT;
goto fail;
}
ret = i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf);
if (ret < 0)
goto fail;
ret = i2c_smbus_write_byte_data(client, ZOPT2201_MAIN_CTRL, 0x00);
if (ret < 0)
goto fail;
mutex_unlock(&data->lock);
return (buf[2] << 16) | (buf[1] << 8) | buf[0];
fail:
mutex_unlock(&data->lock);
return ret;
}
static const struct iio_chan_spec zopt2201_channels[] = {
{
.type = IIO_LIGHT,
.address = ZOPT2201_ALS_DATA,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
},
{
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_UV,
.address = ZOPT2201_UVB_DATA,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME),
},
{
.type = IIO_UVINDEX,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
static int zopt2201_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct zopt2201_data *data = iio_priv(indio_dev);
u64 tmp;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = zopt2201_read(data, chan->address);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
ret = zopt2201_read(data, ZOPT2201_UVB_DATA);
if (ret < 0)
return ret;
*val = ret * 18 *
(1 << (20 - zopt2201_resolution[data->res].bits)) /
zopt2201_gain_uvb[data->gain].gain;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->address) {
case ZOPT2201_ALS_DATA:
*val = zopt2201_gain_als[data->gain].scale;
break;
case ZOPT2201_UVB_DATA:
*val = zopt2201_gain_uvb[data->gain].scale;
break;
default:
return -EINVAL;
}
*val2 = 1000000;
*val2 *= (1 << (zopt2201_resolution[data->res].bits - 13));
tmp = div_s64(*val * 1000000ULL, *val2);
*val = div_s64_rem(tmp, 1000000, val2);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
*val2 = zopt2201_resolution[data->res].us;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int zopt2201_set_resolution(struct zopt2201_data *data, u8 res)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_MEAS_RATE,
(res << ZOPT2201_MEAS_RES_SHIFT) |
data->rate);
if (ret < 0)
return ret;
data->res = res;
return 0;
}
static int zopt2201_write_resolution(struct zopt2201_data *data,
int val, int val2)
{
int i, ret;
if (val != 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
if (val2 == zopt2201_resolution[i].us) {
mutex_lock(&data->lock);
ret = zopt2201_set_resolution(data, i);
mutex_unlock(&data->lock);
return ret;
}
return -EINVAL;
}
static int zopt2201_set_gain(struct zopt2201_data *data, u8 gain)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, ZOPT2201_LS_GAIN, gain);
if (ret < 0)
return ret;
data->gain = gain;
return 0;
}
static int zopt2201_write_scale_als_by_idx(struct zopt2201_data *data, int idx)
{
int ret;
mutex_lock(&data->lock);
ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
if (ret < 0)
goto unlock;
ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
unlock:
mutex_unlock(&data->lock);
return ret;
}
static int zopt2201_write_scale_als(struct zopt2201_data *data,
int val, int val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
if (val == zopt2201_scale_als[i].scale &&
val2 == zopt2201_scale_als[i].uscale) {
return zopt2201_write_scale_als_by_idx(data, i);
}
return -EINVAL;
}
static int zopt2201_write_scale_uvb_by_idx(struct zopt2201_data *data, int idx)
{
int ret;
mutex_lock(&data->lock);
ret = zopt2201_set_resolution(data, zopt2201_scale_als[idx].res);
if (ret < 0)
goto unlock;
ret = zopt2201_set_gain(data, zopt2201_scale_als[idx].gain);
unlock:
mutex_unlock(&data->lock);
return ret;
}
static int zopt2201_write_scale_uvb(struct zopt2201_data *data,
int val, int val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
if (val == zopt2201_scale_uvb[i].scale &&
val2 == zopt2201_scale_uvb[i].uscale)
return zopt2201_write_scale_uvb_by_idx(data, i);
return -EINVAL;
}
static int zopt2201_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct zopt2201_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
return zopt2201_write_resolution(data, val, val2);
case IIO_CHAN_INFO_SCALE:
switch (chan->address) {
case ZOPT2201_ALS_DATA:
return zopt2201_write_scale_als(data, val, val2);
case ZOPT2201_UVB_DATA:
return zopt2201_write_scale_uvb(data, val, val2);
default:
return -EINVAL;
}
}
return -EINVAL;
}
static ssize_t zopt2201_show_int_time_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
size_t len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(zopt2201_resolution); i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06lu ",
zopt2201_resolution[i].us);
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_INT_TIME_AVAIL(zopt2201_show_int_time_available);
static ssize_t zopt2201_show_als_scale_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_als); i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
zopt2201_scale_als[i].scale,
zopt2201_scale_als[i].uscale);
buf[len - 1] = '\n';
return len;
}
static ssize_t zopt2201_show_uvb_scale_avail(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t len = 0;
int i;
for (i = 0; i < ARRAY_SIZE(zopt2201_scale_uvb); i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
zopt2201_scale_uvb[i].scale,
zopt2201_scale_uvb[i].uscale);
buf[len - 1] = '\n';
return len;
}
static IIO_DEVICE_ATTR(in_illuminance_scale_available, 0444,
zopt2201_show_als_scale_avail, NULL, 0);
static IIO_DEVICE_ATTR(in_intensity_uv_scale_available, 0444,
zopt2201_show_uvb_scale_avail, NULL, 0);
static struct attribute *zopt2201_attributes[] = {
&iio_dev_attr_integration_time_available.dev_attr.attr,
&iio_dev_attr_in_illuminance_scale_available.dev_attr.attr,
&iio_dev_attr_in_intensity_uv_scale_available.dev_attr.attr,
NULL
};
static const struct attribute_group zopt2201_attribute_group = {
.attrs = zopt2201_attributes,
};
static const struct iio_info zopt2201_info = {
.read_raw = zopt2201_read_raw,
.write_raw = zopt2201_write_raw,
.attrs = &zopt2201_attribute_group,
};
static int zopt2201_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct zopt2201_data *data;
struct iio_dev *indio_dev;
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK))
return -EOPNOTSUPP;
ret = i2c_smbus_read_byte_data(client, ZOPT2201_PART_ID);
if (ret < 0)
return ret;
if (ret != ZOPT2201_PART_NUMBER)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &zopt2201_info;
indio_dev->channels = zopt2201_channels;
indio_dev->num_channels = ARRAY_SIZE(zopt2201_channels);
indio_dev->name = ZOPT2201_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
data->rate = ZOPT2201_MEAS_FREQ_100MS;
ret = zopt2201_set_resolution(data, ZOPT2201_MEAS_RES_18BIT);
if (ret < 0)
return ret;
ret = zopt2201_set_gain(data, ZOPT2201_LS_GAIN_3);
if (ret < 0)
return ret;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id zopt2201_id[] = {
{ "zopt2201", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, zopt2201_id);
static struct i2c_driver zopt2201_driver = {
.driver = {
.name = ZOPT2201_DRV_NAME,
},
.probe = zopt2201_probe,
.id_table = zopt2201_id,
};
module_i2c_driver(zopt2201_driver);
MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("IDT ZOPT2201 ambient light and UV B sensor driver");
MODULE_LICENSE("GPL");
......@@ -788,6 +788,7 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"AK8975", AK8975},
{"AK8963", AK8963},
{"INVN6500", AK8963},
{"AK009911", AK09911},
{"AK09911", AK09911},
{"AK09912", AK09912},
{ },
......
......@@ -1022,6 +1022,7 @@ static const struct dev_pm_ops sx9500_pm_ops = {
static const struct acpi_device_id sx9500_acpi_match[] = {
{"SSX9500", 0},
{"SASX9500", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
......
......@@ -118,22 +118,23 @@ static inline ssize_t ad7152_start_calib(struct device *dev,
mutex_lock(&chip->state_lock);
ret = i2c_smbus_write_byte_data(chip->client, AD7152_REG_CFG, regval);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
if (ret < 0)
goto unlock;
do {
mdelay(20);
ret = i2c_smbus_read_byte_data(chip->client, AD7152_REG_CFG);
if (ret < 0) {
mutex_unlock(&chip->state_lock);
return ret;
}
if (ret < 0)
goto unlock;
} while ((ret == regval) && timeout--);
mutex_unlock(&chip->state_lock);
return len;
unlock:
mutex_unlock(&chip->state_lock);
return ret;
}
static ssize_t ad7152_start_offset_calib(struct device *dev,
......
......@@ -302,23 +302,24 @@ static inline ssize_t ad7746_start_calib(struct device *dev,
mutex_lock(&chip->lock);
regval |= chip->config;
ret = i2c_smbus_write_byte_data(chip->client, AD7746_REG_CFG, regval);
if (ret < 0) {
mutex_unlock(&chip->lock);
return ret;
}
if (ret < 0)
goto unlock;
do {
msleep(20);
ret = i2c_smbus_read_byte_data(chip->client, AD7746_REG_CFG);
if (ret < 0) {
mutex_unlock(&chip->lock);
return ret;
}
if (ret < 0)
goto unlock;
} while ((ret == regval) && timeout--);
mutex_unlock(&chip->lock);
return len;
unlock:
mutex_unlock(&chip->lock);
return ret;
}
static ssize_t ad7746_start_offset_calib(struct device *dev,
......
......@@ -187,9 +187,9 @@ static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
return -ENOMEM;
st->irq = platform_get_irq(pdev, 0);
if (!st->irq) {
if (st->irq < 0) {
dev_err(&pdev->dev, "No IRQs specified");
return -ENODEV;
return st->irq;
}
ret = iio_bfin_tmr_get_number(st->irq);
......
......@@ -28,4 +28,11 @@ struct iio_map {
void *consumer_data;
};
#define IIO_MAP(_provider_channel, _consumer_dev_name, _consumer_channel) \
{ \
.adc_channel_label = _provider_channel, \
.consumer_dev_name = _consumer_dev_name, \
.consumer_channel = _consumer_channel, \
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment