Second set of new driver, functionality and cleanups for IIO in the 4.2 cycle.

Core functionality
 * i and q modifiers from quadrature channels.
 * IIO_CHAN_INFO_OVERSAMPLING_RATIO added.
 * High pass filter attributes added to mirror the existing low pass filter
   ones.
 
 Core cleanups
 * Make IIO tools building more cross compiler friendly.
 * Substantial rework of the function __iio_update_buffers to greatly simplify
   a hideously evolved function.
 
 New drivers and support
 * ACPI0008 ambient light sensor driver. This one has been around a long time to
   will be good to finally get it into mainline.
 * Berlin SOC ADC support.
 * BMC150 magnetometer.  The accelerometer in the same package has been supported
   for quite some time, so good to have this half as well.
 * m62332 DAC driver
 * MEMSIC MMC35420 magnetometer.
 * ROHM BH1710 and similar ambient light sensors.
 * Sensortek STK3310 light sensor.
 * Sensortek STK8312 accelerometer.
 * Sensortek STK8BA50 accelerometer.
 * ti-adc128s052 gains support form the adc122s021 2 channel ADC.
 
 Driver cleanups and functionality.
 * Allow various drivers to compile with !GPIOLIB if COMPILE_TEST enabled.
 * bmc150 - decouple trigger from buffer to allow other triggers to be used.
 * bmg160 - decouple trigger from buffer to allow other triggers to be used.
   Fix a trivial unused field.
 * Constify a load of platform_device_id structures.
 * inv_mpu6050 - device tree bindings.
 * hid-sensors - fix a memory leak during probe if certain errors occur.
 * ltr501 - illuminance channel derived (in an non obvious fashion) from the
   intensity channels.
 * ltr501 - fix a boundary check on the proximity threshold.
 * mlx90614 - drop a pointless return.
 * mma8452 - Debugfs register access and fix a bug that had no effect (by
   coincidence)
 * ti_am335x_adc - add device tree bindings for sample-delay, open-delay and
   averaging.  The ideal settings for these tend to be board design specific.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJVYfYpAAoJEFSFNJnE9BaI1ScQAIJ2jsFZdf8fcVnWeq0bYx9I
 VUPfz/bJ/kLQRGm/LDgpMPc5o1mOE+rupwFpp/iQf15vVUN86+CRLt0qd5I/cAEg
 I3qbaieS1H9Qyd2dLTgAcZAh6tH7ZvFJm/hB6T5xQAYFGY2IMq/n3qA4//W37tUb
 2bKTRb67LWbGivOvwbxdSpEkBLtVcUw3UNn9nfqjB8BEAHIesh88gJkVKAAuRYqk
 Tm8AzQ7EGsosz2R7mIvukSBwXBcvRyxyOxCdLBPIWSESeLwMiiat0zCfv3MxrYiD
 FVpdlywoReIjDG6z9ALOm4VMtRF2m2VrjPHclQ3kYgYSgyf0fRmoiyGowv7hkeya
 Z+p9ltOZ8qdis+yH1ci9Ch695HURa1m0seirX4exqiv0Crx8UF+iNIvs9Ai84Rv8
 NNVlscoeEyijUaqoBb1YvG/Fryh2IEiGXTkF4Eld+EhW8AKkFFNIqR+Gwvs1YegT
 02A8kHxD0GyMYJo1uEwd+TnKwCBglwsie8omkxOXqsY860DRtBr7jOxyb/RzkSVi
 jGtq1Y4nxVv7q3nkn+vQDRNgAQTbH1EJfrDilpIxIWK+9onNmKMnhKnSTVNAdld/
 Hhn9g/MHptQtmA+DwMcJ3Aqn0xMUdgoE9GIkMGoKSZku9H0DhWHLdxTa2lxdJFUo
 OiWVvP0eJuvu0E0h4eA2
 =uX2k
 -----END PGP SIGNATURE-----

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

Jonathan writes:

Second set of new driver, functionality and cleanups for IIO in the 4.2 cycle.

Core functionality
* i and q modifiers from quadrature channels.
* IIO_CHAN_INFO_OVERSAMPLING_RATIO added.
* High pass filter attributes added to mirror the existing low pass filter
  ones.

Core cleanups
* Make IIO tools building more cross compiler friendly.
* Substantial rework of the function __iio_update_buffers to greatly simplify
  a hideously evolved function.

New drivers and support
* ACPI0008 ambient light sensor driver. This one has been around a long time to
  will be good to finally get it into mainline.
* Berlin SOC ADC support.
* BMC150 magnetometer.  The accelerometer in the same package has been supported
  for quite some time, so good to have this half as well.
* m62332 DAC driver
* MEMSIC MMC35420 magnetometer.
* ROHM BH1710 and similar ambient light sensors.
* Sensortek STK3310 light sensor.
* Sensortek STK8312 accelerometer.
* Sensortek STK8BA50 accelerometer.
* ti-adc128s052 gains support form the adc122s021 2 channel ADC.

Driver cleanups and functionality.
* Allow various drivers to compile with !GPIOLIB if COMPILE_TEST enabled.
* bmc150 - decouple trigger from buffer to allow other triggers to be used.
* bmg160 - decouple trigger from buffer to allow other triggers to be used.
  Fix a trivial unused field.
* Constify a load of platform_device_id structures.
* inv_mpu6050 - device tree bindings.
* hid-sensors - fix a memory leak during probe if certain errors occur.
* ltr501 - illuminance channel derived (in an non obvious fashion) from the
  intensity channels.
* ltr501 - fix a boundary check on the proximity threshold.
* mlx90614 - drop a pointless return.
* mma8452 - Debugfs register access and fix a bug that had no effect (by
  coincidence)
* ti_am335x_adc - add device tree bindings for sample-delay, open-delay and
  averaging.  The ideal settings for these tend to be board design specific.
This commit is contained in:
Greg Kroah-Hartman 2015-05-24 11:45:21 -07:00
commit 61e331202f
53 changed files with 5061 additions and 259 deletions

View file

@ -71,6 +71,8 @@ Description:
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@ -81,6 +83,11 @@ Description:
unique to allow association with event codes. Units after
application of scale and offset are millivolts.
Channels with 'i' and 'q' modifiers always exist in pairs and both
channels refer to the same signal. The 'i' channel contains the in-phase
component of the signal while the 'q' channel contains the quadrature
component.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
@ -246,8 +253,16 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_q_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_i_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@ -273,14 +288,22 @@ Description:
to the _raw output.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_i_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_q_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
@ -328,6 +351,10 @@ Description:
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
@ -420,6 +447,16 @@ Description:
to the underlying data channel, then this parameter
gives the 3dB frequency of the filter in Hz.
What: /sys/.../in_accel_filter_high_pass_3db_frequency
What: /sys/.../in_anglvel_filter_high_pass_3db_frequency
What: /sys/.../in_magn_filter_high_pass_3db_frequency
KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org
Description:
If a known or controllable high pass filter is applied
to the underlying data channel, then this parameter
gives the 3dB frequency of the filter in Hz.
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_raw
KernelVersion: 2.6.37
@ -880,6 +917,26 @@ Description:
met before an event is generated. If direction is not
specified then this period applies to both directions.
What: /sys/.../events/in_accel_thresh_rising_low_pass_filter_3db
What: /sys/.../events/in_anglvel_thresh_rising_low_pass_filter_3db
What: /sys/.../events/in_magn_thresh_rising_low_pass_filter_3db
KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org
Description:
If a low pass filter can be applied to the event generation
this property gives its 3db frequency in Hz.
A value of zero disables the filter.
What: /sys/.../events/in_accel_thresh_rising_high_pass_filter_3db
What: /sys/.../events/in_anglvel_thresh_rising_high_pass_filter_3db
What: /sys/.../events/in_magn_thresh_rising_high_pass_filter_3db
KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org
Description:
If a high pass filter can be applied to the event generation
this property gives its 3db frequency in Hz.
A value of zero disables the filter.
What: /sys/.../events/in_activity_still_thresh_rising_en
What: /sys/.../events/in_activity_still_thresh_falling_en
What: /sys/.../events/in_activity_walking_thresh_rising_en
@ -1016,6 +1073,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY-voltageZ_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_en
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_en
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_en
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en
@ -1034,6 +1095,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_type
What: /sys/.../iio:deviceX/scan_elements/in_voltage_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_type
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_type
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_type
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_type
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type
What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type
What: /sys/.../iio:deviceX/scan_elements/in_pressure_type
@ -1071,6 +1136,10 @@ Description:
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_index
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_index
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_index
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_index
What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_index
What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_x_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_y_index
What: /sys/.../iio:deviceX/scan_elements/in_accel_z_index
@ -1230,6 +1299,8 @@ Description:
or without compensation from tilt sensors.
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw
What: /sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw
KernelVersion: 3.18
Contact: linux-iio@vger.kernel.org
Description:
@ -1238,6 +1309,11 @@ Description:
present, output should be considered as processed with the
unit in milliamps.
Channels with 'i' and 'q' modifiers always exist in pairs and both
channels refer to the same signal. The 'i' channel contains the in-phase
component of the signal while the 'q' channel contains the quadrature
component.
What: /sys/.../iio:deviceX/in_energy_en
What: /sys/.../iio:deviceX/in_distance_en
What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en
@ -1375,3 +1451,15 @@ Description:
The emissivity ratio of the surface in the field of view of the
contactless temperature sensor. Emissivity varies from 0 to 1,
with 1 being the emissivity of a black body.
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_oversampling_ratio
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_oversampling_ratio
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_oversampling_ratio
KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org
Description:
Hardware applied number of measurements for acquiring one
data point. The HW will do <type>[_name]_oversampling_ratio
measurements and return the average value as output data. Each
value resulted from <type>[_name]_oversampling_ratio measurements
is considered as one sample for <type>[_name]_sampling_frequency.

View file

@ -0,0 +1,19 @@
* Berlin Analog to Digital Converter (ADC)
The Berlin ADC has 8 channels, with one connected to a temperature sensor.
It is part of the system controller register set. The ADC node should be a
sub-node of the system controller node.
Required properties:
- compatible: must be "marvell,berlin2-adc"
- interrupts: the interrupts for the ADC and the temperature sensor
- interrupt-names: should be "adc" and "tsen"
Example:
adc: adc {
compatible = "marvell,berlin2-adc";
interrupt-parent = <&sic>;
interrupts = <12>, <14>;
interrupt-names = "adc", "tsen";
};

View file

@ -1,7 +1,7 @@
* Texas Instruments' ADC128S052 ADC chip
* Texas Instruments' ADC128S052 and ADC122S021 ADC chip
Required properties:
- compatible: Should be "ti,adc128s052"
- compatible: Should be "ti,adc128s052" or "ti,adc122s021"
- reg: spi chip select number for the device
- vref-supply: The regulator supply for ADC reference voltage

View file

@ -0,0 +1,17 @@
InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device
http://www.invensense.com/mems/gyro/mpu6050.html
Required properties:
- compatible : should be "invensense,mpu6050"
- reg : the I2C address of the sensor
- interrupt-parent : should be the phandle for the interrupt controller
- interrupts : interrupt mapping for GPIO IRQ
Example:
mpu6050@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
interrupt-parent = <&gpio1>;
interrupts = <18 1>;
};

View file

@ -0,0 +1,22 @@
* Bosch BMC150 magnetometer sensor
http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf
Required properties:
- compatible : should be "bosch,bmc150_magn"
- reg : the I2C address of the magnetometer
Optional properties:
- interrupt-parent : phandle to the parent interrupt controller
- interrupts : interrupt mapping for GPIO IRQ
Example:
bmc150_magn@12 {
compatible = "bosch,bmc150_magn";
reg = <0x12>;
interrupt-parent = <&gpio1>;
interrupts = <0 1>;
};

View file

@ -42,6 +42,27 @@ Optional properties:
hardware knob for adjusting the amount of "settling
time".
- child "adc"
ti,chan-step-opendelay: List of open delays for each channel of
ADC in the order of ti,adc-channels. The
value corresponds to the number of ADC
clock cycles to wait after applying the
step configuration registers and before
sending the start of ADC conversion.
Maximum value is 0x3FFFF.
ti,chan-step-sampledelay: List of sample delays for each channel
of ADC in the order of ti,adc-channels.
The value corresponds to the number of
ADC clock cycles to sample (to hold
start of conversion high).
Maximum value is 0xFF.
ti,chan-step-avg: Number of averages to be performed for each
channel of ADC. If average is 16 then input
is sampled 16 times and averaged to get more
accurate value. This increases the time taken
by ADC to generate a sample. Valid range is 0
average to 16 averages. Maximum value is 16.
Example:
tscadc: tscadc@44e0d000 {
compatible = "ti,am3359-tscadc";
@ -55,5 +76,8 @@ Example:
adc {
ti,adc-channels = <4 5 6 7>;
ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>;
ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>;
ti,chan-step-avg = <16 2 4 8>;
};
}

View file

@ -136,4 +136,25 @@ config MMA9553
To compile this driver as a module, choose M here: the module
will be called mma9553.
config STK8312
tristate "Sensortek STK8312 3-Axis Accelerometer Driver"
depends on I2C
help
Say yes here to get support for the Sensortek STK8312 3-axis
accelerometer.
Choosing M will build the driver as a module. If so, the module
will be called stk8312.
config STK8BA50
tristate "Sensortek STK8BA50 3-Axis Accelerometer Driver"
depends on I2C
help
Say yes here to get support for the Sensortek STK8BA50 3-axis
accelerometer.
Choosing M will build the driver as a module. If so, the module
will be called stk8ba50.
endmenu

View file

@ -14,6 +14,9 @@ obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_MMA9553) += mma9553.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o

View file

@ -196,7 +196,7 @@ struct bmc150_accel_data {
u32 slope_thres;
u32 range;
int ev_enable_state;
int64_t timestamp, old_timestamp;
int64_t timestamp, old_timestamp; /* Only used in hw fifo mode. */
const struct bmc150_accel_chip_info *chip_info;
};
@ -1183,7 +1183,6 @@ static const struct iio_info bmc150_accel_info = {
.write_event_value = bmc150_accel_write_event,
.write_event_config = bmc150_accel_write_event_config,
.read_event_config = bmc150_accel_read_event_config,
.validate_trigger = bmc150_accel_validate_trigger,
.driver_module = THIS_MODULE,
};
@ -1222,7 +1221,7 @@ static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p)
mutex_unlock(&data->mutex);
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
data->timestamp);
pf->timestamp);
err_read:
iio_trigger_notify_done(indio_dev->trig);
@ -1535,6 +1534,13 @@ static int bmc150_accel_fifo_set_mode(struct bmc150_accel_data *data)
return ret;
}
static int bmc150_accel_buffer_preenable(struct iio_dev *indio_dev)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
return bmc150_accel_set_power_state(data, true);
}
static int bmc150_accel_buffer_postenable(struct iio_dev *indio_dev)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
@ -1591,9 +1597,18 @@ out:
return 0;
}
static int bmc150_accel_buffer_postdisable(struct iio_dev *indio_dev)
{
struct bmc150_accel_data *data = iio_priv(indio_dev);
return bmc150_accel_set_power_state(data, false);
}
static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = {
.preenable = bmc150_accel_buffer_preenable,
.postenable = bmc150_accel_buffer_postenable,
.predisable = bmc150_accel_buffer_predisable,
.postdisable = bmc150_accel_buffer_postdisable,
};
static int bmc150_accel_probe(struct i2c_client *client,
@ -1636,6 +1651,15 @@ static int bmc150_accel_probe(struct i2c_client *client,
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &bmc150_accel_info;
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time,
bmc150_accel_trigger_handler,
&bmc150_accel_buffer_ops);
if (ret < 0) {
dev_err(&client->dev, "Failed: iio triggered buffer setup\n");
return ret;
}
if (client->irq < 0)
client->irq = bmc150_accel_gpio_probe(client, data);
@ -1648,7 +1672,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
BMC150_ACCEL_IRQ_NAME,
indio_dev);
if (ret)
return ret;
goto err_buffer_cleanup;
/*
* Set latched mode interrupt. While certain interrupts are
@ -1661,24 +1685,14 @@ static int bmc150_accel_probe(struct i2c_client *client,
BMC150_ACCEL_INT_MODE_LATCH_RESET);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n");
return ret;
goto err_buffer_cleanup;
}
bmc150_accel_interrupts_setup(indio_dev, data);
ret = bmc150_accel_triggers_setup(indio_dev, data);
if (ret)
return ret;
ret = iio_triggered_buffer_setup(indio_dev,
&iio_pollfunc_store_time,
bmc150_accel_trigger_handler,
&bmc150_accel_buffer_ops);
if (ret < 0) {
dev_err(&client->dev,
"Failed: iio triggered buffer setup\n");
goto err_trigger_unregister;
}
goto err_buffer_cleanup;
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) ||
i2c_check_functionality(client->adapter,
@ -1692,7 +1706,7 @@ static int bmc150_accel_probe(struct i2c_client *client,
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "Unable to register iio device\n");
goto err_buffer_cleanup;
goto err_trigger_unregister;
}
ret = pm_runtime_set_active(&client->dev);
@ -1708,11 +1722,10 @@ static int bmc150_accel_probe(struct i2c_client *client,
err_iio_unregister:
iio_device_unregister(indio_dev);
err_buffer_cleanup:
if (indio_dev->pollfunc)
iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
err_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
return ret;
}
@ -1730,6 +1743,8 @@ static int bmc150_accel_remove(struct i2c_client *client)
bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1);
iio_triggered_buffer_cleanup(indio_dev);
mutex_lock(&data->mutex);
bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0);
mutex_unlock(&data->mutex);

View file

@ -299,7 +299,6 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct accel_3d_state *accel_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct accel_3d_state));
@ -320,21 +319,21 @@ static int hid_accel_3d_probe(struct platform_device *pdev)
return ret;
}
channels = kmemdup(accel_3d_channels, sizeof(accel_3d_channels),
GFP_KERNEL);
if (!channels) {
indio_dev->channels = kmemdup(accel_3d_channels,
sizeof(accel_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = accel_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_ACCEL_3D, accel_state);
ret = accel_3d_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_ACCEL_3D, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &accel_3d_info;
@ -400,7 +399,7 @@ static int hid_accel_3d_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_accel_3d_ids[] = {
static const struct platform_device_id hid_accel_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200073",

View file

@ -32,6 +32,9 @@
#define MMA8452_OFF_Z 0x31
#define MMA8452_CTRL_REG1 0x2a
#define MMA8452_CTRL_REG2 0x2b
#define MMA8452_CTRL_REG2_RST BIT(6)
#define MMA8452_MAX_REG 0x31
#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0))
@ -291,6 +294,28 @@ done:
return IRQ_HANDLED;
}
static int mma8452_reg_access_dbg(struct iio_dev *indio_dev,
unsigned reg, unsigned writeval,
unsigned *readval)
{
int ret;
struct mma8452_data *data = iio_priv(indio_dev);
if (reg > MMA8452_MAX_REG)
return -EINVAL;
if (!readval)
return mma8452_change_config(data, reg, writeval);
ret = i2c_smbus_read_byte_data(data->client, reg);
if (ret < 0)
return ret;
*readval = ret;
return 0;
}
#define MMA8452_CHANNEL(axis, idx) { \
.type = IIO_ACCEL, \
.modified = 1, \
@ -330,11 +355,36 @@ static const struct iio_info mma8452_info = {
.attrs = &mma8452_group,
.read_raw = &mma8452_read_raw,
.write_raw = &mma8452_write_raw,
.debugfs_reg_access = &mma8452_reg_access_dbg,
.driver_module = THIS_MODULE,
};
static const unsigned long mma8452_scan_masks[] = {0x7, 0};
static int mma8452_reset(struct i2c_client *client)
{
int i;
int ret;
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2,
MMA8452_CTRL_REG2_RST);
if (ret < 0)
return ret;
for (i = 0; i < 10; i++) {
usleep_range(100, 200);
ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2);
if (ret == -EIO)
continue; /* I2C comm reset */
if (ret < 0)
return ret;
if (!(ret & MMA8452_CTRL_REG2_RST))
return 0;
}
return -ETIMEDOUT;
}
static int mma8452_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -365,10 +415,7 @@ static int mma8452_probe(struct i2c_client *client,
indio_dev->num_channels = ARRAY_SIZE(mma8452_channels);
indio_dev->available_scan_masks = mma8452_scan_masks;
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
ret = mma8452_reset(client);
if (ret < 0)
return ret;
@ -378,6 +425,13 @@ static int mma8452_probe(struct i2c_client *client,
if (ret < 0)
return ret;
data->ctrl_reg1 = MMA8452_CTRL_ACTIVE |
(MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT);
ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1,
data->ctrl_reg1);
if (ret < 0)
return ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL,
mma8452_trigger_handler, NULL);
if (ret < 0)

390
drivers/iio/accel/stk8312.c Normal file
View file

@ -0,0 +1,390 @@
/**
* Sensortek STK8312 3-Axis Accelerometer
*
* Copyright (c) 2015, Intel Corporation.
*
* 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.
*
* IIO driver for STK8312; 7-bit I2C address: 0x3D.
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define STK8312_REG_XOUT 0x00
#define STK8312_REG_YOUT 0x01
#define STK8312_REG_ZOUT 0x02
#define STK8312_REG_MODE 0x07
#define STK8312_REG_STH 0x13
#define STK8312_REG_RESET 0x20
#define STK8312_REG_AFECTRL 0x24
#define STK8312_REG_OTPADDR 0x3D
#define STK8312_REG_OTPDATA 0x3E
#define STK8312_REG_OTPCTRL 0x3F
#define STK8312_MODE_ACTIVE 1
#define STK8312_MODE_STANDBY 0
#define STK8312_MODE_MASK 0x01
#define STK8312_RNG_MASK 0xC0
#define STK8312_RNG_SHIFT 6
#define STK8312_READ_RETRIES 16
#define STK8312_DRIVER_NAME "stk8312"
/*
* The accelerometer has two measurement ranges:
*
* -6g - +6g (8-bit, signed)
* -16g - +16g (8-bit, signed)
*
* scale1 = (6 + 6) * 9.81 / (2^8 - 1) = 0.4616
* scale2 = (16 + 16) * 9.81 / (2^8 - 1) = 1.2311
*/
#define STK8312_SCALE_AVAIL "0.4616 1.2311"
static const int stk8312_scale_table[][2] = {
{0, 461600}, {1, 231100}
};
#define STK8312_ACCEL_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 stk8312_channels[] = {
STK8312_ACCEL_CHANNEL(STK8312_REG_XOUT, X),
STK8312_ACCEL_CHANNEL(STK8312_REG_YOUT, Y),
STK8312_ACCEL_CHANNEL(STK8312_REG_ZOUT, Z),
};
struct stk8312_data {
struct i2c_client *client;
struct mutex lock;
int range;
u8 mode;
};
static IIO_CONST_ATTR(in_accel_scale_available, STK8312_SCALE_AVAIL);
static struct attribute *stk8312_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group stk8312_attribute_group = {
.attrs = stk8312_attributes
};
static int stk8312_otp_init(struct stk8312_data *data)
{
int ret;
int count = 10;
struct i2c_client *client = data->client;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_OTPADDR, 0x70);
if (ret < 0)
goto exit_err;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_OTPCTRL, 0x02);
if (ret < 0)
goto exit_err;
do {
usleep_range(1000, 5000);
ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPCTRL);
if (ret < 0)
goto exit_err;
count--;
} while (!(ret & 0x80) && count > 0);
if (count == 0)
goto exit_err;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA);
if (ret < 0)
goto exit_err;
ret = i2c_smbus_write_byte_data(data->client,
STK8312_REG_AFECTRL, ret);
if (ret < 0)
goto exit_err;
msleep(150);
return ret;
exit_err:
dev_err(&client->dev, "failed to initialize sensor\n");
return ret;
}
static int stk8312_set_mode(struct stk8312_data *data, u8 mode)
{
int ret;
u8 masked_reg;
struct i2c_client *client = data->client;
if (mode > 1)
return -EINVAL;
else if (mode == data->mode)
return 0;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_MODE);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor mode\n");
return ret;
}
masked_reg = ret & (~STK8312_MODE_MASK);
masked_reg |= mode;
ret = i2c_smbus_write_byte_data(client,
STK8312_REG_MODE, masked_reg);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor mode\n");
return ret;
}
data->mode = mode;
if (mode == STK8312_MODE_ACTIVE) {
/* Need to run OTP sequence before entering active mode */
usleep_range(1000, 5000);
ret = stk8312_otp_init(data);
}
return ret;
}
static int stk8312_set_range(struct stk8312_data *data, u8 range)
{
int ret;
u8 masked_reg;
u8 mode;
struct i2c_client *client = data->client;
if (range != 1 && range != 2)
return -EINVAL;
else if (range == data->range)
return 0;
mode = data->mode;
/* We need to go in standby mode to modify registers */
ret = stk8312_set_mode(data, STK8312_MODE_STANDBY);
if (ret < 0)
return ret;
ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor range\n");
return ret;
}
masked_reg = ret & (~STK8312_RNG_MASK);
masked_reg |= range << STK8312_RNG_SHIFT;
ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg);
if (ret < 0)
dev_err(&client->dev, "failed to change sensor range\n");
else
data->range = range;
return stk8312_set_mode(data, mode);
}
static int stk8312_read_accel(struct stk8312_data *data, u8 address)
{
int ret;
struct i2c_client *client = data->client;
if (address > 2)
return -EINVAL;
ret = i2c_smbus_read_byte_data(client, address);
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
return ret;
}
return sign_extend32(ret, 7);
}
static int stk8312_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct stk8312_data *data = iio_priv(indio_dev);
if (chan->type != IIO_ACCEL)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
*val = stk8312_read_accel(data, chan->address);
mutex_unlock(&data->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = stk8312_scale_table[data->range - 1][0];
*val2 = stk8312_scale_table[data->range - 1][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static int stk8312_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int i;
int index = -1;
int ret;
struct stk8312_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
for (i = 0; i < ARRAY_SIZE(stk8312_scale_table); i++)
if (val == stk8312_scale_table[i][0] &&
val2 == stk8312_scale_table[i][1]) {
index = i + 1;
break;
}
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
ret = stk8312_set_range(data, index);
mutex_unlock(&data->lock);
return ret;
}
return -EINVAL;
}
static const struct iio_info stk8312_info = {
.driver_module = THIS_MODULE,
.read_raw = stk8312_read_raw,
.write_raw = stk8312_write_raw,
.attrs = &stk8312_attribute_group,
};
static int stk8312_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct stk8312_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;
i2c_set_clientdata(client, indio_dev);
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &stk8312_info;
indio_dev->name = STK8312_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = stk8312_channels;
indio_dev->num_channels = ARRAY_SIZE(stk8312_channels);
/* A software reset is recommended at power-on */
ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_RESET, 0x00);
if (ret < 0) {
dev_err(&client->dev, "failed to reset sensor\n");
return ret;
}
ret = stk8312_set_range(data, 1);
if (ret < 0)
return ret;
ret = stk8312_set_mode(data, STK8312_MODE_ACTIVE);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
stk8312_set_mode(data, STK8312_MODE_STANDBY);
}
return ret;
}
static int stk8312_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
return stk8312_set_mode(iio_priv(indio_dev), STK8312_MODE_STANDBY);
}
#ifdef CONFIG_PM_SLEEP
static int stk8312_suspend(struct device *dev)
{
struct stk8312_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return stk8312_set_mode(data, STK8312_MODE_STANDBY);
}
static int stk8312_resume(struct device *dev)
{
struct stk8312_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return stk8312_set_mode(data, STK8312_MODE_ACTIVE);
}
static SIMPLE_DEV_PM_OPS(stk8312_pm_ops, stk8312_suspend, stk8312_resume);
#define STK8312_PM_OPS (&stk8312_pm_ops)
#else
#define STK8312_PM_OPS NULL
#endif
static const struct i2c_device_id stk8312_i2c_id[] = {
{"STK8312", 0},
{}
};
static const struct acpi_device_id stk8312_acpi_id[] = {
{"STK8312", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id);
static struct i2c_driver stk8312_driver = {
.driver = {
.name = "stk8312",
.pm = STK8312_PM_OPS,
.acpi_match_table = ACPI_PTR(stk8312_acpi_id),
},
.probe = stk8312_probe,
.remove = stk8312_remove,
.id_table = stk8312_i2c_id,
};
module_i2c_driver(stk8312_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
MODULE_DESCRIPTION("STK8312 3-Axis Accelerometer driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,302 @@
/**
* Sensortek STK8BA50 3-Axis Accelerometer
*
* Copyright (c) 2015, Intel Corporation.
*
* 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.
*
* STK8BA50 7-bit I2C address: 0x18.
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define STK8BA50_REG_XOUT 0x02
#define STK8BA50_REG_YOUT 0x04
#define STK8BA50_REG_ZOUT 0x06
#define STK8BA50_REG_RANGE 0x0F
#define STK8BA50_REG_POWMODE 0x11
#define STK8BA50_REG_SWRST 0x14
#define STK8BA50_MODE_NORMAL 0
#define STK8BA50_MODE_SUSPEND 1
#define STK8BA50_MODE_POWERBIT BIT(7)
#define STK8BA50_DATA_SHIFT 6
#define STK8BA50_RESET_CMD 0xB6
#define STK8BA50_DRIVER_NAME "stk8ba50"
#define STK8BA50_SCALE_AVAIL "0.0384 0.0767 0.1534 0.3069"
/*
* The accelerometer has four measurement ranges:
* +/-2g; +/-4g; +/-8g; +/-16g
*
* Acceleration values are 10-bit, 2's complement.
* Scales are calculated as following:
*
* scale1 = (2 + 2) * 9.81 / (2^10 - 1) = 0.0384
* scale2 = (4 + 4) * 9.81 / (2^10 - 1) = 0.0767
* etc.
*
* Scales are stored in this format:
* { <register value>, <scale value> }
*
* Locally, the range is stored as a table index.
*/
static const int stk8ba50_scale_table[][2] = {
{3, 38400}, {5, 76700}, {8, 153400}, {12, 306900}
};
struct stk8ba50_data {
struct i2c_client *client;
struct mutex lock;
int range;
};
#define STK8BA50_ACCEL_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 stk8ba50_channels[] = {
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_XOUT, X),
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_YOUT, Y),
STK8BA50_ACCEL_CHANNEL(STK8BA50_REG_ZOUT, Z),
};
static IIO_CONST_ATTR(in_accel_scale_available, STK8BA50_SCALE_AVAIL);
static struct attribute *stk8ba50_attributes[] = {
&iio_const_attr_in_accel_scale_available.dev_attr.attr,
NULL,
};
static const struct attribute_group stk8ba50_attribute_group = {
.attrs = stk8ba50_attributes
};
static int stk8ba50_read_accel(struct stk8ba50_data *data, u8 reg)
{
int ret;
struct i2c_client *client = data->client;
ret = i2c_smbus_read_word_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
return ret;
}
return sign_extend32(ret >> STK8BA50_DATA_SHIFT, 9);
}
static int stk8ba50_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct stk8ba50_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
*val = stk8ba50_read_accel(data, chan->address);
mutex_unlock(&data->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = stk8ba50_scale_table[data->range][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static int stk8ba50_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret;
int i;
int index = -1;
struct stk8ba50_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_SCALE:
if (val != 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(stk8ba50_scale_table); i++)
if (val2 == stk8ba50_scale_table[i][1]) {
index = i;
break;
}
if (index < 0)
return -EINVAL;
ret = i2c_smbus_write_byte_data(data->client,
STK8BA50_REG_RANGE,
stk8ba50_scale_table[index][0]);
if (ret < 0)
dev_err(&data->client->dev,
"failed to set measurement range\n");
else
data->range = index;
return ret;
}
return -EINVAL;
}
static const struct iio_info stk8ba50_info = {
.driver_module = THIS_MODULE,
.read_raw = stk8ba50_read_raw,
.write_raw = stk8ba50_write_raw,
.attrs = &stk8ba50_attribute_group,
};
static int stk8ba50_set_power(struct stk8ba50_data *data, bool mode)
{
int ret;
u8 masked_reg;
struct i2c_client *client = data->client;
ret = i2c_smbus_read_byte_data(client, STK8BA50_REG_POWMODE);
if (ret < 0)
goto exit_err;
if (mode)
masked_reg = ret | STK8BA50_MODE_POWERBIT;
else
masked_reg = ret & (~STK8BA50_MODE_POWERBIT);
ret = i2c_smbus_write_byte_data(client, STK8BA50_REG_POWMODE,
masked_reg);
if (ret < 0)
goto exit_err;
return ret;
exit_err:
dev_err(&client->dev, "failed to change sensor mode\n");
return ret;
}
static int stk8ba50_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct stk8ba50_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;
i2c_set_clientdata(client, indio_dev);
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &stk8ba50_info;
indio_dev->name = STK8BA50_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = stk8ba50_channels;
indio_dev->num_channels = ARRAY_SIZE(stk8ba50_channels);
/* Reset all registers on startup */
ret = i2c_smbus_write_byte_data(client,
STK8BA50_REG_SWRST, STK8BA50_RESET_CMD);
if (ret < 0) {
dev_err(&client->dev, "failed to reset sensor\n");
return ret;
}
/* The default range is +/-2g */
data->range = 0;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
}
return ret;
}
static int stk8ba50_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
return stk8ba50_set_power(iio_priv(indio_dev), STK8BA50_MODE_SUSPEND);
}
#ifdef CONFIG_PM_SLEEP
static int stk8ba50_suspend(struct device *dev)
{
struct stk8ba50_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return stk8ba50_set_power(data, STK8BA50_MODE_SUSPEND);
}
static int stk8ba50_resume(struct device *dev)
{
struct stk8ba50_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return stk8ba50_set_power(data, STK8BA50_MODE_NORMAL);
}
static SIMPLE_DEV_PM_OPS(stk8ba50_pm_ops, stk8ba50_suspend, stk8ba50_resume);
#define STK8BA50_PM_OPS (&stk8ba50_pm_ops)
#else
#define STK8BA50_PM_OPS NULL
#endif
static const struct i2c_device_id stk8ba50_i2c_id[] = {
{"stk8ba50", 0},
{}
};
static const struct acpi_device_id stk8ba50_acpi_id[] = {
{"STK8BA50", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, stk8ba50_acpi_id);
static struct i2c_driver stk8ba50_driver = {
.driver = {
.name = "stk8ba50",
.pm = STK8BA50_PM_OPS,
.acpi_match_table = ACPI_PTR(stk8ba50_acpi_id),
},
.probe = stk8ba50_probe,
.remove = stk8ba50_remove,
.id_table = stk8ba50_i2c_id,
};
module_i2c_driver(stk8ba50_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
MODULE_DESCRIPTION("STK8BA50 3-Axis Accelerometer driver");
MODULE_LICENSE("GPL v2");

View file

@ -135,6 +135,13 @@ config AXP288_ADC
device. Depending on platform configuration, this general purpose ADC can
be used for sampling sensors such as thermal resistors.
config BERLIN2_ADC
tristate "Marvell Berlin2 ADC driver"
depends on ARCH_BERLIN
help
Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for
temperature measurement.
config DA9150_GPADC
tristate "Dialog DA9150 GPADC driver support"
depends on MFD_DA9150
@ -285,11 +292,11 @@ config TI_ADC081C
called ti-adc081c.
config TI_ADC128S052
tristate "Texas Instruments ADC128S052"
tristate "Texas Instruments ADC128S052/ADC122S021"
depends on SPI
help
If you say yes here you get support for Texas Instruments ADC128S052
chip.
and ADC122S021 chips.
This driver can also be built as a module. If so, the module will be
called ti-adc128s052.

View file

@ -15,6 +15,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o

View file

@ -238,7 +238,7 @@ static int axp288_adc_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id axp288_adc_id_table[] = {
static const struct platform_device_id axp288_adc_id_table[] = {
{ .name = "axp288_adc" },
{},
};

View file

@ -0,0 +1,378 @@
/*
* Marvell Berlin2 ADC driver
*
* Copyright (C) 2015 Marvell Technology Group Ltd.
*
* Antoine Tenart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/sched.h>
#include <linux/wait.h>
#define BERLIN2_SM_CTRL 0x14
#define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1)
#define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2)
#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */
#define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5)
#define BERLIN2_SM_CTRL_ADC_POWER BIT(9)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10)
#define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK (0x3 << 10)
#define BERLIN2_SM_CTRL_ADC_START BIT(12)
#define BERLIN2_SM_CTRL_ADC_RESET BIT(13)
#define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14)
#define BERLIN2_SM_CTRL_ADC_CONT_SINGLE (0x0 << 15)
#define BERLIN2_SM_CTRL_ADC_CONT_CONTINUOUS (0x1 << 15)
#define BERLIN2_SM_CTRL_ADC_BUFFER_EN BIT(16)
#define BERLIN2_SM_CTRL_ADC_VREF_EXT (0x0 << 17)
#define BERLIN2_SM_CTRL_ADC_VREF_INT (0x1 << 17)
#define BERLIN2_SM_CTRL_ADC_ROTATE BIT(19)
#define BERLIN2_SM_CTRL_TSEN_EN BIT(20)
#define BERLIN2_SM_CTRL_TSEN_CLK_SEL_125 (0x0 << 21) /* 1.25 MHz */
#define BERLIN2_SM_CTRL_TSEN_CLK_SEL_250 (0x1 << 21) /* 2.5 MHz */
#define BERLIN2_SM_CTRL_TSEN_MODE_0_125 (0x0 << 22) /* 0-125 C */
#define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */
#define BERLIN2_SM_CTRL_TSEN_RESET BIT(29)
#define BERLIN2_SM_ADC_DATA 0x20
#define BERLIN2_SM_ADC_MASK 0x3ff
#define BERLIN2_SM_ADC_STATUS 0x1c
#define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf
#define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */
#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16)
#define BERLIN2_SM_TSEN_STATUS 0x24
#define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0)
#define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1)
#define BERLIN2_SM_TSEN_DATA 0x28
#define BERLIN2_SM_TSEN_MASK 0xfff
#define BERLIN2_SM_TSEN_CTRL 0x74
#define BERLIN2_SM_TSEN_CTRL_START BIT(8)
#define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */
#define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */
#define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK (0x1 << 21)
#define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22)
#define BERLIN2_SM_TSEN_CTRL_TRIM_MASK (0xf << 22)
struct berlin2_adc_priv {
struct regmap *regmap;
struct mutex lock;
wait_queue_head_t wq;
bool data_available;
int data;
};
#define BERLIN2_ADC_CHANNEL(n, t) \
{ \
.channel = n, \
.datasheet_name = "channel"#n, \
.type = t, \
.indexed = 1, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
static struct iio_chan_spec berlin2_adc_channels[] = {
BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(3, IIO_VOLTAGE), /* external input */
BERLIN2_ADC_CHANNEL(4, IIO_VOLTAGE), /* reserved */
BERLIN2_ADC_CHANNEL(5, IIO_VOLTAGE), /* reserved */
{ /* temperature sensor */
.channel = 6,
.datasheet_name = "channel6",
.type = IIO_TEMP,
.indexed = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */
IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */
};
#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels)
static int berlin2_adc_read(struct iio_dev *indio_dev, int channel)
{
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
int data, ret;
mutex_lock(&priv->lock);
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_RESET | BERLIN2_SM_CTRL_ADC_SEL_MASK
| BERLIN2_SM_CTRL_ADC_START,
BERLIN2_SM_CTRL_ADC_SEL(channel) | BERLIN2_SM_CTRL_ADC_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
msecs_to_jiffies(1000));
/* Disable the interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0);
if (ret == 0)
ret = -ETIMEDOUT;
if (ret < 0) {
mutex_unlock(&priv->lock);
return ret;
}
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_START, 0);
data = priv->data;
priv->data_available = false;
mutex_unlock(&priv->lock);
return data;
}
static int berlin2_adc_tsen_read(struct iio_dev *indio_dev)
{
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
int data, ret;
mutex_lock(&priv->lock);
/* Configure the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_TSEN_RESET | BERLIN2_SM_CTRL_ADC_ROTATE,
BERLIN2_SM_CTRL_ADC_ROTATE);
/* Configure the temperature sensor */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_TRIM_MASK | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK
| BERLIN2_SM_TSEN_CTRL_START,
BERLIN2_SM_TSEN_CTRL_TRIM(3) | BERLIN2_SM_TSEN_CTRL_SETTLING_12
| BERLIN2_SM_TSEN_CTRL_START);
ret = wait_event_interruptible_timeout(priv->wq, priv->data_available,
msecs_to_jiffies(1000));
/* Disable interrupts */
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN, 0);
if (ret == 0)
ret = -ETIMEDOUT;
if (ret < 0) {
mutex_unlock(&priv->lock);
return ret;
}
regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL,
BERLIN2_SM_TSEN_CTRL_START, 0);
data = priv->data;
priv->data_available = false;
mutex_unlock(&priv->lock);
return data;
}
static int berlin2_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
{
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
int temp;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type != IIO_VOLTAGE)
return -EINVAL;
/* Enable the interrupts */
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS,
BERLIN2_SM_ADC_STATUS_INT_EN(chan->channel));
*val = berlin2_adc_read(indio_dev, chan->channel);
if (*val < 0)
return *val;
return IIO_VAL_INT;
case IIO_CHAN_INFO_PROCESSED:
if (chan->type != IIO_TEMP)
return -EINVAL;
/* Enable interrupts */
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS,
BERLIN2_SM_TSEN_STATUS_INT_EN);
temp = berlin2_adc_tsen_read(indio_dev);
if (temp < 0)
return temp;
if (temp > 2047)
temp = -(4096 - temp);
/* Convert to milli Celsius */
*val = ((temp * 100000) / 264 - 270000);
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static irqreturn_t berlin2_adc_irq(int irq, void *private)
{
struct berlin2_adc_priv *priv = iio_priv(private);
unsigned val;
regmap_read(priv->regmap, BERLIN2_SM_ADC_STATUS, &val);
if (val & BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK) {
regmap_read(priv->regmap, BERLIN2_SM_ADC_DATA, &priv->data);
priv->data &= BERLIN2_SM_ADC_MASK;
val &= ~BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK;
regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, val);
priv->data_available = true;
wake_up_interruptible(&priv->wq);
}
return IRQ_HANDLED;
}
static irqreturn_t berlin2_adc_tsen_irq(int irq, void *private)
{
struct berlin2_adc_priv *priv = iio_priv(private);
unsigned val;
regmap_read(priv->regmap, BERLIN2_SM_TSEN_STATUS, &val);
if (val & BERLIN2_SM_TSEN_STATUS_DATA_RDY) {
regmap_read(priv->regmap, BERLIN2_SM_TSEN_DATA, &priv->data);
priv->data &= BERLIN2_SM_TSEN_MASK;
val &= ~BERLIN2_SM_TSEN_STATUS_DATA_RDY;
regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, val);
priv->data_available = true;
wake_up_interruptible(&priv->wq);
}
return IRQ_HANDLED;
}
static const struct iio_info berlin2_adc_info = {
.driver_module = THIS_MODULE,
.read_raw = berlin2_adc_read_raw,
};
static int berlin2_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct berlin2_adc_priv *priv;
struct device_node *parent_np = of_get_parent(pdev->dev.of_node);
int irq, tsen_irq;
int ret;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct berlin2_adc_priv));
if (!indio_dev)
return -ENOMEM;
priv = iio_priv(indio_dev);
platform_set_drvdata(pdev, indio_dev);
priv->regmap = syscon_node_to_regmap(parent_np);
of_node_put(parent_np);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
irq = platform_get_irq_byname(pdev, "adc");
if (irq < 0)
return -ENODEV;
tsen_irq = platform_get_irq_byname(pdev, "tsen");
if (tsen_irq < 0)
return -ENODEV;
ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0,
pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq,
0, pdev->dev.driver->name, indio_dev);
if (ret)
return ret;
init_waitqueue_head(&priv->wq);
mutex_init(&priv->lock);
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &berlin2_adc_info;
indio_dev->num_channels = BERLIN2_N_CHANNELS;
indio_dev->channels = berlin2_adc_channels;
/* Power up the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, BERLIN2_SM_CTRL_ADC_POWER);
ret = iio_device_register(indio_dev);
if (ret) {
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, 0);
return ret;
}
return 0;
}
static int berlin2_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct berlin2_adc_priv *priv = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
/* Power down the ADC */
regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL,
BERLIN2_SM_CTRL_ADC_POWER, 0);
return 0;
}
static const struct of_device_id berlin2_adc_match[] = {
{ .compatible = "marvell,berlin2-adc", },
{ },
};
MODULE_DEVICE_TABLE(of, berlin2_adc_match);
static struct platform_driver berlin2_adc_driver = {
.driver = {
.name = "berlin2-adc",
.of_match_table = berlin2_adc_match,
},
.probe = berlin2_adc_probe,
.remove = berlin2_adc_remove,
};
module_platform_driver(berlin2_adc_driver);
MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
MODULE_DESCRIPTION("Marvell Berlin2 ADC driver");
MODULE_LICENSE("GPL v2");

View file

@ -1,9 +1,10 @@
/*
* Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com>
*
* Driver for Texas Instruments' ADC128S052 ADC chip.
* Datasheet can be found here:
* Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip.
* Datasheets can be found here:
* http://www.ti.com/lit/ds/symlink/adc128s052.pdf
* http://www.ti.com/lit/ds/symlink/adc122s021.pdf
*
* 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
@ -16,6 +17,11 @@
#include <linux/iio/iio.h>
#include <linux/regulator/consumer.h>
struct adc128_configuration {
const struct iio_chan_spec *channels;
u8 num_channels;
};
struct adc128 {
struct spi_device *spi;
@ -92,7 +98,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \
}
static const struct iio_chan_spec adc128_channels[] = {
static const struct iio_chan_spec adc128s052_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
ADC128_VOLTAGE_CHANNEL(2),
@ -103,6 +109,16 @@ static const struct iio_chan_spec adc128_channels[] = {
ADC128_VOLTAGE_CHANNEL(7),
};
static const struct iio_chan_spec adc122s021_channels[] = {
ADC128_VOLTAGE_CHANNEL(0),
ADC128_VOLTAGE_CHANNEL(1),
};
static const struct adc128_configuration adc128_config[] = {
{ adc128s052_channels, ARRAY_SIZE(adc128s052_channels) },
{ adc122s021_channels, ARRAY_SIZE(adc122s021_channels) },
};
static const struct iio_info adc128_info = {
.read_raw = adc128_read_raw,
.driver_module = THIS_MODULE,
@ -112,6 +128,7 @@ static int adc128_probe(struct spi_device *spi)
{
struct iio_dev *indio_dev;
struct adc128 *adc;
int config = spi_get_device_id(spi)->driver_data;
int ret;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
@ -128,8 +145,8 @@ static int adc128_probe(struct spi_device *spi)
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &adc128_info;
indio_dev->channels = adc128_channels;
indio_dev->num_channels = ARRAY_SIZE(adc128_channels);
indio_dev->channels = adc128_config[config].channels;
indio_dev->num_channels = adc128_config[config].num_channels;
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
@ -158,7 +175,8 @@ static int adc128_remove(struct spi_device *spi)
}
static const struct spi_device_id adc128_id[] = {
{ "adc128s052", 0},
{ "adc128s052", 0}, /* index into adc128_config */
{ "adc122s021", 1},
{ }
};
MODULE_DEVICE_TABLE(spi, adc128_id);

View file

@ -37,6 +37,7 @@ struct tiadc_device {
u8 channel_step[8];
int buffer_en_ch_steps;
u16 data[8];
u32 open_delay[8], sample_delay[8], step_avg[8];
};
static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
@ -85,6 +86,7 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan)
static void tiadc_step_config(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct device *dev = adc_dev->mfd_tscadc->dev;
unsigned int stepconfig;
int i, steps = 0;
@ -98,20 +100,47 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
* needs to be given to ADC to digitalize data.
*/
if (iio_buffer_enabled(indio_dev))
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
| STEPCONFIG_MODE_SWCNT;
else
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
for (i = 0; i < adc_dev->channels; i++) {
int chan;
chan = adc_dev->channel_line[i];
if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) {
dev_warn(dev, "chan %d step_avg truncating to %d\n",
chan, STEPCONFIG_AVG_16);
adc_dev->step_avg[i] = STEPCONFIG_AVG_16;
}
if (adc_dev->step_avg[i])
stepconfig =
STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) |
STEPCONFIG_FIFO1;
else
stepconfig = STEPCONFIG_FIFO1;
if (iio_buffer_enabled(indio_dev))
stepconfig |= STEPCONFIG_MODE_SWCNT;
tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
stepconfig | STEPCONFIG_INP(chan));
if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) {
dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n",
chan);
adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK;
}
if (adc_dev->sample_delay[i] > 0xFF) {
dev_warn(dev, "chan %d sample delay truncating to 0xFF\n",
chan);
adc_dev->sample_delay[i] = 0xFF;
}
tiadc_writel(adc_dev, REG_STEPDELAY(steps),
STEPCONFIG_OPENDLY);
STEPDELAY_OPEN(adc_dev->open_delay[i]) |
STEPDELAY_SAMPLE(adc_dev->sample_delay[i]));
adc_dev->channel_step[i] = steps;
steps++;
}
@ -406,9 +435,22 @@ static int tiadc_parse_dt(struct platform_device *pdev,
of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
adc_dev->channel_line[channels] = val;
/* Set Default values for optional DT parameters */
adc_dev->open_delay[channels] = STEPCONFIG_OPENDLY;
adc_dev->sample_delay[channels] = STEPCONFIG_SAMPLEDLY;
adc_dev->step_avg[channels] = 16;
channels++;
}
of_property_read_u32_array(node, "ti,chan-step-avg",
adc_dev->step_avg, channels);
of_property_read_u32_array(node, "ti,chan-step-opendelay",
adc_dev->open_delay, channels);
of_property_read_u32_array(node, "ti,chan-step-sampledelay",
adc_dev->sample_delay, channels);
adc_dev->channels = channels;
return 0;
}

View file

@ -142,6 +142,16 @@ config AD7303
To compile this driver as module choose M here: the module will be called
ad7303.
config M62332
tristate "Mitsubishi M62332 DAC driver"
depends on I2C
help
If you say yes here you get support for the Mitsubishi M62332
(I2C 8-Bit DACs with rail-to-rail outputs).
This driver can also be built as a module. If so, the module
will be called m62332.
config MAX517
tristate "Maxim MAX517/518/519/520/521 DAC driver"
depends on I2C

View file

@ -16,6 +16,7 @@ obj-$(CONFIG_AD5764) += ad5764.o
obj-$(CONFIG_AD5791) += ad5791.o
obj-$(CONFIG_AD5686) += ad5686.o
obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_M62332) += m62332.o
obj-$(CONFIG_MAX517) += max517.o
obj-$(CONFIG_MAX5821) += max5821.o
obj-$(CONFIG_MCP4725) += mcp4725.o

269
drivers/iio/dac/m62332.c Normal file
View file

@ -0,0 +1,269 @@
/*
* m62332.c - Support for Mitsubishi m62332 DAC
*
* Copyright (c) 2014 Dmitry Eremin-Solenikov
*
* Based on max517 driver:
* Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de>
*
* 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/slab.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/regulator/consumer.h>
#define M62332_CHANNELS 2
struct m62332_data {
struct i2c_client *client;
u16 vref_mv;
struct regulator *vcc;
struct mutex mutex;
u8 raw[M62332_CHANNELS];
#ifdef CONFIG_PM_SLEEP
u8 save[M62332_CHANNELS];
#endif
};
static int m62332_set_value(struct iio_dev *indio_dev,
u8 val, int channel)
{
struct m62332_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[2];
int res;
if (val == data->raw[channel])
return 0;
outbuf[0] = channel;
outbuf[1] = val;
mutex_lock(&data->mutex);
if (val) {
res = regulator_enable(data->vcc);
if (res)
goto out;
}
res = i2c_master_send(client, outbuf, 2);
if (res >= 0 && res != 2)
res = -EIO;
if (res < 0)
goto out;
data->raw[channel] = val;
if (!val)
regulator_disable(data->vcc);
mutex_unlock(&data->mutex);
return 0;
out:
mutex_unlock(&data->mutex);
return res;
}
static int m62332_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long m)
{
struct m62332_data *data = iio_priv(indio_dev);
switch (m) {
case IIO_CHAN_INFO_SCALE:
/* Corresponds to Vref / 2^(bits) */
*val = data->vref_mv;
*val2 = 8;
return IIO_VAL_FRACTIONAL_LOG2;
case IIO_CHAN_INFO_RAW:
*val = data->raw[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET:
*val = 1;
return IIO_VAL_INT;
default:
break;
}
return -EINVAL;
}
static int m62332_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val, int val2, long mask)
{
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < 0 || val > 255)
return -EINVAL;
ret = m62332_set_value(indio_dev, val, chan->channel);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int m62332_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct m62332_data *data = iio_priv(indio_dev);
int ret;
data->save[0] = data->raw[0];
data->save[1] = data->raw[1];
ret = m62332_set_value(indio_dev, 0, 0);
if (ret < 0)
return ret;
return m62332_set_value(indio_dev, 0, 1);
}
static int m62332_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct m62332_data *data = iio_priv(indio_dev);
int ret;
ret = m62332_set_value(indio_dev, data->save[0], 0);
if (ret < 0)
return ret;
return m62332_set_value(indio_dev, data->save[1], 1);
}
static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume);
#define M62332_PM_OPS (&m62332_pm_ops)
#else
#define M62332_PM_OPS NULL
#endif
static const struct iio_info m62332_info = {
.read_raw = m62332_read_raw,
.write_raw = m62332_write_raw,
.driver_module = THIS_MODULE,
};
#define M62332_CHANNEL(chan) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.datasheet_name = "CH" #chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_OFFSET), \
}
static const struct iio_chan_spec m62332_channels[M62332_CHANNELS] = {
M62332_CHANNEL(0),
M62332_CHANNEL(1)
};
static int m62332_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct m62332_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->mutex);
data->vcc = devm_regulator_get(&client->dev, "VCC");
if (IS_ERR(data->vcc))
return PTR_ERR(data->vcc);
/* establish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
indio_dev->num_channels = M62332_CHANNELS;
indio_dev->channels = m62332_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &m62332_info;
ret = regulator_get_voltage(data->vcc);
if (ret < 0)
return ret;
data->vref_mv = ret / 1000; /* mV */
ret = iio_map_array_register(indio_dev, client->dev.platform_data);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0)
goto err;
return 0;
err:
iio_map_array_unregister(indio_dev);
return ret;
}
static int m62332_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
return 0;
}
static const struct i2c_device_id m62332_id[] = {
{ "m62332", },
{ }
};
MODULE_DEVICE_TABLE(i2c, m62332_id);
static struct i2c_driver m62332_driver = {
.driver = {
.name = "m62332",
.pm = M62332_PM_OPS,
},
.probe = m62332_probe,
.remove = m62332_remove,
.id_table = m62332_id,
};
module_i2c_driver(m62332_driver);
MODULE_AUTHOR("Dmitry Eremin-Solenikov");
MODULE_DESCRIPTION("M62332 8-bit DAC");
MODULE_LICENSE("GPL v2");

View file

@ -108,7 +108,6 @@ struct bmg160_data {
int slope_thres;
bool dready_trigger_on;
bool motion_trigger_on;
int64_t timestamp;
};
enum bmg160_axis {
@ -738,17 +737,6 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev,
return 0;
}
static int bmg160_validate_trigger(struct iio_dev *indio_dev,
struct iio_trigger *trig)
{
struct bmg160_data *data = iio_priv(indio_dev);
if (data->dready_trig != trig && data->motion_trig != trig)
return -EINVAL;
return 0;
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 400 1000 2000");
static IIO_CONST_ATTR(in_anglvel_scale_available,
@ -810,7 +798,6 @@ static const struct iio_info bmg160_info = {
.write_event_value = bmg160_write_event,
.write_event_config = bmg160_write_event_config,
.read_event_config = bmg160_read_event_config,
.validate_trigger = bmg160_validate_trigger,
.driver_module = THIS_MODULE,
};
@ -835,7 +822,7 @@ static irqreturn_t bmg160_trigger_handler(int irq, void *p)
mutex_unlock(&data->mutex);
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
data->timestamp);
pf->timestamp);
err:
iio_trigger_notify_done(indio_dev->trig);
@ -938,21 +925,21 @@ static irqreturn_t bmg160_event_handler(int irq, void *private)
IIO_MOD_X,
IIO_EV_TYPE_ROC,
dir),
data->timestamp);
iio_get_time_ns());
if (ret & BMG160_ANY_MOTION_BIT_Y)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
IIO_MOD_Y,
IIO_EV_TYPE_ROC,
dir),
data->timestamp);
iio_get_time_ns());
if (ret & BMG160_ANY_MOTION_BIT_Z)
iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL,
0,
IIO_MOD_Z,
IIO_EV_TYPE_ROC,
dir),
data->timestamp);
iio_get_time_ns());
ack_intr_status:
if (!data->dready_trigger_on) {
@ -973,8 +960,6 @@ static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private)
struct iio_dev *indio_dev = private;
struct bmg160_data *data = iio_priv(indio_dev);
data->timestamp = iio_get_time_ns();
if (data->dready_trigger_on)
iio_trigger_poll(data->dready_trig);
else if (data->motion_trigger_on)
@ -987,6 +972,27 @@ static irqreturn_t bmg160_data_rdy_trig_poll(int irq, void *private)
}
static int bmg160_buffer_preenable(struct iio_dev *indio_dev)
{
struct bmg160_data *data = iio_priv(indio_dev);
return bmg160_set_power_state(data, true);
}
static int bmg160_buffer_postdisable(struct iio_dev *indio_dev)
{
struct bmg160_data *data = iio_priv(indio_dev);
return bmg160_set_power_state(data, false);
}
static const struct iio_buffer_setup_ops bmg160_buffer_setup_ops = {
.preenable = bmg160_buffer_preenable,
.postenable = iio_triggered_buffer_postenable,
.predisable = iio_triggered_buffer_predisable,
.postdisable = bmg160_buffer_postdisable,
};
static int bmg160_gpio_probe(struct i2c_client *client,
struct bmg160_data *data)
@ -1103,16 +1109,16 @@ static int bmg160_probe(struct i2c_client *client,
data->motion_trig = NULL;
goto err_trigger_unregister;
}
}
ret = iio_triggered_buffer_setup(indio_dev,
NULL,
bmg160_trigger_handler,
NULL);
if (ret < 0) {
dev_err(&client->dev,
"iio triggered buffer setup failed\n");
goto err_trigger_unregister;
}
ret = iio_triggered_buffer_setup(indio_dev,
iio_pollfunc_store_time,
bmg160_trigger_handler,
&bmg160_buffer_setup_ops);
if (ret < 0) {
dev_err(&client->dev,
"iio triggered buffer setup failed\n");
goto err_trigger_unregister;
}
ret = iio_device_register(indio_dev);
@ -1135,8 +1141,7 @@ static int bmg160_probe(struct i2c_client *client,
err_iio_unregister:
iio_device_unregister(indio_dev);
err_buffer_cleanup:
if (data->dready_trig)
iio_triggered_buffer_cleanup(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
err_trigger_unregister:
if (data->dready_trig)
iio_trigger_unregister(data->dready_trig);
@ -1156,9 +1161,9 @@ static int bmg160_remove(struct i2c_client *client)
pm_runtime_put_noidle(&client->dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (data->dready_trig) {
iio_triggered_buffer_cleanup(indio_dev);
iio_trigger_unregister(data->dready_trig);
iio_trigger_unregister(data->motion_trig);
}

View file

@ -298,7 +298,6 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct gyro_3d_state *gyro_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state));
if (!indio_dev)
@ -317,21 +316,21 @@ static int hid_gyro_3d_probe(struct platform_device *pdev)
return ret;
}
channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels),
GFP_KERNEL);
if (!channels) {
indio_dev->channels = kmemdup(gyro_3d_channels,
sizeof(gyro_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = gyro_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_GYRO_3D, gyro_state);
ret = gyro_3d_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_GYRO_3D, gyro_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &gyro_3d_info;
@ -397,7 +396,7 @@ static int hid_gyro_3d_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_gyro_3d_ids[] = {
static const struct platform_device_id hid_gyro_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200076",

View file

@ -5,7 +5,7 @@ menu "Humidity sensors"
config DHT11
tristate "DHT11 (and compatible sensors) driver"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
This driver supports reading data via a single interrupt
generating GPIO line. Currently tested are DHT11 and DHT22.

View file

@ -539,26 +539,13 @@ static void iio_buffer_deactivate(struct iio_buffer *buffer)
iio_buffer_put(buffer);
}
void iio_disable_all_buffers(struct iio_dev *indio_dev)
static void iio_buffer_deactivate_all(struct iio_dev *indio_dev)
{
struct iio_buffer *buffer, *_buffer;
if (list_empty(&indio_dev->buffer_list))
return;
if (indio_dev->setup_ops->predisable)
indio_dev->setup_ops->predisable(indio_dev);
list_for_each_entry_safe(buffer, _buffer,
&indio_dev->buffer_list, buffer_list)
iio_buffer_deactivate(buffer);
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
if (indio_dev->available_scan_masks == NULL)
kfree(indio_dev->active_scan_mask);
}
static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
@ -575,167 +562,256 @@ static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
buffer->access->set_bytes_per_datum(buffer, bytes);
}
static int __iio_update_buffers(struct iio_dev *indio_dev,
struct iio_buffer *insert_buffer,
struct iio_buffer *remove_buffer)
static int iio_buffer_request_update(struct iio_dev *indio_dev,
struct iio_buffer *buffer)
{
int ret;
int success = 0;
struct iio_buffer *buffer;
unsigned long *compound_mask;
const unsigned long *old_mask;
/* Wind down existing buffers - iff there are any */
if (!list_empty(&indio_dev->buffer_list)) {
if (indio_dev->setup_ops->predisable) {
ret = indio_dev->setup_ops->predisable(indio_dev);
if (ret)
return ret;
}
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
ret = indio_dev->setup_ops->postdisable(indio_dev);
if (ret)
return ret;
iio_buffer_update_bytes_per_datum(indio_dev, buffer);
if (buffer->access->request_update) {
ret = buffer->access->request_update(buffer);
if (ret) {
dev_dbg(&indio_dev->dev,
"Buffer not started: buffer parameter update failed (%d)\n",
ret);
return ret;
}
}
/* Keep a copy of current setup to allow roll back */
old_mask = indio_dev->active_scan_mask;
return 0;
}
static void iio_free_scan_mask(struct iio_dev *indio_dev,
const unsigned long *mask)
{
/* If the mask is dynamically allocated free it, otherwise do nothing */
if (!indio_dev->available_scan_masks)
indio_dev->active_scan_mask = NULL;
kfree(mask);
}
if (remove_buffer)
iio_buffer_deactivate(remove_buffer);
if (insert_buffer)
iio_buffer_activate(indio_dev, insert_buffer);
struct iio_device_config {
unsigned int mode;
const unsigned long *scan_mask;
unsigned int scan_bytes;
bool scan_timestamp;
};
/* If no buffers in list, we are done */
if (list_empty(&indio_dev->buffer_list)) {
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->available_scan_masks == NULL)
kfree(old_mask);
return 0;
static int iio_verify_update(struct iio_dev *indio_dev,
struct iio_buffer *insert_buffer, struct iio_buffer *remove_buffer,
struct iio_device_config *config)
{
unsigned long *compound_mask;
const unsigned long *scan_mask;
struct iio_buffer *buffer;
bool scan_timestamp;
memset(config, 0, sizeof(*config));
/*
* If there is just one buffer and we are removing it there is nothing
* to verify.
*/
if (remove_buffer && !insert_buffer &&
list_is_singular(&indio_dev->buffer_list))
return 0;
/* Definitely possible for devices to support both of these. */
if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
config->mode = INDIO_BUFFER_TRIGGERED;
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
config->mode = INDIO_BUFFER_HARDWARE;
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
config->mode = INDIO_BUFFER_SOFTWARE;
} else {
/* Can only occur on first buffer */
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
dev_dbg(&indio_dev->dev, "Buffer not started: no trigger\n");
return -EINVAL;
}
/* What scan mask do we actually have? */
compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
sizeof(long), GFP_KERNEL);
if (compound_mask == NULL) {
if (indio_dev->available_scan_masks == NULL)
kfree(old_mask);
if (compound_mask == NULL)
return -ENOMEM;
}
indio_dev->scan_timestamp = 0;
scan_timestamp = false;
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
if (buffer == remove_buffer)
continue;
bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
indio_dev->masklength);
indio_dev->scan_timestamp |= buffer->scan_timestamp;
scan_timestamp |= buffer->scan_timestamp;
}
if (insert_buffer) {
bitmap_or(compound_mask, compound_mask,
insert_buffer->scan_mask, indio_dev->masklength);
scan_timestamp |= insert_buffer->scan_timestamp;
}
if (indio_dev->available_scan_masks) {
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
compound_mask);
if (indio_dev->active_scan_mask == NULL) {
/*
* Roll back.
* Note can only occur when adding a buffer.
*/
iio_buffer_deactivate(insert_buffer);
if (old_mask) {
indio_dev->active_scan_mask = old_mask;
success = -EINVAL;
}
else {
kfree(compound_mask);
ret = -EINVAL;
return ret;
}
}
scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
compound_mask);
kfree(compound_mask);
if (scan_mask == NULL)
return -EINVAL;
} else {
indio_dev->active_scan_mask = compound_mask;
scan_mask = compound_mask;
}
config->scan_bytes = iio_compute_scan_bytes(indio_dev,
scan_mask, scan_timestamp);
config->scan_mask = scan_mask;
config->scan_timestamp = scan_timestamp;
return 0;
}
static int iio_enable_buffers(struct iio_dev *indio_dev,
struct iio_device_config *config)
{
int ret;
indio_dev->active_scan_mask = config->scan_mask;
indio_dev->scan_timestamp = config->scan_timestamp;
indio_dev->scan_bytes = config->scan_bytes;
iio_update_demux(indio_dev);
/* Wind up again */
if (indio_dev->setup_ops->preenable) {
ret = indio_dev->setup_ops->preenable(indio_dev);
if (ret) {
printk(KERN_ERR
dev_dbg(&indio_dev->dev,
"Buffer not started: buffer preenable failed (%d)\n", ret);
goto error_remove_inserted;
}
}
indio_dev->scan_bytes =
iio_compute_scan_bytes(indio_dev,
indio_dev->active_scan_mask,
indio_dev->scan_timestamp);
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
iio_buffer_update_bytes_per_datum(indio_dev, buffer);
if (buffer->access->request_update) {
ret = buffer->access->request_update(buffer);
if (ret) {
printk(KERN_INFO
"Buffer not started: buffer parameter update failed (%d)\n", ret);
goto error_run_postdisable;
}
goto err_undo_config;
}
}
if (indio_dev->info->update_scan_mode) {
ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
if (ret < 0) {
printk(KERN_INFO "Buffer not started: update scan mode failed (%d)\n", ret);
goto error_run_postdisable;
dev_dbg(&indio_dev->dev,
"Buffer not started: update scan mode failed (%d)\n",
ret);
goto err_run_postdisable;
}
}
/* Definitely possible for devices to support both of these. */
if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
} else { /* Should never be reached */
/* Can only occur on first buffer */
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
pr_info("Buffer not started: no trigger\n");
ret = -EINVAL;
goto error_run_postdisable;
}
indio_dev->currentmode = config->mode;
if (indio_dev->setup_ops->postenable) {
ret = indio_dev->setup_ops->postenable(indio_dev);
if (ret) {
printk(KERN_INFO
dev_dbg(&indio_dev->dev,
"Buffer not started: postenable failed (%d)\n", ret);
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
goto error_disable_all_buffers;
goto err_run_postdisable;
}
}
if (indio_dev->available_scan_masks)
kfree(compound_mask);
else
kfree(old_mask);
return 0;
return success;
error_disable_all_buffers:
err_run_postdisable:
indio_dev->currentmode = INDIO_DIRECT_MODE;
error_run_postdisable:
if (indio_dev->setup_ops->postdisable)
indio_dev->setup_ops->postdisable(indio_dev);
error_remove_inserted:
err_undo_config:
indio_dev->active_scan_mask = NULL;
return ret;
}
static int iio_disable_buffers(struct iio_dev *indio_dev)
{
int ret = 0;
int ret2;
/* Wind down existing buffers - iff there are any */
if (list_empty(&indio_dev->buffer_list))
return 0;
/*
* If things go wrong at some step in disable we still need to continue
* to perform the other steps, otherwise we leave the device in a
* inconsistent state. We return the error code for the first error we
* encountered.
*/
if (indio_dev->setup_ops->predisable) {
ret2 = indio_dev->setup_ops->predisable(indio_dev);
if (ret2 && !ret)
ret = ret2;
}
indio_dev->currentmode = INDIO_DIRECT_MODE;
if (indio_dev->setup_ops->postdisable) {
ret2 = indio_dev->setup_ops->postdisable(indio_dev);
if (ret2 && !ret)
ret = ret2;
}
iio_free_scan_mask(indio_dev, indio_dev->active_scan_mask);
indio_dev->active_scan_mask = NULL;
return ret;
}
static int __iio_update_buffers(struct iio_dev *indio_dev,
struct iio_buffer *insert_buffer,
struct iio_buffer *remove_buffer)
{
struct iio_device_config new_config;
int ret;
ret = iio_verify_update(indio_dev, insert_buffer, remove_buffer,
&new_config);
if (ret)
return ret;
if (insert_buffer) {
ret = iio_buffer_request_update(indio_dev, insert_buffer);
if (ret)
goto err_free_config;
}
ret = iio_disable_buffers(indio_dev);
if (ret)
goto err_deactivate_all;
if (remove_buffer)
iio_buffer_deactivate(remove_buffer);
if (insert_buffer)
iio_buffer_deactivate(insert_buffer);
indio_dev->active_scan_mask = old_mask;
kfree(compound_mask);
iio_buffer_activate(indio_dev, insert_buffer);
/* If no buffers in list, we are done */
if (list_empty(&indio_dev->buffer_list))
return 0;
ret = iio_enable_buffers(indio_dev, &new_config);
if (ret)
goto err_deactivate_all;
return 0;
err_deactivate_all:
/*
* We've already verified that the config is valid earlier. If things go
* wrong in either enable or disable the most likely reason is an IO
* error from the device. In this case there is no good recovery
* strategy. Just make sure to disable everything and leave the device
* in a sane state. With a bit of luck the device might come back to
* life again later and userspace can try again.
*/
iio_buffer_deactivate_all(indio_dev);
err_free_config:
iio_free_scan_mask(indio_dev, new_config.scan_mask);
return ret;
}
@ -777,6 +853,12 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(iio_update_buffers);
void iio_disable_all_buffers(struct iio_dev *indio_dev)
{
iio_disable_buffers(indio_dev);
iio_buffer_deactivate_all(indio_dev);
}
static ssize_t iio_buffer_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,

