Commit 040bf7d6 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-3.17d' of...

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

Jonathan writes:

Fourth round of IIO new drivers, functionality and cleanups for the 3.17 cycle

New functionality
* A new modifier to indicate that a rotation is relative to either
  true or magnetic north.  This is to be used by some magnetometers
  that provide data in this way.
* hid magnetometer now supports output rotations from various variants on
  North
* HMC5843 driver converted to regmap and reworked to allow easy support
  of other similar devices.  Support for HMC5983 added via both i2c and SPI.
* Rework of Exynos driver to simplify extension to support more devices.
* Addition of support for the Exynos3250 ADC (which requires an additional
  clock)  Support for quite a few more devices on its way.

Cleanups
* ad7997 - a number of cleanups and tweaks to how the events are controlled
  to make it more intuitive.
* kxcjk - cleanups and minor fixes for this new driver.
parents 16fae052 e6ca2d84
...@@ -260,6 +260,10 @@ What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale ...@@ -260,6 +260,10 @@ What: /sys/bus/iio/devices/iio:deviceX/in_magn_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_scale
What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_scale
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_scale
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_scale
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_scale
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale What: /sys/bus/iio/devices/iio:deviceX/in_pressure_scale
KernelVersion: 2.6.35 KernelVersion: 2.6.35
...@@ -447,6 +451,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en ...@@ -447,6 +451,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en What: /sys/.../iio:deviceX/events/in_magn_y_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en What: /sys/.../iio:deviceX/events/in_magn_z_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en What: /sys/.../iio:deviceX/events/in_magn_z_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en What: /sys/.../iio:deviceX/events/in_voltageY_supply_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en What: /sys/.../iio:deviceX/events/in_voltageY_thresh_rising_en
...@@ -492,6 +504,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_roc_rising_en ...@@ -492,6 +504,14 @@ What: /sys/.../iio:deviceX/events/in_magn_y_roc_rising_en
What: /sys/.../iio:deviceX/events/in_magn_y_roc_falling_en What: /sys/.../iio:deviceX/events/in_magn_y_roc_falling_en
What: /sys/.../iio:deviceX/events/in_magn_z_roc_rising_en What: /sys/.../iio:deviceX/events/in_magn_z_roc_rising_en
What: /sys/.../iio:deviceX/events/in_magn_z_roc_falling_en What: /sys/.../iio:deviceX/events/in_magn_z_roc_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_roc_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_roc_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_roc_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_magnetic_tilt_comp_roc_falling_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_rising_en
What: /sys/.../iio:deviceX/events/in_rot_from_north_true_tilt_comp_roc_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_rising_en
What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en What: /sys/.../iio:deviceX/events/in_voltageY_supply_roc_falling_en
What: /sys/.../iio:deviceX/events/in_voltageY_roc_rising_en What: /sys/.../iio:deviceX/events/in_voltageY_roc_rising_en
...@@ -538,6 +558,14 @@ What: /sys/.../events/in_magn_y_raw_thresh_rising_value ...@@ -538,6 +558,14 @@ What: /sys/.../events/in_magn_y_raw_thresh_rising_value
What: /sys/.../events/in_magn_y_raw_thresh_falling_value What: /sys/.../events/in_magn_y_raw_thresh_falling_value
What: /sys/.../events/in_magn_z_raw_thresh_rising_value What: /sys/.../events/in_magn_z_raw_thresh_rising_value
What: /sys/.../events/in_magn_z_raw_thresh_falling_value What: /sys/.../events/in_magn_z_raw_thresh_falling_value
What: /sys/.../events/in_rot_from_north_magnetic_raw_thresh_rising_value
What: /sys/.../events/in_rot_from_north_magnetic_raw_thresh_falling_value
What: /sys/.../events/in_rot_from_north_true_raw_thresh_rising_value
What: /sys/.../events/in_rot_from_north_true_raw_thresh_falling_value
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_rising_value
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_thresh_falling_value
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_rising_value
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_thresh_falling_value
What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value
What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value
What: /sys/.../events/in_voltageY_raw_thresh_rising_value What: /sys/.../events/in_voltageY_raw_thresh_rising_value
...@@ -588,6 +616,18 @@ What: /sys/.../events/in_magn_y_thresh_either_hysteresis ...@@ -588,6 +616,18 @@ What: /sys/.../events/in_magn_y_thresh_either_hysteresis
What: /sys/.../events/in_magn_z_thresh_rising_hysteresis What: /sys/.../events/in_magn_z_thresh_rising_hysteresis
What: /sys/.../events/in_magn_z_thresh_falling_hysteresis What: /sys/.../events/in_magn_z_thresh_falling_hysteresis
What: /sys/.../events/in_magn_z_thresh_either_hysteresis What: /sys/.../events/in_magn_z_thresh_either_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_thresh_rising_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_thresh_falling_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_thresh_either_hysteresis
What: /sys/.../events/in_rot_from_north_true_thresh_rising_hysteresis
What: /sys/.../events/in_rot_from_north_true_thresh_falling_hysteresis
What: /sys/.../events/in_rot_from_north_true_thresh_either_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_hysteresis
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_either_hysteresis
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_hysteresis
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_hysteresis
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_either_hysteresis
What: /sys/.../events/in_voltageY_thresh_rising_hysteresis What: /sys/.../events/in_voltageY_thresh_rising_hysteresis
What: /sys/.../events/in_voltageY_thresh_falling_hysteresis What: /sys/.../events/in_voltageY_thresh_falling_hysteresis
What: /sys/.../events/in_voltageY_thresh_either_hysteresis What: /sys/.../events/in_voltageY_thresh_either_hysteresis
...@@ -635,6 +675,14 @@ What: /sys/.../events/in_magn_y_raw_roc_rising_value ...@@ -635,6 +675,14 @@ What: /sys/.../events/in_magn_y_raw_roc_rising_value
What: /sys/.../events/in_magn_y_raw_roc_falling_value What: /sys/.../events/in_magn_y_raw_roc_falling_value
What: /sys/.../events/in_magn_z_raw_roc_rising_value What: /sys/.../events/in_magn_z_raw_roc_rising_value
What: /sys/.../events/in_magn_z_raw_roc_falling_value What: /sys/.../events/in_magn_z_raw_roc_falling_value
What: /sys/.../events/in_rot_from_north_magnetic_raw_roc_rising_value
What: /sys/.../events/in_rot_from_north_magnetic_raw_roc_falling_value
What: /sys/.../events/in_rot_from_north_true_raw_roc_rising_value
What: /sys/.../events/in_rot_from_north_true_raw_roc_falling_value
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_rising_value
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_raw_roc_falling_value
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_rising_value
What: /sys/.../events/in_rot_from_north_true_tilt_comp_raw_roc_falling_value
What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value
What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value
What: /sys/.../events/in_voltageY_raw_roc_rising_value What: /sys/.../events/in_voltageY_raw_roc_rising_value
...@@ -690,6 +738,22 @@ What: /sys/.../events/in_magn_z_thresh_rising_period ...@@ -690,6 +738,22 @@ What: /sys/.../events/in_magn_z_thresh_rising_period
What: /sys/.../events/in_magn_z_thresh_falling_period What: /sys/.../events/in_magn_z_thresh_falling_period
What: /sys/.../events/in_magn_z_roc_rising_period What: /sys/.../events/in_magn_z_roc_rising_period
What: /sys/.../events/in_magn_z_roc_falling_period What: /sys/.../events/in_magn_z_roc_falling_period
What: /sys/.../events/in_rot_from_north_magnetic_thresh_rising_period
What: /sys/.../events/in_rot_from_north_magnetic_thresh_falling_period
What: /sys/.../events/in_rot_from_north_magnetic_roc_rising_period
What: /sys/.../events/in_rot_from_north_magnetic_roc_falling_period
What: /sys/.../events/in_rot_from_north_true_thresh_rising_period
What: /sys/.../events/in_rot_from_north_true_thresh_falling_period
What: /sys/.../events/in_rot_from_north_true_roc_rising_period
What: /sys/.../events/in_rot_from_north_true_roc_falling_period
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_rising_period
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_thresh_falling_period
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_rising_period
What: /sys/.../events/in_rot_from_north_magnetic_tilt_comp_roc_falling_period
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_rising_period
What: /sys/.../events/in_rot_from_north_true_tilt_comp_thresh_falling_period
What: /sys/.../events/in_rot_from_north_true_tilt_comp_roc_rising_period
What: /sys/.../events/in_rot_from_north_true_tilt_comp_roc_falling_period
What: /sys/.../events/in_voltageY_supply_thresh_rising_period What: /sys/.../events/in_voltageY_supply_thresh_rising_period
What: /sys/.../events/in_voltageY_supply_thresh_falling_period What: /sys/.../events/in_voltageY_supply_thresh_falling_period
What: /sys/.../events/in_voltageY_supply_roc_rising_period What: /sys/.../events/in_voltageY_supply_roc_rising_period
...@@ -787,6 +851,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_en ...@@ -787,6 +851,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_en
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_en What: /sys/.../iio:deviceX/scan_elements/in_magn_x_en
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_en What: /sys/.../iio:deviceX/scan_elements/in_magn_y_en
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_en What: /sys/.../iio:deviceX/scan_elements/in_magn_z_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_en
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_en
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en 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_supply_en
What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en
...@@ -853,6 +921,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_index ...@@ -853,6 +921,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_anglvel_z_index
What: /sys/.../iio:deviceX/scan_elements/in_magn_x_index What: /sys/.../iio:deviceX/scan_elements/in_magn_x_index
What: /sys/.../iio:deviceX/scan_elements/in_magn_y_index What: /sys/.../iio:deviceX/scan_elements/in_magn_y_index
What: /sys/.../iio:deviceX/scan_elements/in_magn_z_index What: /sys/.../iio:deviceX/scan_elements/in_magn_z_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_magnetic_tilt_comp_index
What: /sys/.../iio:deviceX/scan_elements/in_rot_from_north_true_tilt_comp_index
What: /sys/.../iio:deviceX/scan_elements/in_incli_x_index What: /sys/.../iio:deviceX/scan_elements/in_incli_x_index
What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index What: /sys/.../iio:deviceX/scan_elements/in_incli_y_index
What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index What: /sys/.../iio:deviceX/scan_elements/in_timestamp_index
...@@ -946,3 +1018,13 @@ Description: ...@@ -946,3 +1018,13 @@ Description:
x y z w. Here x, y, and z component represents the axis about x y z w. Here x, y, and z component represents the axis about
which a rotation will occur and w component represents the which a rotation will occur and w component represents the
amount of rotation. amount of rotation.
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_tilt_comp_raw
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_tilt_comp_raw
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_magnetic_raw
What: /sys/bus/iio/devices/iio:deviceX/in_rot_from_north_true_raw
KernelVersion: 3.15
Contact: linux-iio@vger.kernel.org
Description:
Raw value of rotation from true/magnetic north measured with
or without compensation from tilt sensors.
...@@ -14,14 +14,21 @@ Required properties: ...@@ -14,14 +14,21 @@ Required properties:
for exynos4412/5250 controllers. for exynos4412/5250 controllers.
Must be "samsung,exynos-adc-v2" for Must be "samsung,exynos-adc-v2" for
future controllers. future controllers.
Must be "samsung,exynos3250-adc" for
controllers compatible with ADC of Exynos3250.
- reg: Contains ADC register address range (base address and - reg: Contains ADC register address range (base address and
length) and the address of the phy enable register. length) and the address of the phy enable register.
- interrupts: Contains the interrupt information for the timer. The - interrupts: Contains the interrupt information for the timer. The
format is being dependent on which interrupt controller format is being dependent on which interrupt controller
the Samsung device uses. the Samsung device uses.
- #io-channel-cells = <1>; As ADC has multiple outputs - #io-channel-cells = <1>; As ADC has multiple outputs
- clocks From common clock binding: handle to adc clock. - clocks From common clock bindings: handles to clocks specified
- clock-names From common clock binding: Shall be "adc". in "clock-names" property, in the same order.
- clock-names From common clock bindings: list of clock input names
used by ADC block:
- "adc" : ADC bus clock
- "sclk" : ADC special clock (only for Exynos3250 and
compatible ADC block)
- vdd-supply VDD input supply. - vdd-supply VDD input supply.
Note: child nodes can be added for auto probing from device tree. Note: child nodes can be added for auto probing from device tree.
...@@ -41,6 +48,20 @@ adc: adc@12D10000 { ...@@ -41,6 +48,20 @@ adc: adc@12D10000 {
vdd-supply = <&buck5_reg>; vdd-supply = <&buck5_reg>;
}; };
Example: adding device info in dtsi file for Exynos3250 with additional sclk
adc: adc@126C0000 {
compatible = "samsung,exynos3250-adc", "samsung,exynos-adc-v2;
reg = <0x126C0000 0x100>, <0x10020718 0x4>;
interrupts = <0 137 0>;
#io-channel-cells = <1>;
io-channel-ranges;
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
clock-names = "adc", "sclk";
vdd-supply = <&buck5_reg>;
};
Example: Adding child nodes in dts file Example: Adding child nodes in dts file
......
...@@ -6,6 +6,7 @@ Required properties: ...@@ -6,6 +6,7 @@ Required properties:
Other models which are supported with driver are: Other models which are supported with driver are:
"honeywell,hmc5883" "honeywell,hmc5883"
"honeywell,hmc5883l" "honeywell,hmc5883l"
"honeywell,hmc5983"
- reg : the I2C address of the magnetometer - typically 0x1e - reg : the I2C address of the magnetometer - typically 0x1e
Optional properties: Optional properties:
......
...@@ -261,10 +261,11 @@ pdma1: pdma@12690000 { ...@@ -261,10 +261,11 @@ pdma1: pdma@12690000 {
}; };
adc: adc@126C0000 { adc: adc@126C0000 {
compatible = "samsung,exynos-adc-v3"; compatible = "samsung,exynos3250-adc",
"samsung,exynos-adc-v2";
reg = <0x126C0000 0x100>, <0x10020718 0x4>; reg = <0x126C0000 0x100>, <0x10020718 0x4>;
interrupts = <0 137 0>; interrupts = <0 137 0>;
clock-names = "adc", "sclk_tsadc"; clock-names = "adc", "sclk";
clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>; clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
#io-channel-cells = <1>; #io-channel-cells = <1>;
io-channel-ranges; io-channel-ranges;
......
...@@ -98,7 +98,7 @@ static const struct { ...@@ -98,7 +98,7 @@ static const struct {
int val2; int val2;
int odr_bits; int odr_bits;
} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09}, } samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09},
{3, 125000, 0x0A}, {6, 25000, 0x0B}, {12, 5000, 0}, {3, 125000, 0x0A}, {6, 250000, 0x0B}, {12, 500000, 0},
{25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03}, {25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03},
{200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06}, {200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06},
{1600, 0, 0x07} }; {1600, 0, 0x07} };
...@@ -138,19 +138,6 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, ...@@ -138,19 +138,6 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
return 0; return 0;
} }
static int kxcjk1013_chip_ack_intr(struct kxcjk1013_data *data)
{
int ret;
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
if (ret < 0) {
dev_err(&data->client->dev, "Error writing reg_int_rel\n");
return ret;
}
return ret;
}
static int kxcjk1013_chip_init(struct kxcjk1013_data *data) static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
{ {
int ret; int ret;
...@@ -466,7 +453,7 @@ static const struct attribute_group kxcjk1013_attrs_group = { ...@@ -466,7 +453,7 @@ static const struct attribute_group kxcjk1013_attrs_group = {
.realbits = 12, \ .realbits = 12, \
.storagebits = 16, \ .storagebits = 16, \
.shift = 4, \ .shift = 4, \
.endianness = IIO_LE, \ .endianness = IIO_CPU, \
}, \ }, \
} }
...@@ -498,15 +485,11 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) ...@@ -498,15 +485,11 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
indio_dev->masklength) { indio_dev->masklength) {
ret = kxcjk1013_get_acc_reg(data, bit); ret = kxcjk1013_get_acc_reg(data, bit);
if (ret < 0) { if (ret < 0) {
kxcjk1013_chip_ack_intr(data);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
goto err; goto err;
} }
data->buffer[i++] = ret; data->buffer[i++] = ret;
} }
kxcjk1013_chip_ack_intr(data);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
...@@ -517,6 +500,21 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) ...@@ -517,6 +500,21 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int kxcjk1013_trig_try_reen(struct iio_trigger *trig)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
if (ret < 0) {
dev_err(&data->client->dev, "Error reading reg_int_rel\n");
return ret;
}
return 0;
}
static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state) bool state)
{ {
...@@ -543,6 +541,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, ...@@ -543,6 +541,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
static const struct iio_trigger_ops kxcjk1013_trigger_ops = { static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
.set_trigger_state = kxcjk1013_data_rdy_trigger_set_state, .set_trigger_state = kxcjk1013_data_rdy_trigger_set_state,
.try_reenable = kxcjk1013_trig_try_reen,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
...@@ -645,6 +644,7 @@ static int kxcjk1013_probe(struct i2c_client *client, ...@@ -645,6 +644,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
iio_trigger_set_drvdata(trig, indio_dev); iio_trigger_set_drvdata(trig, indio_dev);
data->trig = trig; data->trig = trig;
indio_dev->trig = trig; indio_dev->trig = trig;
iio_trigger_get(indio_dev->trig);
ret = iio_trigger_register(trig); ret = iio_trigger_register(trig);
if (ret) if (ret)
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/bitops.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
...@@ -41,7 +42,7 @@ ...@@ -41,7 +42,7 @@
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#define AD799X_CHANNEL_SHIFT 4 #define AD799X_CHANNEL_SHIFT 4
#define AD799X_STORAGEBITS 16
/* /*
* AD7991, AD7995 and AD7999 defines * AD7991, AD7995 and AD7999 defines
*/ */
...@@ -55,10 +56,10 @@ ...@@ -55,10 +56,10 @@
* AD7992, AD7993, AD7994, AD7997 and AD7998 defines * AD7992, AD7993, AD7994, AD7997 and AD7998 defines
*/ */
#define AD7998_FLTR 0x08 #define AD7998_FLTR BIT(3)
#define AD7998_ALERT_EN 0x04 #define AD7998_ALERT_EN BIT(2)
#define AD7998_BUSY_ALERT 0x02 #define AD7998_BUSY_ALERT BIT(1)
#define AD7998_BUSY_ALERT_POL 0x01 #define AD7998_BUSY_ALERT_POL BIT(0)
#define AD7998_CONV_RES_REG 0x0 #define AD7998_CONV_RES_REG 0x0
#define AD7998_ALERT_STAT_REG 0x1 #define AD7998_ALERT_STAT_REG 0x1
...@@ -69,7 +70,7 @@ ...@@ -69,7 +70,7 @@
#define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5) #define AD7998_DATAHIGH_REG(x) ((x) * 3 + 0x5)
#define AD7998_HYST_REG(x) ((x) * 3 + 0x6) #define AD7998_HYST_REG(x) ((x) * 3 + 0x6)
#define AD7998_CYC_MASK 0x7 #define AD7998_CYC_MASK GENMASK(2, 0)
#define AD7998_CYC_DIS 0x0 #define AD7998_CYC_DIS 0x0
#define AD7998_CYC_TCONF_32 0x1 #define AD7998_CYC_TCONF_32 0x1
#define AD7998_CYC_TCONF_64 0x2 #define AD7998_CYC_TCONF_64 0x2
...@@ -85,10 +86,8 @@ ...@@ -85,10 +86,8 @@
* AD7997 and AD7997 defines * AD7997 and AD7997 defines
*/ */
#define AD7997_8_READ_SINGLE 0x80 #define AD7997_8_READ_SINGLE BIT(7)
#define AD7997_8_READ_SEQUENCE 0x70 #define AD7997_8_READ_SEQUENCE (BIT(6) | BIT(5) | BIT(4))
/* TODO: move this into a common header */
#define RES_MASK(bits) ((1 << (bits)) - 1)
enum { enum {
ad7991, ad7991,
...@@ -102,22 +101,32 @@ enum { ...@@ -102,22 +101,32 @@ enum {
}; };
/** /**
* struct ad799x_chip_info - chip specific information * struct ad799x_chip_config - chip specific information
* @channel: channel specification * @channel: channel specification
* @num_channels: number of channels
* @default_config: device default configuration * @default_config: device default configuration
* @info: pointer to iio_info struct * @info: pointer to iio_info struct
*/ */
struct ad799x_chip_info { struct ad799x_chip_config {
struct iio_chan_spec channel[9]; const struct iio_chan_spec channel[9];
int num_channels;
u16 default_config; u16 default_config;
const struct iio_info *info; const struct iio_info *info;
}; };
/**
* struct ad799x_chip_info - chip specific information
* @num_channels: number of channels
* @noirq_config: device configuration w/o IRQ
* @irq_config: device configuration w/IRQ
*/
struct ad799x_chip_info {
int num_channels;
const struct ad799x_chip_config noirq_config;
const struct ad799x_chip_config irq_config;
};
struct ad799x_state { struct ad799x_state {
struct i2c_client *client; struct i2c_client *client;
const struct ad799x_chip_info *chip_info; const struct ad799x_chip_config *chip_config;
struct regulator *reg; struct regulator *reg;
struct regulator *vref; struct regulator *vref;
unsigned id; unsigned id;
...@@ -127,6 +136,30 @@ struct ad799x_state { ...@@ -127,6 +136,30 @@ struct ad799x_state {
unsigned int transfer_size; unsigned int transfer_size;
}; };
static int ad799x_write_config(struct ad799x_state *st, u16 val)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
val);
default:
return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
val);
}
}
static int ad799x_read_config(struct ad799x_state *st)
{
switch (st->id) {
case ad7997:
case ad7998:
return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
default:
return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
}
}
/** /**
* ad799x_trigger_handler() bh of trigger launched polling to ring buffer * ad799x_trigger_handler() bh of trigger launched polling to ring buffer
* *
...@@ -175,66 +208,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) ...@@ -175,66 +208,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
/* static int ad799x_update_scan_mode(struct iio_dev *indio_dev,
* ad799x register access by I2C
*/
static int ad799x_i2c_read16(struct ad799x_state *st, u8 reg, u16 *data)
{
struct i2c_client *client = st->client;
int ret = 0;
ret = i2c_smbus_read_word_swapped(client, reg);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
*data = (u16)ret;
return 0;
}
static int ad799x_i2c_read8(struct ad799x_state *st, u8 reg, u8 *data)
{
struct i2c_client *client = st->client;
int ret = 0;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "I2C read error\n");
return ret;
}
*data = (u8)ret;
return 0;
}
static int ad799x_i2c_write16(struct ad799x_state *st, u8 reg, u16 data)
{
struct i2c_client *client = st->client;
int ret = 0;
ret = i2c_smbus_write_word_swapped(client, reg, data);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
return ret;
}
static int ad799x_i2c_write8(struct ad799x_state *st, u8 reg, u8 data)
{
struct i2c_client *client = st->client;
int ret = 0;
ret = i2c_smbus_write_byte_data(client, reg, data);
if (ret < 0)
dev_err(&client->dev, "I2C write error\n");
return ret;
}
static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask) const unsigned long *scan_mask)
{ {
struct ad799x_state *st = iio_priv(indio_dev); struct ad799x_state *st = iio_priv(indio_dev);
...@@ -247,33 +221,33 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev, ...@@ -247,33 +221,33 @@ static int ad7997_8_update_scan_mode(struct iio_dev *indio_dev,
st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2; st->transfer_size = bitmap_weight(scan_mask, indio_dev->masklength) * 2;
switch (st->id) { switch (st->id) {
case ad7992:
case ad7993:
case ad7994:
case ad7997: case ad7997:
case ad7998: case ad7998:
return ad799x_i2c_write16(st, AD7998_CONF_REG, st->config &= ~(GENMASK(7, 0) << AD799X_CHANNEL_SHIFT);
st->config | (*scan_mask << AD799X_CHANNEL_SHIFT)); st->config |= (*scan_mask << AD799X_CHANNEL_SHIFT);
return ad799x_write_config(st, st->config);
default: default:
break;
}
return 0; return 0;
}
} }
static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
{ {
u16 rxbuf;
u8 cmd; u8 cmd;
int ret;
switch (st->id) { switch (st->id) {
case ad7991: case ad7991:
case ad7995: case ad7995:
case ad7999: case ad7999:
cmd = st->config | ((1 << ch) << AD799X_CHANNEL_SHIFT); cmd = st->config | (BIT(ch) << AD799X_CHANNEL_SHIFT);
break; break;
case ad7992: case ad7992:
case ad7993: case ad7993:
case ad7994: case ad7994:
cmd = (1 << ch) << AD799X_CHANNEL_SHIFT; cmd = BIT(ch) << AD799X_CHANNEL_SHIFT;
break; break;
case ad7997: case ad7997:
case ad7998: case ad7998:
...@@ -283,11 +257,7 @@ static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch) ...@@ -283,11 +257,7 @@ static int ad799x_scan_direct(struct ad799x_state *st, unsigned ch)
return -EINVAL; return -EINVAL;
} }
ret = ad799x_i2c_read16(st, cmd, &rxbuf); return i2c_smbus_read_word_swapped(st->client, cmd);
if (ret < 0)
return ret;
return rxbuf;
} }
static int ad799x_read_raw(struct iio_dev *indio_dev, static int ad799x_read_raw(struct iio_dev *indio_dev,
...@@ -311,7 +281,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev, ...@@ -311,7 +281,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
if (ret < 0) if (ret < 0)
return ret; return ret;
*val = (ret >> chan->scan_type.shift) & *val = (ret >> chan->scan_type.shift) &
RES_MASK(chan->scan_type.realbits); GENMASK(chan->scan_type.realbits - 1, 0);
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
ret = regulator_get_voltage(st->vref); ret = regulator_get_voltage(st->vref);
...@@ -332,6 +302,7 @@ static const unsigned int ad7998_frequencies[] = { ...@@ -332,6 +302,7 @@ static const unsigned int ad7998_frequencies[] = {
[AD7998_CYC_TCONF_1024] = 488, [AD7998_CYC_TCONF_1024] = 488,
[AD7998_CYC_TCONF_2048] = 244, [AD7998_CYC_TCONF_2048] = 244,
}; };
static ssize_t ad799x_read_frequency(struct device *dev, static ssize_t ad799x_read_frequency(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
char *buf) char *buf)
...@@ -339,15 +310,11 @@ static ssize_t ad799x_read_frequency(struct device *dev, ...@@ -339,15 +310,11 @@ static ssize_t ad799x_read_frequency(struct device *dev,
struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev); struct ad799x_state *st = iio_priv(indio_dev);
int ret; int ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
u8 val; if (ret < 0)
ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &val);
if (ret)
return ret; return ret;
val &= AD7998_CYC_MASK; return sprintf(buf, "%u\n", ad7998_frequencies[ret & AD7998_CYC_MASK]);
return sprintf(buf, "%u\n", ad7998_frequencies[val]);
} }
static ssize_t ad799x_write_frequency(struct device *dev, static ssize_t ad799x_write_frequency(struct device *dev,
...@@ -360,18 +327,17 @@ static ssize_t ad799x_write_frequency(struct device *dev, ...@@ -360,18 +327,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
long val; long val;
int ret, i; int ret, i;
u8 t;
ret = kstrtol(buf, 10, &val); ret = kstrtol(buf, 10, &val);
if (ret) if (ret)
return ret; return ret;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = ad799x_i2c_read8(st, AD7998_CYCLE_TMR_REG, &t); ret = i2c_smbus_read_byte_data(st->client, AD7998_CYCLE_TMR_REG);
if (ret) if (ret < 0)
goto error_ret_mutex; goto error_ret_mutex;
/* Wipe the bits clean */ /* Wipe the bits clean */
t &= ~AD7998_CYC_MASK; ret &= ~AD7998_CYC_MASK;
for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++) for (i = 0; i < ARRAY_SIZE(ad7998_frequencies); i++)
if (val == ad7998_frequencies[i]) if (val == ad7998_frequencies[i])
...@@ -380,13 +346,17 @@ static ssize_t ad799x_write_frequency(struct device *dev, ...@@ -380,13 +346,17 @@ static ssize_t ad799x_write_frequency(struct device *dev,
ret = -EINVAL; ret = -EINVAL;
goto error_ret_mutex; goto error_ret_mutex;
} }
t |= i;
ret = ad799x_i2c_write8(st, AD7998_CYCLE_TMR_REG, t); ret = i2c_smbus_write_byte_data(st->client, AD7998_CYCLE_TMR_REG,
ret | i);
if (ret < 0)
goto error_ret_mutex;
ret = len;
error_ret_mutex: error_ret_mutex:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return ret ? ret : len; return ret;
} }
static int ad799x_read_event_config(struct iio_dev *indio_dev, static int ad799x_read_event_config(struct iio_dev *indio_dev,
...@@ -394,7 +364,48 @@ static int ad799x_read_event_config(struct iio_dev *indio_dev, ...@@ -394,7 +364,48 @@ static int ad799x_read_event_config(struct iio_dev *indio_dev,
enum iio_event_type type, enum iio_event_type type,
enum iio_event_direction dir) enum iio_event_direction dir)
{ {
struct ad799x_state *st = iio_priv(indio_dev);
if (!(st->config & AD7998_ALERT_EN))
return 0;
if ((st->config >> AD799X_CHANNEL_SHIFT) & BIT(chan->scan_index))
return 1; return 1;
return 0;
}
static int ad799x_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)
{
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto done;
}
if (state)
st->config |= BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT;
else
st->config &= ~(BIT(chan->scan_index) << AD799X_CHANNEL_SHIFT);
if (st->config >> AD799X_CHANNEL_SHIFT)
st->config |= AD7998_ALERT_EN;
else
st->config &= ~AD7998_ALERT_EN;
ret = ad799x_write_config(st, st->config);
done:
mutex_unlock(&indio_dev->mlock);
return ret;
} }
static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan, static unsigned int ad799x_threshold_reg(const struct iio_chan_spec *chan,
...@@ -426,11 +437,12 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev, ...@@ -426,11 +437,12 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
int ret; int ret;
struct ad799x_state *st = iio_priv(indio_dev); struct ad799x_state *st = iio_priv(indio_dev);
if (val < 0 || val > RES_MASK(chan->scan_type.realbits)) if (val < 0 || val > GENMASK(chan->scan_type.realbits - 1, 0))
return -EINVAL; return -EINVAL;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = ad799x_i2c_write16(st, ad799x_threshold_reg(chan, dir, info), ret = i2c_smbus_write_word_swapped(st->client,
ad799x_threshold_reg(chan, dir, info),
val << chan->scan_type.shift); val << chan->scan_type.shift);
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
...@@ -446,16 +458,15 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev, ...@@ -446,16 +458,15 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
{ {
int ret; int ret;
struct ad799x_state *st = iio_priv(indio_dev); struct ad799x_state *st = iio_priv(indio_dev);
u16 valin;
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
ret = ad799x_i2c_read16(st, ad799x_threshold_reg(chan, dir, info), ret = i2c_smbus_read_word_swapped(st->client,
&valin); ad799x_threshold_reg(chan, dir, info));
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
if (ret < 0) if (ret < 0)
return ret; return ret;
*val = (valin >> chan->scan_type.shift) & *val = (ret >> chan->scan_type.shift) &
RES_MASK(chan->scan_type.realbits); GENMASK(chan->scan_type.realbits - 1 , 0);
return IIO_VAL_INT; return IIO_VAL_INT;
} }
...@@ -464,20 +475,18 @@ static irqreturn_t ad799x_event_handler(int irq, void *private) ...@@ -464,20 +475,18 @@ static irqreturn_t ad799x_event_handler(int irq, void *private)
{ {
struct iio_dev *indio_dev = private; struct iio_dev *indio_dev = private;
struct ad799x_state *st = iio_priv(private); struct ad799x_state *st = iio_priv(private);
u8 status;
int i, ret; int i, ret;
ret = ad799x_i2c_read8(st, AD7998_ALERT_STAT_REG, &status); ret = i2c_smbus_read_byte_data(st->client, AD7998_ALERT_STAT_REG);
if (ret) if (ret <= 0)
goto done; goto done;
if (!status) if (i2c_smbus_write_byte_data(st->client, AD7998_ALERT_STAT_REG,
AD7998_ALERT_STAT_CLEAR) < 0)
goto done; goto done;
ad799x_i2c_write8(st, AD7998_ALERT_STAT_REG, AD7998_ALERT_STAT_CLEAR);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (status & (1 << i)) if (ret & BIT(i))
iio_push_event(indio_dev, iio_push_event(indio_dev,
i & 0x1 ? i & 0x1 ?
IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE,
...@@ -516,14 +525,21 @@ static const struct iio_info ad7991_info = { ...@@ -516,14 +525,21 @@ static const struct iio_info ad7991_info = {
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };
static const struct iio_info ad7993_4_7_8_info = { static const struct iio_info ad7993_4_7_8_noirq_info = {
.read_raw = &ad799x_read_raw,
.driver_module = THIS_MODULE,
.update_scan_mode = ad799x_update_scan_mode,
};
static const struct iio_info ad7993_4_7_8_irq_info = {
.read_raw = &ad799x_read_raw, .read_raw = &ad799x_read_raw,
.event_attrs = &ad799x_event_attrs_group, .event_attrs = &ad799x_event_attrs_group,
.read_event_config = &ad799x_read_event_config, .read_event_config = &ad799x_read_event_config,
.write_event_config = &ad799x_write_event_config,
.read_event_value = &ad799x_read_event_value, .read_event_value = &ad799x_read_event_value,
.write_event_value = &ad799x_write_event_value, .write_event_value = &ad799x_write_event_value,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
.update_scan_mode = ad7997_8_update_scan_mode, .update_scan_mode = ad799x_update_scan_mode,
}; };
static const struct iio_event_spec ad799x_events[] = { static const struct iio_event_spec ad799x_events[] = {
...@@ -571,6 +587,8 @@ static const struct iio_event_spec ad799x_events[] = { ...@@ -571,6 +587,8 @@ static const struct iio_event_spec ad799x_events[] = {
static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
[ad7991] = { [ad7991] = {
.num_channels = 5,
.noirq_config = {
.channel = { .channel = {
AD799X_CHANNEL(0, 12), AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12), AD799X_CHANNEL(1, 12),
...@@ -578,10 +596,12 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -578,10 +596,12 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL(3, 12), AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}, },
.num_channels = 5,
.info = &ad7991_info, .info = &ad7991_info,
}, },
},
[ad7995] = { [ad7995] = {
.num_channels = 5,
.noirq_config = {
.channel = { .channel = {
AD799X_CHANNEL(0, 10), AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10), AD799X_CHANNEL(1, 10),
...@@ -589,10 +609,12 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -589,10 +609,12 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL(3, 10), AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}, },
.num_channels = 5,
.info = &ad7991_info, .info = &ad7991_info,
}, },
},
[ad7999] = { [ad7999] = {
.num_channels = 5,
.noirq_config = {
.channel = { .channel = {
AD799X_CHANNEL(0, 8), AD799X_CHANNEL(0, 8),
AD799X_CHANNEL(1, 8), AD799X_CHANNEL(1, 8),
...@@ -600,20 +622,42 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -600,20 +622,42 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL(3, 8), AD799X_CHANNEL(3, 8),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}, },
.num_channels = 5,
.info = &ad7991_info, .info = &ad7991_info,
}, },
},
[ad7992] = { [ad7992] = {
.num_channels = 3,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = { .channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12), AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12), AD799X_CHANNEL_WITH_EVENTS(1, 12),
IIO_CHAN_SOFT_TIMESTAMP(3), IIO_CHAN_SOFT_TIMESTAMP(3),
}, },
.num_channels = 3, .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.default_config = AD7998_ALERT_EN, .info = &ad7993_4_7_8_irq_info,
.info = &ad7993_4_7_8_info, },
}, },
[ad7993] = { [ad7993] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = { .channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10), AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10), AD799X_CHANNEL_WITH_EVENTS(1, 10),
...@@ -621,11 +665,23 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -621,11 +665,23 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL_WITH_EVENTS(3, 10), AD799X_CHANNEL_WITH_EVENTS(3, 10),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}, },
.num_channels = 5, .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.default_config = AD7998_ALERT_EN, .info = &ad7993_4_7_8_irq_info,
.info = &ad7993_4_7_8_info, },
}, },
[ad7994] = { [ad7994] = {
.num_channels = 5,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = { .channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12), AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12), AD799X_CHANNEL_WITH_EVENTS(1, 12),
...@@ -633,11 +689,27 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -633,11 +689,27 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL_WITH_EVENTS(3, 12), AD799X_CHANNEL_WITH_EVENTS(3, 12),
IIO_CHAN_SOFT_TIMESTAMP(4), IIO_CHAN_SOFT_TIMESTAMP(4),
}, },
.num_channels = 5, .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.default_config = AD7998_ALERT_EN, .info = &ad7993_4_7_8_irq_info,
.info = &ad7993_4_7_8_info, },
}, },
[ad7997] = { [ad7997] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 10),
AD799X_CHANNEL(1, 10),
AD799X_CHANNEL(2, 10),
AD799X_CHANNEL(3, 10),
AD799X_CHANNEL(4, 10),
AD799X_CHANNEL(5, 10),
AD799X_CHANNEL(6, 10),
AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = { .channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 10), AD799X_CHANNEL_WITH_EVENTS(0, 10),
AD799X_CHANNEL_WITH_EVENTS(1, 10), AD799X_CHANNEL_WITH_EVENTS(1, 10),
...@@ -649,11 +721,27 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -649,11 +721,27 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL(7, 10), AD799X_CHANNEL(7, 10),
IIO_CHAN_SOFT_TIMESTAMP(8), IIO_CHAN_SOFT_TIMESTAMP(8),
}, },
.num_channels = 9, .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.default_config = AD7998_ALERT_EN, .info = &ad7993_4_7_8_irq_info,
.info = &ad7993_4_7_8_info, },
}, },
[ad7998] = { [ad7998] = {
.num_channels = 9,
.noirq_config = {
.channel = {
AD799X_CHANNEL(0, 12),
AD799X_CHANNEL(1, 12),
AD799X_CHANNEL(2, 12),
AD799X_CHANNEL(3, 12),
AD799X_CHANNEL(4, 12),
AD799X_CHANNEL(5, 12),
AD799X_CHANNEL(6, 12),
AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8),
},
.info = &ad7993_4_7_8_noirq_info,
},
.irq_config = {
.channel = { .channel = {
AD799X_CHANNEL_WITH_EVENTS(0, 12), AD799X_CHANNEL_WITH_EVENTS(0, 12),
AD799X_CHANNEL_WITH_EVENTS(1, 12), AD799X_CHANNEL_WITH_EVENTS(1, 12),
...@@ -665,9 +753,9 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = { ...@@ -665,9 +753,9 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
AD799X_CHANNEL(7, 12), AD799X_CHANNEL(7, 12),
IIO_CHAN_SOFT_TIMESTAMP(8), IIO_CHAN_SOFT_TIMESTAMP(8),
}, },
.num_channels = 9, .default_config = AD7998_ALERT_EN | AD7998_BUSY_ALERT,
.default_config = AD7998_ALERT_EN, .info = &ad7993_4_7_8_irq_info,
.info = &ad7993_4_7_8_info, },
}, },
}; };
...@@ -677,6 +765,8 @@ static int ad799x_probe(struct i2c_client *client, ...@@ -677,6 +765,8 @@ static int ad799x_probe(struct i2c_client *client,
int ret; int ret;
struct ad799x_state *st; struct ad799x_state *st;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
const struct ad799x_chip_info *chip_info =
&ad799x_chip_info_tbl[id->driver_data];
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
if (indio_dev == NULL) if (indio_dev == NULL)
...@@ -687,8 +777,10 @@ static int ad799x_probe(struct i2c_client *client, ...@@ -687,8 +777,10 @@ static int ad799x_probe(struct i2c_client *client,
i2c_set_clientdata(client, indio_dev); i2c_set_clientdata(client, indio_dev);
st->id = id->driver_data; st->id = id->driver_data;
st->chip_info = &ad799x_chip_info_tbl[st->id]; if (client->irq > 0 && chip_info->irq_config.info)
st->config = st->chip_info->default_config; st->chip_config = &chip_info->irq_config;
else
st->chip_config = &chip_info->noirq_config;
/* TODO: Add pdata options for filtering and bit delay */ /* TODO: Add pdata options for filtering and bit delay */
...@@ -711,11 +803,19 @@ static int ad799x_probe(struct i2c_client *client, ...@@ -711,11 +803,19 @@ static int ad799x_probe(struct i2c_client *client,
indio_dev->dev.parent = &client->dev; indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name; indio_dev->name = id->name;
indio_dev->info = st->chip_info->info; indio_dev->info = st->chip_config->info;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channel; indio_dev->channels = st->chip_config->channel;
indio_dev->num_channels = st->chip_info->num_channels; indio_dev->num_channels = chip_info->num_channels;
ret = ad799x_write_config(st, st->chip_config->default_config);
if (ret < 0)
goto error_disable_reg;
ret = ad799x_read_config(st);
if (ret < 0)
goto error_disable_reg;
st->config = ret;
ret = iio_triggered_buffer_setup(indio_dev, NULL, ret = iio_triggered_buffer_setup(indio_dev, NULL,
&ad799x_trigger_handler, NULL); &ad799x_trigger_handler, NULL);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -39,11 +40,6 @@ ...@@ -39,11 +40,6 @@
#include <linux/iio/machine.h> #include <linux/iio/machine.h>
#include <linux/iio/driver.h> #include <linux/iio/driver.h>
enum adc_version {
ADC_V1,
ADC_V2
};
/* EXYNOS4412/5250 ADC_V1 registers definitions */ /* EXYNOS4412/5250 ADC_V1 registers definitions */
#define ADC_V1_CON(x) ((x) + 0x00) #define ADC_V1_CON(x) ((x) + 0x00)
#define ADC_V1_DLY(x) ((x) + 0x08) #define ADC_V1_DLY(x) ((x) + 0x08)
...@@ -77,6 +73,7 @@ enum adc_version { ...@@ -77,6 +73,7 @@ enum adc_version {
#define MAX_ADC_V2_CHANNELS 10 #define MAX_ADC_V2_CHANNELS 10
#define MAX_ADC_V1_CHANNELS 8 #define MAX_ADC_V1_CHANNELS 8
#define MAX_EXYNOS3250_ADC_CHANNELS 2
/* Bit definitions common for ADC_V1 and ADC_V2 */ /* Bit definitions common for ADC_V1 and ADC_V2 */
#define ADC_CON_EN_START (1u << 0) #define ADC_CON_EN_START (1u << 0)
...@@ -85,9 +82,12 @@ enum adc_version { ...@@ -85,9 +82,12 @@ enum adc_version {
#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
struct exynos_adc { struct exynos_adc {
struct exynos_adc_data *data;
struct device *dev;
void __iomem *regs; void __iomem *regs;
void __iomem *enable_reg; void __iomem *enable_reg;
struct clk *clk; struct clk *clk;
struct clk *sclk;
unsigned int irq; unsigned int irq;
struct regulator *vdd; struct regulator *vdd;
...@@ -97,26 +97,132 @@ struct exynos_adc { ...@@ -97,26 +97,132 @@ struct exynos_adc {
unsigned int version; unsigned int version;
}; };
static const struct of_device_id exynos_adc_match[] = { struct exynos_adc_data {
{ .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 }, int num_channels;
{ .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 }, bool needs_sclk;
{},
void (*init_hw)(struct exynos_adc *info);
void (*exit_hw)(struct exynos_adc *info);
void (*clear_irq)(struct exynos_adc *info);
void (*start_conv)(struct exynos_adc *info, unsigned long addr);
}; };
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) static void exynos_adc_unprepare_clk(struct exynos_adc *info)
{ {
const struct of_device_id *match; if (info->data->needs_sclk)
clk_unprepare(info->sclk);
clk_unprepare(info->clk);
}
match = of_match_node(exynos_adc_match, pdev->dev.of_node); static int exynos_adc_prepare_clk(struct exynos_adc *info)
return (unsigned int)match->data; {
int ret;
ret = clk_prepare(info->clk);
if (ret) {
dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_prepare(info->sclk);
if (ret) {
clk_unprepare(info->clk);
dev_err(info->dev,
"failed preparing sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
} }
static void exynos_adc_hw_init(struct exynos_adc *info) static void exynos_adc_disable_clk(struct exynos_adc *info)
{
if (info->data->needs_sclk)
clk_disable(info->sclk);
clk_disable(info->clk);
}
static int exynos_adc_enable_clk(struct exynos_adc *info)
{
int ret;
ret = clk_enable(info->clk);
if (ret) {
dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
return ret;
}
if (info->data->needs_sclk) {
ret = clk_enable(info->sclk);
if (ret) {
clk_disable(info->clk);
dev_err(info->dev,
"failed enabling sclk_adc clock: %d\n", ret);
return ret;
}
}
return 0;
}
static void exynos_adc_v1_init_hw(struct exynos_adc *info)
{
u32 con1;
writel(1, info->enable_reg);
/* set default prescaler values and Enable prescaler */
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
/* Enable 12-bit ADC resolution */
con1 |= ADC_V1_CON_RES;
writel(con1, ADC_V1_CON(info->regs));
}
static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
{
u32 con;
writel(0, info->enable_reg);
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
writel(con, ADC_V1_CON(info->regs));
}
static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V1_INTCLR(info->regs));
}
static void exynos_adc_v1_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1;
writel(addr, ADC_V1_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
}
static const struct exynos_adc_data exynos_adc_v1_data = {
.num_channels = MAX_ADC_V1_CHANNELS,
.init_hw = exynos_adc_v1_init_hw,
.exit_hw = exynos_adc_v1_exit_hw,
.clear_irq = exynos_adc_v1_clear_irq,
.start_conv = exynos_adc_v1_start_conv,
};
static void exynos_adc_v2_init_hw(struct exynos_adc *info)
{ {
u32 con1, con2; u32 con1, con2;
if (info->version == ADC_V2) { writel(1, info->enable_reg);
con1 = ADC_V2_CON1_SOFT_RESET; con1 = ADC_V2_CON1_SOFT_RESET;
writel(con1, ADC_V2_CON1(info->regs)); writel(con1, ADC_V2_CON1(info->regs));
...@@ -126,14 +232,78 @@ static void exynos_adc_hw_init(struct exynos_adc *info) ...@@ -126,14 +232,78 @@ static void exynos_adc_hw_init(struct exynos_adc *info)
/* Enable interrupts */ /* Enable interrupts */
writel(1, ADC_V2_INT_EN(info->regs)); writel(1, ADC_V2_INT_EN(info->regs));
} else { }
/* set default prescaler values and Enable prescaler */
con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
/* Enable 12-bit ADC resolution */ static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
con1 |= ADC_V1_CON_RES; {
writel(con1, ADC_V1_CON(info->regs)); u32 con;
}
writel(0, info->enable_reg);
con = readl(ADC_V2_CON1(info->regs));
con &= ~ADC_CON_EN_START;
writel(con, ADC_V2_CON1(info->regs));
}
static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
{
writel(1, ADC_V2_INT_ST(info->regs));
}
static void exynos_adc_v2_start_conv(struct exynos_adc *info,
unsigned long addr)
{
u32 con1, con2;
con2 = readl(ADC_V2_CON2(info->regs));
con2 &= ~ADC_V2_CON2_ACH_MASK;
con2 |= ADC_V2_CON2_ACH_SEL(addr);
writel(con2, ADC_V2_CON2(info->regs));
con1 = readl(ADC_V2_CON1(info->regs));
writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
}
static const struct exynos_adc_data exynos_adc_v2_data = {
.num_channels = MAX_ADC_V2_CHANNELS,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
};
static const struct exynos_adc_data exynos3250_adc_data = {
.num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
.needs_sclk = true,
.init_hw = exynos_adc_v2_init_hw,
.exit_hw = exynos_adc_v2_exit_hw,
.clear_irq = exynos_adc_v2_clear_irq,
.start_conv = exynos_adc_v2_start_conv,
};
static const struct of_device_id exynos_adc_match[] = {
{
.compatible = "samsung,exynos-adc-v1",
.data = &exynos_adc_v1_data,
}, {
.compatible = "samsung,exynos-adc-v2",
.data = &exynos_adc_v2_data,
}, {
.compatible = "samsung,exynos3250-adc",
.data = &exynos3250_adc_data,
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_adc_match);
static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
{
const struct of_device_id *match;
match = of_match_node(exynos_adc_match, pdev->dev.of_node);
return (struct exynos_adc_data *)match->data;
} }
static int exynos_read_raw(struct iio_dev *indio_dev, static int exynos_read_raw(struct iio_dev *indio_dev,
...@@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev, ...@@ -144,7 +314,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
{ {
struct exynos_adc *info = iio_priv(indio_dev); struct exynos_adc *info = iio_priv(indio_dev);
unsigned long timeout; unsigned long timeout;
u32 con1, con2;
int ret; int ret;
if (mask != IIO_CHAN_INFO_RAW) if (mask != IIO_CHAN_INFO_RAW)
...@@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev, ...@@ -154,28 +323,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
reinit_completion(&info->completion); reinit_completion(&info->completion);
/* Select the channel to be used and Trigger conversion */ /* Select the channel to be used and Trigger conversion */
if (info->version == ADC_V2) { if (info->data->start_conv)
con2 = readl(ADC_V2_CON2(info->regs)); info->data->start_conv(info, chan->address);
con2 &= ~ADC_V2_CON2_ACH_MASK;
con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
writel(con2, ADC_V2_CON2(info->regs));
con1 = readl(ADC_V2_CON1(info->regs));
writel(con1 | ADC_CON_EN_START,
ADC_V2_CON1(info->regs));
} else {
writel(chan->address, ADC_V1_MUX(info->regs));
con1 = readl(ADC_V1_CON(info->regs));
writel(con1 | ADC_CON_EN_START,
ADC_V1_CON(info->regs));
}
timeout = wait_for_completion_timeout timeout = wait_for_completion_timeout
(&info->completion, EXYNOS_ADC_TIMEOUT); (&info->completion, EXYNOS_ADC_TIMEOUT);
if (timeout == 0) { if (timeout == 0) {
dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
exynos_adc_hw_init(info); if (info->data->init_hw)
info->data->init_hw(info);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} else { } else {
*val = info->value; *val = info->value;
...@@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id) ...@@ -193,13 +349,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
struct exynos_adc *info = (struct exynos_adc *)dev_id; struct exynos_adc *info = (struct exynos_adc *)dev_id;
/* Read value */ /* Read value */
info->value = readl(ADC_V1_DATX(info->regs)) & info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
ADC_DATX_MASK;
/* clear irq */ /* clear irq */
if (info->version == ADC_V2) if (info->data->clear_irq)
writel(1, ADC_V2_INT_ST(info->regs)); info->data->clear_irq(info);
else
writel(1, ADC_V1_INTCLR(info->regs));
complete(&info->completion); complete(&info->completion);
...@@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -277,6 +431,12 @@ static int exynos_adc_probe(struct platform_device *pdev)
info = iio_priv(indio_dev); info = iio_priv(indio_dev);
info->data = exynos_adc_get_data(pdev);
if (!info->data) {
dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
return -EINVAL;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
info->regs = devm_ioremap_resource(&pdev->dev, mem); info->regs = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(info->regs)) if (IS_ERR(info->regs))
...@@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -294,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
} }
info->irq = irq; info->irq = irq;
info->dev = &pdev->dev;
init_completion(&info->completion); init_completion(&info->completion);
...@@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -304,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev)
return PTR_ERR(info->clk); return PTR_ERR(info->clk);
} }
if (info->data->needs_sclk) {
info->sclk = devm_clk_get(&pdev->dev, "sclk");
if (IS_ERR(info->sclk)) {
dev_err(&pdev->dev,
"failed getting sclk clock, err = %ld\n",
PTR_ERR(info->sclk));
return PTR_ERR(info->sclk);
}
}
info->vdd = devm_regulator_get(&pdev->dev, "vdd"); info->vdd = devm_regulator_get(&pdev->dev, "vdd");
if (IS_ERR(info->vdd)) { if (IS_ERR(info->vdd)) {
dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
...@@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -315,13 +486,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(info->clk); ret = exynos_adc_prepare_clk(info);
if (ret) if (ret)
goto err_disable_reg; goto err_disable_reg;
writel(1, info->enable_reg); ret = exynos_adc_enable_clk(info);
if (ret)
info->version = exynos_adc_get_version(pdev); goto err_unprepare_clk;
platform_set_drvdata(pdev, indio_dev); platform_set_drvdata(pdev, indio_dev);
...@@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -331,11 +502,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
indio_dev->info = &exynos_adc_iio_info; indio_dev->info = &exynos_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = exynos_adc_iio_channels; indio_dev->channels = exynos_adc_iio_channels;
indio_dev->num_channels = info->data->num_channels;
if (info->version == ADC_V1)
indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
else
indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
ret = request_irq(info->irq, exynos_adc_isr, ret = request_irq(info->irq, exynos_adc_isr,
0, dev_name(&pdev->dev), info); 0, dev_name(&pdev->dev), info);
...@@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -349,7 +516,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_irq; goto err_irq;
exynos_adc_hw_init(info); if (info->data->init_hw)
info->data->init_hw(info);
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) { if (ret < 0) {
...@@ -366,8 +534,11 @@ static int exynos_adc_probe(struct platform_device *pdev) ...@@ -366,8 +534,11 @@ static int exynos_adc_probe(struct platform_device *pdev)
err_irq: err_irq:
free_irq(info->irq, info); free_irq(info->irq, info);
err_disable_clk: err_disable_clk:
writel(0, info->enable_reg); if (info->data->exit_hw)
clk_disable_unprepare(info->clk); info->data->exit_hw(info);
exynos_adc_disable_clk(info);
err_unprepare_clk:
exynos_adc_unprepare_clk(info);
err_disable_reg: err_disable_reg:
regulator_disable(info->vdd); regulator_disable(info->vdd);
return ret; return ret;
...@@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev) ...@@ -382,8 +553,10 @@ static int exynos_adc_remove(struct platform_device *pdev)
exynos_adc_remove_devices); exynos_adc_remove_devices);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
free_irq(info->irq, info); free_irq(info->irq, info);
writel(0, info->enable_reg); if (info->data->exit_hw)
clk_disable_unprepare(info->clk); info->data->exit_hw(info);
exynos_adc_disable_clk(info);
exynos_adc_unprepare_clk(info);
regulator_disable(info->vdd); regulator_disable(info->vdd);
return 0; return 0;
...@@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev) ...@@ -394,20 +567,10 @@ static int exynos_adc_suspend(struct device *dev)
{ {
struct iio_dev *indio_dev = dev_get_drvdata(dev); struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct exynos_adc *info = iio_priv(indio_dev); struct exynos_adc *info = iio_priv(indio_dev);
u32 con;
if (info->version == ADC_V2) { if (info->data->exit_hw)
con = readl(ADC_V2_CON1(info->regs)); info->data->exit_hw(info);
con &= ~ADC_CON_EN_START; exynos_adc_disable_clk(info);
writel(con, ADC_V2_CON1(info->regs));
} else {
con = readl(ADC_V1_CON(info->regs));
con |= ADC_V1_CON_STANDBY;
writel(con, ADC_V1_CON(info->regs));
}
writel(0, info->enable_reg);
clk_disable_unprepare(info->clk);
regulator_disable(info->vdd); regulator_disable(info->vdd);
return 0; return 0;
...@@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev) ...@@ -423,12 +586,12 @@ static int exynos_adc_resume(struct device *dev)
if (ret) if (ret)
return ret; return ret;
ret = clk_prepare_enable(info->clk); ret = exynos_adc_enable_clk(info);
if (ret) if (ret)
return ret; return ret;
writel(1, info->enable_reg); if (info->data->init_hw)
exynos_adc_hw_init(info); info->data->init_hw(info);
return 0; return 0;
} }
......
...@@ -87,6 +87,10 @@ static const char * const iio_modifier_names[] = { ...@@ -87,6 +87,10 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_QUATERNION] = "quaternion", [IIO_MOD_QUATERNION] = "quaternion",
[IIO_MOD_TEMP_AMBIENT] = "ambient", [IIO_MOD_TEMP_AMBIENT] = "ambient",
[IIO_MOD_TEMP_OBJECT] = "object", [IIO_MOD_TEMP_OBJECT] = "object",
[IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
[IIO_MOD_NORTH_TRUE] = "from_north_true",
[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
}; };
/* relies on pairs of these shared then separate */ /* relies on pairs of these shared then separate */
......
...@@ -35,6 +35,10 @@ enum magn_3d_channel { ...@@ -35,6 +35,10 @@ enum magn_3d_channel {
CHANNEL_SCAN_INDEX_X, CHANNEL_SCAN_INDEX_X,
CHANNEL_SCAN_INDEX_Y, CHANNEL_SCAN_INDEX_Y,
CHANNEL_SCAN_INDEX_Z, CHANNEL_SCAN_INDEX_Z,
CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP,
CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
CHANNEL_SCAN_INDEX_NORTH_MAGN,
CHANNEL_SCAN_INDEX_NORTH_TRUE,
MAGN_3D_CHANNEL_MAX, MAGN_3D_CHANNEL_MAX,
}; };
...@@ -42,7 +46,12 @@ struct magn_3d_state { ...@@ -42,7 +46,12 @@ struct magn_3d_state {
struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes; struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
u32 magn_val[MAGN_3D_CHANNEL_MAX];
/* dynamically sized array to hold sensor values */
u32 *iio_vals;
/* array of pointers to sensor value */
u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
int scale_pre_decml; int scale_pre_decml;
int scale_post_decml; int scale_post_decml;
int scale_precision; int scale_precision;
...@@ -52,7 +61,11 @@ struct magn_3d_state { ...@@ -52,7 +61,11 @@ struct magn_3d_state {
static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS, HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS, HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS,
HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH,
HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH,
HID_USAGE_SENSOR_ORIENT_MAGN_NORTH,
HID_USAGE_SENSOR_ORIENT_TRUE_NORTH,
}; };
/* Channel definitions */ /* Channel definitions */
...@@ -66,7 +79,6 @@ static const struct iio_chan_spec magn_3d_channels[] = { ...@@ -66,7 +79,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_X,
}, { }, {
.type = IIO_MAGN, .type = IIO_MAGN,
.modified = 1, .modified = 1,
...@@ -76,7 +88,6 @@ static const struct iio_chan_spec magn_3d_channels[] = { ...@@ -76,7 +88,6 @@ static const struct iio_chan_spec magn_3d_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Y,
}, { }, {
.type = IIO_MAGN, .type = IIO_MAGN,
.modified = 1, .modified = 1,
...@@ -86,7 +97,42 @@ static const struct iio_chan_spec magn_3d_channels[] = { ...@@ -86,7 +97,42 @@ static const struct iio_chan_spec magn_3d_channels[] = {
BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS), BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z, }, {
.type = IIO_ROT,
.modified = 1,
.channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
}, {
.type = IIO_ROT,
.modified = 1,
.channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
}, {
.type = IIO_ROT,
.modified = 1,
.channel2 = IIO_MOD_NORTH_MAGN,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
}, {
.type = IIO_ROT,
.modified = 1,
.channel2 = IIO_MOD_NORTH_TRUE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
} }
}; };
...@@ -126,8 +172,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev, ...@@ -126,8 +172,8 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
msleep_interruptible(poll_value * 2); msleep_interruptible(poll_value * 2);
report_id = report_id =
magn_state->magn[chan->scan_index].report_id; magn_state->magn[chan->address].report_id;
address = magn_3d_addresses[chan->scan_index]; address = magn_3d_addresses[chan->address];
if (report_id >= 0) if (report_id >= 0)
*val = sensor_hub_input_attr_get_raw_value( *val = sensor_hub_input_attr_get_raw_value(
magn_state->common_attributes.hsdev, magn_state->common_attributes.hsdev,
...@@ -218,8 +264,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, ...@@ -218,8 +264,8 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n");
if (atomic_read(&magn_state->common_attributes.data_ready)) if (atomic_read(&magn_state->common_attributes.data_ready))
hid_sensor_push_data(indio_dev, hid_sensor_push_data(indio_dev,
magn_state->magn_val, magn_state->iio_vals,
sizeof(magn_state->magn_val)); sizeof(magn_state->iio_vals));
return 0; return 0;
} }
...@@ -233,52 +279,126 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev, ...@@ -233,52 +279,126 @@ static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
struct iio_dev *indio_dev = platform_get_drvdata(priv); struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct magn_3d_state *magn_state = iio_priv(indio_dev); struct magn_3d_state *magn_state = iio_priv(indio_dev);
int offset; int offset;
int ret = -EINVAL; int ret = 0;
u32 *iio_val = NULL;
switch (usage_id) { switch (usage_id) {
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS)
magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = + CHANNEL_SCAN_INDEX_X;
*(u32 *)raw_data;
ret = 0;
break; break;
default: case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH)
+ CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP;
break; break;
default:
return -EINVAL;
} }
iio_val = magn_state->magn_val_addr[offset];
if (iio_val != NULL)
*iio_val = *((u32 *)raw_data);
else
ret = -EINVAL;
return ret; return ret;
} }
/* Parse report which is specific to an usage id*/ /* Parse report which is specific to an usage id*/
static int magn_3d_parse_report(struct platform_device *pdev, static int magn_3d_parse_report(struct platform_device *pdev,
struct hid_sensor_hub_device *hsdev, struct hid_sensor_hub_device *hsdev,
struct iio_chan_spec *channels, struct iio_chan_spec **channels,
int *chan_count,
unsigned usage_id, unsigned usage_id,
struct magn_3d_state *st) struct magn_3d_state *st)
{ {
int ret;
int i; int i;
int attr_count = 0;
struct iio_chan_spec *_channels;
for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { /* Scan for each usage attribute supported */
ret = sensor_hub_input_get_attribute_info(hsdev, for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) {
int status;
u32 address = magn_3d_addresses[i];
/* Check if usage attribute exists in the sensor hub device */
status = sensor_hub_input_get_attribute_info(hsdev,
HID_INPUT_REPORT, HID_INPUT_REPORT,
usage_id, usage_id,
HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i, address,
&st->magn[CHANNEL_SCAN_INDEX_X + i]); &(st->magn[i]));
if (ret < 0) if (!status)
break; attr_count++;
magn_3d_adjust_channel_bit_mask(channels,
CHANNEL_SCAN_INDEX_X + i,
st->magn[CHANNEL_SCAN_INDEX_X + i].size);
} }
dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
if (attr_count <= 0) {
dev_err(&pdev->dev,
"failed to find any supported usage attributes in report\n");
return -EINVAL;
}
dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n",
attr_count);
dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n",
st->magn[0].index, st->magn[0].index,
st->magn[0].report_id, st->magn[0].report_id,
st->magn[1].index, st->magn[1].report_id, st->magn[1].index, st->magn[1].report_id,
st->magn[2].index, st->magn[2].report_id); st->magn[2].index, st->magn[2].report_id);
/* Setup IIO channel array */
_channels = devm_kcalloc(&pdev->dev, attr_count,
sizeof(struct iio_chan_spec),
GFP_KERNEL);
if (!_channels) {
dev_err(&pdev->dev,
"failed to allocate space for iio channels\n");
return -ENOMEM;
}
st->iio_vals = devm_kcalloc(&pdev->dev, attr_count,
sizeof(u32),
GFP_KERNEL);
if (!st->iio_vals) {
dev_err(&pdev->dev,
"failed to allocate space for iio values array\n");
return -ENOMEM;
}
for (i = 0, *chan_count = 0;
i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count;
i++){
if (st->magn[i].index >= 0) {
/* Setup IIO channel struct */
(_channels[*chan_count]) = magn_3d_channels[i];
(_channels[*chan_count]).scan_index = *chan_count;
(_channels[*chan_count]).address = i;
/* Set magn_val_addr to iio value address */
st->magn_val_addr[i] = &(st->iio_vals[*chan_count]);
magn_3d_adjust_channel_bit_mask(_channels,
*chan_count,
st->magn[i].size);
(*chan_count)++;
}
}
if (*chan_count <= 0) {
dev_err(&pdev->dev,
"failed to find any magnetic channels setup\n");
return -EINVAL;
}
*channels = _channels;
dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n",
*chan_count);
st->scale_precision = hid_sensor_format_scale( st->scale_precision = hid_sensor_format_scale(
HID_USAGE_SENSOR_COMPASS_3D, HID_USAGE_SENSOR_COMPASS_3D,
&st->magn[CHANNEL_SCAN_INDEX_X], &st->magn[CHANNEL_SCAN_INDEX_X],
...@@ -296,7 +416,7 @@ static int magn_3d_parse_report(struct platform_device *pdev, ...@@ -296,7 +416,7 @@ static int magn_3d_parse_report(struct platform_device *pdev,
st->common_attributes.sensitivity.report_id); st->common_attributes.sensitivity.report_id);
} }
return ret; return 0;
} }
/* Function to initialize the processing for usage id */ /* Function to initialize the processing for usage id */
...@@ -308,6 +428,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ...@@ -308,6 +428,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
struct magn_3d_state *magn_state; struct magn_3d_state *magn_state;
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
struct iio_chan_spec *channels; struct iio_chan_spec *channels;
int chan_count = 0;
indio_dev = devm_iio_device_alloc(&pdev->dev, indio_dev = devm_iio_device_alloc(&pdev->dev,
sizeof(struct magn_3d_state)); sizeof(struct magn_3d_state));
...@@ -328,22 +449,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ...@@ -328,22 +449,16 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
return ret; return ret;
} }
channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels), ret = magn_3d_parse_report(pdev, hsdev,
GFP_KERNEL); &channels, &chan_count,
if (!channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
ret = magn_3d_parse_report(pdev, hsdev, channels,
HID_USAGE_SENSOR_COMPASS_3D, magn_state); HID_USAGE_SENSOR_COMPASS_3D, magn_state);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n"); dev_err(&pdev->dev, "failed to parse report\n");
goto error_free_dev_mem; return ret;
} }
indio_dev->channels = channels; indio_dev->channels = channels;
indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); indio_dev->num_channels = chan_count;
indio_dev->dev.parent = &pdev->dev; indio_dev->dev.parent = &pdev->dev;
indio_dev->info = &magn_3d_info; indio_dev->info = &magn_3d_info;
indio_dev->name = name; indio_dev->name = name;
...@@ -353,7 +468,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ...@@ -353,7 +468,7 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
NULL, NULL); NULL, NULL);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
goto error_free_dev_mem; return ret;
} }
atomic_set(&magn_state->common_attributes.data_ready, 0); atomic_set(&magn_state->common_attributes.data_ready, 0);
ret = hid_sensor_setup_trigger(indio_dev, name, ret = hid_sensor_setup_trigger(indio_dev, name,
...@@ -387,8 +502,6 @@ static int hid_magn_3d_probe(struct platform_device *pdev) ...@@ -387,8 +502,6 @@ static int hid_magn_3d_probe(struct platform_device *pdev)
hid_sensor_remove_trigger(&magn_state->common_attributes); hid_sensor_remove_trigger(&magn_state->common_attributes);
error_unreg_buffer_funcs: error_unreg_buffer_funcs:
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
error_free_dev_mem:
kfree(indio_dev->channels);
return ret; return ret;
} }
...@@ -403,7 +516,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev) ...@@ -403,7 +516,6 @@ static int hid_magn_3d_remove(struct platform_device *pdev)
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&magn_state->common_attributes); hid_sensor_remove_trigger(&magn_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
kfree(indio_dev->channels);
return 0; return 0;
} }
......
...@@ -4,15 +4,37 @@ ...@@ -4,15 +4,37 @@
menu "Magnetometer sensors" menu "Magnetometer sensors"
config SENSORS_HMC5843 config SENSORS_HMC5843
tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer" tristate
depends on I2C
select IIO_BUFFER select IIO_BUFFER
select IIO_TRIGGERED_BUFFER select IIO_TRIGGERED_BUFFER
config SENSORS_HMC5843_I2C
tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)"
depends on I2C
select SENSORS_HMC5843
select REGMAP_I2C
help help
Say Y here to add support for the Honeywell HMC5843, HMC5883 and Say Y here to add support for the Honeywell HMC5843, HMC5883 and
HMC5883L 3-Axis Magnetometer (digital compass). HMC5883L 3-Axis Magnetometer (digital compass).
To compile this driver as a module, choose M here: the module This driver can also be compiled as a set of modules.
will be called hmc5843. If so, these modules will be created:
- hmc5843_core (core functions)
- hmc5843_i2c (support for HMC5843, HMC5883, HMC5883L and HMC5983)
config SENSORS_HMC5843_SPI
tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)"
depends on SPI_MASTER
select SENSORS_HMC5843
select REGMAP_SPI
help
Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer
(digital compass).
This driver can also be compiled as a set of modules.
If so, these modules will be created:
- hmc5843_core (core functions)
- hmc5843_spi (support for HMC5983)
endmenu endmenu
...@@ -2,4 +2,6 @@ ...@@ -2,4 +2,6 @@
# Makefile for industrial I/O Magnetometer sensors # Makefile for industrial I/O Magnetometer sensors
# #
obj-$(CONFIG_SENSORS_HMC5843) += hmc5843.o obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o
obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o
obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o
/*
* Header file for hmc5843 driver
*
* Split from hmc5843.c
* Copyright (C) Josef Gajdusek <atx@atx.name>
*
* 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.
*
* */
#ifndef HMC5843_CORE_H
#define HMC5843_CORE_H
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#define HMC5843_CONFIG_REG_A 0x00
#define HMC5843_CONFIG_REG_B 0x01
#define HMC5843_MODE_REG 0x02
#define HMC5843_DATA_OUT_MSB_REGS 0x03
#define HMC5843_STATUS_REG 0x09
#define HMC5843_ID_REG 0x0a
#define HMC5843_ID_END 0x0c
enum hmc5843_ids {
HMC5843_ID,
HMC5883_ID,
HMC5883L_ID,
HMC5983_ID,
};
struct hmc5843_data {
struct device *dev;
struct mutex lock;
struct regmap *regmap;
const struct hmc5843_chip_info *variant;
__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
};
int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
enum hmc5843_ids id);
int hmc5843_common_remove(struct device *dev);
int hmc5843_common_suspend(struct device *dev);
int hmc5843_common_resume(struct device *dev);
#ifdef CONFIG_PM_SLEEP
static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops,
hmc5843_common_suspend,
hmc5843_common_resume);
#define HMC5843_PM_OPS (&hmc5843_pm_ops)
#else
#define HMC5843_PM_OPS NULL
#endif
#endif /* HMC5843_CORE_H */
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>. Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
Split to multiple files by Josef Gajdusek <atx@atx.name> - 2014
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
...@@ -20,7 +22,7 @@ ...@@ -20,7 +22,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c.h> #include <linux/regmap.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/sysfs.h> #include <linux/iio/sysfs.h>
#include <linux/iio/trigger_consumer.h> #include <linux/iio/trigger_consumer.h>
...@@ -28,18 +30,7 @@ ...@@ -28,18 +30,7 @@
#include <linux/iio/triggered_buffer.h> #include <linux/iio/triggered_buffer.h>
#include <linux/delay.h> #include <linux/delay.h>
#define HMC5843_CONFIG_REG_A 0x00 #include "hmc5843.h"
#define HMC5843_CONFIG_REG_B 0x01
#define HMC5843_MODE_REG 0x02
#define HMC5843_DATA_OUT_MSB_REGS 0x03
#define HMC5843_STATUS_REG 0x09
#define HMC5843_ID_REG 0x0a
enum hmc5843_ids {
HMC5843_ID,
HMC5883_ID,
HMC5883L_ID,
};
/* /*
* Range gain settings in (+-)Ga * Range gain settings in (+-)Ga
...@@ -48,7 +39,7 @@ enum hmc5843_ids { ...@@ -48,7 +39,7 @@ enum hmc5843_ids {
*/ */
#define HMC5843_RANGE_GAIN_OFFSET 0x05 #define HMC5843_RANGE_GAIN_OFFSET 0x05
#define HMC5843_RANGE_GAIN_DEFAULT 0x01 #define HMC5843_RANGE_GAIN_DEFAULT 0x01
#define HMC5843_RANGE_GAINS 8 #define HMC5843_RANGE_GAIN_MASK 0xe0
/* Device status */ /* Device status */
#define HMC5843_DATA_READY 0x01 #define HMC5843_DATA_READY 0x01
...@@ -67,7 +58,7 @@ enum hmc5843_ids { ...@@ -67,7 +58,7 @@ enum hmc5843_ids {
*/ */
#define HMC5843_RATE_OFFSET 0x02 #define HMC5843_RATE_OFFSET 0x02
#define HMC5843_RATE_DEFAULT 0x04 #define HMC5843_RATE_DEFAULT 0x04
#define HMC5843_RATES 7 #define HMC5843_RATE_MASK 0x1c
/* Device measurement configuration */ /* Device measurement configuration */
#define HMC5843_MEAS_CONF_NORMAL 0x00 #define HMC5843_MEAS_CONF_NORMAL 0x00
...@@ -76,15 +67,15 @@ enum hmc5843_ids { ...@@ -76,15 +67,15 @@ enum hmc5843_ids {
#define HMC5843_MEAS_CONF_MASK 0x03 #define HMC5843_MEAS_CONF_MASK 0x03
/* Scaling factors: 10000000/Gain */ /* Scaling factors: 10000000/Gain */
static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { static const int hmc5843_regval_to_nanoscale[] = {
6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
}; };
static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { static const int hmc5883_regval_to_nanoscale[] = {
7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
}; };
static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { static const int hmc5883l_regval_to_nanoscale[] = {
7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
}; };
...@@ -101,32 +92,27 @@ static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { ...@@ -101,32 +92,27 @@ static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = {
* 6 | 50 | 75 * 6 | 50 | 75
* 7 | Not used | Not used * 7 | Not used | Not used
*/ */
static const int hmc5843_regval_to_samp_freq[7][2] = { static const int hmc5843_regval_to_samp_freq[][2] = {
{0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0}
}; };
static const int hmc5883_regval_to_samp_freq[7][2] = { static const int hmc5883_regval_to_samp_freq[][2] = {
{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
{75, 0} {75, 0}
}; };
static const int hmc5983_regval_to_samp_freq[][2] = {
{0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0},
{75, 0}, {220, 0}
};
/* Describe chip variants */ /* Describe chip variants */
struct hmc5843_chip_info { struct hmc5843_chip_info {
const struct iio_chan_spec *channels; const struct iio_chan_spec *channels;
const int (*regval_to_samp_freq)[2]; const int (*regval_to_samp_freq)[2];
const int n_regval_to_samp_freq;
const int *regval_to_nanoscale; const int *regval_to_nanoscale;
}; const int n_regval_to_nanoscale;
/* Each client has this additional data */
struct hmc5843_data {
struct i2c_client *client;
struct mutex lock;
u8 rate;
u8 meas_conf;
u8 operating_mode;
u8 range;
const struct hmc5843_chip_info *variant;
__be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */
}; };
/* The lower two bits contain the current conversion mode */ /* The lower two bits contain the current conversion mode */
...@@ -135,10 +121,8 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) ...@@ -135,10 +121,8 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
int ret; int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client, HMC5843_MODE_REG, ret = regmap_update_bits(data->regmap, HMC5843_MODE_REG,
operating_mode & HMC5843_MODE_MASK); HMC5843_MODE_MASK, operating_mode);
if (ret >= 0)
data->operating_mode = operating_mode;
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
return ret; return ret;
...@@ -146,21 +130,21 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) ...@@ -146,21 +130,21 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode)
static int hmc5843_wait_measurement(struct hmc5843_data *data) static int hmc5843_wait_measurement(struct hmc5843_data *data)
{ {
s32 result;
int tries = 150; int tries = 150;
int val;
int ret;
while (tries-- > 0) { while (tries-- > 0) {
result = i2c_smbus_read_byte_data(data->client, ret = regmap_read(data->regmap, HMC5843_STATUS_REG, &val);
HMC5843_STATUS_REG); if (ret < 0)
if (result < 0) return ret;
return result; if (val & HMC5843_DATA_READY)
if (result & HMC5843_DATA_READY)
break; break;
msleep(20); msleep(20);
} }
if (tries < 0) { if (tries < 0) {
dev_err(&data->client->dev, "data not ready\n"); dev_err(data->dev, "data not ready\n");
return -EIO; return -EIO;
} }
...@@ -171,20 +155,20 @@ static int hmc5843_wait_measurement(struct hmc5843_data *data) ...@@ -171,20 +155,20 @@ static int hmc5843_wait_measurement(struct hmc5843_data *data)
static int hmc5843_read_measurement(struct hmc5843_data *data, static int hmc5843_read_measurement(struct hmc5843_data *data,
int idx, int *val) int idx, int *val)
{ {
s32 result;
__be16 values[3]; __be16 values[3];
int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
result = hmc5843_wait_measurement(data); ret = hmc5843_wait_measurement(data);
if (result < 0) { if (ret < 0) {
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
return result; return ret;
} }
result = i2c_smbus_read_i2c_block_data(data->client, ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values); values, sizeof(values));
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
if (result < 0) if (ret < 0)
return -EINVAL; return ret;
*val = sign_extend32(be16_to_cpu(values[idx]), 15); *val = sign_extend32(be16_to_cpu(values[idx]), 15);
return IIO_VAL_INT; return IIO_VAL_INT;
...@@ -208,16 +192,13 @@ static int hmc5843_read_measurement(struct hmc5843_data *data, ...@@ -208,16 +192,13 @@ static int hmc5843_read_measurement(struct hmc5843_data *data,
* and BN. * and BN.
* *
*/ */
static s32 hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf) static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf)
{ {
int ret; int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
(meas_conf & HMC5843_MEAS_CONF_MASK) | HMC5843_MEAS_CONF_MASK, meas_conf);
(data->rate << HMC5843_RATE_OFFSET));
if (ret >= 0)
data->meas_conf = meas_conf;
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
return ret; return ret;
...@@ -228,7 +209,15 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev, ...@@ -228,7 +209,15 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
char *buf) char *buf)
{ {
struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", data->meas_conf); int val;
int ret;
ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val);
if (ret)
return ret;
val &= HMC5843_MEAS_CONF_MASK;
return sprintf(buf, "%d\n", val);
} }
static ssize_t hmc5843_set_measurement_configuration(struct device *dev, static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
...@@ -264,7 +253,7 @@ static ssize_t hmc5843_show_samp_freq_avail(struct device *dev, ...@@ -264,7 +253,7 @@ static ssize_t hmc5843_show_samp_freq_avail(struct device *dev,
size_t len = 0; size_t len = 0;
int i; int i;
for (i = 0; i < HMC5843_RATES; i++) for (i = 0; i < data->variant->n_regval_to_samp_freq; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, len += scnprintf(buf + len, PAGE_SIZE - len,
"%d.%d ", data->variant->regval_to_samp_freq[i][0], "%d.%d ", data->variant->regval_to_samp_freq[i][0],
data->variant->regval_to_samp_freq[i][1]); data->variant->regval_to_samp_freq[i][1]);
...@@ -282,10 +271,8 @@ static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate) ...@@ -282,10 +271,8 @@ static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate)
int ret; int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_A,
data->meas_conf | (rate << HMC5843_RATE_OFFSET)); HMC5843_RATE_MASK, rate << HMC5843_RATE_OFFSET);
if (ret >= 0)
data->rate = rate;
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
return ret; return ret;
...@@ -296,7 +283,7 @@ static int hmc5843_get_samp_freq_index(struct hmc5843_data *data, ...@@ -296,7 +283,7 @@ static int hmc5843_get_samp_freq_index(struct hmc5843_data *data,
{ {
int i; int i;
for (i = 0; i < HMC5843_RATES; i++) for (i = 0; i < data->variant->n_regval_to_samp_freq; i++)
if (val == data->variant->regval_to_samp_freq[i][0] && if (val == data->variant->regval_to_samp_freq[i][0] &&
val2 == data->variant->regval_to_samp_freq[i][1]) val2 == data->variant->regval_to_samp_freq[i][1])
return i; return i;
...@@ -309,10 +296,9 @@ static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range) ...@@ -309,10 +296,9 @@ static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range)
int ret; int ret;
mutex_lock(&data->lock); mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B, ret = regmap_update_bits(data->regmap, HMC5843_CONFIG_REG_B,
HMC5843_RANGE_GAIN_MASK,
range << HMC5843_RANGE_GAIN_OFFSET); range << HMC5843_RANGE_GAIN_OFFSET);
if (ret >= 0)
data->range = range;
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
return ret; return ret;
...@@ -326,7 +312,7 @@ static ssize_t hmc5843_show_scale_avail(struct device *dev, ...@@ -326,7 +312,7 @@ static ssize_t hmc5843_show_scale_avail(struct device *dev,
size_t len = 0; size_t len = 0;
int i; int i;
for (i = 0; i < HMC5843_RANGE_GAINS; i++) for (i = 0; i < data->variant->n_regval_to_nanoscale; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, len += scnprintf(buf + len, PAGE_SIZE - len,
"0.%09d ", data->variant->regval_to_nanoscale[i]); "0.%09d ", data->variant->regval_to_nanoscale[i]);
...@@ -346,7 +332,7 @@ static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2) ...@@ -346,7 +332,7 @@ static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2)
if (val != 0) if (val != 0)
return -EINVAL; return -EINVAL;
for (i = 0; i < HMC5843_RANGE_GAINS; i++) for (i = 0; i < data->variant->n_regval_to_nanoscale; i++)
if (val2 == data->variant->regval_to_nanoscale[i]) if (val2 == data->variant->regval_to_nanoscale[i])
return i; return i;
...@@ -358,17 +344,27 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, ...@@ -358,17 +344,27 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask) int *val, int *val2, long mask)
{ {
struct hmc5843_data *data = iio_priv(indio_dev); struct hmc5843_data *data = iio_priv(indio_dev);
int rval;
int ret;
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_RAW:
return hmc5843_read_measurement(data, chan->scan_index, val); return hmc5843_read_measurement(data, chan->scan_index, val);
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_B, &rval);
if (ret < 0)
return ret;
rval >>= HMC5843_RANGE_GAIN_OFFSET;
*val = 0; *val = 0;
*val2 = data->variant->regval_to_nanoscale[data->range]; *val2 = data->variant->regval_to_nanoscale[rval];
return IIO_VAL_INT_PLUS_NANO; return IIO_VAL_INT_PLUS_NANO;
case IIO_CHAN_INFO_SAMP_FREQ: case IIO_CHAN_INFO_SAMP_FREQ:
*val = data->variant->regval_to_samp_freq[data->rate][0]; ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &rval);
*val2 = data->variant->regval_to_samp_freq[data->rate][1]; if (ret < 0)
return ret;
rval >>= HMC5843_RATE_OFFSET;
*val = data->variant->regval_to_samp_freq[rval][0];
*val2 = data->variant->regval_to_samp_freq[rval][1];
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
} }
return -EINVAL; return -EINVAL;
...@@ -426,9 +422,9 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p) ...@@ -426,9 +422,9 @@ static irqreturn_t hmc5843_trigger_handler(int irq, void *p)
goto done; goto done;
} }
ret = i2c_smbus_read_i2c_block_data(data->client, ret = regmap_bulk_read(data->regmap, HMC5843_DATA_OUT_MSB_REGS,
HMC5843_DATA_OUT_MSB_REGS, 3 * sizeof(__be16), data->buffer, 3 * sizeof(__be16));
(u8 *) data->buffer);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
if (ret < 0) if (ret < 0)
goto done; goto done;
...@@ -466,7 +462,7 @@ static const struct iio_chan_spec hmc5843_channels[] = { ...@@ -466,7 +462,7 @@ static const struct iio_chan_spec hmc5843_channels[] = {
IIO_CHAN_SOFT_TIMESTAMP(3), IIO_CHAN_SOFT_TIMESTAMP(3),
}; };
/* Beware: Y and Z are exchanged on HMC5883 */ /* Beware: Y and Z are exchanged on HMC5883 and 5983 */
static const struct iio_chan_spec hmc5883_channels[] = { static const struct iio_chan_spec hmc5883_channels[] = {
HMC5843_CHANNEL(X, 0), HMC5843_CHANNEL(X, 0),
HMC5843_CHANNEL(Z, 1), HMC5843_CHANNEL(Z, 1),
...@@ -489,18 +485,39 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { ...@@ -489,18 +485,39 @@ static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
[HMC5843_ID] = { [HMC5843_ID] = {
.channels = hmc5843_channels, .channels = hmc5843_channels,
.regval_to_samp_freq = hmc5843_regval_to_samp_freq, .regval_to_samp_freq = hmc5843_regval_to_samp_freq,
.n_regval_to_samp_freq =
ARRAY_SIZE(hmc5843_regval_to_samp_freq),
.regval_to_nanoscale = hmc5843_regval_to_nanoscale, .regval_to_nanoscale = hmc5843_regval_to_nanoscale,
.n_regval_to_nanoscale =
ARRAY_SIZE(hmc5843_regval_to_nanoscale),
}, },
[HMC5883_ID] = { [HMC5883_ID] = {
.channels = hmc5883_channels, .channels = hmc5883_channels,
.regval_to_samp_freq = hmc5883_regval_to_samp_freq, .regval_to_samp_freq = hmc5883_regval_to_samp_freq,
.n_regval_to_samp_freq =
ARRAY_SIZE(hmc5883_regval_to_samp_freq),
.regval_to_nanoscale = hmc5883_regval_to_nanoscale, .regval_to_nanoscale = hmc5883_regval_to_nanoscale,
.n_regval_to_nanoscale =
ARRAY_SIZE(hmc5883_regval_to_nanoscale),
}, },
[HMC5883L_ID] = { [HMC5883L_ID] = {
.channels = hmc5883_channels, .channels = hmc5883_channels,
.regval_to_samp_freq = hmc5883_regval_to_samp_freq, .regval_to_samp_freq = hmc5883_regval_to_samp_freq,
.n_regval_to_samp_freq =
ARRAY_SIZE(hmc5883_regval_to_samp_freq),
.regval_to_nanoscale = hmc5883l_regval_to_nanoscale, .regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
.n_regval_to_nanoscale =
ARRAY_SIZE(hmc5883l_regval_to_nanoscale),
}, },
[HMC5983_ID] = {
.channels = hmc5883_channels,
.regval_to_samp_freq = hmc5983_regval_to_samp_freq,
.n_regval_to_samp_freq =
ARRAY_SIZE(hmc5983_regval_to_samp_freq),
.regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
.n_regval_to_nanoscale =
ARRAY_SIZE(hmc5883l_regval_to_nanoscale),
}
}; };
static int hmc5843_init(struct hmc5843_data *data) static int hmc5843_init(struct hmc5843_data *data)
...@@ -508,12 +525,12 @@ static int hmc5843_init(struct hmc5843_data *data) ...@@ -508,12 +525,12 @@ static int hmc5843_init(struct hmc5843_data *data)
int ret; int ret;
u8 id[3]; u8 id[3];
ret = i2c_smbus_read_i2c_block_data(data->client, HMC5843_ID_REG, ret = regmap_bulk_read(data->regmap, HMC5843_ID_REG,
sizeof(id), id); id, ARRAY_SIZE(id));
if (ret < 0) if (ret < 0)
return ret; return ret;
if (id[0] != 'H' || id[1] != '4' || id[2] != '3') { if (id[0] != 'H' || id[1] != '4' || id[2] != '3') {
dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n"); dev_err(data->dev, "no HMC5843/5883/5883L/5983 sensor\n");
return -ENODEV; return -ENODEV;
} }
...@@ -539,27 +556,43 @@ static const struct iio_info hmc5843_info = { ...@@ -539,27 +556,43 @@ static const struct iio_info hmc5843_info = {
static const unsigned long hmc5843_scan_masks[] = {0x7, 0}; static const unsigned long hmc5843_scan_masks[] = {0x7, 0};
static int hmc5843_probe(struct i2c_client *client,
const struct i2c_device_id *id) int hmc5843_common_suspend(struct device *dev)
{
return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
HMC5843_MODE_CONVERSION_CONTINUOUS);
}
EXPORT_SYMBOL(hmc5843_common_suspend);
int hmc5843_common_resume(struct device *dev)
{
return hmc5843_set_mode(iio_priv(dev_get_drvdata(dev)),
HMC5843_MODE_SLEEP);
}
EXPORT_SYMBOL(hmc5843_common_resume);
int hmc5843_common_probe(struct device *dev, struct regmap *regmap,
enum hmc5843_ids id)
{ {
struct hmc5843_data *data; struct hmc5843_data *data;
struct iio_dev *indio_dev; struct iio_dev *indio_dev;
int ret; int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (indio_dev == NULL) if (indio_dev == NULL)
return -ENOMEM; return -ENOMEM;
dev_set_drvdata(dev, indio_dev);
/* default settings at probe */ /* default settings at probe */
data = iio_priv(indio_dev); data = iio_priv(indio_dev);
data->client = client; data->dev = dev;
data->variant = &hmc5843_chip_info_tbl[id->driver_data]; data->regmap = regmap;
data->variant = &hmc5843_chip_info_tbl[id];
mutex_init(&data->lock); mutex_init(&data->lock);
i2c_set_clientdata(client, indio_dev); indio_dev->dev.parent = dev;
indio_dev->info = &hmc5843_info; indio_dev->info = &hmc5843_info;
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = data->variant->channels; indio_dev->channels = data->variant->channels;
indio_dev->num_channels = 4; indio_dev->num_channels = 4;
...@@ -584,10 +617,11 @@ static int hmc5843_probe(struct i2c_client *client, ...@@ -584,10 +617,11 @@ static int hmc5843_probe(struct i2c_client *client,
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
return ret; return ret;
} }
EXPORT_SYMBOL(hmc5843_common_probe);
static int hmc5843_remove(struct i2c_client *client) int hmc5843_common_remove(struct device *dev)
{ {
struct iio_dev *indio_dev = i2c_get_clientdata(client); struct iio_dev *indio_dev = dev_get_drvdata(dev);
iio_device_unregister(indio_dev); iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev); iio_triggered_buffer_cleanup(indio_dev);
...@@ -597,58 +631,8 @@ static int hmc5843_remove(struct i2c_client *client) ...@@ -597,58 +631,8 @@ static int hmc5843_remove(struct i2c_client *client)
return 0; return 0;
} }
EXPORT_SYMBOL(hmc5843_common_remove);
#ifdef CONFIG_PM_SLEEP
static int hmc5843_suspend(struct device *dev)
{
struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return hmc5843_set_mode(data, HMC5843_MODE_SLEEP);
}
static int hmc5843_resume(struct device *dev)
{
struct hmc5843_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS);
}
static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
#define HMC5843_PM_OPS (&hmc5843_pm_ops)
#else
#define HMC5843_PM_OPS NULL
#endif
static const struct i2c_device_id hmc5843_id[] = {
{ "hmc5843", HMC5843_ID },
{ "hmc5883", HMC5883_ID },
{ "hmc5883l", HMC5883L_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, hmc5843_id);
static const struct of_device_id hmc5843_of_match[] = {
{ .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID },
{ .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID },
{ .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID },
{}
};
MODULE_DEVICE_TABLE(of, hmc5843_of_match);
static struct i2c_driver hmc5843_driver = {
.driver = {
.name = "hmc5843",
.pm = HMC5843_PM_OPS,
.of_match_table = hmc5843_of_match,
},
.id_table = hmc5843_id,
.probe = hmc5843_probe,
.remove = hmc5843_remove,
};
module_i2c_driver(hmc5843_driver);
MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>"); MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>");
MODULE_DESCRIPTION("HMC5843/5883/5883L driver"); MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* i2c driver for hmc5843/5843/5883/5883l/5983
*
* Split from hmc5843.c
* Copyright (C) Josef Gajdusek <atx@atx.name>
*
* 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.
*
* */
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include "hmc5843.h"
static const struct regmap_range hmc5843_readable_ranges[] = {
regmap_reg_range(0, HMC5843_ID_END),
};
static struct regmap_access_table hmc5843_readable_table = {
.yes_ranges = hmc5843_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
};
static const struct regmap_range hmc5843_writable_ranges[] = {
regmap_reg_range(0, HMC5843_MODE_REG),
};
static struct regmap_access_table hmc5843_writable_table = {
.yes_ranges = hmc5843_writable_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
};
static const struct regmap_range hmc5843_volatile_ranges[] = {
regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
};
static struct regmap_access_table hmc5843_volatile_table = {
.yes_ranges = hmc5843_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
};
static struct regmap_config hmc5843_i2c_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.rd_table = &hmc5843_readable_table,
.wr_table = &hmc5843_writable_table,
.volatile_table = &hmc5843_volatile_table,
.cache_type = REGCACHE_RBTREE,
};
static int hmc5843_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
return hmc5843_common_probe(&client->dev,
devm_regmap_init_i2c(client, &hmc5843_i2c_regmap_config),
id->driver_data);
}
static int hmc5843_i2c_remove(struct i2c_client *client)
{
return hmc5843_common_remove(&client->dev);
}
static const struct i2c_device_id hmc5843_id[] = {
{ "hmc5843", HMC5843_ID },
{ "hmc5883", HMC5883_ID },
{ "hmc5883l", HMC5883L_ID },
{ "hmc5983", HMC5983_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, hmc5843_id);
static const struct of_device_id hmc5843_of_match[] = {
{ .compatible = "honeywell,hmc5843", .data = (void *)HMC5843_ID },
{ .compatible = "honeywell,hmc5883", .data = (void *)HMC5883_ID },
{ .compatible = "honeywell,hmc5883l", .data = (void *)HMC5883L_ID },
{ .compatible = "honeywell,hmc5983", .data = (void *)HMC5983_ID },
{}
};
MODULE_DEVICE_TABLE(of, hmc5843_of_match);
static struct i2c_driver hmc5843_driver = {
.driver = {
.name = "hmc5843",
.pm = HMC5843_PM_OPS,
.of_match_table = hmc5843_of_match,
},
.id_table = hmc5843_id,
.probe = hmc5843_i2c_probe,
.remove = hmc5843_i2c_remove,
};
module_i2c_driver(hmc5843_driver);
MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 i2c driver");
MODULE_LICENSE("GPL");
/*
* SPI driver for hmc5983
*
* Copyright (C) Josef Gajdusek <atx@atx.name>
*
* 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.
*
* */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/iio/iio.h>
#include "hmc5843.h"
static const struct regmap_range hmc5843_readable_ranges[] = {
regmap_reg_range(0, HMC5843_ID_END),
};
static struct regmap_access_table hmc5843_readable_table = {
.yes_ranges = hmc5843_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges),
};
static const struct regmap_range hmc5843_writable_ranges[] = {
regmap_reg_range(0, HMC5843_MODE_REG),
};
static struct regmap_access_table hmc5843_writable_table = {
.yes_ranges = hmc5843_writable_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges),
};
static const struct regmap_range hmc5843_volatile_ranges[] = {
regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG),
};
static struct regmap_access_table hmc5843_volatile_table = {
.yes_ranges = hmc5843_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges),
};
static struct regmap_config hmc5843_spi_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.rd_table = &hmc5843_readable_table,
.wr_table = &hmc5843_writable_table,
.volatile_table = &hmc5843_volatile_table,
/* Autoincrement address pointer */
.read_flag_mask = 0xc0,
.cache_type = REGCACHE_RBTREE,
};
static int hmc5843_spi_probe(struct spi_device *spi)
{
int ret;
spi->mode = SPI_MODE_3;
spi->max_speed_hz = 8000000;
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret)
return ret;
return hmc5843_common_probe(&spi->dev,
devm_regmap_init_spi(spi, &hmc5843_spi_regmap_config),
HMC5983_ID);
}
static int hmc5843_spi_remove(struct spi_device *spi)
{
return hmc5843_common_remove(&spi->dev);
}
static const struct spi_device_id hmc5843_id[] = {
{ "hmc5983", HMC5983_ID },
{ }
};
static struct spi_driver hmc5843_driver = {
.driver = {
.name = "hmc5843",
.pm = HMC5843_PM_OPS,
.owner = THIS_MODULE,
},
.id_table = hmc5843_id,
.probe = hmc5843_spi_probe,
.remove = hmc5843_spi_remove,
};
module_spi_driver(hmc5843_driver);
MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>");
MODULE_DESCRIPTION("HMC5983 SPI driver");
MODULE_LICENSE("GPL");
...@@ -56,6 +56,10 @@ enum iio_modifier { ...@@ -56,6 +56,10 @@ enum iio_modifier {
IIO_MOD_QUATERNION, IIO_MOD_QUATERNION,
IIO_MOD_TEMP_AMBIENT, IIO_MOD_TEMP_AMBIENT,
IIO_MOD_TEMP_OBJECT, IIO_MOD_TEMP_OBJECT,
IIO_MOD_NORTH_MAGN,
IIO_MOD_NORTH_TRUE,
IIO_MOD_NORTH_MAGN_TILT_COMP,
IIO_MOD_NORTH_TRUE_TILT_COMP
}; };
enum iio_event_type { enum iio_event_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment