提交 41844e36 编写于 作者: L Linus Torvalds

Merge tag 'staging-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging and IIO updates from Greg KH:
 "Here is the big staging and IIO driver pull request for 4.9-rc1.

  There are a lot of patches in here, the majority due to the
  drivers/staging/greybus/ subsystem being merged in with full
  development history that went back a few years, in order to preserve
  the work that those developers did over time.

  Lots and lots of tiny cleanups happened in the tree as well, due to
  the Outreachy application process and lots of other developers showing
  up for the first time to clean code up.  Along with those changes, we
  deleted a wireless driver, and added a raspberrypi driver (currently
  marked broken), and lots of new iio drivers.

  Overall the tree still shrunk with more lines removed than added,
  about 10 thousand lines removed in total. Full details are in the very
  long shortlog below.

  All of this has been in the linux-next tree with no issues. There will
  be some merge problems with other subsystem trees, but those are all
  minor problems and shouldn't be hard to work out when they happen
  (MAINTAINERS and some lustre build problems with the IB tree)"

And furter from me asking for clarification about greybus:
 "Right now there is a phone from Motorola shipping with this code (a
  slightly older version, but the same tree), so even though Ara is not
  alive in the same form, the functionality is happening. We are working
  with the developers of that phone to merge the newer stuff in with
  their fork so they can use the upstream version in future versions of
  their phone product line.

  Toshiba has at least one chip shipping in their catalog that
  needs/uses this protocol over a Unipro link, and rumor has it that
  there might be more in the future.

  There are also other users of the greybus protocols, there is a talk
  next week at ELC that shows how it is being used across a network
  connection to control a device, and previous ELC talks have showed the
  protocol stack being used over USB to drive embedded Linux boards.
  I've also talked to some people who are starting to work to add a host
  controller driver to control arduinos as the greybus PHY protocols are
  very useful to control a serial/i2c/spio/whatever device across a
  random physical link, as it is a way to have a self-describing device
  be attached to a host without needing manual configuration.

  So yes, people are using it, and there is still the chance that it
  will show up in a phone/laptop/tablet/whatever from Google in the
  future as well, the tech isn't dead, even if the original large phone
  project happens to be"

* tag 'staging-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (3703 commits)
  Staging: fbtft: Fix bug in fbtft-core
  staging: rtl8188eu: fix double unlock error in rtw_resume_process()
  staging:r8188eu: remove GEN_MLME_EXT_HANDLER macro
  staging:r8188eu: remove GEN_DRV_CMD_HANDLER macro
  staging:r8188eu: remove GEN_EVT_CODE macro
  staging:r8188eu: remove GEN_CMD_CODE macro
  staging:r8188eu: remove pkt_newalloc member of the recv_buf structure
  staging:r8188eu: remove rtw_handle_dualmac declaration
  staging:r8188eu: remove (RGTRY|BSSID)_(OFT|SZ) macros
  staging:r8188eu: change rtl8188e_process_phy_info function argument type
  Staging: fsl-mc: Remove blank lines
  Staging: fsl-mc: Fix unaligned * in block comments
  Staging: comedi: Align the * in block comments
  Staging : ks7010 : Fix block comments warninig
  Staging: vt6655: Remove explicit NULL comparison using Coccinelle
  staging: rtl8188eu: core: rtw_xmit: Use macros instead of constants
  staging: rtl8188eu: core: rtw_xmit: Move constant of the right side
  staging: dgnc: Fix lines longer than 80 characters
  Staging: dgnc: constify attribute_group structures
  Staging: most: hdm-dim2: constify attribute_group structures
  ...
......@@ -160,6 +160,7 @@ Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
Vlad Dogaru <ddvlad@gmail.com> <vlad.dogaru@intel.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@virtuozzo.com>
Vladimir Davydov <vdavydov.dev@gmail.com> <vdavydov@parallels.com>
Takashi YOSHII <takashi.yoshii.zj@renesas.com>
......
......@@ -38,6 +38,7 @@ dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat
dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors
domintech,dmard09 DMARD09: 3-axis Accelerometer
epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
epson,rx8025 High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE
epson,rx8581 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
......@@ -56,6 +57,7 @@ maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
mc,rv3029c2 Real Time Clock Module with I2C-Bus
mcube,mc3230 mCube 3-axis 8-bit digital accelerometer
microchip,mcp4531-502 Microchip 7-bit Single I2C Digital Potentiometer (5k)
microchip,mcp4531-103 Microchip 7-bit Single I2C Digital Potentiometer (10k)
microchip,mcp4531-503 Microchip 7-bit Single I2C Digital Potentiometer (50k)
......
Device tree bindings for Domintech DMARD05, DMARD06, DMARD07 accelerometers
Required properties:
- compatible : Should be "domintech,dmard05"
or "domintech,dmard06"
or "domintech,dmard07"
- reg : I2C address of the chip. Should be 0x1c
Example:
&i2c1 {
/* ... */
accelerometer@1c {
compatible = "domintech,dmard06";
reg = <0x1c>;
};
/* ... */
};
Kionix KXSD9 Accelerometer device tree bindings
Required properties:
- compatible: should be set to "kionix,kxsd9"
- reg: i2c slave address
Optional properties:
- vdd-supply: The input supply for VDD
- iovdd-supply: The input supply for IOVDD
- interrupts: The movement detection interrupt
- mount-matrix: See mount-matrix.txt
Example:
kxsd9@18 {
compatible = "kionix,kxsd9";
reg = <0x18>;
interrupt-parent = <&foo>;
interrupts = <57 IRQ_TYPE_EDGE_FALLING>;
iovdd-supply = <&bar>;
vdd-supply = <&baz>;
};
MediaTek AUXADC
* Mediatek AUXADC - Analog to Digital Converter on Mediatek mobile soc (mt65xx/mt81xx/mt27xx)
===============
The Auxiliary Analog/Digital Converter (AUXADC) is an ADC found
......@@ -10,12 +10,20 @@ Documentation/devicetree/bindings/thermal/mediatek-thermal.txt
for the Thermal Controller which holds a phandle to the AUXADC.
Required properties:
- compatible: Must be "mediatek,mt8173-auxadc"
- reg: Address range of the AUXADC unit
- compatible: Should be one of:
- "mediatek,mt2701-auxadc": For MT2701 family of SoCs
- "mediatek,mt8173-auxadc": For MT8173 family of SoCs
- reg: Address range of the AUXADC unit.
- clocks: Should contain a clock specifier for each entry in clock-names
- clock-names: Should contain "main".
- #io-channel-cells: Should be 1, see ../iio-bindings.txt
Example:
auxadc: auxadc@11001000 {
compatible = "mediatek,mt8173-auxadc";
auxadc: adc@11001000 {
compatible = "mediatek,mt2701-auxadc";
reg = <0 0x11001000 0 0x1000>;
clocks = <&pericfg CLK_PERI_AUXADC>;
clock-names = "main";
#io-channel-cells = <1>;
};
* Texas Instruments' ADC12130/ADC12132/ADC12138
Required properties:
- compatible: Should be one of
* "ti,adc12130"
* "ti,adc12132"
* "ti,adc12138"
- reg: SPI chip select number for the device
- interrupts: Should contain interrupt for EOC (end of conversion)
- clocks: phandle to conversion clock input
- spi-max-frequency: Definision as per
Documentation/devicetree/bindings/spi/spi-bus.txt
- vref-p-supply: The regulator supply for positive analog voltage reference
Optional properties:
- vref-n-supply: The regulator supply for negative analog voltage reference
(Note that this must not go below GND or exceed vref-p)
If not specified, this is assumed to be analog ground.
- ti,acquisition-time: The number of conversion clock periods for the S/H's
acquisition time. Should be one of 6, 10, 18, 34. If not specified,
default value of 10 is used.
For high source impedances, this value can be increased to 18 or 34.
For less ADC accuracy and/or slower CCLK frequencies this value may be
decreased to 6. See section 6.0 INPUT SOURCE RESISTANCE in the
datasheet for details.
Example:
adc@0 {
compatible = "ti,adc12138";
reg = <0>;
interrupts = <28 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpio1>;
clocks = <&cclk>;
vref-p-supply = <&ldo4_reg>;
spi-max-frequency = <5000000>;
ti,acquisition-time = <6>;
};
* Texas Instruments ADC141S626 and ADC161S626 chips
Required properties:
- compatible: Should be "ti,adc141s626" or "ti,adc161s626"
- reg: spi chip select number for the device
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
Example:
adc@0 {
compatible = "ti,adc161s626";
reg = <0>;
spi-max-frequency = <4300000>;
};
* Atlas Scientific ORP-SM OEM sensor
https://www.atlas-scientific.com/_files/_datasheets/_oem/ORP_oem_datasheet.pdf
Required properties:
- compatible: must be "atlas,orp-sm"
- 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
Refer to interrupt-controller/interrupts.txt for generic interrupt client
node bindings.
Example:
atlas@66 {
compatible = "atlas,orp-sm";
reg = <0x66>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
};
* Asahi Kasei AK8974 magnetometer sensor
Required properties:
- compatible : should be "asahi-kasei,ak8974"
- reg : the I2C address of the magnetometer
Optional properties:
- avdd-supply: regulator supply for the analog voltage
(see regulator/regulator.txt)
- dvdd-supply: regulator supply for the digital voltage
(see regulator/regulator.txt)
- interrupts: data ready (DRDY) and interrupt (INT1) lines
from the chip, the DRDY interrupt must be placed first.
The interrupts can be triggered on rising or falling
edges alike.
- mount-matrix: an optional 3x3 mounting rotation matrix
Example:
ak8974@0f {
compatible = "asahi-kasei,ak8974";
reg = <0x0f>;
avdd-supply = <&foo_reg>;
dvdd-supply = <&bar_reg>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>,
<1 IRQ_TYPE_EDGE_RISING>;
};
Murata ZPA2326 pressure sensor
Pressure sensor from Murata with SPI and I2C bus interfaces.
Required properties:
- compatible: "murata,zpa2326"
- reg: the I2C address or SPI chip select the device will respond to
Recommended properties for SPI bus usage:
- spi-max-frequency: maximum SPI bus frequency as documented in
Documentation/devicetree/bindings/spi/spi-bus.txt
Optional properties:
- vref-supply: an optional regulator that needs to be on to provide VREF
power to the sensor
- vdd-supply: an optional regulator that needs to be on to provide VDD
power to the sensor
- interrupt-parent: phandle to the parent interrupt controller as documented in
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- interrupts: interrupt mapping for IRQ as documented in
Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Example:
zpa2326@5c {
compatible = "murata,zpa2326";
reg = <0x5c>;
interrupt-parent = <&gpio>;
interrupts = <12>;
vdd-supply = <&ldo_1v8_gnss>;
};
Semtech's SX9500 capacitive proximity button device driver
Required properties:
- compatible: must be "semtech,sx9500"
- reg: i2c address where to find the device
- interrupt-parent : should be the phandle for the interrupt controller
- interrupts : the sole interrupt generated by the device
Refer to interrupt-controller/interrupts.txt for generic
interrupt client node bindings.
Optional properties:
- reset-gpios: Reference to the GPIO connected to the device's active
low reset pin.
Example:
sx9500@28 {
compatible = "semtech,sx9500";
reg = <0x28>;
interrupt-parent = <&gpio2>;
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
};
Maxim thermocouple support
* https://datasheets.maximintegrated.com/en/ds/MAX6675.pdf
* https://datasheets.maximintegrated.com/en/ds/MAX31855.pdf
Required properties:
- compatible: must be "maxim,max31855" or "maxim,max6675"
- reg: SPI chip select number for the device
- spi-max-frequency: must be 4300000
- spi-cpha: must be defined for max6675 to enable SPI mode 1
Refer to spi/spi-bus.txt for generic SPI slave bindings.
Example:
max31855@0 {
compatible = "maxim,max31855";
reg = <0>;
spi-max-frequency = <4300000>;
};
......@@ -76,6 +76,7 @@ digilent Diglent, Inc.
dlg Dialog Semiconductor
dlink D-Link Corporation
dmo Data Modul AG
domintech Domintech Co., Ltd.
dptechnics DPTechnics
dragino Dragino Technology Co., Limited
ea Embedded Artists AB
......
......@@ -266,8 +266,12 @@ IIO
devm_iio_device_unregister()
devm_iio_kfifo_allocate()
devm_iio_kfifo_free()
devm_iio_triggered_buffer_setup()
devm_iio_triggered_buffer_cleanup()
devm_iio_trigger_alloc()
devm_iio_trigger_free()
devm_iio_trigger_register()
devm_iio_trigger_unregister()
devm_iio_channel_get()
devm_iio_channel_release()
devm_iio_channel_get_all()
......
......@@ -819,11 +819,11 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/aoa/
APEX EMBEDDED SYSTEMS STX104 DAC DRIVER
APEX EMBEDDED SYSTEMS STX104 IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/dac/stx104.c
F: drivers/iio/adc/stx104.c
APM DRIVER
M: Jiri Kosina <jikos@kernel.org>
......@@ -1993,6 +1993,13 @@ S: Maintained
F: drivers/media/i2c/as3645a.c
F: include/media/i2c/as3645a.h
ASAHI KASEI AK8974 DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
W: http://www.akm.com/
S: Supported
F: drivers/iio/magnetometer/ak8974.c
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
L: linux-hwmon@vger.kernel.org
......@@ -5318,6 +5325,77 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/aeroflex/
GREYBUS SUBSYSTEM
M: Johan Hovold <johan@kernel.org>
M: Alex Elder <elder@kernel.org>
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
S: Maintained
F: drivers/staging/greybus/
GREYBUS AUDIO PROTOCOLS DRIVERS
M: Vaibhav Agarwal <vaibhav.sr@gmail.com>
M: Mark Greer <mgreer@animalcreek.com>
S: Maintained
F: drivers/staging/greybus/audio_apbridgea.c
F: drivers/staging/greybus/audio_apbridgea.h
F: drivers/staging/greybus/audio_codec.c
F: drivers/staging/greybus/audio_codec.h
F: drivers/staging/greybus/audio_gb.c
F: drivers/staging/greybus/audio_manager.c
F: drivers/staging/greybus/audio_manager.h
F: drivers/staging/greybus/audio_manager_module.c
F: drivers/staging/greybus/audio_manager_private.h
F: drivers/staging/greybus/audio_manager_sysfs.c
F: drivers/staging/greybus/audio_module.c
F: drivers/staging/greybus/audio_topology.c
GREYBUS PROTOCOLS DRIVERS
M: Rui Miguel Silva <rmfrfs@gmail.com>
S: Maintained
F: drivers/staging/greybus/sdio.c
F: drivers/staging/greybus/light.c
F: drivers/staging/greybus/gpio.c
F: drivers/staging/greybus/power_supply.c
F: drivers/staging/greybus/spi.c
F: drivers/staging/greybus/spilib.c
GREYBUS PROTOCOLS DRIVERS
M: Bryan O'Donoghue <pure.logic@nexus-software.ie>
S: Maintained
F: drivers/staging/greybus/loopback.c
F: drivers/staging/greybus/timesync.c
F: drivers/staging/greybus/timesync_platform.c
GREYBUS PROTOCOLS DRIVERS
M: Viresh Kumar <vireshk@kernel.org>
S: Maintained
F: drivers/staging/greybus/authentication.c
F: drivers/staging/greybus/bootrom.c
F: drivers/staging/greybus/firmware.h
F: drivers/staging/greybus/fw-core.c
F: drivers/staging/greybus/fw-download.c
F: drivers/staging/greybus/fw-managament.c
F: drivers/staging/greybus/greybus_authentication.h
F: drivers/staging/greybus/greybus_firmware.h
F: drivers/staging/greybus/hid.c
F: drivers/staging/greybus/i2c.c
F: drivers/staging/greybus/spi.c
F: drivers/staging/greybus/spilib.c
F: drivers/staging/greybus/spilib.h
GREYBUS PROTOCOLS DRIVERS
M: David Lin <dtwlin@gmail.com>
S: Maintained
F: drivers/staging/greybus/uart.c
F: drivers/staging/greybus/log.c
GREYBUS PLATFORM DRIVERS
M: Vaibhav Hiremath <hvaibhav.linux@gmail.com>
S: Maintained
F: drivers/staging/greybus/arche-platform.c
F: drivers/staging/greybus/arche-apb-ctrl.c
F: drivers/staging/greybus/arche_platform.h
GSPCA FINEPIX SUBDRIVER
M: Frank Zago <frank@zago.net>
L: linux-media@vger.kernel.org
......@@ -7548,6 +7626,12 @@ L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/potentiometer/mcp4531.c
MEASUREMENT COMPUTING CIO-DAC IIO DRIVER
M: William Breathitt Gray <vilhelm.gray@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: drivers/iio/dac/cio-dac.c
MEDIA DRIVERS FOR RENESAS - FCP
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
......@@ -11263,6 +11347,7 @@ F: drivers/staging/media/lirc/
STAGING - LUSTRE PARALLEL FILESYSTEM
M: Oleg Drokin <oleg.drokin@intel.com>
M: Andreas Dilger <andreas.dilger@intel.com>
M: James Simmons <jsimmons@infradead.org>
L: lustre-devel@lists.lustre.org (moderated for non-subscribers)
W: http://wiki.lustre.org/
S: Maintained
......@@ -11289,13 +11374,6 @@ M: Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
S: Odd Fixes
F: drivers/staging/rtl8712/
STAGING - REALTEK RTL8723U WIRELESS DRIVER
M: Larry Finger <Larry.Finger@lwfinger.net>
M: Jes Sorensen <Jes.Sorensen@redhat.com>
L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/staging/rtl8723au/
STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Teddy Wang <teddy.wang@siliconmotion.com>
......
......@@ -59,7 +59,6 @@ static struct dentry *binder_debugfs_dir_entry_proc;
static struct binder_node *binder_context_mgr_node;
static kuid_t binder_context_mgr_uid = INVALID_UID;
static int binder_last_id;
static struct workqueue_struct *binder_deferred_workqueue;
#define BINDER_DEBUG_ENTRY(name) \
static int binder_##name##_open(struct inode *inode, struct file *file) \
......@@ -3227,7 +3226,7 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
queue_work(binder_deferred_workqueue, &binder_deferred_work);
schedule_work(&binder_deferred_work);
}
mutex_unlock(&binder_deferred_lock);
}
......@@ -3679,10 +3678,6 @@ static int __init binder_init(void)
{
int ret;
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
......
......@@ -17,4 +17,17 @@ config SYNC_FILE
Files fds, to the DRM driver for example. More details at
Documentation/sync_file.txt.
config SW_SYNC
bool "Sync File Validation Framework"
default n
depends on SYNC_FILE
depends on DEBUG_FS
---help---
A sync object driver that uses a 32bit counter to coordinate
synchronization. Useful when there is no hardware primitive backing
the synchronization.
WARNING: improper use of this can result in deadlocking kernel
drivers from userspace. Intended for test and debug only.
endmenu
obj-y := dma-buf.o fence.o reservation.o seqno-fence.o fence-array.o
obj-$(CONFIG_SYNC_FILE) += sync_file.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
/*
* drivers/dma-buf/sw_sync.c
* Sync File validation framework
*
* Copyright (C) 2012 Google, Inc.
*
......@@ -23,8 +23,38 @@
#include "sync_debug.h"
#define CREATE_TRACE_POINTS
#include "trace/sync.h"
#include "sync_trace.h"
/*
* SW SYNC validation framework
*
* A sync object driver that uses a 32bit counter to coordinate
* synchronization. Useful when there is no hardware primitive backing
* the synchronization.
*
* To start the framework just open:
*
* <debugfs>/sync/sw_sync
*
* That will create a sync timeline, all fences created under this timeline
* file descriptor will belong to the this timeline.
*
* The 'sw_sync' file can be opened many times as to create different
* timelines.
*
* Fences can be created with SW_SYNC_IOC_CREATE_FENCE ioctl with struct
* sw_sync_ioctl_create_fence as parameter.
*
* To increment the timeline counter, SW_SYNC_IOC_INC ioctl should be used
* with the increment as u32. This will update the last signaled value
* from the timeline and signal any fence that has a seqno smaller or equal
* to it.
*
* struct sw_sync_ioctl_create_fence
* @value: the seqno to initialise the fence with
* @name: the name of the new sync point
* @fence: return the fd of the new sync_file with the created fence
*/
struct sw_sync_create_fence_data {
__u32 value;
char name[32];
......@@ -35,6 +65,7 @@ struct sw_sync_create_fence_data {
#define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\
struct sw_sync_create_fence_data)
#define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32)
static const struct fence_ops timeline_fence_ops;
......@@ -176,7 +207,7 @@ static void timeline_fence_release(struct fence *fence)
spin_lock_irqsave(fence->lock, flags);
list_del(&pt->child_list);
if (WARN_ON_ONCE(!list_empty(&pt->active_list)))
if (!list_empty(&pt->active_list))
list_del(&pt->active_list);
spin_unlock_irqrestore(fence->lock, flags);
......
/*
* drivers/base/sync.c
* Sync File validation framework and debug information
*
* Copyright (C) 2012 Google, Inc.
*
......
/*
* include/linux/sync.h
* Sync File validation framework and debug infomation
*
* Copyright (C) 2012 Google, Inc.
*
......
#undef TRACE_SYSTEM
#define TRACE_INCLUDE_PATH ../../drivers/staging/android/trace
#define TRACE_SYSTEM sync
#define TRACE_INCLUDE_PATH ../../drivers/dma-buf
#define TRACE_SYSTEM sync_trace
#if !defined(_TRACE_SYNC_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_SYNC_H
#include "../sync_debug.h"
#include "sync_debug.h"
#include <linux/tracepoint.h>
TRACE_EVENT(sync_timeline,
......
......@@ -52,6 +52,27 @@ config BMC150_ACCEL_SPI
tristate
select REGMAP_SPI
config DMARD06
tristate "Domintech DMARD06 Digital Accelerometer Driver"
depends on OF || COMPILE_TEST
depends on I2C
help
Say yes here to build support for the Domintech low-g tri-axial
digital accelerometers: DMARD05, DMARD06, DMARD07.
To compile this driver as a module, choose M here: the
module will be called dmard06.
config DMARD09
tristate "Domintech DMARD09 3-axis Accelerometer Driver"
depends on I2C
help
Say yes here to get support for the Domintech DMARD09 3-axis
accelerometer.
Choosing M will build the driver as a module. If so, the module
will be called dmard09.
config HID_SENSOR_ACCEL_3D
depends on HID_SENSOR_HUB
select IIO_BUFFER
......@@ -98,14 +119,35 @@ config IIO_ST_ACCEL_SPI_3AXIS
config KXSD9
tristate "Kionix KXSD9 Accelerometer Driver"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the Kionix KXSD9 accelerometer.
Currently this only supports the device via an SPI interface.
It can be accessed using an (optional) SPI or I2C interface.
To compile this driver as a module, choose M here: the module
will be called kxsd9.
config KXSD9_SPI
tristate "Kionix KXSD9 SPI transport"
depends on KXSD9
depends on SPI
default KXSD9
select REGMAP_SPI
help
Say yes here to enable the Kionix KXSD9 accelerometer
SPI transport channel.
config KXSD9_I2C
tristate "Kionix KXSD9 I2C transport"
depends on KXSD9
depends on I2C
default KXSD9
select REGMAP_I2C
help
Say yes here to enable the Kionix KXSD9 accelerometer
I2C transport channel.
config KXCJK1013
tristate "Kionix 3-Axis Accelerometer Driver"
depends on I2C
......@@ -119,6 +161,16 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
config MC3230
tristate "mCube MC3230 Digital Accelerometer Driver"
depends on I2C
help
Say yes here to build support for the mCube MC3230 low-g tri-axial
digital accelerometer.
To compile this driver as a module, choose M here: the
module will be called mc3230.
config MMA7455
tristate
select IIO_BUFFER
......
......@@ -8,9 +8,14 @@ obj-$(CONFIG_BMA220) += bma220_spi.o
obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel-core.o
obj-$(CONFIG_BMC150_ACCEL_I2C) += bmc150-accel-i2c.o
obj-$(CONFIG_BMC150_ACCEL_SPI) += bmc150-accel-spi.o
obj-$(CONFIG_DMARD06) += dmard06.o
obj-$(CONFIG_DMARD09) += dmard09.o
obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_KXSD9_SPI) += kxsd9-spi.o
obj-$(CONFIG_KXSD9_I2C) += kxsd9-i2c.o
obj-$(CONFIG_MC3230) += mc3230.o
obj-$(CONFIG_MMA7455) += mma7455_core.o
obj-$(CONFIG_MMA7455_I2C) += mma7455_i2c.o
......
......@@ -469,13 +469,14 @@ static int bma180_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
mutex_lock(&data->mutex);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&data->mutex);
return -EBUSY;
}
ret = bma180_get_data_reg(data, chan->scan_index);
mutex_unlock(&data->mutex);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
*val = sign_extend32(ret >> chan->scan_type.shift,
......
/*
* IIO driver for Domintech DMARD06 accelerometer
*
* Copyright (C) 2016 Aleksei Mamlin <mamlinav@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define DMARD06_DRV_NAME "dmard06"
/* Device data registers */
#define DMARD06_CHIP_ID_REG 0x0f
#define DMARD06_TOUT_REG 0x40
#define DMARD06_XOUT_REG 0x41
#define DMARD06_YOUT_REG 0x42
#define DMARD06_ZOUT_REG 0x43
#define DMARD06_CTRL1_REG 0x44
/* Device ID value */
#define DMARD05_CHIP_ID 0x05
#define DMARD06_CHIP_ID 0x06
#define DMARD07_CHIP_ID 0x07
/* Device values */
#define DMARD05_AXIS_SCALE_VAL 15625
#define DMARD06_AXIS_SCALE_VAL 31250
#define DMARD06_TEMP_CENTER_VAL 25
#define DMARD06_SIGN_BIT 7
/* Device power modes */
#define DMARD06_MODE_NORMAL 0x27
#define DMARD06_MODE_POWERDOWN 0x00
/* Device channels */
#define DMARD06_ACCEL_CHANNEL(_axis, _reg) { \
.type = IIO_ACCEL, \
.address = _reg, \
.channel2 = IIO_MOD_##_axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.modified = 1, \
}
#define DMARD06_TEMP_CHANNEL(_reg) { \
.type = IIO_TEMP, \
.address = _reg, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_OFFSET), \
}
struct dmard06_data {
struct i2c_client *client;
u8 chip_id;
};
static const struct iio_chan_spec dmard06_channels[] = {
DMARD06_ACCEL_CHANNEL(X, DMARD06_XOUT_REG),
DMARD06_ACCEL_CHANNEL(Y, DMARD06_YOUT_REG),
DMARD06_ACCEL_CHANNEL(Z, DMARD06_ZOUT_REG),
DMARD06_TEMP_CHANNEL(DMARD06_TOUT_REG),
};
static int dmard06_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_byte_data(dmard06->client,
chan->address);
if (ret < 0) {
dev_err(&dmard06->client->dev,
"Error reading data: %d\n", ret);
return ret;
}
*val = sign_extend32(ret, DMARD06_SIGN_BIT);
if (dmard06->chip_id == DMARD06_CHIP_ID)
*val = *val >> 1;
switch (chan->type) {
case IIO_ACCEL:
return IIO_VAL_INT;
case IIO_TEMP:
if (dmard06->chip_id != DMARD06_CHIP_ID)
*val = *val / 2;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OFFSET:
switch (chan->type) {
case IIO_TEMP:
*val = DMARD06_TEMP_CENTER_VAL;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ACCEL:
*val = 0;
if (dmard06->chip_id == DMARD06_CHIP_ID)
*val2 = DMARD06_AXIS_SCALE_VAL;
else
*val2 = DMARD05_AXIS_SCALE_VAL;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_info dmard06_info = {
.driver_module = THIS_MODULE,
.read_raw = dmard06_read_raw,
};
static int dmard06_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct dmard06_data *dmard06;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C check functionality failed\n");
return -ENXIO;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dmard06));
if (!indio_dev) {
dev_err(&client->dev, "Failed to allocate iio device\n");
return -ENOMEM;
}
dmard06 = iio_priv(indio_dev);
dmard06->client = client;
ret = i2c_smbus_read_byte_data(dmard06->client, DMARD06_CHIP_ID_REG);
if (ret < 0) {
dev_err(&client->dev, "Error reading chip id: %d\n", ret);
return ret;
}
if (ret != DMARD05_CHIP_ID && ret != DMARD06_CHIP_ID &&
ret != DMARD07_CHIP_ID) {
dev_err(&client->dev, "Invalid chip id: %02d\n", ret);
return -ENODEV;
}
dmard06->chip_id = ret;
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = DMARD06_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dmard06_channels;
indio_dev->num_channels = ARRAY_SIZE(dmard06_channels);
indio_dev->info = &dmard06_info;
return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int dmard06_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
DMARD06_MODE_POWERDOWN);
if (ret < 0)
return ret;
return 0;
}
static int dmard06_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct dmard06_data *dmard06 = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_write_byte_data(dmard06->client, DMARD06_CTRL1_REG,
DMARD06_MODE_NORMAL);
if (ret < 0)
return ret;
return 0;
}
static SIMPLE_DEV_PM_OPS(dmard06_pm_ops, dmard06_suspend, dmard06_resume);
#define DMARD06_PM_OPS (&dmard06_pm_ops)
#else
#define DMARD06_PM_OPS NULL
#endif
static const struct i2c_device_id dmard06_id[] = {
{ "dmard05", 0 },
{ "dmard06", 0 },
{ "dmard07", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, dmard06_id);
static const struct of_device_id dmard06_of_match[] = {
{ .compatible = "domintech,dmard05" },
{ .compatible = "domintech,dmard06" },
{ .compatible = "domintech,dmard07" },
{ }
};
MODULE_DEVICE_TABLE(of, dmard06_of_match);
static struct i2c_driver dmard06_driver = {
.probe = dmard06_probe,
.id_table = dmard06_id,
.driver = {
.name = DMARD06_DRV_NAME,
.of_match_table = of_match_ptr(dmard06_of_match),
.pm = DMARD06_PM_OPS,
},
};
module_i2c_driver(dmard06_driver);
MODULE_AUTHOR("Aleksei Mamlin <mamlinav@gmail.com>");
MODULE_DESCRIPTION("Domintech DMARD06 accelerometer driver");
MODULE_LICENSE("GPL v2");
/*
* IIO driver for the 3-axis accelerometer Domintech DMARD09.
*
* Copyright (c) 2016, Jelle van der Waa <jelle@vdwaa.nl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <asm/unaligned.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define DMARD09_DRV_NAME "dmard09"
#define DMARD09_REG_CHIPID 0x18
#define DMARD09_REG_STAT 0x0A
#define DMARD09_REG_X 0x0C
#define DMARD09_REG_Y 0x0E
#define DMARD09_REG_Z 0x10
#define DMARD09_CHIPID 0x95
#define DMARD09_BUF_LEN 8
#define DMARD09_AXIS_X 0
#define DMARD09_AXIS_Y 1
#define DMARD09_AXIS_Z 2
#define DMARD09_AXIS_X_OFFSET ((DMARD09_AXIS_X + 1) * 2)
#define DMARD09_AXIS_Y_OFFSET ((DMARD09_AXIS_Y + 1 )* 2)
#define DMARD09_AXIS_Z_OFFSET ((DMARD09_AXIS_Z + 1) * 2)
struct dmard09_data {
struct i2c_client *client;
};
#define DMARD09_CHANNEL(_axis, offset) { \
.type = IIO_ACCEL, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.modified = 1, \
.address = offset, \
.channel2 = IIO_MOD_##_axis, \
}
static const struct iio_chan_spec dmard09_channels[] = {
DMARD09_CHANNEL(X, DMARD09_AXIS_X_OFFSET),
DMARD09_CHANNEL(Y, DMARD09_AXIS_Y_OFFSET),
DMARD09_CHANNEL(Z, DMARD09_AXIS_Z_OFFSET),
};
static int dmard09_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct dmard09_data *data = iio_priv(indio_dev);
u8 buf[DMARD09_BUF_LEN];
int ret;
s16 accel;
switch (mask) {
case IIO_CHAN_INFO_RAW:
/*
* Read from the DMAR09_REG_STAT register, since the chip
* caches reads from the individual X, Y, Z registers.
*/
ret = i2c_smbus_read_i2c_block_data(data->client,
DMARD09_REG_STAT,
DMARD09_BUF_LEN, buf);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg %d\n",
DMARD09_REG_STAT);
return ret;
}
accel = get_unaligned_le16(&buf[chan->address]);
/* Remove lower 3 bits and sign extend */
accel <<= 4;
accel >>= 7;
*val = accel;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info dmard09_info = {
.driver_module = THIS_MODULE,
.read_raw = dmard09_read_raw,
};
static int dmard09_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct dmard09_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation failed\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->client = client;
ret = i2c_smbus_read_byte_data(data->client, DMARD09_REG_CHIPID);
if (ret < 0) {
dev_err(&client->dev, "Error reading chip id %d\n", ret);
return ret;
}
if (ret != DMARD09_CHIPID) {
dev_err(&client->dev, "Invalid chip id %d\n", ret);
return -ENODEV;
}
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = DMARD09_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = dmard09_channels;
indio_dev->num_channels = ARRAY_SIZE(dmard09_channels);
indio_dev->info = &dmard09_info;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id dmard09_id[] = {
{ "dmard09", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, dmard09_id);
static struct i2c_driver dmard09_driver = {
.driver = {
.name = DMARD09_DRV_NAME
},
.probe = dmard09_probe,
.id_table = dmard09_id,
};
module_i2c_driver(dmard09_driver);
MODULE_AUTHOR("Jelle van der Waa <jelle@vdwaa.nl>");
MODULE_DESCRIPTION("DMARD09 3-axis accelerometer driver");
MODULE_LICENSE("GPL");
......@@ -1392,6 +1392,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXCJ9000", KXCJ91008},
{"KIOX000A", KXCJ91008},
{"KXTJ1009", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
......
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include "kxsd9.h"
static int kxsd9_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x0e,
};
struct regmap *regmap;
regmap = devm_regmap_init_i2c(i2c, &config);
if (IS_ERR(regmap)) {
dev_err(&i2c->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return kxsd9_common_probe(&i2c->dev,
regmap,
i2c->name);
}
static int kxsd9_i2c_remove(struct i2c_client *client)
{
return kxsd9_common_remove(&client->dev);
}
#ifdef CONFIG_OF
static const struct of_device_id kxsd9_of_match[] = {
{ .compatible = "kionix,kxsd9", },
{ },
};
MODULE_DEVICE_TABLE(of, kxsd9_of_match);
#else
#define kxsd9_of_match NULL
#endif
static const struct i2c_device_id kxsd9_i2c_id[] = {
{"kxsd9", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, kxsd9_i2c_id);
static struct i2c_driver kxsd9_i2c_driver = {
.driver = {
.name = "kxsd9",
.of_match_table = of_match_ptr(kxsd9_of_match),
.pm = &kxsd9_dev_pm_ops,
},
.probe = kxsd9_i2c_probe,
.remove = kxsd9_i2c_remove,
.id_table = kxsd9_i2c_id,
};
module_i2c_driver(kxsd9_i2c_driver);
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/regmap.h>
#include "kxsd9.h"
static int kxsd9_spi_probe(struct spi_device *spi)
{
static const struct regmap_config config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x0e,
};
struct regmap *regmap;
spi->mode = SPI_MODE_0;
regmap = devm_regmap_init_spi(spi, &config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "%s: regmap allocation failed: %ld\n",
__func__, PTR_ERR(regmap));
return PTR_ERR(regmap);
}
return kxsd9_common_probe(&spi->dev,
regmap,
spi_get_device_id(spi)->name);
}
static int kxsd9_spi_remove(struct spi_device *spi)
{
return kxsd9_common_remove(&spi->dev);
}
static const struct spi_device_id kxsd9_spi_id[] = {
{"kxsd9", 0},
{ },
};
MODULE_DEVICE_TABLE(spi, kxsd9_spi_id);
static struct spi_driver kxsd9_spi_driver = {
.driver = {
.name = "kxsd9",
.pm = &kxsd9_dev_pm_ops,
},
.probe = kxsd9_spi_probe,
.remove = kxsd9_spi_remove,
.id_table = kxsd9_spi_id,
};
module_spi_driver(kxsd9_spi_driver);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
MODULE_LICENSE("GPL v2");
......@@ -12,19 +12,25 @@
* I have a suitable wire made up.
*
* TODO: Support the motion detector
* Uses register address incrementing so could have a
* heavily optimized ring buffer access function.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include "kxsd9.h"
#define KXSD9_REG_X 0x00
#define KXSD9_REG_Y 0x02
......@@ -33,28 +39,45 @@
#define KXSD9_REG_RESET 0x0a
#define KXSD9_REG_CTRL_C 0x0c
#define KXSD9_FS_MASK 0x03
#define KXSD9_CTRL_C_FS_MASK 0x03
#define KXSD9_CTRL_C_FS_8G 0x00
#define KXSD9_CTRL_C_FS_6G 0x01
#define KXSD9_CTRL_C_FS_4G 0x02
#define KXSD9_CTRL_C_FS_2G 0x03
#define KXSD9_CTRL_C_MOT_LAT BIT(3)
#define KXSD9_CTRL_C_MOT_LEV BIT(4)
#define KXSD9_CTRL_C_LP_MASK 0xe0
#define KXSD9_CTRL_C_LP_NONE 0x00
#define KXSD9_CTRL_C_LP_2000HZC BIT(5)
#define KXSD9_CTRL_C_LP_2000HZB BIT(6)
#define KXSD9_CTRL_C_LP_2000HZA (BIT(5)|BIT(6))
#define KXSD9_CTRL_C_LP_1000HZ BIT(7)
#define KXSD9_CTRL_C_LP_500HZ (BIT(7)|BIT(5))
#define KXSD9_CTRL_C_LP_100HZ (BIT(7)|BIT(6))
#define KXSD9_CTRL_C_LP_50HZ (BIT(7)|BIT(6)|BIT(5))
#define KXSD9_REG_CTRL_B 0x0d
#define KXSD9_REG_CTRL_A 0x0e
#define KXSD9_READ(a) (0x80 | (a))
#define KXSD9_WRITE(a) (a)
#define KXSD9_CTRL_B_CLK_HLD BIT(7)
#define KXSD9_CTRL_B_ENABLE BIT(6)
#define KXSD9_CTRL_B_ST BIT(5) /* Self-test */
#define KXSD9_REG_CTRL_A 0x0e
#define KXSD9_STATE_RX_SIZE 2
#define KXSD9_STATE_TX_SIZE 2
/**
* struct kxsd9_state - device related storage
* @buf_lock: protect the rx and tx buffers.
* @us: spi device
* @rx: single rx buffer storage
* @tx: single tx buffer storage
**/
* @dev: pointer to the parent device
* @map: regmap to the device
* @orientation: mounting matrix, flipped axis etc
* @regs: regulators for this device, VDD and IOVDD
* @scale: the current scaling setting
*/
struct kxsd9_state {
struct mutex buf_lock;
struct spi_device *us;
u8 rx[KXSD9_STATE_RX_SIZE] ____cacheline_aligned;
u8 tx[KXSD9_STATE_TX_SIZE];
struct device *dev;
struct regmap *map;
struct iio_mount_matrix orientation;
struct regulator_bulk_data regs[2];
u8 scale;
};
#define KXSD9_SCALE_2G "0.011978"
......@@ -65,6 +88,14 @@ struct kxsd9_state {
/* reverse order */
static const int kxsd9_micro_scales[4] = { 47853, 35934, 23927, 11978 };
#define KXSD9_ZERO_G_OFFSET -2048
/*
* Regulator names
*/
static const char kxsd9_reg_vdd[] = "vdd";
static const char kxsd9_reg_iovdd[] = "iovdd";
static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
{
int ret, i;
......@@ -79,42 +110,17 @@ static int kxsd9_write_scale(struct iio_dev *indio_dev, int micro)
if (!foundit)
return -EINVAL;
mutex_lock(&st->buf_lock);
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
ret = regmap_update_bits(st->map,
KXSD9_REG_CTRL_C,
KXSD9_CTRL_C_FS_MASK,
i);
if (ret < 0)
goto error_ret;
st->tx[0] = KXSD9_WRITE(KXSD9_REG_CTRL_C);
st->tx[1] = (ret & ~KXSD9_FS_MASK) | i;
ret = spi_write(st->us, st->tx, 2);
error_ret:
mutex_unlock(&st->buf_lock);
return ret;
}
/* Cached scale when the sensor is powered down */
st->scale = i;
static int kxsd9_read(struct iio_dev *indio_dev, u8 address)
{
int ret;
struct kxsd9_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
.bits_per_word = 8,
.len = 1,
.delay_usecs = 200,
.tx_buf = st->tx,
}, {
.bits_per_word = 8,
.len = 2,
.rx_buf = st->rx,
},
};
mutex_lock(&st->buf_lock);
st->tx[0] = KXSD9_READ(address);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (!ret)
ret = (((u16)(st->rx[0])) << 8) | (st->rx[1] & 0xF0);
mutex_unlock(&st->buf_lock);
error_ret:
return ret;
}
......@@ -136,6 +142,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
long mask)
{
int ret = -EINVAL;
struct kxsd9_state *st = iio_priv(indio_dev);
pm_runtime_get_sync(st->dev);
if (mask == IIO_CHAN_INFO_SCALE) {
/* Check no integer component */
......@@ -144,6 +153,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
ret = kxsd9_write_scale(indio_dev, val2);
}
pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return ret;
}
......@@ -153,46 +165,154 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
{
int ret = -EINVAL;
struct kxsd9_state *st = iio_priv(indio_dev);
unsigned int regval;
__be16 raw_val;
u16 nval;
pm_runtime_get_sync(st->dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = kxsd9_read(indio_dev, chan->address);
if (ret < 0)
ret = regmap_bulk_read(st->map, chan->address, &raw_val,
sizeof(raw_val));
if (ret)
goto error_ret;
*val = ret;
nval = be16_to_cpu(raw_val);
/* Only 12 bits are valid */
nval >>= 4;
*val = nval;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_OFFSET:
/* This has a bias of -2048 */
*val = KXSD9_ZERO_G_OFFSET;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
ret = spi_w8r8(st->us, KXSD9_READ(KXSD9_REG_CTRL_C));
ret = regmap_read(st->map,
KXSD9_REG_CTRL_C,
&regval);
if (ret < 0)
goto error_ret;
*val = 0;
*val2 = kxsd9_micro_scales[ret & KXSD9_FS_MASK];
*val2 = kxsd9_micro_scales[regval & KXSD9_CTRL_C_FS_MASK];
ret = IIO_VAL_INT_PLUS_MICRO;
break;
}
error_ret:
pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return ret;
};
#define KXSD9_ACCEL_CHAN(axis) \
static irqreturn_t kxsd9_trigger_handler(int irq, void *p)
{
const struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct kxsd9_state *st = iio_priv(indio_dev);
int ret;
/* 4 * 16bit values AND timestamp */
__be16 hw_values[8];
ret = regmap_bulk_read(st->map,
KXSD9_REG_X,
&hw_values,
8);
if (ret) {
dev_err(st->dev,
"error reading data\n");
return ret;
}
iio_push_to_buffers_with_timestamp(indio_dev,
hw_values,
iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int kxsd9_buffer_preenable(struct iio_dev *indio_dev)
{
struct kxsd9_state *st = iio_priv(indio_dev);
pm_runtime_get_sync(st->dev);
return 0;
}
static int kxsd9_buffer_postdisable(struct iio_dev *indio_dev)
{
struct kxsd9_state *st = iio_priv(indio_dev);
pm_runtime_mark_last_busy(st->dev);
pm_runtime_put_autosuspend(st->dev);
return 0;
}
static const struct iio_buffer_setup_ops kxsd9_buffer_setup_ops = {
.preenable = kxsd9_buffer_preenable,
.postenable = iio_triggered_buffer_postenable,
.predisable = iio_triggered_buffer_predisable,
.postdisable = kxsd9_buffer_postdisable,
};
static const struct iio_mount_matrix *
kxsd9_get_mount_matrix(const struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct kxsd9_state *st = iio_priv(indio_dev);
return &st->orientation;
}
static const struct iio_chan_spec_ext_info kxsd9_ext_info[] = {
IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, kxsd9_get_mount_matrix),
{ },
};
#define KXSD9_ACCEL_CHAN(axis, index) \
{ \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
.ext_info = kxsd9_ext_info, \
.address = KXSD9_REG_##axis, \
.scan_index = index, \
.scan_type = { \
.sign = 'u', \
.realbits = 12, \
.storagebits = 16, \
.shift = 4, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
KXSD9_ACCEL_CHAN(X, 0),
KXSD9_ACCEL_CHAN(Y, 1),
KXSD9_ACCEL_CHAN(Z, 2),
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.indexed = 1,
.address = KXSD9_REG_AUX,
}
.scan_index = 3,
.scan_type = {
.sign = 'u',
.realbits = 12,
.storagebits = 16,
.shift = 4,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct attribute_group kxsd9_attribute_group = {
......@@ -203,17 +323,69 @@ static int kxsd9_power_up(struct kxsd9_state *st)
{
int ret;
st->tx[0] = 0x0d;
st->tx[1] = 0x40;
ret = spi_write(st->us, st->tx, 2);
/* Enable the regulators */
ret = regulator_bulk_enable(ARRAY_SIZE(st->regs), st->regs);
if (ret) {
dev_err(st->dev, "Cannot enable regulators\n");
return ret;
}
/* Power up */
ret = regmap_write(st->map,
KXSD9_REG_CTRL_B,
KXSD9_CTRL_B_ENABLE);
if (ret)
return ret;
st->tx[0] = 0x0c;
st->tx[1] = 0x9b;
return spi_write(st->us, st->tx, 2);
/*
* Set 1000Hz LPF, 2g fullscale, motion wakeup threshold 1g,
* latched wakeup
*/
ret = regmap_write(st->map,
KXSD9_REG_CTRL_C,
KXSD9_CTRL_C_LP_1000HZ |
KXSD9_CTRL_C_MOT_LEV |
KXSD9_CTRL_C_MOT_LAT |
st->scale);
if (ret)
return ret;
/*
* Power-up time depends on the LPF setting, but typ 15.9 ms, let's
* set 20 ms to allow for some slack.
*/
msleep(20);
return 0;
};
static int kxsd9_power_down(struct kxsd9_state *st)
{
int ret;
/*
* Set into low power mode - since there may be more users of the
* regulators this is the first step of the power saving: it will
* make sure we conserve power even if there are others users on the
* regulators.
*/
ret = regmap_update_bits(st->map,
KXSD9_REG_CTRL_B,
KXSD9_CTRL_B_ENABLE,
0);
if (ret)
return ret;
/* Disable the regulators */
ret = regulator_bulk_disable(ARRAY_SIZE(st->regs), st->regs);
if (ret) {
dev_err(st->dev, "Cannot disable regulators\n");
return ret;
}
return 0;
}
static const struct iio_info kxsd9_info = {
.read_raw = &kxsd9_read_raw,
.write_raw = &kxsd9_write_raw,
......@@ -221,57 +393,136 @@ static const struct iio_info kxsd9_info = {
.driver_module = THIS_MODULE,
};
static int kxsd9_probe(struct spi_device *spi)
/* Four channels apart from timestamp, scan mask = 0x0f */
static const unsigned long kxsd9_scan_masks[] = { 0xf, 0 };
int kxsd9_common_probe(struct device *dev,
struct regmap *map,
const char *name)
{
struct iio_dev *indio_dev;
struct kxsd9_state *st;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
if (!indio_dev)
return -ENOMEM;
st = iio_priv(indio_dev);
spi_set_drvdata(spi, indio_dev);
st->dev = dev;
st->map = map;
st->us = spi;
mutex_init(&st->buf_lock);
indio_dev->channels = kxsd9_channels;
indio_dev->num_channels = ARRAY_SIZE(kxsd9_channels);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->name = name;
indio_dev->dev.parent = dev;
indio_dev->info = &kxsd9_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->available_scan_masks = kxsd9_scan_masks;
/* Read the mounting matrix, if present */
ret = of_iio_read_mount_matrix(dev,
"mount-matrix",
&st->orientation);
if (ret)
return ret;
/* Fetch and turn on regulators */
st->regs[0].supply = kxsd9_reg_vdd;
st->regs[1].supply = kxsd9_reg_iovdd;
ret = devm_regulator_bulk_get(dev,
ARRAY_SIZE(st->regs),
st->regs);
if (ret) {
dev_err(dev, "Cannot get regulators\n");
return ret;
}
/* Default scaling */
st->scale = KXSD9_CTRL_C_FS_2G;
spi->mode = SPI_MODE_0;
spi_setup(spi);
kxsd9_power_up(st);
return iio_device_register(indio_dev);
ret = iio_triggered_buffer_setup(indio_dev,
iio_pollfunc_store_time,
kxsd9_trigger_handler,
&kxsd9_buffer_setup_ops);
if (ret) {
dev_err(dev, "triggered buffer setup failed\n");
goto err_power_down;
}
ret = iio_device_register(indio_dev);
if (ret)
goto err_cleanup_buffer;
dev_set_drvdata(dev, indio_dev);
/* Enable runtime PM */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
/*
* Set autosuspend to two orders of magnitude larger than the
* start-up time. 20ms start-up time means 2000ms autosuspend,
* i.e. 2 seconds.
*/
pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
return 0;
err_cleanup_buffer:
iio_triggered_buffer_cleanup(indio_dev);
err_power_down:
kxsd9_power_down(st);
return ret;
}
EXPORT_SYMBOL(kxsd9_common_probe);
static int kxsd9_remove(struct spi_device *spi)
int kxsd9_common_remove(struct device *dev)
{
iio_device_unregister(spi_get_drvdata(spi));
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct kxsd9_state *st = iio_priv(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
iio_device_unregister(indio_dev);
pm_runtime_get_sync(dev);
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
kxsd9_power_down(st);
return 0;
}
EXPORT_SYMBOL(kxsd9_common_remove);
static const struct spi_device_id kxsd9_id[] = {
{"kxsd9", 0},
{ },
};
MODULE_DEVICE_TABLE(spi, kxsd9_id);
#ifdef CONFIG_PM
static int kxsd9_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct kxsd9_state *st = iio_priv(indio_dev);
static struct spi_driver kxsd9_driver = {
.driver = {
.name = "kxsd9",
},
.probe = kxsd9_probe,
.remove = kxsd9_remove,
.id_table = kxsd9_id,
return kxsd9_power_down(st);
}
static int kxsd9_runtime_resume(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct kxsd9_state *st = iio_priv(indio_dev);
return kxsd9_power_up(st);
}
#endif /* CONFIG_PM */
const struct dev_pm_ops kxsd9_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(kxsd9_runtime_suspend,
kxsd9_runtime_resume, NULL)
};
module_spi_driver(kxsd9_driver);
EXPORT_SYMBOL(kxsd9_dev_pm_ops);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Kionix KXSD9 SPI driver");
MODULE_DESCRIPTION("Kionix KXSD9 driver");
MODULE_LICENSE("GPL v2");
#include <linux/device.h>
#include <linux/kernel.h>
#define KXSD9_STATE_RX_SIZE 2
#define KXSD9_STATE_TX_SIZE 2
int kxsd9_common_probe(struct device *dev,
struct regmap *map,
const char *name);
int kxsd9_common_remove(struct device *dev);
extern const struct dev_pm_ops kxsd9_dev_pm_ops;
/**
* mCube MC3230 3-Axis Accelerometer
*
* Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com>
*
* 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
* (at your option) any later version.
*
* IIO driver for mCube MC3230; 7-bit I2C address: 0x4c.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define MC3230_REG_XOUT 0x00
#define MC3230_REG_YOUT 0x01
#define MC3230_REG_ZOUT 0x02
#define MC3230_REG_MODE 0x07
#define MC3230_MODE_OPCON_MASK 0x03
#define MC3230_MODE_OPCON_WAKE 0x01
#define MC3230_MODE_OPCON_STANDBY 0x03
#define MC3230_REG_CHIP_ID 0x18
#define MC3230_CHIP_ID 0x01
#define MC3230_REG_PRODUCT_CODE 0x3b
#define MC3230_PRODUCT_CODE 0x19
/*
* The accelerometer has one measurement range:
*
* -1.5g - +1.5g (8-bit, signed)
*
* scale = (1.5 + 1.5) * 9.81 / (2^8 - 1) = 0.115411765
*/
static const int mc3230_nscale = 115411765;
#define MC3230_CHANNEL(reg, axis) { \
.type = IIO_ACCEL, \
.address = reg, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
static const struct iio_chan_spec mc3230_channels[] = {
MC3230_CHANNEL(MC3230_REG_XOUT, X),
MC3230_CHANNEL(MC3230_REG_YOUT, Y),
MC3230_CHANNEL(MC3230_REG_ZOUT, Z),
};
struct mc3230_data {
struct i2c_client *client;
};
static int mc3230_set_opcon(struct mc3230_data *data, int opcon)
{
int ret;
struct i2c_client *client = data->client;
ret = i2c_smbus_read_byte_data(client, MC3230_REG_MODE);
if (ret < 0) {
dev_err(&client->dev, "failed to read mode reg: %d\n", ret);
return ret;
}
ret &= ~MC3230_MODE_OPCON_MASK;
ret |= opcon;
ret = i2c_smbus_write_byte_data(client, MC3230_REG_MODE, ret);
if (ret < 0) {
dev_err(&client->dev, "failed to write mode reg: %d\n", ret);
return ret;
}
return 0;
}
static int mc3230_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mc3230_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_byte_data(data->client, chan->address);
if (ret < 0)
return ret;
*val = sign_extend32(ret, 7);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = mc3230_nscale;
return IIO_VAL_INT_PLUS_NANO;
default:
return -EINVAL;
}
}
static const struct iio_info mc3230_info = {
.driver_module = THIS_MODULE,
.read_raw = mc3230_read_raw,
};
static int mc3230_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct mc3230_data *data;
/* First check chip-id and product-id */
ret = i2c_smbus_read_byte_data(client, MC3230_REG_CHIP_ID);
if (ret != MC3230_CHIP_ID)
return (ret < 0) ? ret : -ENODEV;
ret = i2c_smbus_read_byte_data(client, MC3230_REG_PRODUCT_CODE);
if (ret != MC3230_PRODUCT_CODE)
return (ret < 0) ? ret : -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio allocation failed!\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
data->client = client;
i2c_set_clientdata(client, indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &mc3230_info;
indio_dev->name = "mc3230";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mc3230_channels;
indio_dev->num_channels = ARRAY_SIZE(mc3230_channels);
ret = mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
mc3230_set_opcon(data, MC3230_MODE_OPCON_STANDBY);
}
return ret;
}
static int mc3230_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
return mc3230_set_opcon(iio_priv(indio_dev), MC3230_MODE_OPCON_STANDBY);
}
#ifdef CONFIG_PM_SLEEP
static int mc3230_suspend(struct device *dev)
{
struct mc3230_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return mc3230_set_opcon(data, MC3230_MODE_OPCON_STANDBY);
}
static int mc3230_resume(struct device *dev)
{
struct mc3230_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return mc3230_set_opcon(data, MC3230_MODE_OPCON_WAKE);
}
#endif
static SIMPLE_DEV_PM_OPS(mc3230_pm_ops, mc3230_suspend, mc3230_resume);
static const struct i2c_device_id mc3230_i2c_id[] = {
{"mc3230", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mc3230_i2c_id);
static struct i2c_driver mc3230_driver = {
.driver = {
.name = "mc3230",
.pm = &mc3230_pm_ops,
},
.probe = mc3230_probe,
.remove = mc3230_remove,
.id_table = mc3230_i2c_id,
};
module_i2c_driver(mc3230_driver);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("mCube MC3230 3-Axis Accelerometer driver");
MODULE_LICENSE("GPL v2");
......@@ -251,6 +251,7 @@ static const struct i2c_device_id mma7660_i2c_id[] = {
{"mma7660", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mma7660_i2c_id);
static const struct acpi_device_id mma7660_acpi_id[] = {
{"MMA7660", 0},
......
......@@ -154,7 +154,7 @@ static int mxc6255_probe(struct i2c_client *client,
return ret;
}
if (chip_id != MXC6255_CHIP_ID) {
if ((chip_id & 0x1f) != MXC6255_CHIP_ID) {
dev_err(&client->dev, "Invalid chip id %x\n", chip_id);
return -ENODEV;
}
......@@ -171,12 +171,14 @@ static int mxc6255_probe(struct i2c_client *client,
}
static const struct acpi_device_id mxc6255_acpi_match[] = {
{"MXC6225", 0},
{"MXC6255", 0},
{ }
};
MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match);
static const struct i2c_device_id mxc6255_id[] = {
{"mxc6225", 0},
{"mxc6255", 0},
{ }
};
......
......@@ -74,7 +74,7 @@ static int ssp_accel_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static struct iio_info ssp_accel_iio_info = {
static const struct iio_info ssp_accel_iio_info = {
.read_raw = &ssp_accel_read_raw,
.write_raw = &ssp_accel_write_raw,
};
......
......@@ -264,6 +264,15 @@ config LPC18XX_ADC
To compile this driver as a module, choose M here: the module will be
called lpc18xx_adc.
config LTC2485
tristate "Linear Technology LTC2485 ADC driver"
depends on I2C
help
Say yes here to build support for Linear Technology LTC2485 ADC.
To compile this driver as a module, choose M here: the module will be
called ltc2485.
config MAX1027
tristate "Maxim max1027 ADC driver"
depends on SPI
......@@ -317,6 +326,19 @@ config MCP3422
This driver can also be built as a module. If so, the module will be
called mcp3422.
config MEDIATEK_MT6577_AUXADC
tristate "MediaTek AUXADC driver"
depends on ARCH_MEDIATEK || COMPILE_TEST
depends on HAS_IOMEM
help
Say yes here to enable support for MediaTek mt65xx AUXADC.
The driver supports immediate mode operation to read from one of sixteen
channels (external or internal).
This driver can also be built as a module. If so, the module will be
called mt6577_auxadc.
config MEN_Z188_ADC
tristate "MEN 16z188 ADC IP Core support"
depends on MCB
......@@ -397,6 +419,21 @@ config ROCKCHIP_SARADC
To compile this driver as a module, choose M here: the
module will be called rockchip_saradc.
config STX104
tristate "Apex Embedded Systems STX104 driver"
depends on X86 && ISA_BUS_API
select GPIOLIB
help
Say yes here to build support for the Apex Embedded Systems STX104
integrated analog PC/104 card.
This driver supports the 16 channels of single-ended (8 channels of
differential) analog inputs, 2 channels of analog output, 4 digital
inputs, and 4 digital outputs provided by the STX104.
The base port addresses for the devices may be configured via the base
array module parameter.
config TI_ADC081C
tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
depends on I2C
......@@ -417,6 +454,18 @@ config TI_ADC0832
This driver can also be built as a module. If so, the module will be
called ti-adc0832.
config TI_ADC12138
tristate "Texas Instruments ADC12130/ADC12132/ADC12138"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADC12130,
ADC12132 and ADC12138 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc12138.
config TI_ADC128S052
tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021"
depends on SPI
......@@ -427,6 +476,18 @@ config TI_ADC128S052
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.
config TI_ADC161S626
tristate "Texas Instruments ADC161S626 1-channel differential ADC"
depends on SPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
If you say yes here you get support for Texas Instruments ADC141S626,
and ADC161S626 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc161s626.
config TI_ADS1015
tristate "Texas Instruments ADS1015 ADC"
depends on I2C && !SENSORS_ADS1015
......
......@@ -27,10 +27,12 @@ obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_NAU7802) += nau7802.o
......@@ -38,9 +40,12 @@ obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
......
......@@ -481,7 +481,7 @@ static int ad7266_probe(struct spi_device *spi)
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
error_disable_reg:
if (!IS_ERR_OR_NULL(st->reg))
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
......@@ -496,7 +496,7 @@ static int ad7266_remove(struct spi_device *spi)
iio_triggered_buffer_cleanup(indio_dev);
if (!st->fixed_addr)
gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios));
if (!IS_ERR_OR_NULL(st->reg))
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
......
......@@ -239,16 +239,16 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
switch (m) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
} else {
if (chan->address == AD7298_CH_TEMP)
ret = ad7298_scan_temp(st, val);
else
ret = ad7298_scan_direct(st, chan->address);
}
mutex_unlock(&indio_dev->mlock);
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (chan->address == AD7298_CH_TEMP)
ret = ad7298_scan_temp(st, val);
else
ret = ad7298_scan_direct(st, chan->address);
iio_device_release_direct_mode(indio_dev);
if (ret < 0)
return ret;
......
......@@ -519,11 +519,9 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
int ret, i;
unsigned int tmp;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
mutex_unlock(&indio_dev->mlock);
return -EBUSY;
}
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
switch (mask) {
case IIO_CHAN_INFO_SCALE:
......@@ -548,7 +546,7 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
ret = -EINVAL;
}
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
return ret;
}
......
......@@ -113,6 +113,7 @@
#define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */
#define AT91_ADC_TSMR_TSAV_(x) ((x) << 4)
#define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */
#define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16)
#define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */
#define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28)
#define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */
......@@ -150,6 +151,7 @@
#define MAX_RLPOS_BITS 10
#define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */
#define TOUCH_SHTIM 0xa
#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */
/**
* struct at91_adc_reg_desc - Various informations relative to registers
......@@ -1001,7 +1003,9 @@ static void atmel_ts_close(struct input_dev *dev)
static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
{
struct iio_dev *idev = iio_priv_to_dev(st);
u32 reg = 0;
u32 tssctim = 0;
int i = 0;
/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
......@@ -1034,11 +1038,20 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
return 0;
}
/* Touchscreen Switches Closure time needed for allowing the value to
* stabilize.
* Switch Closure Time = (TSSCTIM * 4) ADCClock periods
*/
tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4);
dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n",
adc_clk_khz, tssctim);
if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
else
reg = AT91_ADC_TSMR_TSMODE_5WIRE;
reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM;
reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average)
& AT91_ADC_TSMR_TSAV;
reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC;
......
......@@ -114,7 +114,6 @@ struct ina2xx_chip_info {
struct mutex state_lock;
unsigned int shunt_resistor;
int avg;
s64 prev_ns; /* track buffer capture time, check for underruns */
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
bool allow_async_readout;
......@@ -509,8 +508,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev)
iio_push_to_buffers_with_timestamp(indio_dev,
(unsigned int *)data, time_a);
chip->prev_ns = time_a;
return (unsigned long)(time_b - time_a) / 1000;
};
......@@ -554,8 +551,6 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev)
dev_dbg(&indio_dev->dev, "Async readout mode: %d\n",
chip->allow_async_readout);
chip->prev_ns = iio_get_time_ns(indio_dev);
chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev,
"%s:%d-%uus", indio_dev->name, indio_dev->id,
sampling_us);
......
/*
* ltc2485.c - Driver for Linear Technology LTC2485 ADC
*
* Copyright (C) 2016 Alison Schofield <amsfield22@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* Power-on configuration: rejects both 50/60Hz, operates at 1x speed */
#define LTC2485_CONFIG_DEFAULT 0
struct ltc2485_data {
struct i2c_client *client;
ktime_t time_prev; /* last conversion */
};
static void ltc2485_wait_conv(struct ltc2485_data *data)
{
const unsigned int conv_time = 147; /* conversion time ms */
unsigned int time_elapsed;
/* delay if conversion time not passed since last read or write */
time_elapsed = ktime_ms_delta(ktime_get(), data->time_prev);
if (time_elapsed < conv_time)
msleep(conv_time - time_elapsed);
}
static int ltc2485_read(struct ltc2485_data *data, int *val)
{
struct i2c_client *client = data->client;
__be32 buf = 0;
int ret;
ltc2485_wait_conv(data);
ret = i2c_master_recv(client, (char *)&buf, 4);
if (ret < 0) {
dev_err(&client->dev, "i2c_master_recv failed\n");
return ret;
}
data->time_prev = ktime_get();
*val = sign_extend32(be32_to_cpu(buf) >> 6, 24);
return ret;
}
static int ltc2485_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ltc2485_data *data = iio_priv(indio_dev);
int ret;
if (mask == IIO_CHAN_INFO_RAW) {
ret = ltc2485_read(data, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
} else if (mask == IIO_CHAN_INFO_SCALE) {
*val = 5000; /* on board vref millivolts */
*val2 = 25; /* 25 (24 + sign) data bits */
return IIO_VAL_FRACTIONAL_LOG2;
} else {
return -EINVAL;
}
}
static const struct iio_chan_spec ltc2485_channel[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE)
},
};
static const struct iio_info ltc2485_info = {
.read_raw = ltc2485_read_raw,
.driver_module = THIS_MODULE,
};
static int ltc2485_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ltc2485_data *data;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE))
return -EOPNOTSUPP;
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;
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;
indio_dev->info = &ltc2485_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ltc2485_channel;
indio_dev->num_channels = ARRAY_SIZE(ltc2485_channel);
ret = i2c_smbus_write_byte(data->client, LTC2485_CONFIG_DEFAULT);
if (ret < 0)
return ret;
data->time_prev = ktime_get();
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ltc2485_id[] = {
{ "ltc2485", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ltc2485_id);
static struct i2c_driver ltc2485_driver = {
.driver = {
.name = "ltc2485",
},
.probe = ltc2485_probe,
.id_table = ltc2485_id,
};
module_i2c_driver(ltc2485_driver);
MODULE_AUTHOR("Alison Schofield <amsfield22@gmail.com>");
MODULE_DESCRIPTION("Linear Technology LTC2485 ADC driver");
MODULE_LICENSE("GPL v2");
......@@ -78,7 +78,7 @@ static int z188_iio_read_raw(struct iio_dev *iio_dev,
return ret;
}
static struct iio_info z188_adc_info = {
static const struct iio_info z188_adc_info = {
.read_raw = &z188_iio_read_raw,
.driver_module = THIS_MODULE,
};
......
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Zhiyong Tao <zhiyong.tao@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/iopoll.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
/* Register definitions */
#define MT6577_AUXADC_CON0 0x00
#define MT6577_AUXADC_CON1 0x04
#define MT6577_AUXADC_CON2 0x10
#define MT6577_AUXADC_STA BIT(0)
#define MT6577_AUXADC_DAT0 0x14
#define MT6577_AUXADC_RDY0 BIT(12)
#define MT6577_AUXADC_MISC 0x94
#define MT6577_AUXADC_PDN_EN BIT(14)
#define MT6577_AUXADC_DAT_MASK 0xfff
#define MT6577_AUXADC_SLEEP_US 1000
#define MT6577_AUXADC_TIMEOUT_US 10000
#define MT6577_AUXADC_POWER_READY_MS 1
#define MT6577_AUXADC_SAMPLE_READY_US 25
struct mt6577_auxadc_device {
void __iomem *reg_base;
struct clk *adc_clk;
struct mutex lock;
};
#define MT6577_AUXADC_CHANNEL(idx) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
}
static const struct iio_chan_spec mt6577_auxadc_iio_channels[] = {
MT6577_AUXADC_CHANNEL(0),
MT6577_AUXADC_CHANNEL(1),
MT6577_AUXADC_CHANNEL(2),
MT6577_AUXADC_CHANNEL(3),
MT6577_AUXADC_CHANNEL(4),
MT6577_AUXADC_CHANNEL(5),
MT6577_AUXADC_CHANNEL(6),
MT6577_AUXADC_CHANNEL(7),
MT6577_AUXADC_CHANNEL(8),
MT6577_AUXADC_CHANNEL(9),
MT6577_AUXADC_CHANNEL(10),
MT6577_AUXADC_CHANNEL(11),
MT6577_AUXADC_CHANNEL(12),
MT6577_AUXADC_CHANNEL(13),
MT6577_AUXADC_CHANNEL(14),
MT6577_AUXADC_CHANNEL(15),
};
static inline void mt6577_auxadc_mod_reg(void __iomem *reg,
u32 or_mask, u32 and_mask)
{
u32 val;
val = readl(reg);
val |= or_mask;
val &= ~and_mask;
writel(val, reg);
}
static int mt6577_auxadc_read(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
u32 val;
void __iomem *reg_channel;
int ret;
struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
reg_channel = adc_dev->reg_base + MT6577_AUXADC_DAT0 +
chan->channel * 0x04;
mutex_lock(&adc_dev->lock);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
0, 1 << chan->channel);
/* read channel and make sure old ready bit == 0 */
ret = readl_poll_timeout(reg_channel, val,
((val & MT6577_AUXADC_RDY0) == 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for channel[%d] ready bit clear time out\n",
chan->channel);
goto err_timeout;
}
/* set bit to trigger sample */
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_CON1,
1 << chan->channel, 0);
/* we must delay here for hardware sample channel data */
udelay(MT6577_AUXADC_SAMPLE_READY_US);
/* check MTK_AUXADC_CON2 if auxadc is idle */
ret = readl_poll_timeout(adc_dev->reg_base + MT6577_AUXADC_CON2, val,
((val & MT6577_AUXADC_STA) == 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for auxadc idle time out\n");
goto err_timeout;
}
/* read channel and make sure ready bit == 1 */
ret = readl_poll_timeout(reg_channel, val,
((val & MT6577_AUXADC_RDY0) != 0),
MT6577_AUXADC_SLEEP_US,
MT6577_AUXADC_TIMEOUT_US);
if (ret < 0) {
dev_err(indio_dev->dev.parent,
"wait for channel[%d] data ready time out\n",
chan->channel);
goto err_timeout;
}
/* read data */
val = readl(reg_channel) & MT6577_AUXADC_DAT_MASK;
mutex_unlock(&adc_dev->lock);
return val;
err_timeout:
mutex_unlock(&adc_dev->lock);
return -ETIMEDOUT;
}
static int mt6577_auxadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long info)
{
switch (info) {
case IIO_CHAN_INFO_PROCESSED:
*val = mt6577_auxadc_read(indio_dev, chan);
if (*val < 0) {
dev_err(indio_dev->dev.parent,
"failed to sample data on channel[%d]\n",
chan->channel);
return *val;
}
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_info mt6577_auxadc_info = {
.driver_module = THIS_MODULE,
.read_raw = &mt6577_auxadc_read_raw,
};
static int mt6577_auxadc_probe(struct platform_device *pdev)
{
struct mt6577_auxadc_device *adc_dev;
unsigned long adc_clk_rate;
struct resource *res;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
if (!indio_dev)
return -ENOMEM;
adc_dev = iio_priv(indio_dev);
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->info = &mt6577_auxadc_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = mt6577_auxadc_iio_channels;
indio_dev->num_channels = ARRAY_SIZE(mt6577_auxadc_iio_channels);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(adc_dev->reg_base)) {
dev_err(&pdev->dev, "failed to get auxadc base address\n");
return PTR_ERR(adc_dev->reg_base);
}
adc_dev->adc_clk = devm_clk_get(&pdev->dev, "main");
if (IS_ERR(adc_dev->adc_clk)) {
dev_err(&pdev->dev, "failed to get auxadc clock\n");
return PTR_ERR(adc_dev->adc_clk);
}
ret = clk_prepare_enable(adc_dev->adc_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable auxadc clock\n");
return ret;
}
adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
if (!adc_clk_rate) {
ret = -EINVAL;
dev_err(&pdev->dev, "null clock rate\n");
goto err_disable_clk;
}
mutex_init(&adc_dev->lock);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
MT6577_AUXADC_PDN_EN, 0);
mdelay(MT6577_AUXADC_POWER_READY_MS);
platform_set_drvdata(pdev, indio_dev);
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register iio device\n");
goto err_power_off;
}
return 0;
err_power_off:
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0, MT6577_AUXADC_PDN_EN);
err_disable_clk:
clk_disable_unprepare(adc_dev->adc_clk);
return ret;
}
static int mt6577_auxadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mt6577_auxadc_device *adc_dev = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mt6577_auxadc_mod_reg(adc_dev->reg_base + MT6577_AUXADC_MISC,
0, MT6577_AUXADC_PDN_EN);
clk_disable_unprepare(adc_dev->adc_clk);
return 0;
}
static const struct of_device_id mt6577_auxadc_of_match[] = {
{ .compatible = "mediatek,mt2701-auxadc", },
{ .compatible = "mediatek,mt8173-auxadc", },
{ }
};
MODULE_DEVICE_TABLE(of, mt6577_auxadc_of_match);
static struct platform_driver mt6577_auxadc_driver = {
.driver = {
.name = "mt6577-auxadc",
.of_match_table = mt6577_auxadc_of_match,
},
.probe = mt6577_auxadc_probe,
.remove = mt6577_auxadc_remove,
};
module_platform_driver(mt6577_auxadc_driver);
MODULE_AUTHOR("Zhiyong Tao <zhiyong.tao@mediatek.com>");
MODULE_DESCRIPTION("MTK AUXADC Device Driver");
MODULE_LICENSE("GPL v2");
......@@ -197,7 +197,7 @@ static irqreturn_t nau7802_eoc_trigger(int irq, void *private)
if (st->conversion_count < NAU7802_MIN_CONVERSIONS)
st->conversion_count++;
if (st->conversion_count >= NAU7802_MIN_CONVERSIONS)
complete_all(&st->value_ok);
complete(&st->value_ok);
return IRQ_HANDLED;
}
......
/*
* DAC driver for the Apex Embedded Systems STX104
* IIO driver for the Apex Embedded Systems STX104
* Copyright (C) 2016 William Breathitt Gray
*
* This program is free software; you can redistribute it and/or modify
......@@ -20,19 +20,30 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#define STX104_NUM_CHAN 2
#define STX104_CHAN(chan) { \
#define STX104_OUT_CHAN(chan) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.output = 1 \
}
#define STX104_IN_CHAN(chan, diff) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.channel2 = chan, \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.differential = diff \
}
#define STX104_NUM_OUT_CHAN 2
#define STX104_EXTENT 16
......@@ -47,8 +58,8 @@ MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses");
* @base: base port address of the IIO device
*/
struct stx104_iio {
unsigned chan_out_states[STX104_NUM_CHAN];
unsigned base;
unsigned int chan_out_states[STX104_NUM_OUT_CHAN];
unsigned int base;
};
/**
......@@ -79,28 +90,95 @@ static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
unsigned int adc_config;
int adbu;
int gain;
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
/* get gain configuration */
adc_config = inb(priv->base + 11);
gain = adc_config & 0x3;
*val = 1 << gain;
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
if (chan->output) {
*val = priv->chan_out_states[chan->channel];
return IIO_VAL_INT;
}
/* select ADC channel */
outb(chan->channel | (chan->channel << 4), priv->base + 2);
/* trigger ADC sample capture and wait for completion */
outb(0, priv->base);
while (inb(priv->base + 8) & BIT(7));
*val = inw(priv->base);
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
/* get ADC bipolar/unipolar configuration */
adc_config = inb(priv->base + 11);
adbu = !(adc_config & BIT(2));
*val = -32768 * adbu;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* get ADC bipolar/unipolar and gain configuration */
adc_config = inb(priv->base + 11);
adbu = !(adc_config & BIT(2));
gain = adc_config & 0x3;
*val = 5;
*val2 = 15 - adbu + gain;
return IIO_VAL_FRACTIONAL_LOG2;
}
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
*val = priv->chan_out_states[chan->channel];
return IIO_VAL_INT;
return -EINVAL;
}
static int stx104_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct stx104_iio *const priv = iio_priv(indio_dev);
const unsigned chan_addr_offset = 2 * chan->channel;
if (mask != IIO_CHAN_INFO_RAW)
switch (mask) {
case IIO_CHAN_INFO_HARDWAREGAIN:
/* Only four gain states (x1, x2, x4, x8) */
switch (val) {
case 1:
outb(0, priv->base + 11);
break;
case 2:
outb(1, priv->base + 11);
break;
case 4:
outb(2, priv->base + 11);
break;
case 8:
outb(3, priv->base + 11);
break;
default:
return -EINVAL;
}
return 0;
case IIO_CHAN_INFO_RAW:
if (chan->output) {
/* DAC can only accept up to a 16-bit value */
if ((unsigned int)val > 65535)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
outw(val, priv->base + 4 + 2 * chan->channel);
return 0;
}
return -EINVAL;
}
priv->chan_out_states[chan->channel] = val;
outw(val, priv->base + 4 + chan_addr_offset);
return 0;
return -EINVAL;
}
static const struct iio_info stx104_info = {
......@@ -109,9 +187,22 @@ static const struct iio_info stx104_info = {
.write_raw = stx104_write_raw
};
static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = {
STX104_CHAN(0),
STX104_CHAN(1)
/* single-ended input channels configuration */
static const struct iio_chan_spec stx104_channels_sing[] = {
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0),
STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0),
STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0),
STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0),
STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0),
STX104_IN_CHAN(15, 0)
};
/* differential input channels configuration */
static const struct iio_chan_spec stx104_channels_diff[] = {
STX104_OUT_CHAN(0), STX104_OUT_CHAN(1),
STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1),
STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1),
STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1)
};
static int stx104_gpio_get_direction(struct gpio_chip *chip,
......@@ -204,13 +295,27 @@ static int stx104_probe(struct device *dev, unsigned int id)
indio_dev->info = &stx104_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = stx104_channels;
indio_dev->num_channels = STX104_NUM_CHAN;
/* determine if differential inputs */
if (inb(base[id] + 8) & BIT(5)) {
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff);
indio_dev->channels = stx104_channels_diff;
} else {
indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing);
indio_dev->channels = stx104_channels_sing;
}
indio_dev->name = dev_name(dev);
priv = iio_priv(indio_dev);
priv->base = base[id];
/* configure device for software trigger operation */
outb(0, base[id] + 9);
/* initialize gain setting to x1 */
outb(0, base[id] + 11);
/* initialize DAC output to 0V */
outw(0, base[id] + 4);
outw(0, base[id] + 6);
......@@ -271,5 +376,5 @@ static struct isa_driver stx104_driver = {
module_isa_driver(stx104_driver, num_stx104);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver");
MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver");
MODULE_LICENSE("GPL v2");
/*
* ADC12130/ADC12132/ADC12138 12-bit plus sign ADC driver
*
* Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com>
*
* 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: http://www.ti.com/lit/ds/symlink/adc12138.pdf
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/regulator/consumer.h>
#define ADC12138_MODE_AUTO_CAL 0x08
#define ADC12138_MODE_READ_STATUS 0x0c
#define ADC12138_MODE_ACQUISITION_TIME_6 0x0e
#define ADC12138_MODE_ACQUISITION_TIME_10 0x4e
#define ADC12138_MODE_ACQUISITION_TIME_18 0x8e
#define ADC12138_MODE_ACQUISITION_TIME_34 0xce
#define ADC12138_STATUS_CAL BIT(6)
enum {
adc12130,
adc12132,
adc12138,
};
struct adc12138 {
struct spi_device *spi;
unsigned int id;
/* conversion clock */
struct clk *cclk;
/* positive analog voltage reference */
struct regulator *vref_p;
/* negative analog voltage reference */
struct regulator *vref_n;
struct mutex lock;
struct completion complete;
/* The number of cclk periods for the S/H's acquisition time */
unsigned int acquisition_time;
u8 tx_buf[2] ____cacheline_aligned;
u8 rx_buf[2];
};
#define ADC12138_VOLTAGE_CHANNEL(chan) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = chan, \
.scan_type = { \
.sign = 's', \
.realbits = 13, \
.storagebits = 16, \
.shift = 3, \
.endianness = IIO_BE, \
}, \
}
#define ADC12138_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \
{ \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = (chan1), \
.channel2 = (chan2), \
.differential = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
| BIT(IIO_CHAN_INFO_OFFSET), \
.scan_index = si, \
.scan_type = { \
.sign = 's', \
.realbits = 13, \
.storagebits = 16, \
.shift = 3, \
.endianness = IIO_BE, \
}, \
}
static const struct iio_chan_spec adc12132_channels[] = {
ADC12138_VOLTAGE_CHANNEL(0),
ADC12138_VOLTAGE_CHANNEL(1),
ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 2),
ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 3),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct iio_chan_spec adc12138_channels[] = {
ADC12138_VOLTAGE_CHANNEL(0),
ADC12138_VOLTAGE_CHANNEL(1),
ADC12138_VOLTAGE_CHANNEL(2),
ADC12138_VOLTAGE_CHANNEL(3),
ADC12138_VOLTAGE_CHANNEL(4),
ADC12138_VOLTAGE_CHANNEL(5),
ADC12138_VOLTAGE_CHANNEL(6),
ADC12138_VOLTAGE_CHANNEL(7),
ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 8),
ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 9),
ADC12138_VOLTAGE_CHANNEL_DIFF(2, 3, 10),
ADC12138_VOLTAGE_CHANNEL_DIFF(3, 2, 11),
ADC12138_VOLTAGE_CHANNEL_DIFF(4, 5, 12),
ADC12138_VOLTAGE_CHANNEL_DIFF(5, 4, 13),
ADC12138_VOLTAGE_CHANNEL_DIFF(6, 7, 14),
ADC12138_VOLTAGE_CHANNEL_DIFF(7, 6, 15),
IIO_CHAN_SOFT_TIMESTAMP(16),
};
static int adc12138_mode_programming(struct adc12138 *adc, u8 mode,
void *rx_buf, int len)
{
struct spi_transfer xfer = {
.tx_buf = adc->tx_buf,
.rx_buf = adc->rx_buf,
.len = len,
};
int ret;
/* Skip unused bits for ADC12130 and ADC12132 */
if (adc->id != adc12138)
mode = (mode & 0xc0) | ((mode & 0x0f) << 2);
adc->tx_buf[0] = mode;
ret = spi_sync_transfer(adc->spi, &xfer, 1);
if (ret)
return ret;
memcpy(rx_buf, adc->rx_buf, len);
return 0;
}
static int adc12138_read_status(struct adc12138 *adc)
{
u8 rx_buf[2];
int ret;
ret = adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
rx_buf, 2);
if (ret)
return ret;
return (rx_buf[0] << 1) | (rx_buf[1] >> 7);
}
static int __adc12138_start_conv(struct adc12138 *adc,
struct iio_chan_spec const *channel,
void *data, int len)
{
const u8 ch_to_mux[] = { 0, 4, 1, 5, 2, 6, 3, 7 };
u8 mode = (ch_to_mux[channel->channel] << 4) |
(channel->differential ? 0 : 0x80);
return adc12138_mode_programming(adc, mode, data, len);
}
static int adc12138_start_conv(struct adc12138 *adc,
struct iio_chan_spec const *channel)
{
u8 trash;
return __adc12138_start_conv(adc, channel, &trash, 1);
}
static int adc12138_start_and_read_conv(struct adc12138 *adc,
struct iio_chan_spec const *channel,
__be16 *data)
{
return __adc12138_start_conv(adc, channel, data, 2);
}
static int adc12138_read_conv_data(struct adc12138 *adc, __be16 *value)
{
/* Issue a read status instruction and read previous conversion data */
return adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS,
value, sizeof(*value));
}
static int adc12138_wait_eoc(struct adc12138 *adc, unsigned long timeout)
{
if (!wait_for_completion_timeout(&adc->complete, timeout))
return -ETIMEDOUT;
return 0;
}
static int adc12138_adc_conversion(struct adc12138 *adc,
struct iio_chan_spec const *channel,
__be16 *value)
{
int ret;
reinit_completion(&adc->complete);
ret = adc12138_start_conv(adc, channel);
if (ret)
return ret;
ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
if (ret)
return ret;
return adc12138_read_conv_data(adc, value);
}
static int adc12138_read_raw(struct iio_dev *iio,
struct iio_chan_spec const *channel, int *value,
int *shift, long mask)
{
struct adc12138 *adc = iio_priv(iio);
int ret;
__be16 data;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&adc->lock);
ret = adc12138_adc_conversion(adc, channel, &data);
mutex_unlock(&adc->lock);
if (ret)
return ret;
*value = sign_extend32(be16_to_cpu(data) >> 3, 12);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(adc->vref_p);
if (ret < 0)
return ret;
*value = ret;
if (!IS_ERR(adc->vref_n)) {
ret = regulator_get_voltage(adc->vref_n);
if (ret < 0)
return ret;
*value -= ret;
}
/* convert regulator output voltage to mV */
*value /= 1000;
*shift = channel->scan_type.realbits - 1;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
if (!IS_ERR(adc->vref_n)) {
*value = regulator_get_voltage(adc->vref_n);
if (*value < 0)
return *value;
} else {
*value = 0;
}
/* convert regulator output voltage to mV */
*value /= 1000;
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info adc12138_info = {
.read_raw = adc12138_read_raw,
.driver_module = THIS_MODULE,
};
static int adc12138_init(struct adc12138 *adc)
{
int ret;
int status;
u8 mode;
u8 trash;
reinit_completion(&adc->complete);
ret = adc12138_mode_programming(adc, ADC12138_MODE_AUTO_CAL, &trash, 1);
if (ret)
return ret;
/* data output at this time has no significance */
status = adc12138_read_status(adc);
if (status < 0)
return status;
adc12138_wait_eoc(adc, msecs_to_jiffies(100));
status = adc12138_read_status(adc);
if (status & ADC12138_STATUS_CAL) {
dev_warn(&adc->spi->dev,
"Auto Cal sequence is still in progress: %#x\n",
status);
return -EIO;
}
switch (adc->acquisition_time) {
case 6:
mode = ADC12138_MODE_ACQUISITION_TIME_6;
break;
case 10:
mode = ADC12138_MODE_ACQUISITION_TIME_10;
break;
case 18:
mode = ADC12138_MODE_ACQUISITION_TIME_18;
break;
case 34:
mode = ADC12138_MODE_ACQUISITION_TIME_34;
break;
default:
return -EINVAL;
}
return adc12138_mode_programming(adc, mode, &trash, 1);
}
static irqreturn_t adc12138_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adc12138 *adc = iio_priv(indio_dev);
__be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */
__be16 trash;
int ret;
int scan_index;
int i = 0;
mutex_lock(&adc->lock);
for_each_set_bit(scan_index, indio_dev->active_scan_mask,
indio_dev->masklength) {
const struct iio_chan_spec *scan_chan =
&indio_dev->channels[scan_index];
reinit_completion(&adc->complete);
ret = adc12138_start_and_read_conv(adc, scan_chan,
i ? &data[i - 1] : &trash);
if (ret) {
dev_warn(&adc->spi->dev,
"failed to start conversion\n");
goto out;
}
ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100));
if (ret) {
dev_warn(&adc->spi->dev, "wait eoc timeout\n");
goto out;
}
i++;
}
if (i) {
ret = adc12138_read_conv_data(adc, &data[i - 1]);
if (ret) {
dev_warn(&adc->spi->dev,
"failed to get conversion data\n");
goto out;
}
}
iio_push_to_buffers_with_timestamp(indio_dev, data,
iio_get_time_ns(indio_dev));
out:
mutex_unlock(&adc->lock);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static irqreturn_t adc12138_eoc_handler(int irq, void *p)
{
struct iio_dev *indio_dev = p;
struct adc12138 *adc = iio_priv(indio_dev);
complete(&adc->complete);
return IRQ_HANDLED;
}
static int adc12138_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc12138 *adc;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
return -ENOMEM;
adc = iio_priv(indio_dev);
adc->spi = spi;
adc->id = spi_get_device_id(spi)->driver_data;
mutex_init(&adc->lock);
init_completion(&adc->complete);
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &adc12138_info;
indio_dev->modes = INDIO_DIRECT_MODE;
switch (adc->id) {
case adc12130:
case adc12132:
indio_dev->channels = adc12132_channels;
indio_dev->num_channels = ARRAY_SIZE(adc12132_channels);
break;
case adc12138:
indio_dev->channels = adc12138_channels;
indio_dev->num_channels = ARRAY_SIZE(adc12138_channels);
break;
default:
return -EINVAL;
}
ret = of_property_read_u32(spi->dev.of_node, "ti,acquisition-time",
&adc->acquisition_time);
if (ret)
adc->acquisition_time = 10;
adc->cclk = devm_clk_get(&spi->dev, NULL);
if (IS_ERR(adc->cclk))
return PTR_ERR(adc->cclk);
adc->vref_p = devm_regulator_get(&spi->dev, "vref-p");
if (IS_ERR(adc->vref_p))
return PTR_ERR(adc->vref_p);
adc->vref_n = devm_regulator_get_optional(&spi->dev, "vref-n");
if (IS_ERR(adc->vref_n)) {
/*
* Assume vref_n is 0V if an optional regulator is not
* specified, otherwise return the error code.
*/
ret = PTR_ERR(adc->vref_n);
if (ret != -ENODEV)
return ret;
}
ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler,
IRQF_TRIGGER_RISING, indio_dev->name, indio_dev);
if (ret)
return ret;
ret = clk_prepare_enable(adc->cclk);
if (ret)
return ret;
ret = regulator_enable(adc->vref_p);
if (ret)
goto err_clk_disable;
if (!IS_ERR(adc->vref_n)) {
ret = regulator_enable(adc->vref_n);
if (ret)
goto err_vref_p_disable;
}
ret = adc12138_init(adc);
if (ret)
goto err_vref_n_disable;
spi_set_drvdata(spi, indio_dev);
ret = iio_triggered_buffer_setup(indio_dev, NULL,
adc12138_trigger_handler, NULL);
if (ret)
goto err_vref_n_disable;
ret = iio_device_register(indio_dev);
if (ret)
goto err_buffer_cleanup;
return 0;
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
err_vref_n_disable:
if (!IS_ERR(adc->vref_n))
regulator_disable(adc->vref_n);
err_vref_p_disable:
regulator_disable(adc->vref_p);
err_clk_disable:
clk_disable_unprepare(adc->cclk);
return ret;
}
static int adc12138_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct adc12138 *adc = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (!IS_ERR(adc->vref_n))
regulator_disable(adc->vref_n);
regulator_disable(adc->vref_p);
clk_disable_unprepare(adc->cclk);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id adc12138_dt_ids[] = {
{ .compatible = "ti,adc12130", },
{ .compatible = "ti,adc12132", },
{ .compatible = "ti,adc12138", },
{}
};
MODULE_DEVICE_TABLE(of, adc12138_dt_ids);
#endif
static const struct spi_device_id adc12138_id[] = {
{ "adc12130", adc12130 },
{ "adc12132", adc12132 },
{ "adc12138", adc12138 },
{}
};
MODULE_DEVICE_TABLE(spi, adc12138_id);
static struct spi_driver adc12138_driver = {
.driver = {
.name = "adc12138",
.of_match_table = of_match_ptr(adc12138_dt_ids),
},
.probe = adc12138_probe,
.remove = adc12138_remove,
.id_table = adc12138_id,
};
module_spi_driver(adc12138_driver);
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
MODULE_DESCRIPTION("ADC12130/ADC12132/ADC12138 driver");
MODULE_LICENSE("GPL v2");
/*
* ti-adc161s626.c - Texas Instruments ADC161S626 1-channel differential ADC
*
* ADC Devices Supported:
* adc141s626 - 14-bit ADC
* adc161s626 - 16-bit ADC
*
* Copyright (C) 2016 Matt Ranostay <mranostay@gmail.com>
*
* 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
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
#define TI_ADC_DRV_NAME "ti-adc161s626"
enum {
TI_ADC141S626,
TI_ADC161S626,
};
static const struct iio_chan_spec ti_adc141s626_channels[] = {
{
.type = IIO_VOLTAGE,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 14,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static const struct iio_chan_spec ti_adc161s626_channels[] = {
{
.type = IIO_VOLTAGE,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 16,
.storagebits = 16,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
struct ti_adc_data {
struct iio_dev *indio_dev;
struct spi_device *spi;
u8 read_size;
u8 shift;
u8 buffer[16] ____cacheline_aligned;
};
static int ti_adc_read_measurement(struct ti_adc_data *data,
struct iio_chan_spec const *chan, int *val)
{
int ret;
switch (data->read_size) {
case 2: {
__be16 buf;
ret = spi_read(data->spi, (void *) &buf, 2);
if (ret)
return ret;
*val = be16_to_cpu(buf);
break;
}
case 3: {
__be32 buf;
ret = spi_read(data->spi, (void *) &buf, 3);
if (ret)
return ret;
*val = be32_to_cpu(buf) >> 8;
break;
}
default:
return -EINVAL;
}
*val = sign_extend32(*val >> data->shift, chan->scan_type.realbits - 1);
return 0;
}
static irqreturn_t ti_adc_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct ti_adc_data *data = iio_priv(indio_dev);
int ret;
ret = ti_adc_read_measurement(data, &indio_dev->channels[0],
(int *) &data->buffer);
if (!ret)
iio_push_to_buffers_with_timestamp(indio_dev,
data->buffer,
iio_get_time_ns(indio_dev));
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
static int ti_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct ti_adc_data *data = iio_priv(indio_dev);
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
ret = ti_adc_read_measurement(data, chan, val);
iio_device_release_direct_mode(indio_dev);
if (!ret)
return IIO_VAL_INT;
return 0;
}
static const struct iio_info ti_adc_info = {
.driver_module = THIS_MODULE,
.read_raw = ti_adc_read_raw,
};
static int ti_adc_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ti_adc_data *data;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
indio_dev->info = &ti_adc_info;
indio_dev->dev.parent = &spi->dev;
indio_dev->dev.of_node = spi->dev.of_node;
indio_dev->name = TI_ADC_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
spi_set_drvdata(spi, indio_dev);
data = iio_priv(indio_dev);
data->spi = spi;
switch (spi_get_device_id(spi)->driver_data) {
case TI_ADC141S626:
indio_dev->channels = ti_adc141s626_channels;
indio_dev->num_channels = ARRAY_SIZE(ti_adc141s626_channels);
data->shift = 0;
data->read_size = 2;
break;
case TI_ADC161S626:
indio_dev->channels = ti_adc161s626_channels;
indio_dev->num_channels = ARRAY_SIZE(ti_adc161s626_channels);
data->shift = 6;
data->read_size = 3;
break;
}
ret = iio_triggered_buffer_setup(indio_dev, NULL,
ti_adc_trigger_handler, NULL);
if (ret)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto error_unreg_buffer;
return 0;
error_unreg_buffer:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
static int ti_adc_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
return 0;
}
static const struct of_device_id ti_adc_dt_ids[] = {
{ .compatible = "ti,adc141s626", },
{ .compatible = "ti,adc161s626", },
{}
};
MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
static const struct spi_device_id ti_adc_id[] = {
{"adc141s626", TI_ADC141S626},
{"adc161s626", TI_ADC161S626},
{},
};
MODULE_DEVICE_TABLE(spi, ti_adc_id);
static struct spi_driver ti_adc_driver = {
.driver = {
.name = TI_ADC_DRV_NAME,
.of_match_table = of_match_ptr(ti_adc_dt_ids),
},
.probe = ti_adc_probe,
.remove = ti_adc_remove,
.id_table = ti_adc_id,
};
module_spi_driver(ti_adc_driver);
MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
MODULE_DESCRIPTION("Texas Instruments ADC1x1S 1-channel differential ADC");
MODULE_LICENSE("GPL");
......@@ -522,6 +522,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
if (pga > 6) {
dev_err(&client->dev, "invalid gain on %s\n",
node->full_name);
of_node_put(node);
return -EINVAL;
}
}
......@@ -532,6 +533,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client)
dev_err(&client->dev,
"invalid data_rate on %s\n",
node->full_name);
of_node_put(node);
return -EINVAL;
}
}
......
......@@ -438,7 +438,7 @@ static int ads8688_probe(struct spi_device *spi)
return 0;
error_out:
if (!IS_ERR_OR_NULL(st->reg))
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return ret;
......@@ -451,7 +451,7 @@ static int ads8688_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
if (!IS_ERR_OR_NULL(st->reg))
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
return 0;
......
......@@ -18,6 +18,7 @@ struct iio_cb_buffer {
int (*cb)(const void *data, void *private);
void *private;
struct iio_channel *channels;
struct iio_dev *indio_dev;
};
static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
......@@ -52,7 +53,6 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
{
int ret;
struct iio_cb_buffer *cb_buff;
struct iio_dev *indio_dev;
struct iio_channel *chan;
cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
......@@ -72,17 +72,17 @@ struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
goto error_free_cb_buff;
}
indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->indio_dev = cb_buff->channels[0].indio_dev;
cb_buff->buffer.scan_mask
= kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
GFP_KERNEL);
= kcalloc(BITS_TO_LONGS(cb_buff->indio_dev->masklength),
sizeof(long), GFP_KERNEL);
if (cb_buff->buffer.scan_mask == NULL) {
ret = -ENOMEM;
goto error_release_channels;
}
chan = &cb_buff->channels[0];
while (chan->indio_dev) {
if (chan->indio_dev != indio_dev) {
if (chan->indio_dev != cb_buff->indio_dev) {
ret = -EINVAL;
goto error_free_scan_mask;
}
......@@ -105,17 +105,14 @@ EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
{
return iio_update_buffers(cb_buff->channels[0].indio_dev,
&cb_buff->buffer,
return iio_update_buffers(cb_buff->indio_dev, &cb_buff->buffer,
NULL);
}
EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
{
iio_update_buffers(cb_buff->channels[0].indio_dev,
NULL,
&cb_buff->buffer);
iio_update_buffers(cb_buff->indio_dev, NULL, &cb_buff->buffer);
}
EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
......@@ -133,6 +130,13 @@ struct iio_channel
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
struct iio_dev
*iio_channel_cb_get_iio_dev(const struct iio_cb_buffer *cb_buffer)
{
return cb_buffer->indio_dev;
}
EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev);
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
MODULE_DESCRIPTION("Industrial I/O callback buffer");
MODULE_LICENSE("GPL");
......@@ -98,6 +98,48 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
static void devm_iio_triggered_buffer_clean(struct device *dev, void *res)
{
iio_triggered_buffer_cleanup(*(struct iio_dev **)res);
}
int devm_iio_triggered_buffer_setup(struct device *dev,
struct iio_dev *indio_dev,
irqreturn_t (*h)(int irq, void *p),
irqreturn_t (*thread)(int irq, void *p),
const struct iio_buffer_setup_ops *ops)
{
struct iio_dev **ptr;
int ret;
ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return -ENOMEM;
*ptr = indio_dev;
ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops);
if (!ret)
devres_add(dev, ptr);
else
devres_free(ptr);
return ret;
}
EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup);
void devm_iio_triggered_buffer_cleanup(struct device *dev,
struct iio_dev *indio_dev)
{
int rc;
rc = devres_release(dev, devm_iio_triggered_buffer_clean,
devm_iio_device_match, indio_dev);
WARN_ON(rc);
}
EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
MODULE_LICENSE("GPL");
......@@ -16,6 +16,7 @@ config ATLAS_PH_SENSOR
Atlas Scientific OEM SM sensors:
* pH SM sensor
* EC SM sensor
* ORP SM sensor
To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor.
......
......@@ -66,12 +66,17 @@
#define ATLAS_REG_TDS_DATA 0x1c
#define ATLAS_REG_PSS_DATA 0x20
#define ATLAS_REG_ORP_CALIB_STATUS 0x0d
#define ATLAS_REG_ORP_DATA 0x0e
#define ATLAS_PH_INT_TIME_IN_US 450000
#define ATLAS_EC_INT_TIME_IN_US 650000
#define ATLAS_ORP_INT_TIME_IN_US 450000
enum {
ATLAS_PH_SM,
ATLAS_EC_SM,
ATLAS_ORP_SM,
};
struct atlas_data {
......@@ -84,26 +89,10 @@ struct atlas_data {
__be32 buffer[6]; /* 96-bit data + 32-bit pad + 64-bit timestamp */
};
static const struct regmap_range atlas_volatile_ranges[] = {
regmap_reg_range(ATLAS_REG_INT_CONTROL, ATLAS_REG_INT_CONTROL),
regmap_reg_range(ATLAS_REG_PH_DATA, ATLAS_REG_PH_DATA + 4),
regmap_reg_range(ATLAS_REG_EC_DATA, ATLAS_REG_PSS_DATA + 4),
};
static const struct regmap_access_table atlas_volatile_table = {
.yes_ranges = atlas_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(atlas_volatile_ranges),
};
static const struct regmap_config atlas_regmap_config = {
.name = ATLAS_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &atlas_volatile_table,
.max_register = ATLAS_REG_PSS_DATA + 4,
.cache_type = REGCACHE_RBTREE,
};
static const struct iio_chan_spec atlas_ph_channels[] = {
......@@ -175,6 +164,23 @@ static const struct iio_chan_spec atlas_ec_channels[] = {
},
};
static const struct iio_chan_spec atlas_orp_channels[] = {
{
.type = IIO_VOLTAGE,
.address = ATLAS_REG_ORP_DATA,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.scan_index = 0,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
.endianness = IIO_BE,
},
},
IIO_CHAN_SOFT_TIMESTAMP(1),
};
static int atlas_check_ph_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
......@@ -240,6 +246,22 @@ static int atlas_check_ec_calibration(struct atlas_data *data)
return 0;
}
static int atlas_check_orp_calibration(struct atlas_data *data)
{
struct device *dev = &data->client->dev;
int ret;
unsigned int val;
ret = regmap_read(data->regmap, ATLAS_REG_ORP_CALIB_STATUS, &val);
if (ret)
return ret;
if (!val)
dev_warn(dev, "device has not been calibrated\n");
return 0;
};
struct atlas_device {
const struct iio_chan_spec *channels;
int num_channels;
......@@ -264,7 +286,13 @@ static struct atlas_device atlas_devices[] = {
.calibration = &atlas_check_ec_calibration,
.delay = ATLAS_EC_INT_TIME_IN_US,
},
[ATLAS_ORP_SM] = {
.channels = atlas_orp_channels,
.num_channels = 2,
.data_reg = ATLAS_REG_ORP_DATA,
.calibration = &atlas_check_orp_calibration,
.delay = ATLAS_ORP_INT_TIME_IN_US,
},
};
static int atlas_set_powermode(struct atlas_data *data, int on)
......@@ -402,15 +430,14 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
case IIO_PH:
case IIO_CONCENTRATION:
case IIO_ELECTRICALCONDUCTIVITY:
mutex_lock(&indio_dev->mlock);
case IIO_VOLTAGE:
ret = iio_device_claim_direct_mode(indio_dev);
if (ret)
return ret;
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
else
ret = atlas_read_measurement(data,
chan->address, &reg);
ret = atlas_read_measurement(data, chan->address, &reg);
mutex_unlock(&indio_dev->mlock);
iio_device_release_direct_mode(indio_dev);
break;
default:
ret = -EINVAL;
......@@ -440,6 +467,10 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
*val = 0; /* 0.000000001 */
*val2 = 1000;
return IIO_VAL_INT_PLUS_NANO;
case IIO_VOLTAGE:
*val = 1; /* 0.1 */
*val2 = 10;
break;
default:
return -EINVAL;
}
......@@ -475,6 +506,7 @@ static const struct iio_info atlas_info = {
static const struct i2c_device_id atlas_id[] = {
{ "atlas-ph-sm", ATLAS_PH_SM},
{ "atlas-ec-sm", ATLAS_EC_SM},
{ "atlas-orp-sm", ATLAS_ORP_SM},
{}
};
MODULE_DEVICE_TABLE(i2c, atlas_id);
......@@ -482,6 +514,7 @@ MODULE_DEVICE_TABLE(i2c, atlas_id);
static const struct of_device_id atlas_dt_ids[] = {
{ .compatible = "atlas,ph-sm", .data = (void *)ATLAS_PH_SM, },
{ .compatible = "atlas,ec-sm", .data = (void *)ATLAS_EC_SM, },
{ .compatible = "atlas,orp-sm", .data = (void *)ATLAS_ORP_SM, },
{ }
};
MODULE_DEVICE_TABLE(of, atlas_dt_ids);
......
......@@ -19,25 +19,55 @@
#include <linux/mutex.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define VZ89X_REG_MEASUREMENT 0x09
#define VZ89X_REG_MEASUREMENT_SIZE 6
#define VZ89X_REG_MEASUREMENT_RD_SIZE 6
#define VZ89X_REG_MEASUREMENT_WR_SIZE 3
#define VZ89X_VOC_CO2_IDX 0
#define VZ89X_VOC_SHORT_IDX 1
#define VZ89X_VOC_TVOC_IDX 2
#define VZ89X_VOC_RESISTANCE_IDX 3
#define VZ89TE_REG_MEASUREMENT 0x0c
#define VZ89TE_REG_MEASUREMENT_RD_SIZE 7
#define VZ89TE_REG_MEASUREMENT_WR_SIZE 6
#define VZ89TE_VOC_TVOC_IDX 0
#define VZ89TE_VOC_CO2_IDX 1
#define VZ89TE_VOC_RESISTANCE_IDX 2
enum {
VZ89X,
VZ89TE,
};
struct vz89x_chip_data;
struct vz89x_data {
struct i2c_client *client;
const struct vz89x_chip_data *chip;
struct mutex lock;
int (*xfer)(struct vz89x_data *data, u8 cmd);
bool is_valid;
unsigned long last_update;
u8 buffer[VZ89X_REG_MEASUREMENT_SIZE];
u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE];
};
struct vz89x_chip_data {
bool (*valid)(struct vz89x_data *data);
const struct iio_chan_spec *channels;
u8 num_channels;
u8 cmd;
u8 read_size;
u8 write_size;
};
static const struct iio_chan_spec vz89x_channels[] = {
......@@ -70,6 +100,40 @@ static const struct iio_chan_spec vz89x_channels[] = {
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.address = VZ89X_VOC_RESISTANCE_IDX,
.scan_index = -1,
.scan_type = {
.endianness = IIO_LE,
},
},
};
static const struct iio_chan_spec vz89te_channels[] = {
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_VOC,
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
.address = VZ89TE_VOC_TVOC_IDX,
},
{
.type = IIO_CONCENTRATION,
.channel2 = IIO_MOD_CO2,
.modified = 1,
.info_mask_separate =
BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW),
.address = VZ89TE_VOC_CO2_IDX,
},
{
.type = IIO_RESISTANCE,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
.address = VZ89TE_VOC_RESISTANCE_IDX,
.scan_index = -1,
.scan_type = {
.endianness = IIO_BE,
},
},
};
......@@ -93,29 +157,45 @@ static const struct attribute_group vz89x_attrs_group = {
* always zero, and by also confirming the VOC_short isn't zero.
*/
static int vz89x_measurement_is_valid(struct vz89x_data *data)
static bool vz89x_measurement_is_valid(struct vz89x_data *data)
{
if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0)
return 1;
return true;
return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0);
return !!(data->buffer[data->chip->read_size - 1] > 0);
}
/* VZ89TE device has a modified CRC-8 two complement check */
static bool vz89te_measurement_is_valid(struct vz89x_data *data)
{
u8 crc = 0;
int i, sum = 0;
for (i = 0; i < (data->chip->read_size - 1); i++) {
sum = crc + data->buffer[i];
crc = sum;
crc += sum / 256;
}
return !((0xff - crc) == data->buffer[data->chip->read_size - 1]);
}
static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd)
{
const struct vz89x_chip_data *chip = data->chip;
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
int ret;
u8 buf[3] = { cmd, 0, 0};
u8 buf[6] = { cmd, 0, 0, 0, 0, 0xf3 };
msg[0].addr = client->addr;
msg[0].flags = client->flags;
msg[0].len = 3;
msg[0].len = chip->write_size;
msg[0].buf = (char *) &buf;
msg[1].addr = client->addr;
msg[1].flags = client->flags | I2C_M_RD;
msg[1].len = VZ89X_REG_MEASUREMENT_SIZE;
msg[1].len = chip->read_size;
msg[1].buf = (char *) &data->buffer;
ret = i2c_transfer(client->adapter, msg, 2);
......@@ -133,7 +213,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
if (ret < 0)
return ret;
for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) {
for (i = 0; i < data->chip->read_size; i++) {
ret = i2c_smbus_read_byte(client);
if (ret < 0)
return ret;
......@@ -145,30 +225,47 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd)
static int vz89x_get_measurement(struct vz89x_data *data)
{
const struct vz89x_chip_data *chip = data->chip;
int ret;
/* sensor can only be polled once a second max per datasheet */
if (!time_after(jiffies, data->last_update + HZ))
return 0;
return data->is_valid ? 0 : -EAGAIN;
data->is_valid = false;
data->last_update = jiffies;
ret = data->xfer(data, VZ89X_REG_MEASUREMENT);
ret = data->xfer(data, chip->cmd);
if (ret < 0)
return ret;
ret = vz89x_measurement_is_valid(data);
ret = chip->valid(data);
if (ret)
return -EAGAIN;
data->last_update = jiffies;
data->is_valid = true;
return 0;
}
static int vz89x_get_resistance_reading(struct vz89x_data *data)
static int vz89x_get_resistance_reading(struct vz89x_data *data,
struct iio_chan_spec const *chan,
int *val)
{
u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX];
u8 *tmp = (u8 *) &data->buffer[chan->address];
return buf[0] | (buf[1] << 8);
switch (chan->scan_type.endianness) {
case IIO_LE:
*val = le32_to_cpup((__le32 *) tmp) & GENMASK(23, 0);
break;
case IIO_BE:
*val = be32_to_cpup((__be32 *) tmp) >> 8;
break;
default:
return -EINVAL;
}
return 0;
}
static int vz89x_read_raw(struct iio_dev *indio_dev,
......@@ -187,15 +284,15 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
if (ret)
return ret;
switch (chan->address) {
case VZ89X_VOC_CO2_IDX:
case VZ89X_VOC_SHORT_IDX:
case VZ89X_VOC_TVOC_IDX:
switch (chan->type) {
case IIO_CONCENTRATION:
*val = data->buffer[chan->address];
return IIO_VAL_INT;
case VZ89X_VOC_RESISTANCE_IDX:
*val = vz89x_get_resistance_reading(data);
return IIO_VAL_INT;
case IIO_RESISTANCE:
ret = vz89x_get_resistance_reading(data, chan, val);
if (!ret)
return IIO_VAL_INT;
break;
default:
return -EINVAL;
}
......@@ -210,12 +307,12 @@ static int vz89x_read_raw(struct iio_dev *indio_dev,
}
break;
case IIO_CHAN_INFO_OFFSET:
switch (chan->address) {
case VZ89X_VOC_CO2_IDX:
switch (chan->channel2) {
case IIO_MOD_CO2:
*val = 44;
*val2 = 250000;
return IIO_VAL_INT_PLUS_MICRO;
case VZ89X_VOC_TVOC_IDX:
case IIO_MOD_VOC:
*val = -13;
return IIO_VAL_INT;
default:
......@@ -232,11 +329,43 @@ static const struct iio_info vz89x_info = {
.driver_module = THIS_MODULE,
};
static const struct vz89x_chip_data vz89x_chips[] = {
{
.valid = vz89x_measurement_is_valid,
.cmd = VZ89X_REG_MEASUREMENT,
.read_size = VZ89X_REG_MEASUREMENT_RD_SIZE,
.write_size = VZ89X_REG_MEASUREMENT_WR_SIZE,
.channels = vz89x_channels,
.num_channels = ARRAY_SIZE(vz89x_channels),
},
{
.valid = vz89te_measurement_is_valid,
.cmd = VZ89TE_REG_MEASUREMENT,
.read_size = VZ89TE_REG_MEASUREMENT_RD_SIZE,
.write_size = VZ89TE_REG_MEASUREMENT_WR_SIZE,
.channels = vz89te_channels,
.num_channels = ARRAY_SIZE(vz89te_channels),
},
};
static const struct of_device_id vz89x_dt_ids[] = {
{ .compatible = "sgx,vz89x", .data = (void *) VZ89X },
{ .compatible = "sgx,vz89te", .data = (void *) VZ89TE },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static int vz89x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct vz89x_data *data;
const struct of_device_id *of_id;
int chip_id;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
......@@ -251,8 +380,15 @@ static int vz89x_probe(struct i2c_client *client,
else
return -EOPNOTSUPP;
of_id = of_match_device(vz89x_dt_ids, &client->dev);
if (!of_id)
chip_id = id->driver_data;
else
chip_id = (unsigned long)of_id->data;
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->chip = &vz89x_chips[chip_id];
data->last_update = jiffies - HZ;
mutex_init(&data->lock);
......@@ -261,24 +397,19 @@ static int vz89x_probe(struct i2c_client *client,
indio_dev->name = dev_name(&client->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = vz89x_channels;
indio_dev->num_channels = ARRAY_SIZE(vz89x_channels);
indio_dev->channels = data->chip->channels;
indio_dev->num_channels = data->chip->num_channels;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id vz89x_id[] = {
{ "vz89x", 0 },
{ "vz89x", VZ89X },
{ "vz89te", VZ89TE },
{ }
};
MODULE_DEVICE_TABLE(i2c, vz89x_id);
static const struct of_device_id vz89x_dt_ids[] = {
{ .compatible = "sgx,vz89x" },
{ }
};
MODULE_DEVICE_TABLE(of, vz89x_dt_ids);
static struct i2c_driver vz89x_driver = {
.driver = {
.name = "vz89x",
......
......@@ -122,6 +122,14 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
#endif
}
static void hid_sensor_set_power_work(struct work_struct *work)
{
struct hid_sensor_common *attrb = container_of(work,
struct hid_sensor_common,
work);
_hid_sensor_power_state(attrb, true);
}
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
......@@ -130,6 +138,7 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
cancel_work_sync(&attrb->work);
iio_trigger_unregister(attrb->trigger);
iio_trigger_free(attrb->trigger);
}
......@@ -170,6 +179,9 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
goto error_unreg_trigger;
iio_device_set_drvdata(indio_dev, attrb);
INIT_WORK(&attrb->work, hid_sensor_set_power_work);
pm_suspend_ignore_children(&attrb->pdev->dev, true);
pm_runtime_enable(&attrb->pdev->dev);
/* Default to 3 seconds, but can be changed from sysfs */
......@@ -187,8 +199,7 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);
#ifdef CONFIG_PM
static int hid_sensor_suspend(struct device *dev)
static int __maybe_unused hid_sensor_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
......@@ -197,21 +208,27 @@ static int hid_sensor_suspend(struct device *dev)
return _hid_sensor_power_state(attrb, false);
}
static int hid_sensor_resume(struct device *dev)
static int __maybe_unused hid_sensor_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
schedule_work(&attrb->work);
return 0;
}
static int __maybe_unused hid_sensor_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
return _hid_sensor_power_state(attrb, true);
}
#endif
const struct dev_pm_ops hid_sensor_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
SET_RUNTIME_PM_OPS(hid_sensor_suspend,
hid_sensor_resume, NULL)
hid_sensor_runtime_resume, NULL)
};
EXPORT_SYMBOL(hid_sensor_pm_ops);
......
......@@ -63,7 +63,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
* the hardware trigger) and the hw_timestamp may get updated.
* By storing it in a local variable first, we are safe.
*/
if (sdata->hw_irq_trigger)
if (iio_trigger_using_own(indio_dev))
timestamp = sdata->hw_timestamp;
else
timestamp = iio_get_time_ns(indio_dev);
......
......@@ -234,39 +234,35 @@ int st_sensors_power_enable(struct iio_dev *indio_dev)
int err;
/* Regulators not mandatory, but if requested we should enable them. */
pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd");
if (!IS_ERR(pdata->vdd)) {
err = regulator_enable(pdata->vdd);
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd supply\n");
return err;
}
} else {
err = PTR_ERR(pdata->vdd);
if (err != -ENODEV)
return err;
pdata->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd");
if (IS_ERR(pdata->vdd)) {
dev_err(&indio_dev->dev, "unable to get Vdd supply\n");
return PTR_ERR(pdata->vdd);
}
err = regulator_enable(pdata->vdd);
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd supply\n");
return err;
}
pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio");
if (!IS_ERR(pdata->vdd_io)) {
err = regulator_enable(pdata->vdd_io);
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd_IO supply\n");
goto st_sensors_disable_vdd;
}
} else {
pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio");
if (IS_ERR(pdata->vdd_io)) {
dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n");
err = PTR_ERR(pdata->vdd_io);
if (err != -ENODEV)
goto st_sensors_disable_vdd;
goto st_sensors_disable_vdd;
}
err = regulator_enable(pdata->vdd_io);
if (err != 0) {
dev_warn(&indio_dev->dev,
"Failed to enable specified Vdd_IO supply\n");
goto st_sensors_disable_vdd;
}
return 0;
st_sensors_disable_vdd:
if (!IS_ERR_OR_NULL(pdata->vdd))
regulator_disable(pdata->vdd);
regulator_disable(pdata->vdd);
return err;
}
EXPORT_SYMBOL(st_sensors_power_enable);
......@@ -275,11 +271,8 @@ void st_sensors_power_disable(struct iio_dev *indio_dev)
{
struct st_sensor_data *pdata = iio_priv(indio_dev);
if (!IS_ERR_OR_NULL(pdata->vdd))
regulator_disable(pdata->vdd);
if (!IS_ERR_OR_NULL(pdata->vdd_io))
regulator_disable(pdata->vdd_io);
regulator_disable(pdata->vdd);
regulator_disable(pdata->vdd_io);
}
EXPORT_SYMBOL(st_sensors_power_disable);
......
......@@ -66,7 +66,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
* @irq: irq number
* @p: private handler data
*/
irqreturn_t st_sensors_irq_handler(int irq, void *p)
static irqreturn_t st_sensors_irq_handler(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
......@@ -82,7 +82,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p)
* @irq: irq number
* @p: private handler data
*/
irqreturn_t st_sensors_irq_thread(int irq, void *p)
static irqreturn_t st_sensors_irq_thread(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
......
......@@ -181,6 +181,25 @@ config AD7303
To compile this driver as module choose M here: the module will be called
ad7303.
config CIO_DAC
tristate "Measurement Computing CIO-DAC IIO driver"
depends on X86 && ISA_BUS_API
help
Say yes here to build support for the Measurement Computing CIO-DAC
analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The
base port addresses for the devices may be configured via the base
array module parameter.
config AD8801
tristate "Analog Devices AD8801/AD8803 DAC driver"
depends on SPI_MASTER
help
Say yes here to build support for Analog Devices AD8801, AD8803 Digital to
Analog Converters (DAC).
To compile this driver as a module choose M here: the module will be called
ad8801.
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
......@@ -245,16 +264,6 @@ config MCP4922
To compile this driver as a module, choose M here: the module
will be called mcp4922.
config STX104
tristate "Apex Embedded Systems STX104 DAC driver"
depends on X86 && ISA_BUS_API
select GPIOLIB
help
Say yes here to build support for the 2-channel DAC and GPIO on the
Apex Embedded Systems STX104 integrated analog PC/104 card. The base
port addresses for the devices may be configured via the base array
module parameter.
config VF610_DAC
tristate "Vybrid vf610 DAC driver"
depends on OF
......
......@@ -20,11 +20,12 @@ obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o
obj-$(CONFIG_MCP4922) += mcp4922.o
obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_VF610_DAC) += vf610_dac.o
......@@ -655,7 +655,7 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev)
devnr = 0;
for_each_child_of_node(np, pp) {
if (devnr > AD5755_NUM_CHANNELS) {
if (devnr >= AD5755_NUM_CHANNELS) {
dev_err(dev,
"There is to many channels defined in DT\n");
goto error_out;
......
/*
* IIO DAC driver for Analog Devices AD8801 DAC
*
* Copyright (C) 2016 Gwenhael Goavec-Merou
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
*/
#include <linux/iio/iio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#define AD8801_CFG_ADDR_OFFSET 8
enum ad8801_device_ids {
ID_AD8801,
ID_AD8803,
};
struct ad8801_state {
struct spi_device *spi;
unsigned char dac_cache[8]; /* Value write on each channel */
unsigned int vrefh_mv;
unsigned int vrefl_mv;
struct regulator *vrefh_reg;
struct regulator *vrefl_reg;
__be16 data ____cacheline_aligned;
};
static int ad8801_spi_write(struct ad8801_state *state,
u8 channel, unsigned char value)
{
state->data = cpu_to_be16((channel << AD8801_CFG_ADDR_OFFSET) | value);
return spi_write(state->spi, &state->data, sizeof(state->data));
}
static int ad8801_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct ad8801_state *state = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val >= 256 || val < 0)
return -EINVAL;
ret = ad8801_spi_write(state, chan->channel, val);
if (ret == 0)
state->dac_cache[chan->channel] = val;
break;
default:
ret = -EINVAL;
}
return ret;
}
static int ad8801_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long info)
{
struct ad8801_state *state = iio_priv(indio_dev);
switch (info) {
case IIO_CHAN_INFO_RAW:
*val = state->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = state->vrefh_mv - state->vrefl_mv;
*val2 = 8;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_OFFSET:
*val = state->vrefl_mv;
return IIO_VAL_INT;
default:
return -EINVAL;
}
return -EINVAL;
}
static const struct iio_info ad8801_info = {
.read_raw = ad8801_read_raw,
.write_raw = ad8801_write_raw,
.driver_module = THIS_MODULE,
};
#define AD8801_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec ad8801_channels[] = {
AD8801_CHANNEL(0),
AD8801_CHANNEL(1),
AD8801_CHANNEL(2),
AD8801_CHANNEL(3),
AD8801_CHANNEL(4),
AD8801_CHANNEL(5),
AD8801_CHANNEL(6),
AD8801_CHANNEL(7),
};
static int ad8801_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct ad8801_state *state;
const struct spi_device_id *id;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
if (indio_dev == NULL)
return -ENOMEM;
state = iio_priv(indio_dev);
state->spi = spi;
id = spi_get_device_id(spi);
state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh");
if (IS_ERR(state->vrefh_reg)) {
dev_err(&spi->dev, "Vrefh regulator not specified\n");
return PTR_ERR(state->vrefh_reg);
}
ret = regulator_enable(state->vrefh_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n",
ret);
return ret;
}
ret = regulator_get_voltage(state->vrefh_reg);
if (ret < 0) {
dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n",
ret);
goto error_disable_vrefh_reg;
}
state->vrefh_mv = ret / 1000;
if (id->driver_data == ID_AD8803) {
state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl");
if (IS_ERR(state->vrefl_reg)) {
dev_err(&spi->dev, "Vrefl regulator not specified\n");
ret = PTR_ERR(state->vrefl_reg);
goto error_disable_vrefh_reg;
}
ret = regulator_enable(state->vrefl_reg);
if (ret) {
dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n",
ret);
goto error_disable_vrefh_reg;
}
ret = regulator_get_voltage(state->vrefl_reg);
if (ret < 0) {
dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n",
ret);
goto error_disable_vrefl_reg;
}
state->vrefl_mv = ret / 1000;
} else {
state->vrefl_mv = 0;
state->vrefl_reg = NULL;
}
spi_set_drvdata(spi, indio_dev);
indio_dev->dev.parent = &spi->dev;
indio_dev->info = &ad8801_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = ad8801_channels;
indio_dev->num_channels = ARRAY_SIZE(ad8801_channels);
indio_dev->name = id->name;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&spi->dev, "Failed to register iio device: %d\n",
ret);
goto error_disable_vrefl_reg;
}
return 0;
error_disable_vrefl_reg:
if (state->vrefl_reg)
regulator_disable(state->vrefl_reg);
error_disable_vrefh_reg:
regulator_disable(state->vrefh_reg);
return ret;
}
static int ad8801_remove(struct spi_device *spi)
{
struct iio_dev *indio_dev = spi_get_drvdata(spi);
struct ad8801_state *state = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
if (state->vrefl_reg)
regulator_disable(state->vrefl_reg);
regulator_disable(state->vrefh_reg);
return 0;
}
static const struct spi_device_id ad8801_ids[] = {
{"ad8801", ID_AD8801},
{"ad8803", ID_AD8803},
{}
};
MODULE_DEVICE_TABLE(spi, ad8801_ids);
static struct spi_driver ad8801_driver = {
.driver = {
.name = "ad8801",
},
.probe = ad8801_probe,
.remove = ad8801_remove,
.id_table = ad8801_ids,
};
module_spi_driver(ad8801_driver);
MODULE_AUTHOR("Gwenhael Goavec-Merou <gwenhael.goavec-merou@trabucayre.com>");
MODULE_DESCRIPTION("Analog Devices AD8801/AD8803 DAC");
MODULE_LICENSE("GPL v2");
/*
* IIO driver for the Measurement Computing CIO-DAC
* Copyright (C) 2016 William Breathitt Gray
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* This driver supports the following Measurement Computing devices: CIO-DAC16,
* CIO-DAC06, and PC104-DAC06.
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/iio/iio.h>
#include <linux/iio/types.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/isa.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#define CIO_DAC_NUM_CHAN 16
#define CIO_DAC_CHAN(chan) { \
.type = IIO_VOLTAGE, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.indexed = 1, \
.output = 1 \
}
#define CIO_DAC_EXTENT 32
static unsigned int base[max_num_isa_dev(CIO_DAC_EXTENT)];
static unsigned int num_cio_dac;
module_param_array(base, uint, &num_cio_dac, 0);
MODULE_PARM_DESC(base, "Measurement Computing CIO-DAC base addresses");
/**
* struct cio_dac_iio - IIO device private data structure
* @chan_out_states: channels' output states
* @base: base port address of the IIO device
*/
struct cio_dac_iio {
int chan_out_states[CIO_DAC_NUM_CHAN];
unsigned int base;
};
static int cio_dac_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
*val = priv->chan_out_states[chan->channel];
return IIO_VAL_INT;
}
static int cio_dac_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
struct cio_dac_iio *const priv = iio_priv(indio_dev);
const unsigned int chan_addr_offset = 2 * chan->channel;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
/* DAC can only accept up to a 16-bit value */
if ((unsigned int)val > 65535)
return -EINVAL;
priv->chan_out_states[chan->channel] = val;
outw(val, priv->base + chan_addr_offset);
return 0;
}
static const struct iio_info cio_dac_info = {
.driver_module = THIS_MODULE,
.read_raw = cio_dac_read_raw,
.write_raw = cio_dac_write_raw
};
static const struct iio_chan_spec cio_dac_channels[CIO_DAC_NUM_CHAN] = {
CIO_DAC_CHAN(0), CIO_DAC_CHAN(1), CIO_DAC_CHAN(2), CIO_DAC_CHAN(3),
CIO_DAC_CHAN(4), CIO_DAC_CHAN(5), CIO_DAC_CHAN(6), CIO_DAC_CHAN(7),
CIO_DAC_CHAN(8), CIO_DAC_CHAN(9), CIO_DAC_CHAN(10), CIO_DAC_CHAN(11),
CIO_DAC_CHAN(12), CIO_DAC_CHAN(13), CIO_DAC_CHAN(14), CIO_DAC_CHAN(15)
};
static int cio_dac_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct cio_dac_iio *priv;
unsigned int i;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!indio_dev)
return -ENOMEM;
if (!devm_request_region(dev, base[id], CIO_DAC_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to request port addresses (0x%X-0x%X)\n",
base[id], base[id] + CIO_DAC_EXTENT);
return -EBUSY;
}
indio_dev->info = &cio_dac_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = cio_dac_channels;
indio_dev->num_channels = CIO_DAC_NUM_CHAN;
indio_dev->name = dev_name(dev);
priv = iio_priv(indio_dev);
priv->base = base[id];
/* initialize DAC outputs to 0V */
for (i = 0; i < 32; i += 2)
outw(0, base[id] + i);
return devm_iio_device_register(dev, indio_dev);
}
static struct isa_driver cio_dac_driver = {
.probe = cio_dac_probe,
.driver = {
.name = "cio-dac"
}
};
module_isa_driver(cio_dac_driver, num_cio_dac);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("Measurement Computing CIO-DAC IIO driver");
MODULE_LICENSE("GPL v2");
......@@ -74,7 +74,7 @@ static int ssp_gyro_write_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
static struct iio_info ssp_gyro_iio_info = {
static const struct iio_info ssp_gyro_iio_info = {
.read_raw = &ssp_gyro_read_raw,
.write_raw = &ssp_gyro_write_raw,
};
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -26,6 +26,7 @@ obj-$(CONFIG_OPT3001) += opt3001.o
obj-$(CONFIG_PA12203001) += pa12203001.o
obj-$(CONFIG_RPR0521) += rpr0521.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SI1145) += si1145.o
obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册