View file

@ -101,6 +101,8 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_WALKING] = "walking",
[IIO_MOD_STILL] = "still",
[IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
[IIO_MOD_I] = "i",
[IIO_MOD_Q] = "q",
};
/* relies on pairs of these shared then separate */
@ -117,6 +119,8 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
= "filter_low_pass_3db_frequency",
[IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY]
= "filter_high_pass_3db_frequency",
[IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
[IIO_CHAN_INFO_FREQUENCY] = "frequency",
[IIO_CHAN_INFO_PHASE] = "phase",
@ -129,6 +133,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count",
[IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
[IIO_CHAN_INFO_CALIBEMISSIVITY] = "calibemissivity",
[IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio",
};
/**

View file

@ -211,6 +211,8 @@ static const char * const iio_ev_info_text[] = {
[IIO_EV_INFO_VALUE] = "value",
[IIO_EV_INFO_HYSTERESIS] = "hysteresis",
[IIO_EV_INFO_PERIOD] = "period",
[IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db",
[IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db",
};
static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr)

View file

@ -5,6 +5,19 @@
menu "Light sensors"
config ACPI_ALS
tristate "ACPI Ambient Light Sensor"
depends on ACPI
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IIO_KFIFO_BUF
help
Say Y here if you want to build a driver for the ACPI0008
Ambient Light Sensor.
To compile this driver as a module, choose M here: the module will
be called acpi-als.
config ADJD_S311
tristate "ADJD-S311-CR999 digital color sensor"
select IIO_BUFFER
@ -37,6 +50,16 @@ config APDS9300
To compile this driver as a module, choose M here: the
module will be called apds9300.
config BH1750
tristate "ROHM BH1750 ambient light sensor"
depends on I2C
help
Say Y here to build support for the ROHM BH1710, BH1715, BH1721,
BH1750, BH1751 ambient light sensors.
To compile this driver as a module, choose M here: the module will
be called bh1750.
config CM32181
depends on I2C
tristate "CM32181 driver"
@ -175,6 +198,17 @@ config LTR501
This driver can also be built as a module. If so, the module
will be called ltr501.
config STK3310
tristate "STK3310 ALS and proximity sensor"
depends on I2C
help
Say yes here to get support for the Sensortek STK3310 ambient light
and proximity sensor. The STK3311 model is also supported by this
driver.
Choosing M will build the driver as a module. If so, the module
will be called stk3310.
config TCS3414
tristate "TAOS TCS3414 digital color sensor"
depends on I2C

View file

@ -3,9 +3,11 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ACPI_ALS) += acpi-als.o
obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_BH1750) += bh1750.o
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
obj-$(CONFIG_CM3323) += cm3323.o
@ -18,6 +20,7 @@ obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_STK3310) += stk3310.o
obj-$(CONFIG_TCS3414) += tcs3414.o
obj-$(CONFIG_TCS3472) += tcs3472.o
obj-$(CONFIG_TSL4531) += tsl4531.o

View file

@ -0,0 +1,231 @@
/*
* ACPI Ambient Light Sensor Driver
*
* Based on ALS driver:
* Copyright (C) 2009 Zhang Rui <rui.zhang@intel.com>
*
* Rework for IIO subsystem:
* Copyright (C) 2012-2013 Martin Liska <marxin.liska@gmail.com>
*
* Final cleanup and debugging:
* Copyright (C) 2013-2014 Marek Vasut <marex@denx.de>
* Copyright (C) 2015 Gabriele Mazzotta <gabriele.mzt@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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#define ACPI_ALS_CLASS "als"
#define ACPI_ALS_DEVICE_NAME "acpi-als"
#define ACPI_ALS_NOTIFY_ILLUMINANCE 0x80
ACPI_MODULE_NAME("acpi-als");
/*
* So far, there's only one channel in here, but the specification for
* ACPI0008 says there can be more to what the block can report. Like
* chromaticity and such. We are ready for incoming additions!
*/
static const struct iio_chan_spec acpi_als_channels[] = {
{
.type = IIO_LIGHT,
.scan_type = {
.sign = 's',
.realbits = 32,
.storagebits = 32,
},
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
},
};
/*
* The event buffer contains timestamp and all the data from
* the ACPI0008 block. There are multiple, but so far we only
* support _ALI (illuminance). Once someone adds new channels
* to acpi_als_channels[], the evt_buffer below will grow
* automatically.
*/
#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels)
#define EVT_BUFFER_SIZE \
(sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32)))
struct acpi_als {
struct acpi_device *device;
struct mutex lock;
s32 evt_buffer[EVT_BUFFER_SIZE];
};
/*
* All types of properties the ACPI0008 block can report. The ALI, ALC, ALT
* and ALP can all be handled by als_read_value() below, while the ALR is
* special.
*
* The _ALR property returns tables that can be used to fine-tune the values
* reported by the other props based on the particular hardware type and it's
* location (it contains tables for "rainy", "bright inhouse lighting" etc.).
*
* So far, we support only ALI (illuminance).
*/
#define ACPI_ALS_ILLUMINANCE "_ALI"
#define ACPI_ALS_CHROMATICITY "_ALC"
#define ACPI_ALS_COLOR_TEMP "_ALT"
#define ACPI_ALS_POLLING "_ALP"
#define ACPI_ALS_TABLES "_ALR"
static int als_read_value(struct acpi_als *als, char *prop, s32 *val)
{
unsigned long long temp_val;
acpi_status status;
status = acpi_evaluate_integer(als->device->handle, prop, NULL,
&temp_val);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Error reading ALS %s", prop));
return -EIO;
}
*val = temp_val;
return 0;
}
static void acpi_als_notify(struct acpi_device *device, u32 event)
{
struct iio_dev *indio_dev = acpi_driver_data(device);
struct acpi_als *als = iio_priv(indio_dev);
s32 *buffer = als->evt_buffer;
s64 time_ns = iio_get_time_ns();
s32 val;
int ret;
mutex_lock(&als->lock);
memset(buffer, 0, EVT_BUFFER_SIZE);
switch (event) {
case ACPI_ALS_NOTIFY_ILLUMINANCE:
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val);
if (ret < 0)
goto out;
*buffer++ = val;
break;
default:
/* Unhandled event */
dev_dbg(&device->dev, "Unhandled ACPI ALS event (%08x)!\n",
event);
goto out;
}
iio_push_to_buffers_with_timestamp(indio_dev, als->evt_buffer, time_ns);
out:
mutex_unlock(&als->lock);
}
static int acpi_als_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct acpi_als *als = iio_priv(indio_dev);
s32 temp_val;
int ret;
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
/* we support only illumination (_ALI) so far. */
if (chan->type != IIO_LIGHT)
return -EINVAL;
ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val);
if (ret < 0)
return ret;
*val = temp_val;
return IIO_VAL_INT;
}
static const struct iio_info acpi_als_info = {
.driver_module = THIS_MODULE,
.read_raw = acpi_als_read_raw,
};
static int acpi_als_add(struct acpi_device *device)
{
struct acpi_als *als;
struct iio_dev *indio_dev;
struct iio_buffer *buffer;
indio_dev = devm_iio_device_alloc(&device->dev, sizeof(*als));
if (!indio_dev)
return -ENOMEM;
als = iio_priv(indio_dev);
device->driver_data = indio_dev;
als->device = device;
mutex_init(&als->lock);
indio_dev->name = ACPI_ALS_DEVICE_NAME;
indio_dev->dev.parent = &device->dev;
indio_dev->info = &acpi_als_info;
indio_dev->modes = INDIO_BUFFER_SOFTWARE;
indio_dev->channels = acpi_als_channels;
indio_dev->num_channels = ARRAY_SIZE(acpi_als_channels);
buffer = devm_iio_kfifo_allocate(&device->dev);
if (!buffer)
return -ENOMEM;
iio_device_attach_buffer(indio_dev, buffer);
return devm_iio_device_register(&device->dev, indio_dev);
}
static const struct acpi_device_id acpi_als_device_ids[] = {
{"ACPI0008", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, acpi_als_device_ids);
static struct acpi_driver acpi_als_driver = {
.name = "acpi_als",
.class = ACPI_ALS_CLASS,
.ids = acpi_als_device_ids,
.ops = {
.add = acpi_als_add,
.notify = acpi_als_notify,
},
};
module_acpi_driver(acpi_als_driver);
MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
MODULE_AUTHOR("Martin Liska <marxin.liska@gmail.com>");
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
MODULE_DESCRIPTION("ACPI Ambient Light Sensor Driver");
MODULE_LICENSE("GPL");

334
drivers/iio/light/bh1750.c Normal file
View file

@ -0,0 +1,334 @@
/*
* ROHM BH1710/BH1715/BH1721/BH1750/BH1751 ambient light sensor driver
*
* Copyright (c) Tomasz Duszynski <tduszyns@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.
*
* Data sheets:
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1710fvc-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1715fvc-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1721fvc-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf
* http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1751fvi-e.pdf
*
* 7-bit I2C slave addresses:
* 0x23 (ADDR pin low)
* 0x5C (ADDR pin high)
*
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>
#define BH1750_POWER_DOWN 0x00
#define BH1750_ONE_TIME_H_RES_MODE 0x20 /* auto-mode for BH1721 */
#define BH1750_CHANGE_INT_TIME_H_BIT 0x40
#define BH1750_CHANGE_INT_TIME_L_BIT 0x60
enum {
BH1710,
BH1721,
BH1750,
};
struct bh1750_chip_info;
struct bh1750_data {
struct i2c_client *client;
struct mutex lock;
const struct bh1750_chip_info *chip_info;
u16 mtreg;
};
struct bh1750_chip_info {
u16 mtreg_min;
u16 mtreg_max;
u16 mtreg_default;
int mtreg_to_usec;
int mtreg_to_scale;
/*
* For BH1710/BH1721 all possible integration time values won't fit
* into one page so displaying is limited to every second one.
* Note, that user can still write proper values which were not
* listed.
*/
int inc;
u16 int_time_low_mask;
u16 int_time_high_mask;
}
static const bh1750_chip_info_tbl[] = {
[BH1710] = { 140, 1022, 300, 400, 250000000, 2, 0x001F, 0x03E0 },
[BH1721] = { 140, 1020, 300, 400, 250000000, 2, 0x0010, 0x03E0 },
[BH1750] = { 31, 254, 69, 1740, 57500000, 1, 0x001F, 0x00E0 },
};
static int bh1750_change_int_time(struct bh1750_data *data, int usec)
{
int ret;
u16 val;
u8 regval;
const struct bh1750_chip_info *chip_info = data->chip_info;
if ((usec % chip_info->mtreg_to_usec) != 0)
return -EINVAL;
val = usec / chip_info->mtreg_to_usec;
if (val < chip_info->mtreg_min || val > chip_info->mtreg_max)
return -EINVAL;
ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
if (ret < 0)
return ret;
regval = (val & chip_info->int_time_high_mask) >> 5;
ret = i2c_smbus_write_byte(data->client,
BH1750_CHANGE_INT_TIME_H_BIT | regval);
if (ret < 0)
return ret;
regval = val & chip_info->int_time_low_mask;
ret = i2c_smbus_write_byte(data->client,
BH1750_CHANGE_INT_TIME_L_BIT | regval);
if (ret < 0)
return ret;
data->mtreg = val;
return 0;
}
static int bh1750_read(struct bh1750_data *data, int *val)
{
int ret;
__be16 result;
const struct bh1750_chip_info *chip_info = data->chip_info;
unsigned long delay = chip_info->mtreg_to_usec * data->mtreg;
/*
* BH1721 will enter continuous mode on receiving this command.
* Note, that this eliminates need for bh1750_resume().
*/
ret = i2c_smbus_write_byte(data->client, BH1750_ONE_TIME_H_RES_MODE);
if (ret < 0)
return ret;
usleep_range(delay + 15000, delay + 40000);
ret = i2c_master_recv(data->client, (char *)&result, 2);
if (ret < 0)
return ret;
*val = be16_to_cpu(result);
return 0;
}
static int bh1750_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret, tmp;
struct bh1750_data *data = iio_priv(indio_dev);
const struct bh1750_chip_info *chip_info = data->chip_info;
switch (mask) {
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
mutex_lock(&data->lock);
ret = bh1750_read(data, val);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
tmp = chip_info->mtreg_to_scale / data->mtreg;
*val = tmp / 1000000;
*val2 = tmp % 1000000;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
*val2 = chip_info->mtreg_to_usec * data->mtreg;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static int bh1750_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret;
struct bh1750_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
if (val != 0)
return -EINVAL;
mutex_lock(&data->lock);
ret = bh1750_change_int_time(data, val2);
mutex_unlock(&data->lock);
return ret;
default:
return -EINVAL;
}
}
static ssize_t bh1750_show_int_time_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
int i;
size_t len = 0;
struct bh1750_data *data = iio_priv(dev_to_iio_dev(dev));
const struct bh1750_chip_info *chip_info = data->chip_info;
for (i = chip_info->mtreg_min; i <= chip_info->mtreg_max; i += chip_info->inc)
len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06d ",
chip_info->mtreg_to_usec * i);
buf[len - 1] = '\n';
return len;
}
static IIO_DEV_ATTR_INT_TIME_AVAIL(bh1750_show_int_time_available);
static struct attribute *bh1750_attributes[] = {
&iio_dev_attr_integration_time_available.dev_attr.attr,
NULL,
};
static struct attribute_group bh1750_attribute_group = {
.attrs = bh1750_attributes,
};
static const struct iio_info bh1750_info = {
.driver_module = THIS_MODULE,
.attrs = &bh1750_attribute_group,
.read_raw = bh1750_read_raw,
.write_raw = bh1750_write_raw,
};
static const struct iio_chan_spec bh1750_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME)
}
};
static int bh1750_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret, usec;
struct bh1750_data *data;
struct iio_dev *indio_dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_WRITE_BYTE))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->chip_info = &bh1750_chip_info_tbl[id->driver_data];
usec = data->chip_info->mtreg_to_usec * data->chip_info->mtreg_default;
ret = bh1750_change_int_time(data, usec);
if (ret < 0)
return ret;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &bh1750_info;
indio_dev->name = id->name;
indio_dev->channels = bh1750_channels;
indio_dev->num_channels = ARRAY_SIZE(bh1750_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
return iio_device_register(indio_dev);
}
static int bh1750_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct bh1750_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_lock(&data->lock);
i2c_smbus_write_byte(client, BH1750_POWER_DOWN);
mutex_unlock(&data->lock);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int bh1750_suspend(struct device *dev)
{
int ret;
struct bh1750_data *data =
iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
/*
* This is mainly for BH1721 which doesn't enter power down
* mode automatically.
*/
mutex_lock(&data->lock);
ret = i2c_smbus_write_byte(data->client, BH1750_POWER_DOWN);
mutex_unlock(&data->lock);
return ret;
}
static SIMPLE_DEV_PM_OPS(bh1750_pm_ops, bh1750_suspend, NULL);
#define BH1750_PM_OPS (&bh1750_pm_ops)
#else
#define BH1750_PM_OPS NULL
#endif
static const struct i2c_device_id bh1750_id[] = {
{ "bh1710", BH1710 },
{ "bh1715", BH1750 },
{ "bh1721", BH1721 },
{ "bh1750", BH1750 },
{ "bh1751", BH1750 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bh1750_id);
static struct i2c_driver bh1750_driver = {
.driver = {
.name = "bh1750",
.owner = THIS_MODULE,
.pm = BH1750_PM_OPS,
},
.probe = bh1750_probe,
.remove = bh1750_remove,
.id_table = bh1750_id,
};
module_i2c_driver(bh1750_driver);
MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>");
MODULE_DESCRIPTION("ROHM BH1710/BH1715/BH1721/BH1750/BH1751 als driver");
MODULE_LICENSE("GPL v2");

View file

@ -263,7 +263,6 @@ static int hid_als_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct als_state *als_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct als_state));
if (!indio_dev)
@ -281,20 +280,21 @@ static int hid_als_probe(struct platform_device *pdev)
return ret;
}
channels = kmemdup(als_channels, sizeof(als_channels), GFP_KERNEL);
if (!channels) {
indio_dev->channels = kmemdup(als_channels,
sizeof(als_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = als_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_ALS, als_state);
ret = als_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_ALS, als_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels =
ARRAY_SIZE(als_channels);
indio_dev->dev.parent = &pdev->dev;
@ -361,7 +361,7 @@ static int hid_als_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_als_ids[] = {
static const struct platform_device_id hid_als_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200041",

View file

@ -350,7 +350,7 @@ static int hid_prox_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_prox_ids[] = {
static const struct platform_device_id hid_prox_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200011",

View file

@ -66,6 +66,9 @@
#define LTR501_REGMAP_NAME "ltr501_regmap"
#define LTR501_LUX_CONV(vis_coeff, vis_data, ir_coeff, ir_data) \
((vis_coeff * vis_data) - (ir_coeff * ir_data))
static const int int_time_mapping[] = {100000, 50000, 200000, 400000};
static const struct reg_field reg_field_it =
@ -298,6 +301,29 @@ static int ltr501_ps_read_samp_period(struct ltr501_data *data, int *val)
return IIO_VAL_INT;
}
/* IR and visible spectrum coeff's are given in data sheet */
static unsigned long ltr501_calculate_lux(u16 vis_data, u16 ir_data)
{
unsigned long ratio, lux;
if (vis_data == 0)
return 0;
/* multiply numerator by 100 to avoid handling ratio < 1 */
ratio = DIV_ROUND_UP(ir_data * 100, ir_data + vis_data);
if (ratio < 45)
lux = LTR501_LUX_CONV(1774, vis_data, -1105, ir_data);
else if (ratio >= 45 && ratio < 64)
lux = LTR501_LUX_CONV(3772, vis_data, 1336, ir_data);
else if (ratio >= 64 && ratio < 85)
lux = LTR501_LUX_CONV(1690, vis_data, 169, ir_data);
else
lux = 0;
return lux / 1000;
}
static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask)
{
int tries = 100;
@ -548,7 +574,14 @@ static const struct iio_event_spec ltr501_pxs_event_spec[] = {
.num_event_specs = _evsize,\
}
#define LTR501_LIGHT_CHANNEL() { \
.type = IIO_LIGHT, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.scan_index = -1, \
}
static const struct iio_chan_spec ltr501_channels[] = {
LTR501_LIGHT_CHANNEL(),
LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0,
ltr501_als_event_spec,
ARRAY_SIZE(ltr501_als_event_spec)),
@ -576,6 +609,7 @@ static const struct iio_chan_spec ltr501_channels[] = {
};
static const struct iio_chan_spec ltr301_channels[] = {
LTR501_LIGHT_CHANNEL(),
LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0,
ltr501_als_event_spec,
ARRAY_SIZE(ltr501_als_event_spec)),
@ -596,6 +630,23 @@ static int ltr501_read_raw(struct iio_dev *indio_dev,
int ret, i;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
switch (chan->type) {
case IIO_LIGHT:
mutex_lock(&data->lock_als);
ret = ltr501_read_als(data, buf);
mutex_unlock(&data->lock_als);
if (ret < 0)
return ret;
*val = ltr501_calculate_lux(le16_to_cpu(buf[1]),
le16_to_cpu(buf[0]));
return IIO_VAL_INT;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
@ -865,9 +916,9 @@ static int ltr501_write_thresh(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_PROXIMITY:
switch (dir) {
if (val > LTR501_PS_THRESH_MASK)
return -EINVAL;
switch (dir) {
case IIO_EV_DIR_RISING:
mutex_lock(&data->lock_ps);
ret = regmap_bulk_write(data->regmap,

722
drivers/iio/light/stk3310.c Normal file
View file

@ -0,0 +1,722 @@
/**
* Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor
*
* Copyright (c) 2015, Intel Corporation.
*
* 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.
*
* IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define STK3310_REG_STATE 0x00
#define STK3310_REG_PSCTRL 0x01
#define STK3310_REG_ALSCTRL 0x02
#define STK3310_REG_INT 0x04
#define STK3310_REG_THDH_PS 0x06
#define STK3310_REG_THDL_PS 0x08
#define STK3310_REG_FLAG 0x10
#define STK3310_REG_PS_DATA_MSB 0x11
#define STK3310_REG_PS_DATA_LSB 0x12
#define STK3310_REG_ALS_DATA_MSB 0x13
#define STK3310_REG_ALS_DATA_LSB 0x14
#define STK3310_REG_ID 0x3E
#define STK3310_MAX_REG 0x80
#define STK3310_STATE_EN_PS 0x01
#define STK3310_STATE_EN_ALS 0x02
#define STK3310_STATE_STANDBY 0x00
#define STK3310_CHIP_ID_VAL 0x13
#define STK3311_CHIP_ID_VAL 0x1D
#define STK3310_PSINT_EN 0x01
#define STK3310_PS_MAX_VAL 0xFFFF
#define STK3310_THRESH_MAX 0xFFFF
#define STK3310_DRIVER_NAME "stk3310"
#define STK3310_REGMAP_NAME "stk3310_regmap"
#define STK3310_EVENT "stk3310_event"
#define STK3310_GPIO "stk3310_gpio"
#define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1"
#define STK3310_IT_AVAILABLE \
"0.000185 0.000370 0.000741 0.001480 0.002960 0.005920 0.011840 " \
"0.023680 0.047360 0.094720 0.189440 0.378880 0.757760 1.515520 " \
"3.031040 6.062080"
#define STK3310_REGFIELD(name) \
do { \
data->reg_##name = \
devm_regmap_field_alloc(&client->dev, regmap, \
stk3310_reg_field_##name); \
if (IS_ERR(data->reg_##name)) { \
dev_err(&client->dev, "reg field alloc failed.\n"); \
return PTR_ERR(data->reg_##name); \
} \
} while (0)
static const struct reg_field stk3310_reg_field_state =
REG_FIELD(STK3310_REG_STATE, 0, 2);
static const struct reg_field stk3310_reg_field_als_gain =
REG_FIELD(STK3310_REG_ALSCTRL, 4, 5);
static const struct reg_field stk3310_reg_field_ps_gain =
REG_FIELD(STK3310_REG_PSCTRL, 4, 5);
static const struct reg_field stk3310_reg_field_als_it =
REG_FIELD(STK3310_REG_ALSCTRL, 0, 3);
static const struct reg_field stk3310_reg_field_ps_it =
REG_FIELD(STK3310_REG_PSCTRL, 0, 3);
static const struct reg_field stk3310_reg_field_int_ps =
REG_FIELD(STK3310_REG_INT, 0, 2);
static const struct reg_field stk3310_reg_field_flag_psint =
REG_FIELD(STK3310_REG_FLAG, 4, 4);
static const struct reg_field stk3310_reg_field_flag_nf =
REG_FIELD(STK3310_REG_FLAG, 0, 0);
/*
* Maximum PS values with regard to scale. Used to export the 'inverse'
* PS value (high values for far objects, low values for near objects).
*/
static const int stk3310_ps_max[4] = {
STK3310_PS_MAX_VAL / 64,
STK3310_PS_MAX_VAL / 16,
STK3310_PS_MAX_VAL / 4,
STK3310_PS_MAX_VAL,
};
static const int stk3310_scale_table[][2] = {
{6, 400000}, {1, 600000}, {0, 400000}, {0, 100000}
};
/* Integration time in seconds, microseconds */
static const int stk3310_it_table[][2] = {
{0, 185}, {0, 370}, {0, 741}, {0, 1480},
{0, 2960}, {0, 5920}, {0, 11840}, {0, 23680},
{0, 47360}, {0, 94720}, {0, 189440}, {0, 378880},
{0, 757760}, {1, 515520}, {3, 31040}, {6, 62080},
};
struct stk3310_data {
struct i2c_client *client;
struct mutex lock;
bool als_enabled;
bool ps_enabled;
u64 timestamp;
struct regmap *regmap;
struct regmap_field *reg_state;
struct regmap_field *reg_als_gain;
struct regmap_field *reg_ps_gain;
struct regmap_field *reg_als_it;
struct regmap_field *reg_ps_it;
struct regmap_field *reg_int_ps;
struct regmap_field *reg_flag_psint;
struct regmap_field *reg_flag_nf;
};
static const struct iio_event_spec stk3310_events[] = {
/* Proximity event */
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
/* Out-of-proximity event */
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) |
BIT(IIO_EV_INFO_ENABLE),
},
};
static const struct iio_chan_spec stk3310_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME),
},
{
.type = IIO_PROXIMITY,
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_INT_TIME),
.event_spec = stk3310_events,
.num_event_specs = ARRAY_SIZE(stk3310_events),
}
};
static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE);
static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE);
static IIO_CONST_ATTR(in_illuminance_integration_time_available,
STK3310_IT_AVAILABLE);
static IIO_CONST_ATTR(in_proximity_integration_time_available,
STK3310_IT_AVAILABLE);
static struct attribute *stk3310_attributes[] = {
&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
&iio_const_attr_in_proximity_scale_available.dev_attr.attr,
&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
NULL,
};
static const struct attribute_group stk3310_attribute_group = {
.attrs = stk3310_attributes
};
static int stk3310_get_index(const int table[][2], int table_size,
int val, int val2)
{
int i;
for (i = 0; i < table_size; i++) {
if (val == table[i][0] && val2 == table[i][1])
return i;
}
return -EINVAL;
}
static int stk3310_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
u8 reg;
u16 buf;
int ret;
unsigned int index;
struct stk3310_data *data = iio_priv(indio_dev);
if (info != IIO_EV_INFO_VALUE)
return -EINVAL;
/*
* Only proximity interrupts are implemented at the moment.
* Since we're inverting proximity values, the sensor's 'high'
* threshold will become our 'low' threshold, associated with
* 'near' events. Similarly, the sensor's 'low' threshold will
* be our 'high' threshold, associated with 'far' events.
*/
if (dir == IIO_EV_DIR_RISING)
reg = STK3310_REG_THDL_PS;
else if (dir == IIO_EV_DIR_FALLING)
reg = STK3310_REG_THDH_PS;
else
return -EINVAL;
mutex_lock(&data->lock);
ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
mutex_unlock(&data->lock);
if (ret < 0) {
dev_err(&data->client->dev, "register read failed\n");
return ret;
}
regmap_field_read(data->reg_ps_gain, &index);
*val = swab16(stk3310_ps_max[index] - buf);
return IIO_VAL_INT;
}
static int stk3310_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
u8 reg;
u16 buf;
int ret;
unsigned int index;
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
regmap_field_read(data->reg_ps_gain, &index);
if (val > stk3310_ps_max[index])
return -EINVAL;
if (dir == IIO_EV_DIR_RISING)
reg = STK3310_REG_THDL_PS;
else if (dir == IIO_EV_DIR_FALLING)
reg = STK3310_REG_THDH_PS;
else
return -EINVAL;
buf = swab16(stk3310_ps_max[index] - val);
ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
if (ret < 0)
dev_err(&client->dev, "failed to set PS threshold!\n");
return ret;
}
static int stk3310_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
unsigned int event_val;
struct stk3310_data *data = iio_priv(indio_dev);
regmap_field_read(data->reg_int_ps, &event_val);
return event_val;
}
static int stk3310_write_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
int state)
{
int ret;
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
if (state < 0 || state > 7)
return -EINVAL;
/* Set INT_PS value */
mutex_lock(&data->lock);
ret = regmap_field_write(data->reg_int_ps, state);
if (ret < 0)
dev_err(&client->dev, "failed to set interrupt mode\n");
mutex_unlock(&data->lock);
return ret;
}
static int stk3310_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
u8 reg;
u16 buf;
int ret;
unsigned int index;
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->type == IIO_LIGHT)
reg = STK3310_REG_ALS_DATA_MSB;
else if (chan->type == IIO_PROXIMITY)
reg = STK3310_REG_PS_DATA_MSB;
else
return -EINVAL;
mutex_lock(&data->lock);
ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
if (ret < 0) {
dev_err(&client->dev, "register read failed\n");
mutex_unlock(&data->lock);
return ret;
}
*val = swab16(buf);
if (chan->type == IIO_PROXIMITY) {
/*
* Invert the proximity data so we return low values
* for close objects and high values for far ones.
*/
regmap_field_read(data->reg_ps_gain, &index);
*val = stk3310_ps_max[index] - *val;
}
mutex_unlock(&data->lock);
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
if (chan->type == IIO_LIGHT)
regmap_field_read(data->reg_als_it, &index);
else
regmap_field_read(data->reg_ps_it, &index);
*val = stk3310_it_table[index][0];
*val2 = stk3310_it_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_LIGHT)
regmap_field_read(data->reg_als_gain, &index);
else
regmap_field_read(data->reg_ps_gain, &index);
*val = stk3310_scale_table[index][0];
*val2 = stk3310_scale_table[index][1];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
static int stk3310_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
int ret;
unsigned int index;
struct stk3310_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
index = stk3310_get_index(stk3310_it_table,
ARRAY_SIZE(stk3310_it_table),
val, val2);
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
if (chan->type == IIO_LIGHT)
ret = regmap_field_write(data->reg_als_it, index);
else
ret = regmap_field_write(data->reg_ps_it, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
case IIO_CHAN_INFO_SCALE:
index = stk3310_get_index(stk3310_scale_table,
ARRAY_SIZE(stk3310_scale_table),
val, val2);
if (index < 0)
return -EINVAL;
mutex_lock(&data->lock);
if (chan->type == IIO_LIGHT)
ret = regmap_field_write(data->reg_als_gain, index);
else
ret = regmap_field_write(data->reg_ps_gain, index);
if (ret < 0)
dev_err(&data->client->dev,
"sensor configuration failed\n");
mutex_unlock(&data->lock);
return ret;
}
return -EINVAL;
}
static const struct iio_info stk3310_info = {
.driver_module = THIS_MODULE,
.read_raw = stk3310_read_raw,
.write_raw = stk3310_write_raw,
.attrs = &stk3310_attribute_group,
.read_event_value = stk3310_read_event,
.write_event_value = stk3310_write_event,
.read_event_config = stk3310_read_event_config,
.write_event_config = stk3310_write_event_config,
};
static int stk3310_set_state(struct stk3310_data *data, u8 state)
{
int ret;
struct i2c_client *client = data->client;
/* 3-bit state; 0b100 is not supported. */
if (state > 7 || state == 4)
return -EINVAL;
mutex_lock(&data->lock);
ret = regmap_field_write(data->reg_state, state);
if (ret < 0) {
dev_err(&client->dev, "failed to change sensor state\n");
} else if (state != STK3310_STATE_STANDBY) {
/* Don't reset the 'enabled' flags if we're going in standby */
data->ps_enabled = !!(state & 0x01);
data->als_enabled = !!(state & 0x02);
}
mutex_unlock(&data->lock);
return ret;
}
static int stk3310_init(struct iio_dev *indio_dev)
{
int ret;
int chipid;
u8 state;
struct stk3310_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
regmap_read(data->regmap, STK3310_REG_ID, &chipid);
if (chipid != STK3310_CHIP_ID_VAL &&
chipid != STK3311_CHIP_ID_VAL) {
dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
return -ENODEV;
}
state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS;
ret = stk3310_set_state(data, state);
if (ret < 0) {
dev_err(&client->dev, "failed to enable sensor");
return ret;
}
/* Enable PS interrupts */
ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN);
if (ret < 0)
dev_err(&client->dev, "failed to enable interrupts!\n");
return ret;
}
static int stk3310_gpio_probe(struct i2c_client *client)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case STK3310_REG_ALS_DATA_MSB:
case STK3310_REG_ALS_DATA_LSB:
case STK3310_REG_PS_DATA_LSB:
case STK3310_REG_PS_DATA_MSB:
case STK3310_REG_FLAG:
return true;
default:
return false;
}
}
static struct regmap_config stk3310_regmap_config = {
.name = STK3310_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.max_register = STK3310_MAX_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = stk3310_is_volatile_reg,
};
static int stk3310_regmap_init(struct stk3310_data *data)
{
struct regmap *regmap;
struct i2c_client *client;
client = data->client;
regmap = devm_regmap_init_i2c(client, &stk3310_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap initialization failed.\n");
return PTR_ERR(regmap);
}
data->regmap = regmap;
STK3310_REGFIELD(state);
STK3310_REGFIELD(als_gain);
STK3310_REGFIELD(ps_gain);
STK3310_REGFIELD(als_it);
STK3310_REGFIELD(ps_it);
STK3310_REGFIELD(int_ps);
STK3310_REGFIELD(flag_psint);
STK3310_REGFIELD(flag_nf);
return 0;
}
static irqreturn_t stk3310_irq_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct stk3310_data *data = iio_priv(indio_dev);
data->timestamp = iio_get_time_ns();
return IRQ_WAKE_THREAD;
}
static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
{
int ret;
unsigned int dir;
u64 event;
struct iio_dev *indio_dev = private;
struct stk3310_data *data = iio_priv(indio_dev);
/* Read FLAG_NF to figure out what threshold has been met. */
mutex_lock(&data->lock);
ret = regmap_field_read(data->reg_flag_nf, &dir);
if (ret < 0) {
dev_err(&data->client->dev, "register read failed\n");
mutex_unlock(&data->lock);
return ret;
}
event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
IIO_EV_TYPE_THRESH,
(dir ? IIO_EV_DIR_RISING :
IIO_EV_DIR_FALLING));
iio_push_event(indio_dev, event, data->timestamp);
/* Reset the interrupt flag */
ret = regmap_field_write(data->reg_flag_psint, 0);
if (ret < 0)
dev_err(&data->client->dev, "failed to reset interrupts\n");
mutex_unlock(&data->lock);
return IRQ_HANDLED;
}
static int stk3310_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct stk3310_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;
i2c_set_clientdata(client, indio_dev);
mutex_init(&data->lock);
ret = stk3310_regmap_init(data);
if (ret < 0)
return ret;
indio_dev->dev.parent = &client->dev;
indio_dev->info = &stk3310_info;
indio_dev->name = STK3310_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = stk3310_channels;
indio_dev->num_channels = ARRAY_SIZE(stk3310_channels);
ret = stk3310_init(indio_dev);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "device_register failed\n");
stk3310_set_state(data, STK3310_STATE_STANDBY);
}
if (client->irq <= 0)
client->irq = stk3310_gpio_probe(client);
if (client->irq >= 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
stk3310_irq_handler,
stk3310_irq_event_handler,
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
STK3310_EVENT, indio_dev);
if (ret < 0)
dev_err(&client->dev, "request irq %d failed\n",
client->irq);
}
return ret;
}
static int stk3310_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY);
}
#ifdef CONFIG_PM_SLEEP
static int stk3310_suspend(struct device *dev)
{
struct stk3310_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return stk3310_set_state(data, STK3310_STATE_STANDBY);
}
static int stk3310_resume(struct device *dev)
{
int state = 0;
struct stk3310_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
if (data->ps_enabled)
state |= STK3310_STATE_EN_PS;
if (data->als_enabled)
state |= STK3310_STATE_EN_ALS;
return stk3310_set_state(data, state);
}
static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume);
#define STK3310_PM_OPS (&stk3310_pm_ops)
#else
#define STK3310_PM_OPS NULL
#endif
static const struct i2c_device_id stk3310_i2c_id[] = {
{"STK3310", 0},
{"STK3311", 0},
{}
};
static const struct acpi_device_id stk3310_acpi_id[] = {
{"STK3310", 0},
{"STK3311", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
static struct i2c_driver stk3310_driver = {
.driver = {
.name = "stk3310",
.pm = STK3310_PM_OPS,
.acpi_match_table = ACPI_PTR(stk3310_acpi_id),
},
.probe = stk3310_probe,
.remove = stk3310_remove,
.id_table = stk3310_i2c_id,
};
module_i2c_driver(stk3310_driver);
MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
MODULE_DESCRIPTION("STK3310 Ambient Light and Proximity Sensor driver");
MODULE_LICENSE("GPL v2");

View file

@ -8,7 +8,7 @@ menu "Magnetometer sensors"
config AK8975
tristate "Asahi Kasei AK 3-Axis Magnetometer"
depends on I2C
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Asahi Kasei AK8975, AK8963,
AK09911 or AK09912 3-Axis Magnetometer.
@ -19,7 +19,7 @@ config AK8975
config AK09911
tristate "Asahi Kasei AK09911 3-axis Compass"
depends on I2C
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
select AK8975
help
Deprecated: AK09911 is now supported by AK8975 driver.
@ -47,6 +47,17 @@ config HID_SENSOR_MAGNETOMETER_3D
Say yes here to build support for the HID SENSOR
Magnetometer 3D.
config MMC35240
tristate "MEMSIC MMC35240 3-axis magnetic sensor"
select REGMAP_I2C
depends on I2C
help
Say yes here to build support for the MEMSIC MMC35240 3-axis
magnetic sensor.
To compile this driver as a module, choose M here: the module
will be called mmc35240.
config IIO_ST_MAGN_3AXIS
tristate "STMicroelectronics magnetometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
@ -76,4 +87,18 @@ config IIO_ST_MAGN_SPI_3AXIS
depends on IIO_ST_MAGN_3AXIS
depends on IIO_ST_SENSORS_SPI
config BMC150_MAGN
tristate "Bosch BMC150 Magnetometer Driver"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for the BMC150 magnetometer.
Currently this only supports the device via an i2c interface.
This is a combo module with both accelerometer and magnetometer.
This driver is only implementing magnetometer part, which has
its own address and register map.
endmenu

View file

@ -6,6 +6,7 @@
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
obj-$(CONFIG_MMC35240) += mmc35240.o
obj-$(CONFIG_IIO_ST_MAGN_3AXIS) += st_magn.o
st_magn-y := st_magn_core.o
@ -13,3 +14,5 @@ st_magn-$(CONFIG_IIO_BUFFER) += st_magn_buffer.o
obj-$(CONFIG_IIO_ST_MAGN_I2C_3AXIS) += st_magn_i2c.o
obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o
obj-$(CONFIG_BMC150_MAGN) += bmc150_magn.o

File diff suppressed because it is too large Load diff

View file

@ -510,7 +510,7 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_magn_3d_ids[] = {
static const struct platform_device_id hid_magn_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200083",

View file

@ -0,0 +1,512 @@
/*
* MMC35240 - MEMSIC 3-axis Magnetic Sensor
*
* Copyright (c) 2015, Intel Corporation.
*
* 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.
*
* IIO driver for MMC35240 (7-bit I2C slave address 0x30).
*
* TODO: offset, ACPI, continuous measurement mode, PM
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/regmap.h>
#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#define MMC35240_DRV_NAME "mmc35240"
#define MMC35240_REGMAP_NAME "mmc35240_regmap"
#define MMC35240_REG_XOUT_L 0x00
#define MMC35240_REG_XOUT_H 0x01
#define MMC35240_REG_YOUT_L 0x02
#define MMC35240_REG_YOUT_H 0x03
#define MMC35240_REG_ZOUT_L 0x04
#define MMC35240_REG_ZOUT_H 0x05
#define MMC35240_REG_STATUS 0x06
#define MMC35240_REG_CTRL0 0x07
#define MMC35240_REG_CTRL1 0x08
#define MMC35240_REG_ID 0x20
#define MMC35240_STATUS_MEAS_DONE_BIT BIT(0)
#define MMC35240_CTRL0_REFILL_BIT BIT(7)
#define MMC35240_CTRL0_RESET_BIT BIT(6)
#define MMC35240_CTRL0_SET_BIT BIT(5)
#define MMC35240_CTRL0_CMM_BIT BIT(1)
#define MMC35240_CTRL0_TM_BIT BIT(0)
/* output resolution bits */
#define MMC35240_CTRL1_BW0_BIT BIT(0)
#define MMC35240_CTRL1_BW1_BIT BIT(1)
#define MMC35240_CTRL1_BW_MASK (MMC35240_CTRL1_BW0_BIT | \
MMC35240_CTRL1_BW1_BIT)
#define MMC35240_CTRL1_BW_SHIFT 0
#define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */
#define MMC53240_WAIT_SET_RESET 1000 /* us */
enum mmc35240_resolution {
MMC35240_16_BITS_SLOW = 0, /* 100 Hz */
MMC35240_16_BITS_FAST, /* 200 Hz */
MMC35240_14_BITS, /* 333 Hz */
MMC35240_12_BITS, /* 666 Hz */
};
enum mmc35240_axis {
AXIS_X = 0,
AXIS_Y,
AXIS_Z,
};
static const struct {
int sens[3]; /* sensitivity per X, Y, Z axis */
int nfo; /* null field output */
} mmc35240_props_table[] = {
/* 16 bits, 100Hz ODR */
{
{1024, 1024, 770},
32768,
},
/* 16 bits, 200Hz ODR */
{
{1024, 1024, 770},
32768,
},
/* 14 bits, 333Hz ODR */
{
{256, 256, 193},
8192,
},
/* 12 bits, 666Hz ODR */
{
{64, 64, 48},
2048,
},
};
struct mmc35240_data {
struct i2c_client *client;
struct mutex mutex;
struct regmap *regmap;
enum mmc35240_resolution res;
};
static const int mmc35240_samp_freq[] = {100, 200, 333, 666};
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 333 666");
#define MMC35240_CHANNEL(_axis) { \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_ ## _axis, \
.address = AXIS_ ## _axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
static const struct iio_chan_spec mmc35240_channels[] = {
MMC35240_CHANNEL(X),
MMC35240_CHANNEL(Y),
MMC35240_CHANNEL(Z),
};
static struct attribute *mmc35240_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
};
static const struct attribute_group mmc35240_attribute_group = {
.attrs = mmc35240_attributes,
};
static int mmc35240_get_samp_freq_index(struct mmc35240_data *data,
int val, int val2)
{
int i;
for (i = 0; i < ARRAY_SIZE(mmc35240_samp_freq); i++)
if (mmc35240_samp_freq[i] == val)
return i;
return -EINVAL;
}
static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
{
int ret;
u8 coil_bit;
/*
* Recharge the capacitor at VCAP pin, requested to be issued
* before a SET/RESET command.
*/
ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
MMC35240_CTRL0_REFILL_BIT,
MMC35240_CTRL0_REFILL_BIT);
if (ret < 0)
return ret;
usleep_range(MMC35240_WAIT_CHARGE_PUMP, MMC35240_WAIT_CHARGE_PUMP + 1);
if (set)
coil_bit = MMC35240_CTRL0_SET_BIT;
else
coil_bit = MMC35240_CTRL0_RESET_BIT;
return regmap_update_bits(data->regmap, MMC35240_REG_CTRL0,
MMC35240_CTRL0_REFILL_BIT,
coil_bit);
}
static int mmc35240_init(struct mmc35240_data *data)
{
int ret;
unsigned int reg_id;
ret = regmap_read(data->regmap, MMC35240_REG_ID, &reg_id);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading product id\n");
return ret;
}
dev_dbg(&data->client->dev, "MMC35240 chip id %x\n", reg_id);
/*
* make sure we restore sensor characteristics, by doing
* a RESET/SET sequence
*/
ret = mmc35240_hw_set(data, false);
if (ret < 0)
return ret;
usleep_range(MMC53240_WAIT_SET_RESET, MMC53240_WAIT_SET_RESET + 1);
ret = mmc35240_hw_set(data, true);
if (ret < 0)
return ret;
/* set default sampling frequency */
return regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,
MMC35240_CTRL1_BW_MASK,
data->res << MMC35240_CTRL1_BW_SHIFT);
}
static int mmc35240_take_measurement(struct mmc35240_data *data)
{
int ret, tries = 100;
unsigned int reg_status;
ret = regmap_write(data->regmap, MMC35240_REG_CTRL0,
MMC35240_CTRL0_TM_BIT);
if (ret < 0)
return ret;
while (tries-- > 0) {
ret = regmap_read(data->regmap, MMC35240_REG_STATUS,
&reg_status);
if (ret < 0)
return ret;
if (reg_status & MMC35240_STATUS_MEAS_DONE_BIT)
break;
msleep(20);
}
if (tries < 0) {
dev_err(&data->client->dev, "data not ready\n");
return -EIO;
}
return 0;
}
static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
{
int ret;
ret = mmc35240_take_measurement(data);
if (ret < 0)
return ret;
return regmap_bulk_read(data->regmap, MMC35240_REG_XOUT_L, (u8 *)buf,
3 * sizeof(__le16));
}
static int mmc35240_raw_to_gauss(struct mmc35240_data *data, int index,
__le16 buf[],
int *val, int *val2)
{
int raw_x, raw_y, raw_z;
int sens_x, sens_y, sens_z;
int nfo;
raw_x = le16_to_cpu(buf[AXIS_X]);
raw_y = le16_to_cpu(buf[AXIS_Y]);
raw_z = le16_to_cpu(buf[AXIS_Z]);
sens_x = mmc35240_props_table[data->res].sens[AXIS_X];
sens_y = mmc35240_props_table[data->res].sens[AXIS_Y];
sens_z = mmc35240_props_table[data->res].sens[AXIS_Z];
nfo = mmc35240_props_table[data->res].nfo;
switch (index) {
case AXIS_X:
*val = (raw_x - nfo) / sens_x;
*val2 = ((raw_x - nfo) % sens_x) * 1000000;
break;
case AXIS_Y:
*val = (raw_y - nfo) / sens_y - (raw_z - nfo) / sens_z;
*val2 = (((raw_y - nfo) % sens_y - (raw_z - nfo) % sens_z))
* 1000000;
break;
case AXIS_Z:
*val = (raw_y - nfo) / sens_y + (raw_z - nfo) / sens_z;
*val2 = (((raw_y - nfo) % sens_y + (raw_z - nfo) % sens_z))
* 1000000;
break;
default:
return -EINVAL;
}
return 0;
}
static int mmc35240_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct mmc35240_data *data = iio_priv(indio_dev);
int ret, i;
unsigned int reg;
__le16 buf[3];
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&data->mutex);
ret = mmc35240_read_measurement(data, buf);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
ret = mmc35240_raw_to_gauss(data, chan->address,
buf, val, val2);
if (ret < 0)
return ret;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&data->mutex);
ret = regmap_read(data->regmap, MMC35240_REG_CTRL1, &reg);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
i = (reg & MMC35240_CTRL1_BW_MASK) >> MMC35240_CTRL1_BW_SHIFT;
if (i < 0 || i > ARRAY_SIZE(mmc35240_samp_freq))
return -EINVAL;
*val = mmc35240_samp_freq[i];
*val2 = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int mmc35240_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct mmc35240_data *data = iio_priv(indio_dev);
int i, ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
i = mmc35240_get_samp_freq_index(data, val, val2);
if (i < 0)
return -EINVAL;
mutex_lock(&data->mutex);
ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,
MMC35240_CTRL1_BW_MASK,
i << MMC35240_CTRL1_BW_SHIFT);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static const struct iio_info mmc35240_info = {
.driver_module = THIS_MODULE,
.read_raw = mmc35240_read_raw,
.write_raw = mmc35240_write_raw,
.attrs = &mmc35240_attribute_group,
};
static bool mmc35240_is_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MMC35240_REG_CTRL0:
case MMC35240_REG_CTRL1:
return true;
default:
return false;
}
}
static bool mmc35240_is_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MMC35240_REG_XOUT_L:
case MMC35240_REG_XOUT_H:
case MMC35240_REG_YOUT_L:
case MMC35240_REG_YOUT_H:
case MMC35240_REG_ZOUT_L:
case MMC35240_REG_ZOUT_H:
case MMC35240_REG_STATUS:
case MMC35240_REG_ID:
return true;
default:
return false;
}
}
static bool mmc35240_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case MMC35240_REG_CTRL0:
case MMC35240_REG_CTRL1:
return false;
default:
return true;
}
}
static struct reg_default mmc35240_reg_defaults[] = {
{ MMC35240_REG_CTRL0, 0x00 },
{ MMC35240_REG_CTRL1, 0x00 },
};
static const struct regmap_config mmc35240_regmap_config = {
.name = MMC35240_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.max_register = MMC35240_REG_ID,
.cache_type = REGCACHE_FLAT,
.writeable_reg = mmc35240_is_writeable_reg,
.readable_reg = mmc35240_is_readable_reg,
.volatile_reg = mmc35240_is_volatile_reg,
.reg_defaults = mmc35240_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(mmc35240_reg_defaults),
};
static int mmc35240_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mmc35240_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
regmap = devm_regmap_init_i2c(client, &mmc35240_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "regmap initialization failed\n");
return PTR_ERR(regmap);
}
data = iio_priv(indio_dev);
data->client = client;
data->regmap = regmap;
data->res = MMC35240_16_BITS_SLOW;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &mmc35240_info;
indio_dev->name = MMC35240_DRV_NAME;
indio_dev->channels = mmc35240_channels;
indio_dev->num_channels = ARRAY_SIZE(mmc35240_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
ret = mmc35240_init(data);
if (ret < 0) {
dev_err(&client->dev, "mmc35240 chip init failed\n");
return ret;
}
return devm_iio_device_register(&client->dev, indio_dev);
}
#ifdef CONFIG_PM_SLEEP
static int mmc35240_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mmc35240_data *data = iio_priv(indio_dev);
regcache_cache_only(data->regmap, true);
return 0;
}
static int mmc35240_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mmc35240_data *data = iio_priv(indio_dev);
int ret;
regcache_mark_dirty(data->regmap);
ret = regcache_sync_region(data->regmap, MMC35240_REG_CTRL0,
MMC35240_REG_CTRL1);
if (ret < 0)
dev_err(dev, "Failed to restore control registers\n");
regcache_cache_only(data->regmap, false);
return 0;
}
#endif
static const struct dev_pm_ops mmc35240_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume)
};
static const struct acpi_device_id mmc35240_acpi_match[] = {
{"MMC35240", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
static const struct i2c_device_id mmc35240_id[] = {
{"MMC35240", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mmc35240_id);
static struct i2c_driver mmc35240_driver = {
.driver = {
.name = MMC35240_DRV_NAME,
.pm = &mmc35240_pm_ops,
.acpi_match_table = ACPI_PTR(mmc35240_acpi_match),
},
.probe = mmc35240_probe,
.id_table = mmc35240_id,
};
module_i2c_driver(mmc35240_driver);
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
MODULE_DESCRIPTION("MEMSIC MMC35240 magnetic sensor driver");
MODULE_LICENSE("GPL v2");

View file

@ -315,7 +315,6 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct incl_3d_state *incl_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct incl_3d_state));
@ -336,21 +335,22 @@ static int hid_incl_3d_probe(struct platform_device *pdev)
return ret;
}
channels = kmemdup(incl_3d_channels, sizeof(incl_3d_channels),
GFP_KERNEL);
if (!channels) {
indio_dev->channels = kmemdup(incl_3d_channels,
sizeof(incl_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = incl_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_INCLINOMETER_3D, incl_state);
ret = incl_3d_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_INCLINOMETER_3D,
incl_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &incl_3d_info;
@ -417,7 +417,7 @@ static int hid_incl_3d_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_incl_3d_ids[] = {
static const struct platform_device_id hid_incl_3d_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200086",

View file

@ -222,7 +222,6 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct dev_rot_state *rot_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct dev_rot_state));
@ -243,21 +242,23 @@ static int hid_dev_rot_probe(struct platform_device *pdev)
return ret;
}
channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
sizeof(dev_rot_channels), GFP_KERNEL);
if (!channels) {
indio_dev->channels = devm_kmemdup(&pdev->dev, dev_rot_channels,
sizeof(dev_rot_channels),
GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = dev_rot_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_DEVICE_ORIENTATION, rot_state);
ret = dev_rot_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_DEVICE_ORIENTATION,
rot_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
return ret;
}
indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(dev_rot_channels);
indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &dev_rot_info;
@ -321,7 +322,7 @@ static int hid_dev_rot_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_dev_rot_ids[] = {
static const struct platform_device_id hid_dev_rot_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-20008a",

View file

@ -260,7 +260,6 @@ static int hid_press_probe(struct platform_device *pdev)
struct iio_dev *indio_dev;
struct press_state *press_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels;
indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct press_state));
@ -280,20 +279,21 @@ static int hid_press_probe(struct platform_device *pdev)
return ret;
}
channels = kmemdup(press_channels, sizeof(press_channels), GFP_KERNEL);
if (!channels) {
indio_dev->channels = kmemdup(press_channels, sizeof(press_channels),
GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = press_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_PRESSURE, press_state);
ret = press_parse_report(pdev, hsdev,
(struct iio_chan_spec *)indio_dev->channels,
HID_USAGE_SENSOR_PRESSURE, press_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
}
indio_dev->channels = channels;
indio_dev->num_channels =
ARRAY_SIZE(press_channels);
indio_dev->dev.parent = &pdev->dev;
@ -360,7 +360,7 @@ static int hid_press_remove(struct platform_device *pdev)
return 0;
}
static struct platform_device_id hid_press_ids[] = {
static const struct platform_device_id hid_press_ids[] = {
{
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200031",

View file

@ -254,9 +254,7 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev,
mutex_unlock(&data->lock);
mlx90614_power_put(data);
if (ret < 0)
return ret;
return 0;
return ret;
default:
return -EINVAL;
}

View file

@ -79,7 +79,7 @@ config LIS3L02DQ
depends on SPI
select IIO_TRIGGER if IIO_BUFFER
depends on !IIO_BUFFER || IIO_KFIFO_BUF
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say Y here to build SPI support for the ST microelectronics
accelerometer. The driver supplies direct access via sysfs files

View file

@ -5,7 +5,7 @@ menu "Analog to digital converters"
config AD7606
tristate "Analog Devices AD7606 ADC driver"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
@ -39,7 +39,7 @@ config AD7606_IFACE_SPI
config AD7780
tristate "Analog Devices AD7780 and similar ADCs driver"
depends on SPI
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
select AD_SIGMA_DELTA
help
Say yes here to build support for Analog Devices AD7170, AD7171,
@ -52,7 +52,7 @@ config AD7780
config AD7816
tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver"
depends on SPI
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices AD7816/7/8
temperature sensors and ADC.

View file

@ -5,7 +5,7 @@ menu "Analog digital bi-direction converters"
config ADT7316
tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver"
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318
and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC.

View file

@ -16,7 +16,7 @@ config AD2S90
config AD2S1200
tristate "Analog Devices ad2s1200/ad2s1205 driver"
depends on SPI
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s1200 and ad2s1205, provides direct access
@ -28,7 +28,7 @@ config AD2S1200
config AD2S1210
tristate "Analog Devices ad2s1210 driver"
depends on SPI
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say yes here to build support for Analog Devices spi resolver
to digital converters, ad2s1210, provides direct access via sysfs.

View file

@ -32,6 +32,7 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
IIO_CHAN_INFO_AVERAGE_RAW,
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY,
IIO_CHAN_INFO_SAMP_FREQ,
IIO_CHAN_INFO_FREQUENCY,
IIO_CHAN_INFO_PHASE,
@ -44,6 +45,7 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_DEBOUNCE_COUNT,
IIO_CHAN_INFO_DEBOUNCE_TIME,
IIO_CHAN_INFO_CALIBEMISSIVITY,
IIO_CHAN_INFO_OVERSAMPLING_RATIO,
};
enum iio_shared_by {

View file

@ -17,6 +17,8 @@ enum iio_event_info {
IIO_EV_INFO_VALUE,
IIO_EV_INFO_HYSTERESIS,
IIO_EV_INFO_PERIOD,
IIO_EV_INFO_HIGH_PASS_FILTER_3DB,
IIO_EV_INFO_LOW_PASS_FILTER_3DB,
};
#define IIO_VAL_INT 1

View file

@ -70,6 +70,8 @@ enum iio_modifier {
IIO_MOD_WALKING,
IIO_MOD_STILL,
IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
IIO_MOD_I,
IIO_MOD_Q,
};
enum iio_event_type {

View file

@ -1,5 +1,5 @@
CC = gcc
CFLAGS = -Wall -g -D_GNU_SOURCE
CC = $(CROSS_COMPILE)gcc
CFLAGS += -Wall -g -D_GNU_SOURCE
all: iio_event_monitor lsiio generic_buffer