1
0
Fork 0

First round of IIO new drivers, cleanups and functionality for the 3.20 cycle take 2

Updated pull request with Daniel's fix on top for the power management
 Kconfig changes that had snuck in since last update of the IIO tree
 worked it's way through from mainline.
 
 Original pull message
 
 New device support
 * jsa1212 proxmity / ambient light sensor
 * SM08500 supported added to the kxcjk-1013 accelerometer driver
 * KMX61 Accelerometer/Magnetometer.  This took a somewhat rocky path
   being first merged, then reverted for a rewrite after a discussion of
   how to support additional functionality and finally being merged prior
   to some last reviews coming in, with resultant follow up patches.
 * Freescale mma9551l driver (minor follow up warning supression patch).
 * Semtech SX9500 proximity device driver.
 * ak8975 gains support for ak09911 and ak09912 and drop the standalone driver
   for the ak09911.
 
 New functionality
  * Dummy driver gains some virtual registers making it more flexible.
  * IIO_ACTIVITY channel types, with modifiers running, walking etc.  This is
    to support on chip motion clasifiers.  As such it is in the form of a
    confidence percentage.  The only devices so far only do binary decisions
    but this gives us room when other devices give more nuanced clasification.
  * IIO_EV_DIR_NONE type for events where there is no obvious direction.
    First case is step detection.
  * IIO_STEPS channel type for pedometers.
  * ENABLE mask element used to control turning on counting types such as
    the pedometer that need a 'start point'.
  * INSTANCE event type to support things that happen once.
  * info element for height calibration (used in various motion estimation
    algorithms). Note heigh tof use
  * dummy driver demonstration of the use of all the new bits above.
  * event monitor support for the new events.
  * inv_mpu6050 gains an i2c mux to allow bypassing the device to access
    additional devices connected on the other side of it.  Note that in
    Windows these are handled by firmware on the device and not exposed
    directly.
  * inv_mpu6050 gains ACPI enumeration.
  * inkern interface gains iio_write_channel_raw to allow in kernel users
    of DAC functionality via a simple wrapper.
  * Document input current readings in the ABI docs.
  * Add an error message when we get an out of range error in device tree
    processing for the in kernel interfaces.  Basically a device tree debugging
    aid.
  * Add a sanity check that a scan index for a channel is unique during
    registration.  There to help catch bugs as this should never happen
    in a bug free driver.
 
 Cleanups and fixlets
 
  A rework of buffer registration from Lars - a precursor to some other
  upcoming new stuff (a few patches from others rolled in here as well).
  * Ensure all drivers register the same channels for the device and buffer.
  * Move buffer registration into the core rather than using the old
    two step approach.  Now we have simple ways of using a unified set channels
    for both without requiring channels be exposed by both interface, this
    removes a fair bit of boilerplate.
  * Stop sca3000 and ad5933 (both in staging) enabling buffer channels by
    default. It has long be convention in IIO to startup with no channels
    enabled and leave it up to userspace to say what goes in the buffer.
    Getting rid of these allows us to drop export of iio_scan_mask_set.
  * Drop get_bytes_per_datum from iio_buffer_access_funcs as not been used
    for a while.
  * Allocate standard buffer attributes in the core rather than in every
    driver with a buffer.
  * Make the length attribute read only when a driver is not able to set
    the length.
  * Drop the get_length callback for buffers as it is already available in
    struct iio_buffer.
  * Drop an unused arguement form iio_kfifo_allocate and add devm allocator
    for it.
  * some kconfig entries gain anotation with the resulting module name.
  * Fix a resulting compile issue in dummy driver due to a stub taking
    wrong parameters as a result of the above rework.
  * Fix an off by 2 error in copying the core assigned buffer attributes.
 
 Other cleanups,
  * Trivial space before comma fixups.
  * ak8975 fixlets - none critical.  Rework to allow more device support.
  * Drop unnecessary sizeof(u8) calls.
  * bmp280 - refactor the compensation code to reduce copy operations and
    code length.  A second patch futher optimized this and performed some
    other minor cleanups.
  * kxcjk-1013 - various power control cleanups to avoid unnecessary enable
    / disable of device.  Make sure it is only controlled at all if CONFIG_PM
    is enabled.  Also som cleanups of error paths.
  * Small cleanups in adf4530 driver - pointless message and unnecessary braces.
  * Clarifiy the proximity ABI docs to make it clear it should get bigger
    as we move futher away.
  * Drop a misleading comment form industrialio-core.c
  * Trivial white space cleanups.
  * sca3000 looses an unused debug function.
  * Fix char unsigned ordering in ad8366
  * Increase the sleep time in ad9523 to make it predictable (value didn't
    really matter so make it more than 20 msecs)
  * mxs-lradc touchscreen property cleanups in device tree are fixed to ensure
    the meet all the 'interesting' documentation.
  * A couple of cleanups for the staging ad5933 driver to avoid unnecessary
    conversion to a processed temperature vlaue in kernel and remove
    platform data form the state structure as not needed after probe.
  * Fix a wrong scale factor in the docs.
 
 Misc
  * Add IIO include files to the maintainers entry.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJUvtDlAAoJEFSFNJnE9BaIaNMQAI9ZYOrOmvSpxPV4ab71it9z
 gi03VG8+iJl0dPgwcSHeFZvSDiNAOWSX/XdWLoxFAdpjpsnytIp01s9+c3ogz58j
 pYbjxuOT2Qcf+36REuaFkQPFV2ppXMvwDwFUUNeFVupu+bVUKeZuNafBDp00aN1c
 o4MPDwoS1EcTHL+77iCg06exL8LozOwLabfUTRVIRkhIqikemghcmubQHH06m+dk
 EMddtNcXTVR4cJLX076nkKsNDHgmfoBYL9Hy/OvQbjWYAxoZg+q90ZX8yCy0Z5oW
 otChj5XpoYRIa7X6xvP5kTebD4iiR/COWer83EyqFosXhmQ/27rWasST42j1K3q/
 mU40skbscDef4F6COMlgBtVh1FhKUm9AHPAGk5swW792Qjpd4xdt+GShU5bJCa4O
 OOZYk8ulraELeWVz2IK+CrOvJYeTSrNQR6VA6sBjWRHeqxtB0yOJkhxX9NUcSIgJ
 GwM8qNTrQUkvI7OGvFGvf8hp9cboJTKEfzC+yspj+OJSjgJgNWw2pOjzJjsexxaL
 nT2rKhPg46hC+FR4IvPPjhGihCtMSgBWkwbHSeXH+TgRfbbTUh6y6sqEUZraVhnQ
 LKde54G0aH1XBFIM6fwWIPgdWBWsI3b3pFuBRMzhORdcCuAUOvDSyc5hVcaA8qb5
 UZghapUruB556xjoMV3n
 =LlJD
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-3.20a_take2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-testing

Jonathan writes:

First round of IIO new drivers, cleanups and functionality for the 3.20 cycle take 2

Updated pull request with Daniel's fix on top for the power management
Kconfig changes that had snuck in since last update of the IIO tree
worked it's way through from mainline.

Original pull message

New device support
* jsa1212 proxmity / ambient light sensor
* SM08500 supported added to the kxcjk-1013 accelerometer driver
* KMX61 Accelerometer/Magnetometer.  This took a somewhat rocky path
  being first merged, then reverted for a rewrite after a discussion of
  how to support additional functionality and finally being merged prior
  to some last reviews coming in, with resultant follow up patches.
* Freescale mma9551l driver (minor follow up warning supression patch).
* Semtech SX9500 proximity device driver.
* ak8975 gains support for ak09911 and ak09912 and drop the standalone driver
  for the ak09911.

New functionality
 * Dummy driver gains some virtual registers making it more flexible.
 * IIO_ACTIVITY channel types, with modifiers running, walking etc.  This is
   to support on chip motion clasifiers.  As such it is in the form of a
   confidence percentage.  The only devices so far only do binary decisions
   but this gives us room when other devices give more nuanced clasification.
 * IIO_EV_DIR_NONE type for events where there is no obvious direction.
   First case is step detection.
 * IIO_STEPS channel type for pedometers.
 * ENABLE mask element used to control turning on counting types such as
   the pedometer that need a 'start point'.
 * INSTANCE event type to support things that happen once.
 * info element for height calibration (used in various motion estimation
   algorithms). Note heigh tof use
 * dummy driver demonstration of the use of all the new bits above.
 * event monitor support for the new events.
 * inv_mpu6050 gains an i2c mux to allow bypassing the device to access
   additional devices connected on the other side of it.  Note that in
   Windows these are handled by firmware on the device and not exposed
   directly.
 * inv_mpu6050 gains ACPI enumeration.
 * inkern interface gains iio_write_channel_raw to allow in kernel users
   of DAC functionality via a simple wrapper.
 * Document input current readings in the ABI docs.
 * Add an error message when we get an out of range error in device tree
   processing for the in kernel interfaces.  Basically a device tree debugging
   aid.
 * Add a sanity check that a scan index for a channel is unique during
   registration.  There to help catch bugs as this should never happen
   in a bug free driver.

Cleanups and fixlets

 A rework of buffer registration from Lars - a precursor to some other
 upcoming new stuff (a few patches from others rolled in here as well).
 * Ensure all drivers register the same channels for the device and buffer.
 * Move buffer registration into the core rather than using the old
   two step approach.  Now we have simple ways of using a unified set channels
   for both without requiring channels be exposed by both interface, this
   removes a fair bit of boilerplate.
 * Stop sca3000 and ad5933 (both in staging) enabling buffer channels by
   default. It has long be convention in IIO to startup with no channels
   enabled and leave it up to userspace to say what goes in the buffer.
   Getting rid of these allows us to drop export of iio_scan_mask_set.
 * Drop get_bytes_per_datum from iio_buffer_access_funcs as not been used
   for a while.
 * Allocate standard buffer attributes in the core rather than in every
   driver with a buffer.
 * Make the length attribute read only when a driver is not able to set
   the length.
 * Drop the get_length callback for buffers as it is already available in
   struct iio_buffer.
 * Drop an unused arguement form iio_kfifo_allocate and add devm allocator
   for it.
 * some kconfig entries gain anotation with the resulting module name.
 * Fix a resulting compile issue in dummy driver due to a stub taking
   wrong parameters as a result of the above rework.
 * Fix an off by 2 error in copying the core assigned buffer attributes.

Other cleanups,
 * Trivial space before comma fixups.
 * ak8975 fixlets - none critical.  Rework to allow more device support.
 * Drop unnecessary sizeof(u8) calls.
 * bmp280 - refactor the compensation code to reduce copy operations and
   code length.  A second patch futher optimized this and performed some
   other minor cleanups.
 * kxcjk-1013 - various power control cleanups to avoid unnecessary enable
   / disable of device.  Make sure it is only controlled at all if CONFIG_PM
   is enabled.  Also som cleanups of error paths.
 * Small cleanups in adf4530 driver - pointless message and unnecessary braces.
 * Clarifiy the proximity ABI docs to make it clear it should get bigger
   as we move futher away.
 * Drop a misleading comment form industrialio-core.c
 * Trivial white space cleanups.
 * sca3000 looses an unused debug function.
 * Fix char unsigned ordering in ad8366
 * Increase the sleep time in ad9523 to make it predictable (value didn't
   really matter so make it more than 20 msecs)
 * mxs-lradc touchscreen property cleanups in device tree are fixed to ensure
   the meet all the 'interesting' documentation.
 * A couple of cleanups for the staging ad5933 driver to avoid unnecessary
   conversion to a processed temperature vlaue in kernel and remove
   platform data form the state structure as not needed after probe.
 * Fix a wrong scale factor in the docs.

Misc
 * Add IIO include files to the maintainers entry.
hifive-unleashed-5.1
Greg Kroah-Hartman 2015-01-21 10:13:37 +08:00
commit 6e49557b31
63 changed files with 5314 additions and 1116 deletions

View File

@ -92,6 +92,18 @@ Description:
is required is a consistent labeling. Units after application
of scale and offset are millivolts.
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
KernelVersion: 3.17
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no bias removal etc.) current measurement from
channel Y. In special cases where the channel does not
correspond to externally available input one of the named
versions may be used. The number must always be specified and
unique to allow association with event codes. Units after
application of scale and offset are milliamps.
What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
KernelVersion: 3.2
Contact: linux-iio@vger.kernel.org
@ -234,6 +246,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@ -262,6 +276,9 @@ What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale
@ -323,6 +340,14 @@ Description:
production inaccuracies). If shared across all channels,
<type>_calibscale is used.
What: /sys/bus/iio/devices/iio:deviceX/in_steps_calibheight
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Height of the user (in centimeters) used by some pedometers
to compute the stride length, distance, speed and activity
type.
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale_available
What: /sys/.../iio:deviceX/in_voltageX_scale_available
What: /sys/.../iio:deviceX/in_voltage-voltage_scale_available
@ -790,6 +815,40 @@ Description:
met before an event is generated. If direction is not
specified then this period applies to both directions.
What: /sys/.../events/in_activity_still_thresh_rising_en
What: /sys/.../events/in_activity_still_thresh_falling_en
What: /sys/.../events/in_activity_walking_thresh_rising_en
What: /sys/.../events/in_activity_walking_thresh_falling_en
What: /sys/.../events/in_activity_jogging_thresh_rising_en
What: /sys/.../events/in_activity_jogging_thresh_falling_en
What: /sys/.../events/in_activity_running_thresh_rising_en
What: /sys/.../events/in_activity_running_thresh_falling_en
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Enables or disables activitity events. Depending on direction
an event is generated when sensor ENTERS or LEAVES a given state.
What: /sys/.../events/in_activity_still_thresh_rising_value
What: /sys/.../events/in_activity_still_thresh_falling_value
What: /sys/.../events/in_activity_walking_thresh_rising_value
What: /sys/.../events/in_activity_walking_thresh_falling_value
What: /sys/.../events/in_activity_jogging_thresh_rising_value
What: /sys/.../events/in_activity_jogging_thresh_falling_value
What: /sys/.../events/in_activity_running_thresh_rising_value
What: /sys/.../events/in_activity_running_thresh_falling_value
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Confidence value (in units as percentage) to be used
for deciding when an event should be generated. E.g for
running: If the confidence value reported by the sensor
is greater than in_activity_running_thresh_rising_value
then the sensor ENTERS running state. Conversely, if the
confidence value reported by the sensor is lower than
in_activity_running_thresh_falling_value then the sensor
is LEAVING running state.
What: /sys/.../iio:deviceX/events/in_accel_mag_en
What: /sys/.../iio:deviceX/events/in_accel_mag_rising_en
What: /sys/.../iio:deviceX/events/in_accel_mag_falling_en
@ -822,6 +881,13 @@ Description:
number or direction is not specified, applies to all channels of
this type.
What: /sys/.../events/in_steps_instance_en
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Enables or disables step detection. Each time the user takes a step an
event of this type will be generated.
What: /sys/bus/iio/devices/iio:deviceX/trigger/current_trigger
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
@ -956,6 +1022,16 @@ Description:
and the relevant _type attributes to establish the data storage
format.
What: /sys/.../iio:deviceX/in_activity_still_input
What: /sys/.../iio:deviceX/in_activity_walking_input
What: /sys/.../iio:deviceX/in_activity_jogging_input
What: /sys/.../iio:deviceX/in_activity_running_input
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to read the confidence for an activity
expressed in units as percentage.
What: /sys/.../iio:deviceX/in_anglvel_z_quadrature_correction_raw
KernelVersion: 2.6.38
Contact: linux-iio@vger.kernel.org
@ -992,7 +1068,9 @@ Description:
reflectivity of infrared or ultrasound emitted.
Often these sensors are unit less and as such conversion
to SI units is not possible. Where it is, the units should
be meters.
be meters. If such a conversion is not possible, the reported
values should behave in the same way as a distance, i.e. lower
values indicate something is closer to the sensor.
What: /sys/.../iio:deviceX/in_illuminanceY_input
What: /sys/.../iio:deviceX/in_illuminanceY_raw
@ -1051,3 +1129,18 @@ Description:
after application of scale and offset. If no offset or scale is
present, output should be considered as processed with the
unit in milliamps.
What: /sys/.../iio:deviceX/in_steps_en
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
Activates the step counter. After activation, the number of steps
taken by the user will be counted in hardware and exported through
in_steps_input.
What: /sys/.../iio:deviceX/in_steps_input
KernelVersion: 3.19
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to read the number of steps taken by the user
since the last reboot while activated.

View File

@ -12,9 +12,9 @@ Optional properties:
property is not present, then the touchscreen is
disabled. 5 wires is valid for i.MX28 SoC only.
- fsl,ave-ctrl: number of samples per direction to calculate an average value.
Allowed value is 1 ... 31, default is 4
Allowed value is 1 ... 32, default is 4
- fsl,ave-delay: delay between consecutive samples. Allowed value is
1 ... 2047. It is used if 'fsl,ave-ctrl' > 1, counts at
2 ... 2048. It is used if 'fsl,ave-ctrl' > 1, counts at
2 kHz and its default is 2 (= 1 ms)
- fsl,settling: delay between plate switch to next sample. Allowed value is
1 ... 2047. It counts at 2 kHz and its default is

View File

@ -258,6 +258,8 @@ IIO
devm_iio_device_free()
devm_iio_device_register()
devm_iio_device_unregister()
devm_iio_kfifo_allocate()
devm_iio_kfifo_free()
devm_iio_trigger_alloc()
devm_iio_trigger_free()

View File

@ -43,6 +43,9 @@ config HID_SENSOR_ACCEL_3D
Say yes here to build support for the HID SENSOR
accelerometers 3D.
To compile this driver as a module, choose M here: the
module will be called hid-sensor-accel-3d.
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
@ -80,6 +83,9 @@ config KXSD9
Say yes here to build support for the Kionix KXSD9 accelerometer.
Currently this only supports the device via an SPI interface.
To compile this driver as a module, choose M here: the module
will be called kxsd9.
config MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
depends on I2C
@ -105,4 +111,14 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
config MMA9551
tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
depends on I2C
help
Say yes here to build support for the Freescale MMA9551L
Intelligent Motion-Sensing Platform Driver.
To compile this driver as a module, choose M here: the module
will be called mma9551.
endmenu

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_MMA8452) += mma8452.o
obj-$(CONFIG_MMA9551) += mma9551.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
st_accel-y := st_accel_core.o

View File

@ -108,6 +108,7 @@ struct kxcjk1013_data {
bool motion_trigger_on;
int64_t timestamp;
enum kx_chipset chipset;
bool is_smo8500_device;
};
enum kxcjk1013_axis {
@ -377,6 +378,7 @@ static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
{
#ifdef CONFIG_PM
int ret;
if (on)
@ -388,8 +390,11 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: kxcjk1013_set_power_state for %d\n", on);
if (on)
pm_runtime_put_noidle(&data->client->dev);
return ret;
}
#endif
return 0;
}
@ -858,6 +863,8 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev,
ret = kxcjk1013_setup_any_motion_interrupt(data, state);
if (ret < 0) {
kxcjk1013_set_power_state(data, false);
data->ev_enable_state = 0;
mutex_unlock(&data->mutex);
return ret;
}
@ -1008,6 +1015,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
else
ret = kxcjk1013_setup_new_data_interrupt(data, state);
if (ret < 0) {
kxcjk1013_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
@ -1131,12 +1139,16 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
}
static const char *kxcjk1013_match_acpi_device(struct device *dev,
enum kx_chipset *chipset)
enum kx_chipset *chipset,
bool *is_smo8500_device)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
if (strcmp(id->id, "SMO8500") == 0)
*is_smo8500_device = true;
*chipset = (enum kx_chipset)id->driver_data;
return dev_name(dev);
@ -1151,6 +1163,8 @@ static int kxcjk1013_gpio_probe(struct i2c_client *client,
if (!client)
return -EINVAL;
if (data->is_smo8500_device)
return -ENOTSUPP;
dev = &client->dev;
@ -1200,7 +1214,8 @@ static int kxcjk1013_probe(struct i2c_client *client,
name = id->name;
} else if (ACPI_HANDLE(&client->dev)) {
name = kxcjk1013_match_acpi_device(&client->dev,
&data->chipset);
&data->chipset,
&data->is_smo8500_device);
} else
return -ENODEV;
@ -1228,21 +1243,25 @@ static int kxcjk1013_probe(struct i2c_client *client,
KXCJK1013_IRQ_NAME,
indio_dev);
if (ret)
return ret;
goto err_poweroff;
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
indio_dev->id);
if (!data->dready_trig)
return -ENOMEM;
if (!data->dready_trig) {
ret = -ENOMEM;
goto err_poweroff;
}
data->motion_trig = devm_iio_trigger_alloc(&client->dev,
"%s-any-motion-dev%d",
indio_dev->name,
indio_dev->id);
if (!data->motion_trig)
return -ENOMEM;
if (!data->motion_trig) {
ret = -ENOMEM;
goto err_poweroff;
}
data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &kxcjk1013_trigger_ops;
@ -1251,7 +1270,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
iio_trigger_get(indio_dev->trig);
ret = iio_trigger_register(data->dready_trig);
if (ret)
return ret;
goto err_poweroff;
data->motion_trig->dev.parent = &client->dev;
data->motion_trig->ops = &kxcjk1013_trigger_ops;
@ -1300,6 +1319,8 @@ err_trigger_unregister:
iio_trigger_unregister(data->dready_trig);
if (data->motion_trig)
iio_trigger_unregister(data->motion_trig);
err_poweroff:
kxcjk1013_set_mode(data, STANDBY);
return ret;
}
@ -1349,10 +1370,7 @@ static int kxcjk1013_resume(struct device *dev)
int ret = 0;
mutex_lock(&data->mutex);
/* Check, if the suspend occured while active */
if (data->dready_trigger_on || data->motion_trigger_on ||
data->ev_enable_state)
ret = kxcjk1013_set_mode(data, OPERATION);
ret = kxcjk1013_set_mode(data, OPERATION);
mutex_unlock(&data->mutex);
return ret;
@ -1364,8 +1382,14 @@ static int kxcjk1013_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct kxcjk1013_data *data = iio_priv(indio_dev);
int ret;
return kxcjk1013_set_mode(data, STANDBY);
ret = kxcjk1013_set_mode(data, STANDBY);
if (ret < 0) {
dev_err(&data->client->dev, "powering off device failed\n");
return -EAGAIN;
}
return 0;
}
static int kxcjk1013_runtime_resume(struct device *dev)
@ -1399,6 +1423,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXTJ1009", KXTJ21009},
{"SMO8500", KXCJ91008},
{ },
};
MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
@ -1407,6 +1432,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{"SMO8500", KXCJ91008},
{}
};

View File

@ -111,7 +111,7 @@ static const int mma8452_samp_freq[8][2] = {
{6, 250000}, {1, 560000}
};
/*
/*
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor is given by:

View File

@ -0,0 +1,956 @@
/*
* Freescale MMA9551L Intelligent Motion-Sensing Platform driver
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#define MMA9551_DRV_NAME "mma9551"
#define MMA9551_IRQ_NAME "mma9551_event"
#define MMA9551_GPIO_NAME "mma9551_int"
#define MMA9551_GPIO_COUNT 4
/* Applications IDs */
#define MMA9551_APPID_VERSION 0x00
#define MMA9551_APPID_GPIO 0x03
#define MMA9551_APPID_AFE 0x06
#define MMA9551_APPID_TILT 0x0B
#define MMA9551_APPID_SLEEP_WAKE 0x12
#define MMA9551_APPID_RESET 0x17
#define MMA9551_APPID_NONE 0xff
/* Command masks for mailbox write command */
#define MMA9551_CMD_READ_VERSION_INFO 0x00
#define MMA9551_CMD_READ_CONFIG 0x10
#define MMA9551_CMD_WRITE_CONFIG 0x20
#define MMA9551_CMD_READ_STATUS 0x30
enum mma9551_gpio_pin {
mma9551_gpio6 = 0,
mma9551_gpio7,
mma9551_gpio8,
mma9551_gpio9,
mma9551_gpio_max = mma9551_gpio9,
};
/* Mailbox read command */
#define MMA9551_RESPONSE_COCO BIT(7)
/* Error-Status codes returned in mailbox read command */
#define MMA9551_MCI_ERROR_NONE 0x00
#define MMA9551_MCI_ERROR_PARAM 0x04
#define MMA9551_MCI_INVALID_COUNT 0x19
#define MMA9551_MCI_ERROR_COMMAND 0x1C
#define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21
#define MMA9551_MCI_ERROR_FIFO_BUSY 0x22
#define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23
#define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24
/* GPIO Application */
#define MMA9551_GPIO_POL_MSB 0x08
#define MMA9551_GPIO_POL_LSB 0x09
/* Sleep/Wake application */
#define MMA9551_SLEEP_CFG 0x06
#define MMA9551_SLEEP_CFG_SNCEN BIT(0)
#define MMA9551_SLEEP_CFG_SCHEN BIT(2)
/* AFE application */
#define MMA9551_AFE_X_ACCEL_REG 0x00
#define MMA9551_AFE_Y_ACCEL_REG 0x02
#define MMA9551_AFE_Z_ACCEL_REG 0x04
/* Tilt application (inclination in IIO terms). */
#define MMA9551_TILT_XZ_ANG_REG 0x00
#define MMA9551_TILT_YZ_ANG_REG 0x01
#define MMA9551_TILT_XY_ANG_REG 0x02
#define MMA9551_TILT_ANGFLG BIT(7)
#define MMA9551_TILT_QUAD_REG 0x03
#define MMA9551_TILT_XY_QUAD_SHIFT 0
#define MMA9551_TILT_YZ_QUAD_SHIFT 2
#define MMA9551_TILT_XZ_QUAD_SHIFT 4
#define MMA9551_TILT_CFG_REG 0x01
#define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0)
/* Tilt events are mapped to the first three GPIO pins. */
enum mma9551_tilt_axis {
mma9551_x = 0,
mma9551_y,
mma9551_z,
};
/*
* A response is composed of:
* - control registers: MB0-3
* - data registers: MB4-31
*
* A request is composed of:
* - mbox to write to (always 0)
* - control registers: MB1-4
* - data registers: MB5-31
*/
#define MMA9551_MAILBOX_CTRL_REGS 4
#define MMA9551_MAX_MAILBOX_DATA_REGS 28
#define MMA9551_MAILBOX_REGS 32
#define MMA9551_I2C_READ_RETRIES 5
#define MMA9551_I2C_READ_DELAY 50 /* us */
struct mma9551_mbox_request {
u8 start_mbox; /* Always 0. */
u8 app_id;
/*
* See Section 5.3.1 of the MMA955xL Software Reference Manual.
*
* Bit 7: reserved, always 0
* Bits 6-4: command
* Bits 3-0: upper bits of register offset
*/
u8 cmd_off;
u8 lower_off;
u8 nbytes;
u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
} __packed;
struct mma9551_mbox_response {
u8 app_id;
/*
* See Section 5.3.3 of the MMA955xL Software Reference Manual.
*
* Bit 7: COCO
* Bits 6-0: Error code.
*/
u8 coco_err;
u8 nbytes;
u8 req_bytes;
u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
} __packed;
struct mma9551_version_info {
__be32 device_id;
u8 rom_version[2];
u8 fw_version[2];
u8 hw_version[2];
u8 fw_build[2];
};
struct mma9551_data {
struct i2c_client *client;
struct mutex mutex;
int event_enabled[3];
int irqs[MMA9551_GPIO_COUNT];
};
static int mma9551_transfer(struct i2c_client *client,
u8 app_id, u8 command, u16 offset,
u8 *inbytes, int num_inbytes,
u8 *outbytes, int num_outbytes)
{
struct mma9551_mbox_request req;
struct mma9551_mbox_response rsp;
struct i2c_msg in, out;
u8 req_len, err_code;
int ret, retries;
if (offset >= 1 << 12) {
dev_err(&client->dev, "register offset too large\n");
return -EINVAL;
}
req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
req.start_mbox = 0;
req.app_id = app_id;
req.cmd_off = command | (offset >> 8);
req.lower_off = offset;
if (command == MMA9551_CMD_WRITE_CONFIG)
req.nbytes = num_inbytes;
else
req.nbytes = num_outbytes;
if (num_inbytes)
memcpy(req.buf, inbytes, num_inbytes);
out.addr = client->addr;
out.flags = 0;
out.len = req_len;
out.buf = (u8 *)&req;
ret = i2c_transfer(client->adapter, &out, 1);
if (ret < 0) {
dev_err(&client->dev, "i2c write failed\n");
return ret;
}
retries = MMA9551_I2C_READ_RETRIES;
do {
udelay(MMA9551_I2C_READ_DELAY);
in.addr = client->addr;
in.flags = I2C_M_RD;
in.len = sizeof(rsp);
in.buf = (u8 *)&rsp;
ret = i2c_transfer(client->adapter, &in, 1);
if (ret < 0) {
dev_err(&client->dev, "i2c read failed\n");
return ret;
}
if (rsp.coco_err & MMA9551_RESPONSE_COCO)
break;
} while (--retries > 0);
if (retries == 0) {
dev_err(&client->dev,
"timed out while waiting for command response\n");
return -ETIMEDOUT;
}
if (rsp.app_id != app_id) {
dev_err(&client->dev,
"app_id mismatch in response got %02x expected %02x\n",
rsp.app_id, app_id);
return -EINVAL;
}
err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
if (err_code != MMA9551_MCI_ERROR_NONE) {
dev_err(&client->dev, "read returned error %x\n", err_code);
return -EINVAL;
}
if (rsp.nbytes != rsp.req_bytes) {
dev_err(&client->dev,
"output length mismatch got %d expected %d\n",
rsp.nbytes, rsp.req_bytes);
return -EINVAL;
}
if (num_outbytes)
memcpy(outbytes, rsp.buf, num_outbytes);
return 0;
}
static int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
u16 reg, u8 *val)
{
return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
reg, NULL, 0, val, 1);
}
static int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
u16 reg, u8 val)
{
return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
&val, 1, NULL, 0);
}
static int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
u16 reg, u8 *val)
{
return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
reg, NULL, 0, val, 1);
}
static int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
u16 reg, u16 *val)
{
int ret;
__be16 v;
ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
reg, NULL, 0, (u8 *)&v, 2);
*val = be16_to_cpu(v);
return ret;
}
static int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
u16 reg, u8 mask, u8 val)
{
int ret;
u8 tmp, orig;
ret = mma9551_read_config_byte(client, app_id, reg, &orig);
if (ret < 0)
return ret;
tmp = orig & ~mask;
tmp |= val & mask;
if (tmp == orig)
return 0;
return mma9551_write_config_byte(client, app_id, reg, tmp);
}
/*
* The polarity parameter is described in section 6.2.2, page 66, of the
* Software Reference Manual. Basically, polarity=0 means the interrupt
* line has the same value as the selected bit, while polarity=1 means
* the line is inverted.
*/
static int mma9551_gpio_config(struct i2c_client *client,
enum mma9551_gpio_pin pin,
u8 app_id, u8 bitnum, int polarity)
{
u8 reg, pol_mask, pol_val;
int ret;
if (pin > mma9551_gpio_max) {
dev_err(&client->dev, "bad GPIO pin\n");
return -EINVAL;
}
/*
* Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
* 0x03, and so on.
*/
reg = pin * 2;
ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
reg, app_id);
if (ret < 0) {
dev_err(&client->dev, "error setting GPIO app_id\n");
return ret;
}
ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
reg + 1, bitnum);
if (ret < 0) {
dev_err(&client->dev, "error setting GPIO bit number\n");
return ret;
}
switch (pin) {
case mma9551_gpio6:
reg = MMA9551_GPIO_POL_LSB;
pol_mask = 1 << 6;
break;
case mma9551_gpio7:
reg = MMA9551_GPIO_POL_LSB;
pol_mask = 1 << 7;
break;
case mma9551_gpio8:
reg = MMA9551_GPIO_POL_MSB;
pol_mask = 1 << 0;
break;
case mma9551_gpio9:
reg = MMA9551_GPIO_POL_MSB;
pol_mask = 1 << 1;
break;
}
pol_val = polarity ? pol_mask : 0;
ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
pol_mask, pol_val);
if (ret < 0)
dev_err(&client->dev, "error setting GPIO polarity\n");
return ret;
}
static int mma9551_read_version(struct i2c_client *client)
{
struct mma9551_version_info info;
int ret;
ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
NULL, 0, (u8 *)&info, sizeof(info));
if (ret < 0)
return ret;
dev_info(&client->dev, "Device ID 0x%x, firmware version %02x.%02x\n",
be32_to_cpu(info.device_id), info.fw_version[0],
info.fw_version[1]);
return 0;
}
/*
* Use 'false' as the second parameter to cause the device to enter
* sleep.
*/
static int mma9551_set_device_state(struct i2c_client *client,
bool enable)
{
return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
MMA9551_SLEEP_CFG,
MMA9551_SLEEP_CFG_SNCEN,
enable ? 0 : MMA9551_SLEEP_CFG_SNCEN);
}
static int mma9551_read_incli_chan(struct i2c_client *client,
const struct iio_chan_spec *chan,
int *val)
{
u8 quad_shift, angle, quadrant;
u16 reg_addr;
int ret;
switch (chan->channel2) {
case IIO_MOD_X:
reg_addr = MMA9551_TILT_YZ_ANG_REG;
quad_shift = MMA9551_TILT_YZ_QUAD_SHIFT;
break;
case IIO_MOD_Y:
reg_addr = MMA9551_TILT_XZ_ANG_REG;
quad_shift = MMA9551_TILT_XZ_QUAD_SHIFT;
break;
case IIO_MOD_Z:
reg_addr = MMA9551_TILT_XY_ANG_REG;
quad_shift = MMA9551_TILT_XY_QUAD_SHIFT;
break;
default:
return -EINVAL;
}
ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
reg_addr, &angle);
if (ret < 0)
return ret;
ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
MMA9551_TILT_QUAD_REG, &quadrant);
if (ret < 0)
return ret;
angle &= ~MMA9551_TILT_ANGFLG;
quadrant = (quadrant >> quad_shift) & 0x03;
if (quadrant == 1 || quadrant == 3)
*val = 90 * (quadrant + 1) - angle;
else
*val = angle + 90 * quadrant;
return IIO_VAL_INT;
}
static int mma9551_read_accel_chan(struct i2c_client *client,
const struct iio_chan_spec *chan,
int *val, int *val2)
{
u16 reg_addr;
s16 raw_accel;
int ret;
switch (chan->channel2) {
case IIO_MOD_X:
reg_addr = MMA9551_AFE_X_ACCEL_REG;
break;
case IIO_MOD_Y:
reg_addr = MMA9551_AFE_Y_ACCEL_REG;
break;
case IIO_MOD_Z:
reg_addr = MMA9551_AFE_Z_ACCEL_REG;
break;
default:
return -EINVAL;
}
ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
reg_addr, &raw_accel);
if (ret < 0)
return ret;
*val = raw_accel;
return IIO_VAL_INT;
}
static int mma9551_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mma9551_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_INCLI:
mutex_lock(&data->mutex);
ret = mma9551_read_incli_chan(data->client, chan, val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_ACCEL:
mutex_lock(&data->mutex);
ret = mma9551_read_accel_chan(data->client,
chan, val, val2);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_ACCEL:
*val = 0;
*val2 = 2440;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int mma9551_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct mma9551_data *data = iio_priv(indio_dev);
switch (chan->type) {
case IIO_INCLI:
/* IIO counts axes from 1, because IIO_NO_MOD is 0. */
return data->event_enabled[chan->channel2 - 1];
default:
return -EINVAL;
}
}
static int mma9551_config_incli_event(struct iio_dev *indio_dev,
enum iio_modifier axis,
int state)
{
struct mma9551_data *data = iio_priv(indio_dev);
enum mma9551_tilt_axis mma_axis;
int ret;
/* IIO counts axes from 1, because IIO_NO_MOD is 0. */
mma_axis = axis - 1;
if (data->event_enabled[mma_axis] == state)
return 0;
if (state == 0) {
ret = mma9551_gpio_config(data->client,
(enum mma9551_gpio_pin)mma_axis,
MMA9551_APPID_NONE, 0, 0);
if (ret < 0)
return ret;
} else {
int bitnum;
/* Bit 7 of each angle register holds the angle flag. */
switch (axis) {
case IIO_MOD_X:
bitnum = 7 + 8 * MMA9551_TILT_YZ_ANG_REG;
break;
case IIO_MOD_Y:
bitnum = 7 + 8 * MMA9551_TILT_XZ_ANG_REG;
break;
case IIO_MOD_Z:
bitnum = 7 + 8 * MMA9551_TILT_XY_ANG_REG;
break;
default:
return -EINVAL;
}
ret = mma9551_gpio_config(data->client,
(enum mma9551_gpio_pin)mma_axis,
MMA9551_APPID_TILT, bitnum, 0);
if (ret < 0)
return ret;
}
data->event_enabled[mma_axis] = state;
return ret;
}
static int mma9551_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 mma9551_data *data = iio_priv(indio_dev);
int ret;
switch (chan->type) {
case IIO_INCLI:
mutex_lock(&data->mutex);
ret = mma9551_config_incli_event(indio_dev,
chan->channel2, state);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static int mma9551_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int val, int val2)
{
struct mma9551_data *data = iio_priv(indio_dev);
int ret;
switch (chan->type) {
case IIO_INCLI:
if (val2 != 0 || val < 1 || val > 10)
return -EINVAL;
mutex_lock(&data->mutex);
ret = mma9551_update_config_bits(data->client,
MMA9551_APPID_TILT,
MMA9551_TILT_CFG_REG,
MMA9551_TILT_ANG_THRESH_MASK,
val);
mutex_unlock(&data->mutex);
return ret;
default:
return -EINVAL;
}
}
static int mma9551_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info,
int *val, int *val2)
{
struct mma9551_data *data = iio_priv(indio_dev);
int ret;
u8 tmp;
switch (chan->type) {
case IIO_INCLI:
mutex_lock(&data->mutex);
ret = mma9551_read_config_byte(data->client,
MMA9551_APPID_TILT,
MMA9551_TILT_CFG_REG, &tmp);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
*val = tmp & MMA9551_TILT_ANG_THRESH_MASK;
*val2 = 0;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static const struct iio_event_spec mma9551_incli_event = {
.type = IIO_EV_TYPE_ROC,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
.mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
};
#define MMA9551_ACCEL_CHANNEL(axis) { \
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
#define MMA9551_INCLI_CHANNEL(axis) { \
.type = IIO_INCLI, \
.modified = 1, \
.channel2 = axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
.event_spec = &mma9551_incli_event, \
.num_event_specs = 1, \
}
static const struct iio_chan_spec mma9551_channels[] = {
MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
MMA9551_INCLI_CHANNEL(IIO_MOD_X),
MMA9551_INCLI_CHANNEL(IIO_MOD_Y),
MMA9551_INCLI_CHANNEL(IIO_MOD_Z),
};
static const struct iio_info mma9551_info = {
.driver_module = THIS_MODULE,
.read_raw = mma9551_read_raw,
.read_event_config = mma9551_read_event_config,
.write_event_config = mma9551_write_event_config,
.read_event_value = mma9551_read_event_value,
.write_event_value = mma9551_write_event_value,
};
static irqreturn_t mma9551_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct mma9551_data *data = iio_priv(indio_dev);
int i, ret, mma_axis = -1;
u16 reg;
u8 val;
mutex_lock(&data->mutex);
for (i = 0; i < 3; i++)
if (irq == data->irqs[i]) {
mma_axis = i;
break;
}
if (mma_axis == -1) {
/* IRQ was triggered on 4th line, which we don't use. */
dev_warn(&data->client->dev,
"irq triggered on unused line %d\n", data->irqs[3]);
goto out;
}
switch (mma_axis) {
case mma9551_x:
reg = MMA9551_TILT_YZ_ANG_REG;
break;
case mma9551_y:
reg = MMA9551_TILT_XZ_ANG_REG;
break;
case mma9551_z:
reg = MMA9551_TILT_XY_ANG_REG;
break;
}
/*
* Read the angle even though we don't use it, otherwise we
* won't get any further interrupts.
*/
ret = mma9551_read_status_byte(data->client, MMA9551_APPID_TILT,
reg, &val);
if (ret < 0) {
dev_err(&data->client->dev,
"error %d reading tilt register in IRQ\n", ret);
goto out;
}
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1),
IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING),
iio_get_time_ns());
out:
mutex_unlock(&data->mutex);
return IRQ_HANDLED;
}
static int mma9551_init(struct mma9551_data *data)
{
int ret;
ret = mma9551_read_version(data->client);
if (ret)
return ret;
/* Power on chip and enable doze mode. */
return mma9551_update_config_bits(data->client,
MMA9551_APPID_SLEEP_WAKE,
MMA9551_SLEEP_CFG,
MMA9551_SLEEP_CFG_SCHEN | MMA9551_SLEEP_CFG_SNCEN,
MMA9551_SLEEP_CFG_SCHEN);
}
static int mma9551_gpio_probe(struct iio_dev *indio_dev)
{
struct gpio_desc *gpio;
int i, ret;
struct mma9551_data *data = iio_priv(indio_dev);
struct device *dev = &data->client->dev;
for (i = 0; i < MMA9551_GPIO_COUNT; i++) {
gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
data->irqs[i] = gpiod_to_irq(gpio);
ret = devm_request_threaded_irq(dev, data->irqs[i],
NULL, mma9551_event_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
MMA9551_IRQ_NAME, indio_dev);
if (ret < 0) {
dev_err(dev, "request irq %d failed\n", data->irqs[i]);
return ret;
}
dev_dbg(dev, "gpio resource, no:%d irq:%d\n",
desc_to_gpio(gpio), data->irqs[i]);
}
return 0;
}
static const char *mma9551_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
return dev_name(dev);
}
static int mma9551_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mma9551_data *data;
struct iio_dev *indio_dev;
const char *name = NULL;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
if (id)
name = id->name;
else if (ACPI_HANDLE(&client->dev))
name = mma9551_match_acpi_device(&client->dev);
ret = mma9551_init(data);
if (ret < 0)
return ret;
mutex_init(&data->mutex);
indio_dev->dev.parent = &client->dev;
indio_dev->channels = mma9551_channels;
indio_dev->num_channels = ARRAY_SIZE(mma9551_channels);
indio_dev->name = name;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mma9551_info;
ret = mma9551_gpio_probe(indio_dev);
if (ret < 0)
goto out_poweroff;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev, "unable to register iio device\n");
goto out_poweroff;
}
return 0;
out_poweroff:
mma9551_set_device_state(client, false);
return ret;
}
static int mma9551_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct mma9551_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int mma9551_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mma9551_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, false);
mutex_unlock(&data->mutex);
return 0;
}
static int mma9551_resume(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct mma9551_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
mma9551_set_device_state(data->client, true);
mutex_unlock(&data->mutex);
return 0;
}
#else
#define mma9551_suspend NULL
#define mma9551_resume NULL
#endif
static const struct dev_pm_ops mma9551_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
};
static const struct acpi_device_id mma9551_acpi_match[] = {
{"MMA9551", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
static const struct i2c_device_id mma9551_id[] = {
{"mma9551", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, mma9551_id);
static struct i2c_driver mma9551_driver = {
.driver = {
.name = MMA9551_DRV_NAME,
.acpi_match_table = ACPI_PTR(mma9551_acpi_match),
.pm = &mma9551_pm_ops,
},
.probe = mma9551_probe,
.remove = mma9551_remove,
.id_table = mma9551_id,
};
module_i2c_driver(mma9551_driver);
MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver");

View File

@ -250,7 +250,7 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
struct iio_buffer *buffer;
int ret;
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
@ -264,16 +264,8 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
indio_dev->setup_ops = setup_ops;
indio_dev->modes |= INDIO_BUFFER_HARDWARE;
ret = iio_buffer_register(indio_dev,
indio_dev->channels,
indio_dev->num_channels);
if (ret)
goto error_free_irq;
return 0;
error_free_irq:
free_irq(irq, indio_dev);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
@ -285,7 +277,6 @@ static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev)
free_irq(adc_dev->mfd_tscadc->irq, indio_dev);
iio_kfifo_free(indio_dev->buffer);
iio_buffer_unregister(indio_dev);
}

View File

@ -31,7 +31,7 @@ struct ad8366_state {
};
static int ad8366_write(struct iio_dev *indio_dev,
unsigned char ch_a, char unsigned ch_b)
unsigned char ch_a, unsigned char ch_b)
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
@ -166,7 +166,7 @@ static int ad8366_probe(struct spi_device *spi)
if (ret)
goto error_disable_reg;
ad8366_write(indio_dev, 0 , 0);
ad8366_write(indio_dev, 0, 0);
return 0;

View File

@ -54,7 +54,7 @@ static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
if (err)
goto acc_spi_read_error;
memcpy(data, tb->rx_buf, len*sizeof(u8));
memcpy(data, tb->rx_buf, len);
mutex_unlock(&tb->buf_lock);
return len;

View File

@ -445,7 +445,7 @@ static int ad9523_store_eeprom(struct iio_dev *indio_dev)
tmp = 4;
do {
msleep(16);
msleep(20);
ret = ad9523_read(indio_dev,
AD9523_EEPROM_DATA_XFER_STATUS);
if (ret < 0)

View File

@ -387,10 +387,8 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "could not allocate memory for platform data\n");
if (!pdata)
return NULL;
}
strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
@ -613,9 +611,8 @@ static int adf4350_remove(struct spi_device *spi)
if (st->clk)
clk_disable_unprepare(st->clk);
if (!IS_ERR(reg)) {
if (!IS_ERR(reg))
regulator_disable(reg);
}
return 0;
}

View File

@ -48,6 +48,8 @@ unsigned int iio_buffer_poll(struct file *filp,
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr (&iio_buffer_poll)
#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
@ -60,6 +62,13 @@ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr NULL
#define iio_buffer_read_first_n_outer_addr NULL
static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{
return 0;
}
static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}

View File

@ -25,6 +25,17 @@ config ADIS16480
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
config KMX61
tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
depends on I2C
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for Kionix KMX61 6-axis
accelerometer and magnetometer.
To compile this driver as module, choose M here: the module will
be called kmx61.
source "drivers/iio/imu/inv_mpu6050/Kconfig"
endmenu

View File

@ -14,3 +14,5 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o

View File

@ -7,6 +7,7 @@ config INV_MPU6050_IIO
depends on I2C && SYSFS
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select I2C_MUX
help
This driver supports the Invensense MPU6050 devices.
This driver can also support MPU6500 in MPU6050 compatibility mode

View File

@ -23,6 +23,8 @@
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
#include <linux/i2c-mux.h>
#include <linux/acpi.h>
#include "inv_mpu_iio.h"
/*
@ -52,6 +54,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
.int_enable = INV_MPU6050_REG_INT_ENABLE,
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
.int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
};
static const struct inv_mpu6050_chip_config chip_config_6050 = {
@ -77,6 +80,83 @@ int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d)
return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d);
}
/*
* The i2c read/write needs to happen in unlocked mode. As the parent
* adapter is common. If we use locked versions, it will fail as
* the mux adapter will lock the parent i2c adapter, while calling
* select/deselect functions.
*/
static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
u8 reg, u8 d)
{
int ret;
u8 buf[2];
struct i2c_msg msg[1] = {
{
.addr = st->client->addr,
.flags = 0,
.len = sizeof(buf),
.buf = buf,
}
};
buf[0] = reg;
buf[1] = d;
ret = __i2c_transfer(st->client->adapter, msg, 1);
if (ret != 1)
return ret;
return 0;
}
static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
u32 chan_id)
{
struct iio_dev *indio_dev = mux_priv;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
int ret = 0;
/* Use the same mutex which was used everywhere to protect power-op */
mutex_lock(&indio_dev->mlock);
if (!st->powerup_count) {
ret = inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
0);
if (ret)
goto write_error;
msleep(INV_MPU6050_REG_UP_TIME);
}
if (!ret) {
st->powerup_count++;
ret = inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
st->client->irq |
INV_MPU6050_BIT_BYPASS_EN);
}
write_error:
mutex_unlock(&indio_dev->mlock);
return ret;
}
static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
void *mux_priv, u32 chan_id)
{
struct iio_dev *indio_dev = mux_priv;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
/* It doesn't really mattter, if any of the calls fails */
inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
st->client->irq);
st->powerup_count--;
if (!st->powerup_count)
inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
mutex_unlock(&indio_dev->mlock);
return 0;
}
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
{
u8 d, mgmt_1;
@ -133,13 +213,22 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
{
int result;
int result = 0;
if (power_on) {
/* Already under indio-dev->mlock mutex */
if (!st->powerup_count)
result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
0);
if (!result)
st->powerup_count++;
} else {
st->powerup_count--;
if (!st->powerup_count)
result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
}
if (power_on)
result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0);
else
result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
INV_MPU6050_BIT_SLEEP);
if (result)
return result;
@ -673,6 +762,7 @@ static int inv_mpu_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
st->client = client;
st->powerup_count = 0;
pdata = dev_get_platdata(&client->dev);
if (pdata)
st->plat_data = *pdata;
@ -720,8 +810,21 @@ static int inv_mpu_probe(struct i2c_client *client,
goto out_remove_trigger;
}
st->mux_adapter = i2c_add_mux_adapter(client->adapter,
&client->dev,
indio_dev,
0, 0, 0,
inv_mpu6050_select_bypass,
inv_mpu6050_deselect_bypass);
if (!st->mux_adapter) {
result = -ENODEV;
goto out_unreg_device;
}
return 0;
out_unreg_device:
iio_device_unregister(indio_dev);
out_remove_trigger:
inv_mpu6050_remove_trigger(st);
out_unreg_ring:
@ -734,6 +837,7 @@ static int inv_mpu_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
i2c_del_mux_adapter(st->mux_adapter);
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
iio_triggered_buffer_cleanup(indio_dev);
@ -772,6 +876,13 @@ static const struct i2c_device_id inv_mpu_id[] = {
MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
static const struct acpi_device_id inv_acpi_match[] = {
{"INVN6500", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
static struct i2c_driver inv_mpu_driver = {
.probe = inv_mpu_probe,
.remove = inv_mpu_remove,
@ -780,6 +891,7 @@ static struct i2c_driver inv_mpu_driver = {
.owner = THIS_MODULE,
.name = "inv-mpu6050",
.pm = INV_MPU6050_PMOPS,
.acpi_match_table = ACPI_PTR(inv_acpi_match),
},
};

View File

@ -54,6 +54,7 @@ struct inv_mpu6050_reg_map {
u8 int_enable;
u8 pwr_mgmt_1;
u8 pwr_mgmt_2;
u8 int_pin_cfg;
};
/*device enum */
@ -119,6 +120,8 @@ struct inv_mpu6050_state {
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct i2c_client *client;
struct i2c_adapter *mux_adapter;
unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
};
@ -179,6 +182,9 @@ struct inv_mpu6050_state {
/* 6 + 6 round up and plus 8 */
#define INV_MPU6050_OUTPUT_DATA_SIZE 24
#define INV_MPU6050_REG_INT_PIN_CFG 0x37
#define INV_MPU6050_BIT_BYPASS_EN 0x2
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
#define INV_MPU6050_TIME_STAMP_TOR 5

File diff suppressed because it is too large Load Diff

View File

@ -178,6 +178,80 @@ static ssize_t iio_scan_el_show(struct device *dev,
return sprintf(buf, "%d\n", ret);
}
/* Note NULL used as error indicator as it doesn't make sense. */
static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
unsigned int masklength,
const unsigned long *mask)
{
if (bitmap_empty(mask, masklength))
return NULL;
while (*av_masks) {
if (bitmap_subset(mask, av_masks, masklength))
return av_masks;
av_masks += BITS_TO_LONGS(masklength);
}
return NULL;
}
static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
const unsigned long *mask)
{
if (!indio_dev->setup_ops->validate_scan_mask)
return true;
return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
}
/**
* iio_scan_mask_set() - set particular bit in the scan mask
* @indio_dev: the iio device
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
*
* Note that at this point we have no way of knowing what other
* buffers might request, hence this code only verifies that the
* individual buffers request is plausible.
*/
static int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
const unsigned long *mask;
unsigned long *trialmask;
trialmask = kmalloc(sizeof(*trialmask)*
BITS_TO_LONGS(indio_dev->masklength),
GFP_KERNEL);
if (trialmask == NULL)
return -ENOMEM;
if (!indio_dev->masklength) {
WARN_ON("Trying to set scanmask prior to registering buffer\n");
goto err_invalid_mask;
}
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
set_bit(bit, trialmask);
if (!iio_validate_scan_mask(indio_dev, trialmask))
goto err_invalid_mask;
if (indio_dev->available_scan_masks) {
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
trialmask);
if (!mask)
goto err_invalid_mask;
}
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
kfree(trialmask);
return 0;
err_invalid_mask:
kfree(trialmask);
return -EINVAL;
}
static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
{
clear_bit(bit, buffer->scan_mask);
@ -309,115 +383,19 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
return ret;
}
static const char * const iio_scan_elements_group_name = "scan_elements";
int iio_buffer_register(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels,
int num_channels)
{
struct iio_dev_attr *p;
struct attribute **attr;
struct iio_buffer *buffer = indio_dev->buffer;
int ret, i, attrn, attrcount, attrcount_orig = 0;
if (buffer->attrs)
indio_dev->groups[indio_dev->groupcounter++] = buffer->attrs;
if (buffer->scan_el_attrs != NULL) {
attr = buffer->scan_el_attrs->attrs;
while (*attr++ != NULL)
attrcount_orig++;
}
attrcount = attrcount_orig;
INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
if (channels) {
/* new magic */
for (i = 0; i < num_channels; i++) {
if (channels[i].scan_index < 0)
continue;
/* Establish necessary mask length */
if (channels[i].scan_index >
(int)indio_dev->masklength - 1)
indio_dev->masklength
= channels[i].scan_index + 1;
ret = iio_buffer_add_channel_sysfs(indio_dev,
&channels[i]);
if (ret < 0)
goto error_cleanup_dynamic;
attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
indio_dev->scan_index_timestamp =
channels[i].scan_index;
}
if (indio_dev->masklength && buffer->scan_mask == NULL) {
buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
sizeof(*buffer->scan_mask),
GFP_KERNEL);
if (buffer->scan_mask == NULL) {
ret = -ENOMEM;
goto error_cleanup_dynamic;
}
}
}
buffer->scan_el_group.name = iio_scan_elements_group_name;
buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
sizeof(buffer->scan_el_group.attrs[0]),
GFP_KERNEL);
if (buffer->scan_el_group.attrs == NULL) {
ret = -ENOMEM;
goto error_free_scan_mask;
}
if (buffer->scan_el_attrs)
memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
attrn = attrcount_orig;
list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
return 0;
error_free_scan_mask:
kfree(buffer->scan_mask);
error_cleanup_dynamic:
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
return ret;
}
EXPORT_SYMBOL(iio_buffer_register);
void iio_buffer_unregister(struct iio_dev *indio_dev)
{
kfree(indio_dev->buffer->scan_mask);
kfree(indio_dev->buffer->scan_el_group.attrs);
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
}
EXPORT_SYMBOL(iio_buffer_unregister);
ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf)
static ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
if (buffer->access->get_length)
return sprintf(buf, "%d\n",
buffer->access->get_length(buffer));
return 0;
return sprintf(buf, "%d\n", buffer->length);
}
EXPORT_SYMBOL(iio_buffer_read_length);
ssize_t iio_buffer_write_length(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
static ssize_t iio_buffer_write_length(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
@ -428,47 +406,28 @@ ssize_t iio_buffer_write_length(struct device *dev,
if (ret)
return ret;
if (buffer->access->get_length)
if (val == buffer->access->get_length(buffer))
return len;
if (val == buffer->length)
return len;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) {
ret = -EBUSY;
} else {
if (buffer->access->set_length)
buffer->access->set_length(buffer, val);
buffer->access->set_length(buffer, val);
ret = 0;
}
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
EXPORT_SYMBOL(iio_buffer_write_length);
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
static ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
/* Note NULL used as error indicator as it doesn't make sense. */
static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
unsigned int masklength,
const unsigned long *mask)
{
if (bitmap_empty(mask, masklength))
return NULL;
while (*av_masks) {
if (bitmap_subset(mask, av_masks, masklength))
return av_masks;
av_masks += BITS_TO_LONGS(masklength);
}
return NULL;
}
static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
const unsigned long *mask, bool timestamp)
@ -755,10 +714,10 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(iio_update_buffers);
ssize_t iio_buffer_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
static ssize_t iio_buffer_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len)
{
int ret;
bool requested_state;
@ -790,7 +749,130 @@ done:
mutex_unlock(&indio_dev->mlock);
return (ret < 0) ? ret : len;
}
EXPORT_SYMBOL(iio_buffer_store_enable);
static const char * const iio_scan_elements_group_name = "scan_elements";
static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
iio_buffer_write_length);
static struct device_attribute dev_attr_length_ro = __ATTR(length,
S_IRUGO, iio_buffer_read_length, NULL);
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
iio_buffer_show_enable, iio_buffer_store_enable);
int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{
struct iio_dev_attr *p;
struct attribute **attr;
struct iio_buffer *buffer = indio_dev->buffer;
int ret, i, attrn, attrcount, attrcount_orig = 0;
const struct iio_chan_spec *channels;
if (!buffer)
return 0;
attrcount = 0;
if (buffer->attrs) {
while (buffer->attrs[attrcount] != NULL)
attrcount++;
}
buffer->buffer_group.name = "buffer";
buffer->buffer_group.attrs = kcalloc(attrcount + 3,
sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
if (!buffer->buffer_group.attrs)
return -ENOMEM;
if (buffer->access->set_length)
buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
else
buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
if (buffer->attrs)
memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
sizeof(*&buffer->buffer_group.attrs) * attrcount);
buffer->buffer_group.attrs[attrcount+2] = NULL;
indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
if (buffer->scan_el_attrs != NULL) {
attr = buffer->scan_el_attrs->attrs;
while (*attr++ != NULL)
attrcount_orig++;
}
attrcount = attrcount_orig;
INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
channels = indio_dev->channels;
if (channels) {
/* new magic */
for (i = 0; i < indio_dev->num_channels; i++) {
if (channels[i].scan_index < 0)
continue;
/* Establish necessary mask length */
if (channels[i].scan_index >
(int)indio_dev->masklength - 1)
indio_dev->masklength
= channels[i].scan_index + 1;
ret = iio_buffer_add_channel_sysfs(indio_dev,
&channels[i]);
if (ret < 0)
goto error_cleanup_dynamic;
attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
indio_dev->scan_index_timestamp =
channels[i].scan_index;
}
if (indio_dev->masklength && buffer->scan_mask == NULL) {
buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
sizeof(*buffer->scan_mask),
GFP_KERNEL);
if (buffer->scan_mask == NULL) {
ret = -ENOMEM;
goto error_cleanup_dynamic;
}
}
}
buffer->scan_el_group.name = iio_scan_elements_group_name;
buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
sizeof(buffer->scan_el_group.attrs[0]),
GFP_KERNEL);
if (buffer->scan_el_group.attrs == NULL) {
ret = -ENOMEM;
goto error_free_scan_mask;
}
if (buffer->scan_el_attrs)
memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
attrn = attrcount_orig;
list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
return 0;
error_free_scan_mask:
kfree(buffer->scan_mask);
error_cleanup_dynamic:
iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
kfree(indio_dev->buffer->buffer_group.attrs);
return ret;
}
void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
{
if (!indio_dev->buffer)
return;
kfree(indio_dev->buffer->scan_mask);
kfree(indio_dev->buffer->buffer_group.attrs);
kfree(indio_dev->buffer->scan_el_group.attrs);
iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
}
/**
* iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected
@ -808,66 +890,6 @@ bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
}
EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
const unsigned long *mask)
{
if (!indio_dev->setup_ops->validate_scan_mask)
return true;
return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
}
/**
* iio_scan_mask_set() - set particular bit in the scan mask
* @indio_dev: the iio device
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
*
* Note that at this point we have no way of knowing what other
* buffers might request, hence this code only verifies that the
* individual buffers request is plausible.
*/
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
const unsigned long *mask;
unsigned long *trialmask;
trialmask = kmalloc(sizeof(*trialmask)*
BITS_TO_LONGS(indio_dev->masklength),
GFP_KERNEL);
if (trialmask == NULL)
return -ENOMEM;
if (!indio_dev->masklength) {
WARN_ON("Trying to set scanmask prior to registering buffer\n");
goto err_invalid_mask;
}
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
set_bit(bit, trialmask);
if (!iio_validate_scan_mask(indio_dev, trialmask))
goto err_invalid_mask;
if (indio_dev->available_scan_masks) {
mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
trialmask);
if (!mask)
goto err_invalid_mask;
}
bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
kfree(trialmask);
return 0;
err_invalid_mask:
kfree(trialmask);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(iio_scan_mask_set);
int iio_scan_mask_query(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{

View File

@ -70,6 +70,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
[IIO_HUMIDITYRELATIVE] = "humidityrelative",
[IIO_ACTIVITY] = "activity",
[IIO_STEPS] = "steps",
};
static const char * const iio_modifier_names[] = {
@ -91,6 +93,10 @@ static const char * const iio_modifier_names[] = {
[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",
[IIO_MOD_RUNNING] = "running",
[IIO_MOD_JOGGING] = "jogging",
[IIO_MOD_WALKING] = "walking",
[IIO_MOD_STILL] = "still",
};
/* relies on pairs of these shared then separate */
@ -113,6 +119,8 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
[IIO_CHAN_INFO_INT_TIME] = "integration_time",
[IIO_CHAN_INFO_ENABLE] = "en",
[IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
};
/**
@ -1035,7 +1043,6 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
if (!ptr)
return NULL;
/* use raw alloc_dr for kmalloc caller tracing */
iio_dev = iio_device_alloc(sizeof_priv);
if (iio_dev) {
*ptr = iio_dev;
@ -1127,6 +1134,29 @@ static const struct file_operations iio_buffer_fileops = {
.compat_ioctl = iio_ioctl,
};
static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
{
int i, j;
const struct iio_chan_spec *channels = indio_dev->channels;
if (!(indio_dev->modes & INDIO_ALL_BUFFER_MODES))
return 0;
for (i = 0; i < indio_dev->num_channels - 1; i++) {
if (channels[i].scan_index < 0)
continue;
for (j = i + 1; j < indio_dev->num_channels; j++)
if (channels[i].scan_index == channels[j].scan_index) {
dev_err(&indio_dev->dev,
"Duplicate scan index %d\n",
channels[i].scan_index);
return -EINVAL;
}
}
return 0;
}
static const struct iio_buffer_setup_ops noop_ring_setup_ops;
/**
@ -1141,6 +1171,10 @@ int iio_device_register(struct iio_dev *indio_dev)
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
ret = iio_check_unique_scan_index(indio_dev);
if (ret < 0)
return ret;
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
@ -1150,11 +1184,19 @@ int iio_device_register(struct iio_dev *indio_dev)
"Failed to register debugfs interfaces\n");
return ret;
}
ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to create buffer sysfs interfaces\n");
goto error_unreg_debugfs;
}
ret = iio_device_register_sysfs(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to register sysfs interfaces\n");
goto error_unreg_debugfs;
goto error_buffer_free_sysfs;
}
ret = iio_device_register_eventset(indio_dev);
if (ret) {
@ -1187,6 +1229,8 @@ error_unreg_eventset:
iio_device_unregister_eventset(indio_dev);
error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
error_buffer_free_sysfs:
iio_buffer_free_sysfs_and_mask(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
return ret;
@ -1215,6 +1259,8 @@ void iio_device_unregister(struct iio_dev *indio_dev)
iio_buffer_wakeup_poll(indio_dev);
mutex_unlock(&indio_dev->info_exist_lock);
iio_buffer_free_sysfs_and_mask(indio_dev);
}
EXPORT_SYMBOL(iio_device_unregister);

View File

@ -197,6 +197,7 @@ static const char * const iio_ev_type_text[] = {
[IIO_EV_TYPE_ROC] = "roc",
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
[IIO_EV_TYPE_INSTANCE] = "instance",
};
static const char * const iio_ev_dir_text[] = {
@ -327,9 +328,15 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
for_each_set_bit(i, mask, sizeof(*mask)*8) {
if (i >= ARRAY_SIZE(iio_ev_info_text))
return -EINVAL;
postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_ev_type_text[type], iio_ev_dir_text[dir],
iio_ev_info_text[i]);
if (dir != IIO_EV_DIR_NONE)
postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
iio_ev_type_text[type],
iio_ev_dir_text[dir],
iio_ev_info_text[i]);
else
postfix = kasprintf(GFP_KERNEL, "%s_%s",
iio_ev_type_text[type],
iio_ev_info_text[i]);
if (postfix == NULL)
return -ENOMEM;

View File

@ -32,7 +32,7 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
*
* This function combines some common tasks which will normally be performed
* when setting up a triggered buffer. It will allocate the buffer and the
* pollfunc, as well as register the buffer with the IIO core.
* pollfunc.
*
* Before calling this function the indio_dev structure should already be
* completely initialized, but not yet registered. In practice this means that
@ -49,7 +49,7 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
struct iio_buffer *buffer;
int ret;
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (!buffer) {
ret = -ENOMEM;
goto error_ret;
@ -78,16 +78,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
/* Flag that polled ring buffering is possible */
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
ret = iio_buffer_register(indio_dev,
indio_dev->channels,
indio_dev->num_channels);
if (ret)
goto error_dealloc_pollfunc;
return 0;
error_dealloc_pollfunc:
iio_dealloc_pollfunc(indio_dev->pollfunc);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
error_ret:
@ -101,7 +93,6 @@ EXPORT_SYMBOL(iio_triggered_buffer_setup);
*/
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
{
iio_buffer_unregister(indio_dev);
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_kfifo_free(indio_dev->buffer);
}

View File

@ -116,8 +116,11 @@ static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
if (!iiospec->args_count)
return 0;
if (iiospec->args[0] >= indio_dev->num_channels)
if (iiospec->args[0] >= indio_dev->num_channels) {
dev_err(&indio_dev->dev, "invalid channel index %u\n",
iiospec->args[0]);
return -EINVAL;
}
return iiospec->args[0];
}
@ -634,3 +637,28 @@ err_unlock:
return ret;
}
EXPORT_SYMBOL_GPL(iio_get_channel_type);
static int iio_channel_write(struct iio_channel *chan, int val, int val2,
enum iio_chan_info_enum info)
{
return chan->indio_dev->info->write_raw(chan->indio_dev,
chan->channel, val, val2, info);
}
int iio_write_channel_raw(struct iio_channel *chan, int val)
{
int ret;
mutex_lock(&chan->indio_dev->info_exist_lock);
if (chan->indio_dev->info == NULL) {
ret = -ENODEV;
goto err_unlock;
}
ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW);
err_unlock:
mutex_unlock(&chan->indio_dev->info_exist_lock);
return ret;
}
EXPORT_SYMBOL_GPL(iio_write_channel_raw);

View File

@ -47,30 +47,6 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
return ret;
}
static int iio_get_length_kfifo(struct iio_buffer *r)
{
return r->length;
}
static IIO_BUFFER_ENABLE_ATTR;
static IIO_BUFFER_LENGTH_ATTR;
static struct attribute *iio_kfifo_attributes[] = {
&dev_attr_length.attr,
&dev_attr_enable.attr,
NULL,
};
static struct attribute_group iio_kfifo_attribute_group = {
.attrs = iio_kfifo_attributes,
.name = "buffer",
};
static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
{
return r->bytes_per_datum;
}
static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
{
struct iio_kfifo *kf = iio_to_kfifo(r);
@ -159,26 +135,25 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.read_first_n = &iio_read_first_n_kfifo,
.data_available = iio_kfifo_buf_data_available,
.request_update = &iio_request_update_kfifo,
.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
.get_length = &iio_get_length_kfifo,
.set_length = &iio_set_length_kfifo,
.release = &iio_kfifo_buffer_release,
};
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
struct iio_buffer *iio_kfifo_allocate(void)
{
struct iio_kfifo *kf;
kf = kzalloc(sizeof *kf, GFP_KERNEL);
kf = kzalloc(sizeof(*kf), GFP_KERNEL);
if (!kf)
return NULL;
kf->update_needed = true;
iio_buffer_init(&kf->buffer);
kf->buffer.attrs = &iio_kfifo_attribute_group;
kf->buffer.access = &kfifo_access_funcs;
kf->buffer.length = 2;
mutex_init(&kf->user_lock);
return &kf->buffer;
}
EXPORT_SYMBOL(iio_kfifo_allocate);
@ -189,4 +164,58 @@ void iio_kfifo_free(struct iio_buffer *r)
}
EXPORT_SYMBOL(iio_kfifo_free);
static void devm_iio_kfifo_release(struct device *dev, void *res)
{
iio_kfifo_free(*(struct iio_buffer **)res);
}
static int devm_iio_kfifo_match(struct device *dev, void *res, void *data)
{
struct iio_buffer **r = res;
if (WARN_ON(!r || !*r))
return 0;
return *r == data;
}
/**
* devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
* @dev: Device to allocate kfifo buffer for
*
* RETURNS:
* Pointer to allocated iio_buffer on success, NULL on failure.
*/
struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
{
struct iio_buffer **ptr, *r;
ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
r = iio_kfifo_allocate();
if (r) {
*ptr = r;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return r;
}
EXPORT_SYMBOL(devm_iio_kfifo_allocate);
/**
* devm_iio_fifo_free - Resource-managed iio_kfifo_free()
* @dev: Device the buffer belongs to
* @r: The buffer associated with the device
*/
void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r)
{
WARN_ON(devres_release(dev, devm_iio_kfifo_release,
devm_iio_kfifo_match, r));
}
EXPORT_SYMBOL(devm_iio_kfifo_free);
MODULE_LICENSE("GPL");

View File

@ -95,6 +95,9 @@ config HID_SENSOR_ALS
Say yes here to build support for the HID SENSOR
Ambient light sensor.
To compile this driver as a module, choose M here: the
module will be called hid-sensor-als.
config HID_SENSOR_PROX
depends on HID_SENSOR_HUB
select IIO_BUFFER
@ -109,6 +112,16 @@ config HID_SENSOR_PROX
To compile this driver as a module, choose M here: the
module will be called hid-sensor-prox.
config JSA1212
tristate "JSA1212 ALS and proximity sensor driver"
depends on I2C
help
Say Y here if you want to build a IIO driver for JSA1212
proximity & ALS sensor device.
To compile this driver as a module, choose M here:
the module will be called jsa1212.
config SENSORS_LM3533
tristate "LM3533 ambient light sensor"
depends on MFD_LM3533

View File

@ -12,6 +12,7 @@ obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
obj-$(CONFIG_ISL29125) += isl29125.o
obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o

View File

@ -0,0 +1,471 @@
/*
* JSA1212 Ambient Light & Proximity Sensor Driver
*
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* JSA1212 I2C slave address: 0x44(ADDR tied to GND), 0x45(ADDR tied to VDD)
*
* TODO: Interrupt support, thresholds, range support.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
/* JSA1212 reg address */
#define JSA1212_CONF_REG 0x01
#define JSA1212_INT_REG 0x02
#define JSA1212_PXS_LT_REG 0x03
#define JSA1212_PXS_HT_REG 0x04
#define JSA1212_ALS_TH1_REG 0x05
#define JSA1212_ALS_TH2_REG 0x06
#define JSA1212_ALS_TH3_REG 0x07
#define JSA1212_PXS_DATA_REG 0x08
#define JSA1212_ALS_DT1_REG 0x09
#define JSA1212_ALS_DT2_REG 0x0A
#define JSA1212_ALS_RNG_REG 0x0B
#define JSA1212_MAX_REG 0x0C
/* JSA1212 reg masks */
#define JSA1212_CONF_MASK 0xFF
#define JSA1212_INT_MASK 0xFF
#define JSA1212_PXS_LT_MASK 0xFF
#define JSA1212_PXS_HT_MASK 0xFF
#define JSA1212_ALS_TH1_MASK 0xFF
#define JSA1212_ALS_TH2_LT_MASK 0x0F
#define JSA1212_ALS_TH2_HT_MASK 0xF0
#define JSA1212_ALS_TH3_MASK 0xFF
#define JSA1212_PXS_DATA_MASK 0xFF
#define JSA1212_ALS_DATA_MASK 0x0FFF
#define JSA1212_ALS_DT1_MASK 0xFF
#define JSA1212_ALS_DT2_MASK 0x0F
#define JSA1212_ALS_RNG_MASK 0x07
/* JSA1212 CONF REG bits */
#define JSA1212_CONF_PXS_MASK 0x80
#define JSA1212_CONF_PXS_ENABLE 0x80
#define JSA1212_CONF_PXS_DISABLE 0x00
#define JSA1212_CONF_ALS_MASK 0x04
#define JSA1212_CONF_ALS_ENABLE 0x04
#define JSA1212_CONF_ALS_DISABLE 0x00
#define JSA1212_CONF_IRDR_MASK 0x08
/* Proxmity sensing IRDR current sink settings */
#define JSA1212_CONF_IRDR_200MA 0x08
#define JSA1212_CONF_IRDR_100MA 0x00
#define JSA1212_CONF_PXS_SLP_MASK 0x70
#define JSA1212_CONF_PXS_SLP_0MS 0x70
#define JSA1212_CONF_PXS_SLP_12MS 0x60
#define JSA1212_CONF_PXS_SLP_50MS 0x50
#define JSA1212_CONF_PXS_SLP_75MS 0x40
#define JSA1212_CONF_PXS_SLP_100MS 0x30
#define JSA1212_CONF_PXS_SLP_200MS 0x20
#define JSA1212_CONF_PXS_SLP_400MS 0x10
#define JSA1212_CONF_PXS_SLP_800MS 0x00
/* JSA1212 INT REG bits */
#define JSA1212_INT_CTRL_MASK 0x01
#define JSA1212_INT_CTRL_EITHER 0x00
#define JSA1212_INT_CTRL_BOTH 0x01
#define JSA1212_INT_ALS_PRST_MASK 0x06
#define JSA1212_INT_ALS_PRST_1CONV 0x00
#define JSA1212_INT_ALS_PRST_4CONV 0x02
#define JSA1212_INT_ALS_PRST_8CONV 0x04
#define JSA1212_INT_ALS_PRST_16CONV 0x06
#define JSA1212_INT_ALS_FLAG_MASK 0x08
#define JSA1212_INT_ALS_FLAG_CLR 0x00
#define JSA1212_INT_PXS_PRST_MASK 0x60
#define JSA1212_INT_PXS_PRST_1CONV 0x00
#define JSA1212_INT_PXS_PRST_4CONV 0x20
#define JSA1212_INT_PXS_PRST_8CONV 0x40
#define JSA1212_INT_PXS_PRST_16CONV 0x60
#define JSA1212_INT_PXS_FLAG_MASK 0x80
#define JSA1212_INT_PXS_FLAG_CLR 0x00
/* JSA1212 ALS RNG REG bits */
#define JSA1212_ALS_RNG_0_2048 0x00
#define JSA1212_ALS_RNG_0_1024 0x01
#define JSA1212_ALS_RNG_0_512 0x02
#define JSA1212_ALS_RNG_0_256 0x03
#define JSA1212_ALS_RNG_0_128 0x04
/* JSA1212 INT threshold range */
#define JSA1212_ALS_TH_MIN 0x0000
#define JSA1212_ALS_TH_MAX 0x0FFF
#define JSA1212_PXS_TH_MIN 0x00
#define JSA1212_PXS_TH_MAX 0xFF
#define JSA1212_ALS_DELAY_MS 200
#define JSA1212_PXS_DELAY_MS 100
#define JSA1212_DRIVER_NAME "jsa1212"
#define JSA1212_REGMAP_NAME "jsa1212_regmap"
enum jsa1212_op_mode {
JSA1212_OPMODE_ALS_EN,
JSA1212_OPMODE_PXS_EN,
};
struct jsa1212_data {
struct i2c_client *client;
struct mutex lock;
u8 als_rng_idx;
bool als_en; /* ALS enable status */
bool pxs_en; /* proximity enable status */
struct regmap *regmap;
};
/* ALS range idx to val mapping */
static const int jsa1212_als_range_val[] = {2048, 1024, 512, 256, 128,
128, 128, 128};
/* Enables or disables ALS function based on status */
static int jsa1212_als_enable(struct jsa1212_data *data, u8 status)
{
int ret;
ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
JSA1212_CONF_ALS_MASK,
status);
if (ret < 0)
return ret;
data->als_en = !!status;
return 0;
}
/* Enables or disables PXS function based on status */
static int jsa1212_pxs_enable(struct jsa1212_data *data, u8 status)
{
int ret;
ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
JSA1212_CONF_PXS_MASK,
status);
if (ret < 0)
return ret;
data->pxs_en = !!status;
return 0;
}
static int jsa1212_read_als_data(struct jsa1212_data *data,
unsigned int *val)
{
int ret;
__le16 als_data;
ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
if (ret < 0)
return ret;
/* Delay for data output */
msleep(JSA1212_ALS_DELAY_MS);
/* Read 12 bit data */
ret = regmap_bulk_read(data->regmap, JSA1212_ALS_DT1_REG, &als_data, 2);
if (ret < 0) {
dev_err(&data->client->dev, "als data read err\n");
goto als_data_read_err;
}
*val = le16_to_cpu(als_data);
als_data_read_err:
return jsa1212_als_enable(data, JSA1212_CONF_ALS_DISABLE);
}
static int jsa1212_read_pxs_data(struct jsa1212_data *data,
unsigned int *val)
{
int ret;
unsigned int pxs_data;
ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
if (ret < 0)
return ret;
/* Delay for data output */
msleep(JSA1212_PXS_DELAY_MS);
/* Read out all data */
ret = regmap_read(data->regmap, JSA1212_PXS_DATA_REG, &pxs_data);
if (ret < 0) {
dev_err(&data->client->dev, "pxs data read err\n");
goto pxs_data_read_err;
}
*val = pxs_data & JSA1212_PXS_DATA_MASK;
pxs_data_read_err:
return jsa1212_pxs_enable(data, JSA1212_CONF_PXS_DISABLE);
}
static int jsa1212_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
int ret;
struct jsa1212_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
switch (chan->type) {
case IIO_LIGHT:
ret = jsa1212_read_als_data(data, val);
break;
case IIO_PROXIMITY:
ret = jsa1212_read_pxs_data(data, val);
break;
default:
ret = -EINVAL;
break;
}
mutex_unlock(&data->lock);
return ret < 0 ? ret : IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_LIGHT:
*val = jsa1212_als_range_val[data->als_rng_idx];
*val2 = BIT(12); /* Max 12 bit value */
return IIO_VAL_FRACTIONAL;
default:
break;
}
break;
default:
break;
}
return -EINVAL;
}
static const struct iio_chan_spec jsa1212_channels[] = {
{
.type = IIO_LIGHT,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
{
.type = IIO_PROXIMITY,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
}
};
static const struct iio_info jsa1212_info = {
.driver_module = THIS_MODULE,
.read_raw = &jsa1212_read_raw,
};
static int jsa1212_chip_init(struct jsa1212_data *data)
{
int ret;
ret = regmap_write(data->regmap, JSA1212_CONF_REG,
(JSA1212_CONF_PXS_SLP_50MS |
JSA1212_CONF_IRDR_200MA));
if (ret < 0)
return ret;
ret = regmap_write(data->regmap, JSA1212_INT_REG,
JSA1212_INT_ALS_PRST_4CONV);
if (ret < 0)
return ret;
data->als_rng_idx = JSA1212_ALS_RNG_0_2048;
return 0;
}
static bool jsa1212_is_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case JSA1212_PXS_DATA_REG:
case JSA1212_ALS_DT1_REG:
case JSA1212_ALS_DT2_REG:
case JSA1212_INT_REG:
return true;
default:
return false;
}
}
static struct regmap_config jsa1212_regmap_config = {
.name = JSA1212_REGMAP_NAME,
.reg_bits = 8,
.val_bits = 8,
.max_register = JSA1212_MAX_REG,
.cache_type = REGCACHE_RBTREE,
.volatile_reg = jsa1212_is_volatile_reg,
};
static int jsa1212_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct jsa1212_data *data;
struct iio_dev *indio_dev;
struct regmap *regmap;
int ret;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
regmap = devm_regmap_init_i2c(client, &jsa1212_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Regmap initialization failed.\n");
return PTR_ERR(regmap);
}
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
data->regmap = regmap;
mutex_init(&data->lock);
ret = jsa1212_chip_init(data);
if (ret < 0)
return ret;
indio_dev->dev.parent = &client->dev;
indio_dev->channels = jsa1212_channels;
indio_dev->num_channels = ARRAY_SIZE(jsa1212_channels);
indio_dev->name = JSA1212_DRIVER_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &jsa1212_info;
ret = iio_device_register(indio_dev);
if (ret < 0)
dev_err(&client->dev, "%s: register device failed\n", __func__);
return ret;
}
/* power off the device */
static int jsa1212_power_off(struct jsa1212_data *data)
{
int ret;
mutex_lock(&data->lock);
ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
JSA1212_CONF_ALS_MASK |
JSA1212_CONF_PXS_MASK,
JSA1212_CONF_ALS_DISABLE |
JSA1212_CONF_PXS_DISABLE);
if (ret < 0)
dev_err(&data->client->dev, "power off cmd failed\n");
mutex_unlock(&data->lock);
return ret;
}
static int jsa1212_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct jsa1212_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
return jsa1212_power_off(data);
}
#ifdef CONFIG_PM_SLEEP
static int jsa1212_suspend(struct device *dev)
{
struct jsa1212_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
return jsa1212_power_off(data);
}
static int jsa1212_resume(struct device *dev)
{
int ret = 0;
struct jsa1212_data *data;
data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
mutex_lock(&data->lock);
if (data->als_en) {
ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
if (ret < 0) {
dev_err(dev, "als resume failed\n");
goto unlock_and_ret;
}
}
if (data->pxs_en) {
ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
if (ret < 0)
dev_err(dev, "pxs resume failed\n");
}
unlock_and_ret:
mutex_unlock(&data->lock);
return ret;
}
static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, jsa1212_resume);
#define JSA1212_PM_OPS (&jsa1212_pm_ops)
#else
#define JSA1212_PM_OPS NULL
#endif
static const struct acpi_device_id jsa1212_acpi_match[] = {
{"JSA1212", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
static const struct i2c_device_id jsa1212_id[] = {
{ JSA1212_DRIVER_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, jsa1212_id);
static struct i2c_driver jsa1212_driver = {
.driver = {
.name = JSA1212_DRIVER_NAME,
.pm = JSA1212_PM_OPS,
.owner = THIS_MODULE,
.acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
},
.probe = jsa1212_probe,
.remove = jsa1212_remove,
.id_table = jsa1212_id,
};
module_i2c_driver(jsa1212_driver);
MODULE_AUTHOR("Sathya Kuppuswamy <sathyanarayanan.kuppuswamy@linux.intel.com>");
MODULE_DESCRIPTION("JSA1212 proximity/ambient light sensor driver");
MODULE_LICENSE("GPL v2");

View File

@ -657,7 +657,7 @@ static ALS_HYSTERESIS_ATTR_RO(3);
#define ILLUMINANCE_ATTR_RO(_name) \
DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
#define ILLUMINANCE_ATTR_RW(_name) \
DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR , \
DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR, \
show_##_name, store_##_name)
/*
* ALS Zone threshold-event enable

View File

@ -6,26 +6,21 @@
menu "Magnetometer sensors"
config AK8975
tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
tristate "Asahi Kasei AK 3-Axis Magnetometer"
depends on I2C
depends on GPIOLIB
help
Say yes here to build support for Asahi Kasei AK8975 3-Axis
Magnetometer. This driver can also support AK8963, if i2c
device name is identified as ak8963.
Say yes here to build support for Asahi Kasei AK8975, AK8963,
AK09911 or AK09912 3-Axis Magnetometer.
To compile this driver as a module, choose M here: the module
will be called ak8975.
config AK09911
tristate "Asahi Kasei AK09911 3-axis Compass"
depends on I2C
select AK8975
help
Say yes here to build support for Asahi Kasei AK09911 3-Axis
Magnetometer.
To compile this driver as a module, choose M here: the module
will be called ak09911.
Deprecated: AK09911 is now supported by AK8975 driver.
config MAG3110
tristate "Freescale MAG3110 3-Axis Magnetometer"

View File

@ -3,7 +3,6 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AK09911) += ak09911.o
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o

View File

@ -1,326 +0,0 @@
/*
* AK09911 3-axis compass driver
* Copyright (c) 2014, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/iio/iio.h>
#define AK09911_REG_WIA1 0x00
#define AK09911_REG_WIA2 0x01
#define AK09911_WIA1_VALUE 0x48
#define AK09911_WIA2_VALUE 0x05
#define AK09911_REG_ST1 0x10
#define AK09911_REG_HXL 0x11
#define AK09911_REG_HXH 0x12
#define AK09911_REG_HYL 0x13
#define AK09911_REG_HYH 0x14
#define AK09911_REG_HZL 0x15
#define AK09911_REG_HZH 0x16
#define AK09911_REG_ASAX 0x60
#define AK09911_REG_ASAY 0x61
#define AK09911_REG_ASAZ 0x62
#define AK09911_REG_CNTL1 0x30
#define AK09911_REG_CNTL2 0x31
#define AK09911_REG_CNTL3 0x32
#define AK09911_MODE_SNG_MEASURE 0x01
#define AK09911_MODE_SELF_TEST 0x10
#define AK09911_MODE_FUSE_ACCESS 0x1F
#define AK09911_MODE_POWERDOWN 0x00
#define AK09911_RESET_DATA 0x01
#define AK09911_REG_CNTL1 0x30
#define AK09911_REG_CNTL2 0x31
#define AK09911_REG_CNTL3 0x32
#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256)
#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500
#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
struct ak09911_data {
struct i2c_client *client;
struct mutex lock;
u8 asa[3];
long raw_to_gauss[3];
};
static const int ak09911_index_to_reg[] = {
AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
};
static int ak09911_set_mode(struct i2c_client *client, u8 mode)
{
int ret;
switch (mode) {
case AK09911_MODE_SNG_MEASURE:
case AK09911_MODE_SELF_TEST:
case AK09911_MODE_FUSE_ACCESS:
case AK09911_MODE_POWERDOWN:
ret = i2c_smbus_write_byte_data(client,
AK09911_REG_CNTL2, mode);
if (ret < 0) {
dev_err(&client->dev, "set_mode error\n");
return ret;
}
/* After mode change wait atleast 100us */
usleep_range(100, 500);
break;
default:
dev_err(&client->dev,
"%s: Unknown mode(%d).", __func__, mode);
return -EINVAL;
}
return ret;
}
/* Get Sensitivity Adjustment value */
static int ak09911_get_asa(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ak09911_data *data = iio_priv(indio_dev);
int ret;
ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
if (ret < 0)
return ret;
/* Get asa data and store in the device data. */
ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
3, data->asa);
if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n");
return ret;
}
ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN);
if (ret < 0)
return ret;
data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
return 0;
}
static int ak09911_verify_chip_id(struct i2c_client *client)
{
u8 wia_val[2];
int ret;
ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
2, wia_val);
if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n");
return ret;
}
dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
if (wia_val[0] != AK09911_WIA1_VALUE ||
wia_val[1] != AK09911_WIA2_VALUE) {
dev_err(&client->dev, "Device ak09911 not found\n");
return -ENODEV;
}
return 0;
}
static int wait_conversion_complete_polled(struct ak09911_data *data)
{
struct i2c_client *client = data->client;
u8 read_status;
u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
int ret;
/* Wait for the conversion to complete. */
while (timeout_ms) {
msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST1\n");
return ret;
}
read_status = ret & 0x01;
if (read_status)
break;
timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
}
if (!timeout_ms) {
dev_err(&client->dev, "Conversion timeout happened\n");
return -EIO;
}
return read_status;
}
static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
{
struct ak09911_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
int ret;
mutex_lock(&data->lock);
ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
if (ret < 0)
goto fn_exit;
ret = wait_conversion_complete_polled(data);
if (ret < 0)
goto fn_exit;
/* Read data */
ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
if (ret < 0) {
dev_err(&client->dev, "Read axis data fails\n");
goto fn_exit;
}
mutex_unlock(&data->lock);
/* Clamp to valid range. */
*val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
return IIO_VAL_INT;
fn_exit:
mutex_unlock(&data->lock);
return ret;
}
static int ak09911_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2,
long mask)
{
struct ak09911_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_RAW:
return ak09911_read_axis(indio_dev, chan->address, val);
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->raw_to_gauss[chan->address];
return IIO_VAL_INT_PLUS_MICRO;
}
return -EINVAL;
}
#define AK09911_CHANNEL(axis, index) \
{ \
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_SCALE), \
.address = index, \
}
static const struct iio_chan_spec ak09911_channels[] = {
AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
};
static const struct iio_info ak09911_info = {
.read_raw = &ak09911_read_raw,
.driver_module = THIS_MODULE,
};
static const struct acpi_device_id ak_acpi_match[] = {
{"AK009911", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
static int ak09911_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct ak09911_data *data;
const char *name;
int ret;
ret = ak09911_verify_chip_id(client);
if (ret) {
dev_err(&client->dev, "AK00911 not detected\n");
return -ENODEV;
}
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (indio_dev == NULL)
return -ENOMEM;
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
ret = ak09911_get_asa(client);
if (ret)
return ret;
if (id)
name = id->name;
else if (ACPI_HANDLE(&client->dev))
name = dev_name(&client->dev);
else
return -ENODEV;
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
indio_dev->dev.parent = &client->dev;
indio_dev->channels = ak09911_channels;
indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
indio_dev->info = &ak09911_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = name;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ak09911_id[] = {
{"ak09911", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ak09911_id);
static struct i2c_driver ak09911_driver = {
.driver = {
.name = "ak09911",
.acpi_match_table = ACPI_PTR(ak_acpi_match),
},
.probe = ak09911_probe,
.id_table = ak09911_id,
};
module_i2c_driver(ak09911_driver);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("AK09911 Compass driver");

View File

@ -64,10 +64,10 @@
#define AK8975_REG_CNTL 0x0A
#define AK8975_REG_CNTL_MODE_SHIFT 0
#define AK8975_REG_CNTL_MODE_MASK (0xF << AK8975_REG_CNTL_MODE_SHIFT)
#define AK8975_REG_CNTL_MODE_POWER_DOWN 0
#define AK8975_REG_CNTL_MODE_ONCE 1
#define AK8975_REG_CNTL_MODE_SELF_TEST 8
#define AK8975_REG_CNTL_MODE_FUSE_ROM 0xF
#define AK8975_REG_CNTL_MODE_POWER_DOWN 0x00
#define AK8975_REG_CNTL_MODE_ONCE 0x01
#define AK8975_REG_CNTL_MODE_SELF_TEST 0x08
#define AK8975_REG_CNTL_MODE_FUSE_ROM 0x0F
#define AK8975_REG_RSVC 0x0B
#define AK8975_REG_ASTC 0x0C
@ -80,19 +80,279 @@
#define AK8975_MAX_REGS AK8975_REG_ASAZ
/*
* AK09912 Register definitions
*/
#define AK09912_REG_WIA1 0x00
#define AK09912_REG_WIA2 0x01
#define AK09912_DEVICE_ID 0x04
#define AK09911_DEVICE_ID 0x05
#define AK09911_REG_INFO1 0x02
#define AK09911_REG_INFO2 0x03
#define AK09912_REG_ST1 0x10
#define AK09912_REG_ST1_DRDY_SHIFT 0
#define AK09912_REG_ST1_DRDY_MASK (1 << AK09912_REG_ST1_DRDY_SHIFT)
#define AK09912_REG_HXL 0x11
#define AK09912_REG_HXH 0x12
#define AK09912_REG_HYL 0x13
#define AK09912_REG_HYH 0x14
#define AK09912_REG_HZL 0x15
#define AK09912_REG_HZH 0x16
#define AK09912_REG_TMPS 0x17
#define AK09912_REG_ST2 0x18
#define AK09912_REG_ST2_HOFL_SHIFT 3
#define AK09912_REG_ST2_HOFL_MASK (1 << AK09912_REG_ST2_HOFL_SHIFT)
#define AK09912_REG_CNTL1 0x30
#define AK09912_REG_CNTL2 0x31
#define AK09912_REG_CNTL_MODE_POWER_DOWN 0x00
#define AK09912_REG_CNTL_MODE_ONCE 0x01
#define AK09912_REG_CNTL_MODE_SELF_TEST 0x10
#define AK09912_REG_CNTL_MODE_FUSE_ROM 0x1F
#define AK09912_REG_CNTL2_MODE_SHIFT 0
#define AK09912_REG_CNTL2_MODE_MASK (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
#define AK09912_REG_CNTL3 0x32
#define AK09912_REG_TS1 0x33
#define AK09912_REG_TS2 0x34
#define AK09912_REG_TS3 0x35
#define AK09912_REG_I2CDIS 0x36
#define AK09912_REG_TS4 0x37
#define AK09912_REG_ASAX 0x60
#define AK09912_REG_ASAY 0x61
#define AK09912_REG_ASAZ 0x62
#define AK09912_MAX_REGS AK09912_REG_ASAZ
/*
* Miscellaneous values.
*/
#define AK8975_MAX_CONVERSION_TIMEOUT 500
#define AK8975_CONVERSION_DONE_POLL_TIME 10
#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
/*
* Precalculate scale factor (in Gauss units) for each axis and
* store in the device data.
*
* This scale factor is axis-dependent, and is derived from 3 calibration
* factors ASA(x), ASA(y), and ASA(z).
*
* These ASA values are read from the sensor device at start of day, and
* cached in the device context struct.
*
* Adjusting the flux value with the sensitivity adjustment value should be
* done via the following formula:
*
* Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
* where H is the raw value, ASA is the sensitivity adjustment, and Hadj
* is the resultant adjusted value.
*
* We reduce the formula to:
*
* Hadj = H * (ASA + 128) / 256
*
* H is in the range of -4096 to 4095. The magnetometer has a range of
* +-1229uT. To go from the raw value to uT is:
*
* HuT = H * 1229/4096, or roughly, 3/10.
*
* Since 1uT = 0.01 gauss, our final scale factor becomes:
*
* Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
* Hadj = H * ((ASA + 128) * 0.003) / 256
*
* Since ASA doesn't change, we cache the resultant scale factor into the
* device context in ak8975_setup().
*
* Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
* multiply the stored scale value by 1e6.
*/
static long ak8975_raw_to_gauss(u16 data)
{
return (((long)data + 128) * 3000) / 256;
}
/*
* For AK8963 and AK09911, same calculation, but the device is less sensitive:
*
* H is in the range of +-8190. The magnetometer has a range of
* +-4912uT. To go from the raw value to uT is:
*
* HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
*/
static long ak8963_09911_raw_to_gauss(u16 data)
{
return (((long)data + 128) * 6000) / 256;
}
/*
* For AK09912, same calculation, except the device is more sensitive:
*
* H is in the range of -32752 to 32752. The magnetometer has a range of
* +-4912uT. To go from the raw value to uT is:
*
* HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
*/
static long ak09912_raw_to_gauss(u16 data)
{
return (((long)data + 128) * 1500) / 256;
}
/* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset {
AK8975,
AK8963,
AK09911,
AK09912,
AK_MAX_TYPE
};
enum ak_ctrl_reg_addr {
ST1,
ST2,
CNTL,
ASA_BASE,
MAX_REGS,
REGS_END,
};
enum ak_ctrl_reg_mask {
ST1_DRDY,
ST2_HOFL,
ST2_DERR,
CNTL_MODE,
MASK_END,
};
enum ak_ctrl_mode {
POWER_DOWN,
MODE_ONCE,
SELF_TEST,
FUSE_ROM,
MODE_END,
};
struct ak_def {
enum asahi_compass_chipset type;
long (*raw_to_gauss)(u16 data);
u16 range;
u8 ctrl_regs[REGS_END];
u8 ctrl_masks[MASK_END];
u8 ctrl_modes[MODE_END];
u8 data_regs[3];
};
static struct ak_def ak_def_array[AK_MAX_TYPE] = {
{
.type = AK8975,
.raw_to_gauss = ak8975_raw_to_gauss,
.range = 4096,
.ctrl_regs = {
AK8975_REG_ST1,
AK8975_REG_ST2,
AK8975_REG_CNTL,
AK8975_REG_ASAX,
AK8975_MAX_REGS},
.ctrl_masks = {
AK8975_REG_ST1_DRDY_MASK,
AK8975_REG_ST2_HOFL_MASK,
AK8975_REG_ST2_DERR_MASK,
AK8975_REG_CNTL_MODE_MASK},
.ctrl_modes = {
AK8975_REG_CNTL_MODE_POWER_DOWN,
AK8975_REG_CNTL_MODE_ONCE,
AK8975_REG_CNTL_MODE_SELF_TEST,
AK8975_REG_CNTL_MODE_FUSE_ROM},
.data_regs = {
AK8975_REG_HXL,
AK8975_REG_HYL,
AK8975_REG_HZL},
},
{
.type = AK8963,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8190,
.ctrl_regs = {
AK8975_REG_ST1,
AK8975_REG_ST2,
AK8975_REG_CNTL,
AK8975_REG_ASAX,
AK8975_MAX_REGS},
.ctrl_masks = {
AK8975_REG_ST1_DRDY_MASK,
AK8975_REG_ST2_HOFL_MASK,
0,
AK8975_REG_CNTL_MODE_MASK},
.ctrl_modes = {
AK8975_REG_CNTL_MODE_POWER_DOWN,
AK8975_REG_CNTL_MODE_ONCE,
AK8975_REG_CNTL_MODE_SELF_TEST,
AK8975_REG_CNTL_MODE_FUSE_ROM},
.data_regs = {
AK8975_REG_HXL,
AK8975_REG_HYL,
AK8975_REG_HZL},
},
{
.type = AK09911,
.raw_to_gauss = ak8963_09911_raw_to_gauss,
.range = 8192,
.ctrl_regs = {
AK09912_REG_ST1,
AK09912_REG_ST2,
AK09912_REG_CNTL2,
AK09912_REG_ASAX,
AK09912_MAX_REGS},
.ctrl_masks = {
AK09912_REG_ST1_DRDY_MASK,
AK09912_REG_ST2_HOFL_MASK,
0,
AK09912_REG_CNTL2_MODE_MASK},
.ctrl_modes = {
AK09912_REG_CNTL_MODE_POWER_DOWN,
AK09912_REG_CNTL_MODE_ONCE,
AK09912_REG_CNTL_MODE_SELF_TEST,
AK09912_REG_CNTL_MODE_FUSE_ROM},
.data_regs = {
AK09912_REG_HXL,
AK09912_REG_HYL,
AK09912_REG_HZL},
},
{
.type = AK09912,
.raw_to_gauss = ak09912_raw_to_gauss,
.range = 32752,
.ctrl_regs = {
AK09912_REG_ST1,
AK09912_REG_ST2,
AK09912_REG_CNTL2,
AK09912_REG_ASAX,
AK09912_MAX_REGS},
.ctrl_masks = {
AK09912_REG_ST1_DRDY_MASK,
AK09912_REG_ST2_HOFL_MASK,
0,
AK09912_REG_CNTL2_MODE_MASK},
.ctrl_modes = {
AK09912_REG_CNTL_MODE_POWER_DOWN,
AK09912_REG_CNTL_MODE_ONCE,
AK09912_REG_CNTL_MODE_SELF_TEST,
AK09912_REG_CNTL_MODE_FUSE_ROM},
.data_regs = {
AK09912_REG_HXL,
AK09912_REG_HYL,
AK09912_REG_HZL},
}
};
/*
@ -100,40 +360,82 @@ enum asahi_compass_chipset {
*/
struct ak8975_data {
struct i2c_client *client;
struct ak_def *def;
struct attribute_group attrs;
struct mutex lock;
u8 asa[3];
long raw_to_gauss[3];
u8 reg_cache[AK8975_MAX_REGS];
int eoc_gpio;
int eoc_irq;
wait_queue_head_t data_ready_queue;
unsigned long flags;
enum asahi_compass_chipset chipset;
};
static const int ak8975_index_to_reg[] = {
AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
u8 cntl_cache;
};
/*
* Helper function to write to the I2C device's registers.
* Return 0 if the i2c device is the one we expect.
* return a negative error number otherwise
*/
static int ak8975_write_data(struct i2c_client *client,
u8 reg, u8 val, u8 mask, u8 shift)
static int ak8975_who_i_am(struct i2c_client *client,
enum asahi_compass_chipset type)
{
u8 wia_val[2];
int ret;
/*
* Signature for each device:
* Device | WIA1 | WIA2
* AK09912 | DEVICE_ID | AK09912_DEVICE_ID
* AK09911 | DEVICE_ID | AK09911_DEVICE_ID
* AK8975 | DEVICE_ID | NA
* AK8963 | DEVICE_ID | NA
*/
ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
2, wia_val);
if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n");
return ret;
}
if (wia_val[0] != AK8975_DEVICE_ID)
return -ENODEV;
switch (type) {
case AK8975:
case AK8963:
return 0;
case AK09911:
if (wia_val[1] == AK09911_DEVICE_ID)
return 0;
break;
case AK09912:
if (wia_val[1] == AK09912_DEVICE_ID)
return 0;
break;
default:
dev_err(&client->dev, "Type %d unknown\n", type);
}
return -ENODEV;
}
/*
* Helper function to write to CNTL register.
*/
static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ak8975_data *data = iio_priv(indio_dev);
u8 regval;
int ret;
regval = (data->reg_cache[reg] & ~mask) | (val << shift);
ret = i2c_smbus_write_byte_data(client, reg, regval);
regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
data->def->ctrl_modes[mode];
ret = i2c_smbus_write_byte_data(data->client,
data->def->ctrl_regs[CNTL], regval);
if (ret < 0) {
dev_err(&client->dev, "Write to device fails status %x\n", ret);
return ret;
}
data->reg_cache[reg] = regval;
data->cntl_cache = regval;
/* After mode change wait atleast 100us */
usleep_range(100, 500);
return 0;
}
@ -166,8 +468,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
irq = gpio_to_irq(data->eoc_gpio);
rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&client->dev), data);
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
dev_name(&client->dev), data);
if (rc < 0) {
dev_err(&client->dev,
"irq %d request failed, (gpio %d): %d\n",
@ -191,34 +493,18 @@ static int ak8975_setup(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ak8975_data *data = iio_priv(indio_dev);
u8 device_id;
int ret;
/* Confirm that the device we're talking to is really an AK8975. */
ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
if (ret < 0) {
dev_err(&client->dev, "Error reading WIA\n");
return ret;
}
device_id = ret;
if (device_id != AK8975_DEVICE_ID) {
dev_err(&client->dev, "Device ak8975 not found\n");
return -ENODEV;
}
/* Write the fused rom access mode. */
ret = ak8975_write_data(client,
AK8975_REG_CNTL,
AK8975_REG_CNTL_MODE_FUSE_ROM,
AK8975_REG_CNTL_MODE_MASK,
AK8975_REG_CNTL_MODE_SHIFT);
ret = ak8975_set_mode(data, FUSE_ROM);
if (ret < 0) {
dev_err(&client->dev, "Error in setting fuse access mode\n");
return ret;
}
/* Get asa data and store in the device data. */
ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
ret = i2c_smbus_read_i2c_block_data(client,
data->def->ctrl_regs[ASA_BASE],
3, data->asa);
if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n");
@ -226,13 +512,13 @@ static int ak8975_setup(struct i2c_client *client)
}
/* After reading fuse ROM data set power-down mode */
ret = ak8975_write_data(client,
AK8975_REG_CNTL,
AK8975_REG_CNTL_MODE_POWER_DOWN,
AK8975_REG_CNTL_MODE_MASK,
AK8975_REG_CNTL_MODE_SHIFT);
ret = ak8975_set_mode(data, POWER_DOWN);
if (ret < 0) {
dev_err(&client->dev, "Error in setting power-down mode\n");
return ret;
}
if (data->eoc_gpio > 0 || client->irq) {
if (data->eoc_gpio > 0 || client->irq > 0) {
ret = ak8975_setup_irq(data);
if (ret < 0) {
dev_err(&client->dev,
@ -241,61 +527,9 @@ static int ak8975_setup(struct i2c_client *client)
}
}
if (ret < 0) {
dev_err(&client->dev, "Error in setting power-down mode\n");
return ret;
}
/*
* Precalculate scale factor (in Gauss units) for each axis and
* store in the device data.
*
* This scale factor is axis-dependent, and is derived from 3 calibration
* factors ASA(x), ASA(y), and ASA(z).
*
* These ASA values are read from the sensor device at start of day, and
* cached in the device context struct.
*
* Adjusting the flux value with the sensitivity adjustment value should be
* done via the following formula:
*
* Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
*
* where H is the raw value, ASA is the sensitivity adjustment, and Hadj
* is the resultant adjusted value.
*
* We reduce the formula to:
*
* Hadj = H * (ASA + 128) / 256
*
* H is in the range of -4096 to 4095. The magnetometer has a range of
* +-1229uT. To go from the raw value to uT is:
*
* HuT = H * 1229/4096, or roughly, 3/10.
*
* Since 1uT = 0.01 gauss, our final scale factor becomes:
*
* Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
* Hadj = H * ((ASA + 128) * 0.003) / 256
*
* Since ASA doesn't change, we cache the resultant scale factor into the
* device context in ak8975_setup().
*/
if (data->chipset == AK8963) {
/*
* H range is +-8190 and magnetometer range is +-4912.
* So HuT using the above explanation for 8975,
* 4912/8190 = ~ 6/10.
* So the Hadj should use 6/10 instead of 3/10.
*/
data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
} else {
data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
}
data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
return 0;
}
@ -318,7 +552,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
return -EINVAL;
}
ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
if (ret < 0)
dev_err(&client->dev, "Error in reading ST1\n");
@ -335,7 +569,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
/* Wait for the conversion to complete. */
while (timeout_ms) {
msleep(AK8975_CONVERSION_DONE_POLL_TIME);
ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
ret = i2c_smbus_read_byte_data(client,
data->def->ctrl_regs[ST1]);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST1\n");
return ret;
@ -378,11 +613,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
mutex_lock(&data->lock);
/* Set up the device for taking a sample. */
ret = ak8975_write_data(client,
AK8975_REG_CNTL,
AK8975_REG_CNTL_MODE_ONCE,
AK8975_REG_CNTL_MODE_MASK,
AK8975_REG_CNTL_MODE_SHIFT);
ret = ak8975_set_mode(data, MODE_ONCE);
if (ret < 0) {
dev_err(&client->dev, "Error in setting operating mode\n");
goto exit;
@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
goto exit;
/* This will be executed only for non-interrupt based waiting case */
if (ret & AK8975_REG_ST1_DRDY_MASK) {
ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
if (ret & data->def->ctrl_masks[ST1_DRDY]) {
ret = i2c_smbus_read_byte_data(client,
data->def->ctrl_regs[ST2]);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST2\n");
goto exit;
}
if (ret & (AK8975_REG_ST2_DERR_MASK |
AK8975_REG_ST2_HOFL_MASK)) {
if (ret & (data->def->ctrl_masks[ST2_DERR] |
data->def->ctrl_masks[ST2_HOFL])) {
dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
ret = -EINVAL;
goto exit;
@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
/* Read the flux value from the appropriate register
(the register is specified in the iio device attributes). */
ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
if (ret < 0) {
dev_err(&client->dev, "Read axis data fails\n");
goto exit;
@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
mutex_unlock(&data->lock);
/* Clamp to valid range. */
*val = clamp_t(s16, ret, -4096, 4095);
*val = clamp_t(s16, ret, -data->def->range, data->def->range);
return IIO_VAL_INT;
exit:
@ -473,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"AK8975", AK8975},
{"AK8963", AK8963},
{"INVN6500", AK8963},
{"AK09911", AK09911},
{"AK09912", AK09912},
{ },
};
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
@ -498,6 +732,7 @@ static int ak8975_probe(struct i2c_client *client,
int eoc_gpio;
int err;
const char *name = NULL;
enum asahi_compass_chipset chipset;
/* Grab and set up the supplied GPIO. */
if (client->dev.platform_data)
@ -537,42 +772,49 @@ static int ak8975_probe(struct i2c_client *client,
/* id will be NULL when enumerated via ACPI */
if (id) {
data->chipset =
(enum asahi_compass_chipset)(id->driver_data);
chipset = (enum asahi_compass_chipset)(id->driver_data);
name = id->name;
} else if (ACPI_HANDLE(&client->dev))
name = ak8975_match_acpi_device(&client->dev, &data->chipset);
name = ak8975_match_acpi_device(&client->dev, &chipset);
else
return -ENOSYS;
if (chipset >= AK_MAX_TYPE) {
dev_err(&client->dev, "AKM device type unsupported: %d\n",
chipset);
return -ENODEV;
}
data->def = &ak_def_array[chipset];
err = ak8975_who_i_am(client, data->def->type);
if (err < 0) {
dev_err(&client->dev, "Unexpected device\n");
return err;
}
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
/* Perform some basic start-of-day setup of the device. */
err = ak8975_setup(client);
if (err < 0) {
dev_err(&client->dev, "AK8975 initialization fails\n");
dev_err(&client->dev, "%s initialization fails\n", name);
return err;
}
data->client = client;
mutex_init(&data->lock);
data->eoc_gpio = eoc_gpio;
indio_dev->dev.parent = &client->dev;
indio_dev->channels = ak8975_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
indio_dev->info = &ak8975_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = name;
err = devm_iio_device_register(&client->dev, indio_dev);
if (err < 0)
return err;
return 0;
return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ak8975_id[] = {
{"ak8975", AK8975},
{"ak8963", AK8963},
{"ak09911", AK09911},
{"ak09912", AK09912},
{}
};
@ -581,14 +823,20 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
static const struct of_device_id ak8975_of_match[] = {
{ .compatible = "asahi-kasei,ak8975", },
{ .compatible = "ak8975", },
{ }
{ .compatible = "asahi-kasei,ak8963", },
{ .compatible = "ak8963", },
{ .compatible = "asahi-kasei,ak09911", },
{ .compatible = "ak09911", },
{ .compatible = "asahi-kasei,ak09912", },
{ .compatible = "ak09912", },
{}
};
MODULE_DEVICE_TABLE(of, ak8975_of_match);
static struct i2c_driver ak8975_driver = {
.driver = {
.name = "ak8975",
.of_match_table = ak8975_of_match,
.of_match_table = of_match_ptr(ak8975_of_match),
.acpi_match_table = ACPI_PTR(ak_acpi_match),
},
.probe = ak8975_probe,

View File

@ -80,16 +80,12 @@ struct bmp280_data {
s32 t_fine;
};
/* Compensation parameters. */
struct bmp280_comp_temp {
u16 dig_t1;
s16 dig_t2, dig_t3;
};
struct bmp280_comp_press {
u16 dig_p1;
s16 dig_p2, dig_p3, dig_p4, dig_p5, dig_p6, dig_p7, dig_p8, dig_p9;
};
/*
* These enums are used for indexing into the array of compensation
* parameters.
*/
enum { T1, T2, T3 };
enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 };
static const struct iio_chan_spec bmp280_channels[] = {
{
@ -141,10 +137,18 @@ static const struct regmap_config bmp280_regmap_config = {
.volatile_reg = bmp280_is_volatile_reg,
};
static int bmp280_read_compensation_temp(struct bmp280_data *data,
struct bmp280_comp_temp *comp)
/*
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
* "5123" equals 51.23 DegC. t_fine carries fine temperature as global
* value.
*
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static s32 bmp280_compensate_temp(struct bmp280_data *data,
s32 adc_temp)
{
int ret;
s32 var1, var2;
__le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
@ -155,63 +159,21 @@ static int bmp280_read_compensation_temp(struct bmp280_data *data,
return ret;
}
comp->dig_t1 = (u16) le16_to_cpu(buf[0]);
comp->dig_t2 = (s16) le16_to_cpu(buf[1]);
comp->dig_t3 = (s16) le16_to_cpu(buf[2]);
/*
* The double casts are necessary because le16_to_cpu returns an
* unsigned 16-bit value. Casting that value directly to a
* signed 32-bit will not do proper sign extension.
*
* Conversely, T1 and P1 are unsigned values, so they can be
* cast straight to the larger type.
*/
var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) *
((s32)(s16)le16_to_cpu(buf[T2]))) >> 11;
var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) *
((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) *
((s32)(s16)le16_to_cpu(buf[T3]))) >> 14;
return 0;
}
static int bmp280_read_compensation_press(struct bmp280_data *data,
struct bmp280_comp_press *comp)
{
int ret;
__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
buf, BMP280_COMP_PRESS_REG_COUNT);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to read pressure calibration parameters\n");
return ret;
}
comp->dig_p1 = (u16) le16_to_cpu(buf[0]);
comp->dig_p2 = (s16) le16_to_cpu(buf[1]);
comp->dig_p3 = (s16) le16_to_cpu(buf[2]);
comp->dig_p4 = (s16) le16_to_cpu(buf[3]);
comp->dig_p5 = (s16) le16_to_cpu(buf[4]);
comp->dig_p6 = (s16) le16_to_cpu(buf[5]);
comp->dig_p7 = (s16) le16_to_cpu(buf[6]);
comp->dig_p8 = (s16) le16_to_cpu(buf[7]);
comp->dig_p9 = (s16) le16_to_cpu(buf[8]);
return 0;
}
/*
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
* "5123" equals 51.23 DegC. t_fine carries fine temperature as global
* value.
*
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static s32 bmp280_compensate_temp(struct bmp280_data *data,
struct bmp280_comp_temp *comp,
s32 adc_temp)
{
s32 var1, var2, t;
var1 = (((adc_temp >> 3) - ((s32) comp->dig_t1 << 1)) *
((s32) comp->dig_t2)) >> 11;
var2 = (((((adc_temp >> 4) - ((s32) comp->dig_t1)) *
((adc_temp >> 4) - ((s32) comp->dig_t1))) >> 12) *
((s32) comp->dig_t3)) >> 14;
data->t_fine = var1 + var2;
t = (data->t_fine * 5 + 128) >> 8;
return t;
return (data->t_fine * 5 + 128) >> 8;
}
/*
@ -222,29 +184,38 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static u32 bmp280_compensate_press(struct bmp280_data *data,
struct bmp280_comp_press *comp,
s32 adc_press)
{
int ret;
s64 var1, var2, p;
__le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
var1 = ((s64) data->t_fine) - 128000;
var2 = var1 * var1 * (s64) comp->dig_p6;
var2 = var2 + ((var1 * (s64) comp->dig_p5) << 17);
var2 = var2 + (((s64) comp->dig_p4) << 35);
var1 = ((var1 * var1 * (s64) comp->dig_p3) >> 8) +
((var1 * (s64) comp->dig_p2) << 12);
var1 = (((((s64) 1) << 47) + var1)) * ((s64) comp->dig_p1) >> 33;
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
buf, BMP280_COMP_PRESS_REG_COUNT);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to read pressure calibration parameters\n");
return ret;
}
var1 = ((s64)data->t_fine) - 128000;
var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]);
var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17;
var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35;
var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) +
((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12);
var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33;
if (var1 == 0)
return 0;
p = ((((s64) 1048576 - adc_press) << 31) - var2) * 3125;
p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;
p = div64_s64(p, var1);
var1 = (((s64) comp->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((s64) comp->dig_p8) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((s64) comp->dig_p7) << 4);
var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25;
var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4);
return (u32) p;
return (u32)p;
}
static int bmp280_read_temp(struct bmp280_data *data,
@ -253,11 +224,6 @@ static int bmp280_read_temp(struct bmp280_data *data,
int ret;
__be32 tmp = 0;
s32 adc_temp, comp_temp;
struct bmp280_comp_temp comp;
ret = bmp280_read_compensation_temp(data, &comp);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
(u8 *) &tmp, 3);
@ -267,7 +233,7 @@ static int bmp280_read_temp(struct bmp280_data *data,
}
adc_temp = be32_to_cpu(tmp) >> 12;
comp_temp = bmp280_compensate_temp(data, &comp, adc_temp);
comp_temp = bmp280_compensate_temp(data, adc_temp);
/*
* val might be NULL if we're called by the read_press routine,
@ -288,11 +254,6 @@ static int bmp280_read_press(struct bmp280_data *data,
__be32 tmp = 0;
s32 adc_press;
u32 comp_press;
struct bmp280_comp_press comp;
ret = bmp280_read_compensation_press(data, &comp);
if (ret < 0)
return ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp280_read_temp(data, NULL);
@ -307,7 +268,7 @@ static int bmp280_read_press(struct bmp280_data *data,
}
adc_press = be32_to_cpu(tmp) >> 12;
comp_press = bmp280_compensate_press(data, &comp, adc_press);
comp_press = bmp280_compensate_press(data, adc_press);
*val = comp_press;
*val2 = 256000;
@ -366,7 +327,7 @@ static int bmp280_chip_init(struct bmp280_data *data)
BMP280_MODE_NORMAL);
if (ret < 0) {
dev_err(&data->client->dev,
"failed to write config register\n");
"failed to write ctrl_meas register\n");
return ret;
}
@ -394,7 +355,6 @@ static int bmp280_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
i2c_set_clientdata(client, indio_dev);
data = iio_priv(indio_dev);
mutex_init(&data->lock);
data->client = client;

View File

@ -17,3 +17,20 @@ config AS3935
module will be called as3935
endmenu
menu "Proximity sensors"
config SX9500
tristate "SX9500 Semtech proximity sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select REGMAP_I2C
depends on I2C
help
Say Y here to build a driver for Semtech's SX9500 capacitive
proximity/button sensor.
To compile this driver as a module, choose M here: the
module will be called sx9500.
endmenu

View File

@ -4,3 +4,4 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_SX9500) += sx9500.o

View File

@ -0,0 +1,752 @@
/*
* Copyright (c) 2014 Intel Corporation
*
* Driver for Semtech's SX9500 capacitive proximity/button solution.
* Datasheet available at
* <http://www.semtech.com/images/datasheet/sx9500.pdf>.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
#define SX9500_DRIVER_NAME "sx9500"
#define SX9500_IRQ_NAME "sx9500_event"
#define SX9500_GPIO_NAME "sx9500_gpio"
/* Register definitions. */
#define SX9500_REG_IRQ_SRC 0x00
#define SX9500_REG_STAT 0x01
#define SX9500_REG_IRQ_MSK 0x03
#define SX9500_REG_PROX_CTRL0 0x06
#define SX9500_REG_PROX_CTRL1 0x07
#define SX9500_REG_PROX_CTRL2 0x08
#define SX9500_REG_PROX_CTRL3 0x09
#define SX9500_REG_PROX_CTRL4 0x0a
#define SX9500_REG_PROX_CTRL5 0x0b
#define SX9500_REG_PROX_CTRL6 0x0c
#define SX9500_REG_PROX_CTRL7 0x0d
#define SX9500_REG_PROX_CTRL8 0x0e
#define SX9500_REG_SENSOR_SEL 0x20
#define SX9500_REG_USE_MSB 0x21
#define SX9500_REG_USE_LSB 0x22
#define SX9500_REG_AVG_MSB 0x23
#define SX9500_REG_AVG_LSB 0x24
#define SX9500_REG_DIFF_MSB 0x25
#define SX9500_REG_DIFF_LSB 0x26
#define SX9500_REG_OFFSET_MSB 0x27
#define SX9500_REG_OFFSET_LSB 0x28
#define SX9500_REG_RESET 0x7f
/* Write this to REG_RESET to do a soft reset. */
#define SX9500_SOFT_RESET 0xde
#define SX9500_SCAN_PERIOD_MASK GENMASK(6, 4)
#define SX9500_SCAN_PERIOD_SHIFT 4
/*
* These serve for identifying IRQ source in the IRQ_SRC register, and
* also for masking the IRQs in the IRQ_MSK register.
*/
#define SX9500_CLOSE_IRQ BIT(6)
#define SX9500_FAR_IRQ BIT(5)
#define SX9500_CONVDONE_IRQ BIT(3)
#define SX9500_PROXSTAT_SHIFT 4
#define SX9500_NUM_CHANNELS 4
struct sx9500_data {
struct mutex mutex;
struct i2c_client *client;
struct iio_trigger *trig;
struct regmap *regmap;
/*
* Last reading of the proximity status for each channel. We
* only send an event to user space when this changes.
*/
bool prox_stat[SX9500_NUM_CHANNELS];
bool event_enabled[SX9500_NUM_CHANNELS];
bool trigger_enabled;
u16 *buffer;
};
static const struct iio_event_spec sx9500_events[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_EITHER,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
},
};
#define SX9500_CHANNEL(idx) \
{ \
.type = IIO_PROXIMITY, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.indexed = 1, \
.channel = idx, \
.event_spec = sx9500_events, \
.num_event_specs = ARRAY_SIZE(sx9500_events), \
.scan_index = idx, \
.scan_type = { \
.sign = 'u', \
.realbits = 16, \
.storagebits = 16, \
.shift = 0, \
}, \
}
static const struct iio_chan_spec sx9500_channels[] = {
SX9500_CHANNEL(0),
SX9500_CHANNEL(1),
SX9500_CHANNEL(2),
SX9500_CHANNEL(3),
IIO_CHAN_SOFT_TIMESTAMP(4),
};
static const struct {
int val;
int val2;
} sx9500_samp_freq_table[] = {
{33, 333333},
{16, 666666},
{11, 111111},
{8, 333333},
{6, 666666},
{5, 0},
{3, 333333},
{2, 500000},
};
static const struct regmap_range sx9500_writable_reg_ranges[] = {
regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK),
regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8),
regmap_reg_range(SX9500_REG_SENSOR_SEL, SX9500_REG_SENSOR_SEL),
regmap_reg_range(SX9500_REG_OFFSET_MSB, SX9500_REG_OFFSET_LSB),
regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
};
static const struct regmap_access_table sx9500_writeable_regs = {
.yes_ranges = sx9500_writable_reg_ranges,
.n_yes_ranges = ARRAY_SIZE(sx9500_writable_reg_ranges),
};
/*
* All allocated registers are readable, so we just list unallocated
* ones.
*/
static const struct regmap_range sx9500_non_readable_reg_ranges[] = {
regmap_reg_range(SX9500_REG_STAT + 1, SX9500_REG_STAT + 1),
regmap_reg_range(SX9500_REG_IRQ_MSK + 1, SX9500_REG_PROX_CTRL0 - 1),
regmap_reg_range(SX9500_REG_PROX_CTRL8 + 1, SX9500_REG_SENSOR_SEL - 1),
regmap_reg_range(SX9500_REG_OFFSET_LSB + 1, SX9500_REG_RESET - 1),
};
static const struct regmap_access_table sx9500_readable_regs = {
.no_ranges = sx9500_non_readable_reg_ranges,
.n_no_ranges = ARRAY_SIZE(sx9500_non_readable_reg_ranges),
};
static const struct regmap_range sx9500_volatile_reg_ranges[] = {
regmap_reg_range(SX9500_REG_IRQ_SRC, SX9500_REG_STAT),
regmap_reg_range(SX9500_REG_USE_MSB, SX9500_REG_OFFSET_LSB),
regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
};
static const struct regmap_access_table sx9500_volatile_regs = {
.yes_ranges = sx9500_volatile_reg_ranges,
.n_yes_ranges = ARRAY_SIZE(sx9500_volatile_reg_ranges),
};
static const struct regmap_config sx9500_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SX9500_REG_RESET,
.cache_type = REGCACHE_RBTREE,
.wr_table = &sx9500_writeable_regs,
.rd_table = &sx9500_readable_regs,
.volatile_table = &sx9500_volatile_regs,
};
static int sx9500_read_proximity(struct sx9500_data *data,
const struct iio_chan_spec *chan,
int *val)
{
int ret;
__be16 regval;
ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, &regval, 2);
if (ret < 0)
return ret;
*val = 32767 - (s16)be16_to_cpu(regval);
return IIO_VAL_INT;
}
static int sx9500_read_samp_freq(struct sx9500_data *data,
int *val, int *val2)
{
int ret;
unsigned int regval;
mutex_lock(&data->mutex);
ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &regval);
mutex_unlock(&data->mutex);
if (ret < 0)
return ret;
regval = (regval & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT;
*val = sx9500_samp_freq_table[regval].val;
*val2 = sx9500_samp_freq_table[regval].val2;
return IIO_VAL_INT_PLUS_MICRO;
}
static int sx9500_read_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct sx9500_data *data = iio_priv(indio_dev);
int ret;
switch (chan->type) {
case IIO_PROXIMITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (iio_buffer_enabled(indio_dev))
return -EBUSY;
mutex_lock(&data->mutex);
ret = sx9500_read_proximity(data, chan, val);
mutex_unlock(&data->mutex);
return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9500_read_samp_freq(data, val, val2);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int sx9500_set_samp_freq(struct sx9500_data *data,
int val, int val2)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(sx9500_samp_freq_table); i++)
if (val == sx9500_samp_freq_table[i].val &&
val2 == sx9500_samp_freq_table[i].val2)
break;
if (i == ARRAY_SIZE(sx9500_samp_freq_table))
return -EINVAL;
mutex_lock(&data->mutex);
ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
SX9500_SCAN_PERIOD_MASK,
i << SX9500_SCAN_PERIOD_SHIFT);
mutex_unlock(&data->mutex);
return ret;
}
static int sx9500_write_raw(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
int val, int val2, long mask)
{
struct sx9500_data *data = iio_priv(indio_dev);
switch (chan->type) {
case IIO_PROXIMITY:
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9500_set_samp_freq(data, val, val2);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static irqreturn_t sx9500_irq_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct sx9500_data *data = iio_priv(indio_dev);
if (data->trigger_enabled)
iio_trigger_poll(data->trig);
/*
* Even if no event is enabled, we need to wake the thread to
* clear the interrupt state by reading SX9500_REG_IRQ_SRC. It
* is not possible to do that here because regmap_read takes a
* mutex.
*/
return IRQ_WAKE_THREAD;
}
static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct sx9500_data *data = iio_priv(indio_dev);
int ret;
unsigned int val, chan;
mutex_lock(&data->mutex);
ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
if (ret < 0) {
dev_err(&data->client->dev, "i2c transfer error in irq\n");
goto out;
}
if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)))
goto out;
ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
if (ret < 0) {
dev_err(&data->client->dev, "i2c transfer error in irq\n");
goto out;
}
val >>= SX9500_PROXSTAT_SHIFT;
for (chan = 0; chan < SX9500_NUM_CHANNELS; chan++) {
int dir;
u64 ev;
bool new_prox = val & BIT(chan);
if (!data->event_enabled[chan])
continue;
if (new_prox == data->prox_stat[chan])
/* No change on this channel. */
continue;
dir = new_prox ? IIO_EV_DIR_FALLING :
IIO_EV_DIR_RISING;
ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
chan,
IIO_EV_TYPE_THRESH,
dir);
iio_push_event(indio_dev, ev, iio_get_time_ns());
data->prox_stat[chan] = new_prox;
}
out:
mutex_unlock(&data->mutex);
return IRQ_HANDLED;
}
static int sx9500_read_event_config(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir)
{
struct sx9500_data *data = iio_priv(indio_dev);
if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
dir != IIO_EV_DIR_EITHER)
return -EINVAL;
return data->event_enabled[chan->channel];
}
static int sx9500_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 sx9500_data *data = iio_priv(indio_dev);
int ret, i;
bool any_active = false;
unsigned int irqmask;
if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
dir != IIO_EV_DIR_EITHER)
return -EINVAL;
mutex_lock(&data->mutex);
data->event_enabled[chan->channel] = state;
for (i = 0; i < SX9500_NUM_CHANNELS; i++)
if (data->event_enabled[i]) {
any_active = true;
break;
}
irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ;
if (any_active)
ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
irqmask, irqmask);
else
ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
irqmask, 0);
mutex_unlock(&data->mutex);
return ret;
}
static int sx9500_update_scan_mode(struct iio_dev *indio_dev,
const unsigned long *scan_mask)
{
struct sx9500_data *data = iio_priv(indio_dev);
mutex_lock(&data->mutex);
kfree(data->buffer);
data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
mutex_unlock(&data->mutex);
if (data->buffer == NULL)
return -ENOMEM;
return 0;
}
static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
"2.500000 3.333333 5 6.666666 8.333333 11.111111 16.666666 33.333333");
static struct attribute *sx9500_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL,
};
static const struct attribute_group sx9500_attribute_group = {
.attrs = sx9500_attributes,
};
static const struct iio_info sx9500_info = {
.driver_module = THIS_MODULE,
.attrs = &sx9500_attribute_group,
.read_raw = &sx9500_read_raw,
.write_raw = &sx9500_write_raw,
.read_event_config = &sx9500_read_event_config,
.write_event_config = &sx9500_write_event_config,
.update_scan_mode = &sx9500_update_scan_mode,
};
static int sx9500_set_trigger_state(struct iio_trigger *trig,
bool state)
{
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct sx9500_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->mutex);
ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
SX9500_CONVDONE_IRQ,
state ? SX9500_CONVDONE_IRQ : 0);
if (ret == 0)
data->trigger_enabled = state;
mutex_unlock(&data->mutex);
return ret;
}
static const struct iio_trigger_ops sx9500_trigger_ops = {
.set_trigger_state = sx9500_set_trigger_state,
.owner = THIS_MODULE,
};
static irqreturn_t sx9500_trigger_handler(int irq, void *private)
{
struct iio_poll_func *pf = private;
struct iio_dev *indio_dev = pf->indio_dev;
struct sx9500_data *data = iio_priv(indio_dev);
int val, bit, ret, i = 0;
mutex_lock(&data->mutex);
for_each_set_bit(bit, indio_dev->buffer->scan_mask,
indio_dev->masklength) {
ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
&val);
if (ret < 0)
goto out;
data->buffer[i++] = val;
}
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
iio_get_time_ns());
out:
mutex_unlock(&data->mutex);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
}
struct sx9500_reg_default {
u8 reg;
u8 def;
};
static const struct sx9500_reg_default sx9500_default_regs[] = {
{
.reg = SX9500_REG_PROX_CTRL1,
/* Shield enabled, small range. */
.def = 0x43,
},
{
.reg = SX9500_REG_PROX_CTRL2,
/* x8 gain, 167kHz frequency, finest resolution. */
.def = 0x77,
},
{
.reg = SX9500_REG_PROX_CTRL3,
/* Doze enabled, 2x scan period doze, no raw filter. */
.def = 0x40,
},
{
.reg = SX9500_REG_PROX_CTRL4,
/* Average threshold. */
.def = 0x30,
},
{
.reg = SX9500_REG_PROX_CTRL5,
/*
* Debouncer off, lowest average negative filter,
* highest average postive filter.
*/
.def = 0x0f,
},
{
.reg = SX9500_REG_PROX_CTRL6,
/* Proximity detection threshold: 280 */
.def = 0x0e,
},
{
.reg = SX9500_REG_PROX_CTRL7,
/*
* No automatic compensation, compensate each pin
* independently, proximity hysteresis: 32, close
* debouncer off, far debouncer off.
*/
.def = 0x00,
},
{
.reg = SX9500_REG_PROX_CTRL8,
/* No stuck timeout, no periodic compensation. */
.def = 0x00,
},
{
.reg = SX9500_REG_PROX_CTRL0,
/* Scan period: 30ms, all sensors enabled. */
.def = 0x0f,
},
};
static int sx9500_init_device(struct iio_dev *indio_dev)
{
struct sx9500_data *data = iio_priv(indio_dev);
int ret, i;
unsigned int val;
ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0);
if (ret < 0)
return ret;
ret = regmap_write(data->regmap, SX9500_REG_RESET,
SX9500_SOFT_RESET);
if (ret < 0)
return ret;
ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(sx9500_default_regs); i++) {
ret = regmap_write(data->regmap,
sx9500_default_regs[i].reg,
sx9500_default_regs[i].def);
if (ret < 0)
return ret;
}
return 0;
}
static int sx9500_gpio_probe(struct i2c_client *client,
struct sx9500_data *data)
{
struct device *dev;
struct gpio_desc *gpio;
int ret;
if (!client)
return -EINVAL;
dev = &client->dev;
/* data ready gpio interrupt pin */
gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0);
if (IS_ERR(gpio)) {
dev_err(dev, "acpi gpio get index failed\n");
return PTR_ERR(gpio);
}
ret = gpiod_direction_input(gpio);
if (ret)
return ret;
ret = gpiod_to_irq(gpio);
dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
return ret;
}
static int sx9500_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
struct iio_dev *indio_dev;
struct sx9500_data *data;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (indio_dev == NULL)
return -ENOMEM;
data = iio_priv(indio_dev);
data->client = client;
mutex_init(&data->mutex);
data->trigger_enabled = false;
data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config);
if (IS_ERR(data->regmap))
return PTR_ERR(data->regmap);
sx9500_init_device(indio_dev);
indio_dev->dev.parent = &client->dev;
indio_dev->name = SX9500_DRIVER_NAME;
indio_dev->channels = sx9500_channels;
indio_dev->num_channels = ARRAY_SIZE(sx9500_channels);
indio_dev->info = &sx9500_info;
indio_dev->modes = INDIO_DIRECT_MODE;
i2c_set_clientdata(client, indio_dev);
if (client->irq <= 0)
client->irq = sx9500_gpio_probe(client, data);
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
sx9500_irq_handler, sx9500_irq_thread_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
SX9500_IRQ_NAME, indio_dev);
if (ret < 0)
return ret;
data->trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d", indio_dev->name, indio_dev->id);
if (!data->trig)
return -ENOMEM;
data->trig->dev.parent = &client->dev;
data->trig->ops = &sx9500_trigger_ops;
iio_trigger_set_drvdata(data->trig, indio_dev);
ret = iio_trigger_register(data->trig);
if (ret)
return ret;
}
ret = iio_triggered_buffer_setup(indio_dev, NULL,
sx9500_trigger_handler, NULL);
if (ret < 0)
goto out_trigger_unregister;
ret = iio_device_register(indio_dev);
if (ret < 0)
goto out_buffer_cleanup;
return 0;
out_buffer_cleanup:
iio_triggered_buffer_cleanup(indio_dev);
out_trigger_unregister:
if (client->irq > 0)
iio_trigger_unregister(data->trig);
return ret;
}
static int sx9500_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct sx9500_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_triggered_buffer_cleanup(indio_dev);
if (client->irq > 0)
iio_trigger_unregister(data->trig);
kfree(data->buffer);
return 0;
}
static const struct acpi_device_id sx9500_acpi_match[] = {
{"SSX9500", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
static const struct i2c_device_id sx9500_id[] = {
{"sx9500", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, sx9500_id);
static struct i2c_driver sx9500_driver = {
.driver = {
.name = SX9500_DRIVER_NAME,
.acpi_match_table = ACPI_PTR(sx9500_acpi_match),
},
.probe = sx9500_probe,
.remove = sx9500_remove,
.id_table = sx9500_id,
};
module_i2c_driver(sx9500_driver);
MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
MODULE_DESCRIPTION("Driver for Semtech SX9500 proximity sensor");
MODULE_LICENSE("GPL v2");

View File

@ -135,6 +135,7 @@ static int iio_sysfs_trigger_probe(int id)
struct iio_sysfs_trig *t;
int ret;
bool foundit = false;
mutex_lock(&iio_sysfs_trig_list_mut);
list_for_each_entry(t, &iio_sysfs_trig_list, l)
if (id == t->id) {
@ -185,6 +186,7 @@ static int iio_sysfs_trigger_remove(int id)
{
bool foundit = false;
struct iio_sysfs_trig *t;
mutex_lock(&iio_sysfs_trig_list_mut);
list_for_each_entry(t, &iio_sysfs_trig_list, l)
if (id == t->id) {

View File

@ -49,6 +49,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
[IIO_HUMIDITYRELATIVE] = "humidityrelative",
[IIO_ACTIVITY] = "activity",
[IIO_STEPS] = "steps",
};
static const char * const iio_ev_type_text[] = {
@ -57,6 +59,7 @@ static const char * const iio_ev_type_text[] = {
[IIO_EV_TYPE_ROC] = "roc",
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
[IIO_EV_TYPE_INSTANCE] = "instance",
};
static const char * const iio_ev_dir_text[] = {
@ -92,6 +95,10 @@ static const char * const iio_modifier_names[] = {
[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",
[IIO_MOD_RUNNING] = "running",
[IIO_MOD_JOGGING] = "jogging",
[IIO_MOD_WALKING] = "walking",
[IIO_MOD_STILL] = "still",
};
static bool event_is_known(struct iio_event_data *event)
@ -121,6 +128,8 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_CCT:
case IIO_PRESSURE:
case IIO_HUMIDITYRELATIVE:
case IIO_ACTIVITY:
case IIO_STEPS:
break;
default:
return false;
@ -154,6 +163,10 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_MOD_NORTH_TRUE:
case IIO_MOD_NORTH_MAGN_TILT_COMP:
case IIO_MOD_NORTH_TRUE_TILT_COMP:
case IIO_MOD_RUNNING:
case IIO_MOD_JOGGING:
case IIO_MOD_WALKING:
case IIO_MOD_STILL:
break;
default:
return false;
@ -165,6 +178,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_EV_TYPE_ROC:
case IIO_EV_TYPE_THRESH_ADAPTIVE:
case IIO_EV_TYPE_MAG_ADAPTIVE:
case IIO_EV_TYPE_INSTANCE:
break;
default:
return false;
@ -174,6 +188,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_EV_DIR_EITHER:
case IIO_EV_DIR_RISING:
case IIO_EV_DIR_FALLING:
case IIO_EV_DIR_NONE:
break;
default:
return false;
@ -214,9 +229,11 @@ static void print_event(struct iio_event_data *event)
else if (chan >= 0)
printf("channel: %d, ", chan);
printf("evtype: %s, direction: %s\n",
iio_ev_type_text[ev_type],
iio_ev_dir_text[dir]);
printf("evtype: %s", iio_ev_type_text[ev_type]);
if (dir != IIO_EV_DIR_NONE)
printf(", direction: %s", iio_ev_dir_text[dir]);
printf("\n");
}
int main(int argc, char **argv)

View File

@ -39,9 +39,9 @@ request_update
If parameters have changed that require reinitialization or configuration of
the buffer this will trigger it.
get_bytes_per_datum, set_bytes_per_datum
Get/set the number of bytes for a complete scan. (All samples + timestamp)
set_bytes_per_datum
Set the number of bytes for a complete scan. (All samples + timestamp)
get_length / set_length
Get/set the number of complete scans that may be held by the buffer.
set_length
Set the number of complete scans that may be held by the buffer.

View File

@ -716,14 +716,6 @@ static int lis3l02dq_probe(struct spi_device *spi)
if (ret)
return ret;
ret = iio_buffer_register(indio_dev,
lis3l02dq_channels,
ARRAY_SIZE(lis3l02dq_channels));
if (ret) {
dev_err(&spi->dev, "failed to initialize the buffer\n");
goto error_unreg_buffer_funcs;
}
if (spi->irq) {
ret = request_threaded_irq(st->us->irq,
&lis3l02dq_th,
@ -732,7 +724,7 @@ static int lis3l02dq_probe(struct spi_device *spi)
"lis3l02dq",
indio_dev);
if (ret)
goto error_uninitialize_buffer;
goto error_unreg_buffer_funcs;
ret = lis3l02dq_probe_trigger(indio_dev);
if (ret)
@ -756,8 +748,6 @@ error_remove_trigger:
error_free_interrupt:
if (spi->irq)
free_irq(st->us->irq, indio_dev);
error_uninitialize_buffer:
iio_buffer_unregister(indio_dev);
error_unreg_buffer_funcs:
lis3l02dq_unconfigure_buffer(indio_dev);
return ret;
@ -804,7 +794,6 @@ static int lis3l02dq_remove(struct spi_device *spi)
free_irq(st->us->irq, indio_dev);
lis3l02dq_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
lis3l02dq_unconfigure_buffer(indio_dev);
return 0;

View File

@ -393,7 +393,7 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev)
int ret;
struct iio_buffer *buffer;
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;

View File

@ -223,33 +223,6 @@ error_ret:
return ret;
}
#ifdef SCA3000_DEBUG
/**
* sca3000_check_status() check the status register
*
* Only used for debugging purposes
**/
static int sca3000_check_status(struct device *dev)
{
int ret;
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1);
if (ret < 0)
goto error_ret;
if (st->rx[0] & SCA3000_EEPROM_CS_ERROR)
dev_err(dev, "eeprom error\n");
if (st->rx[0] & SCA3000_SPI_FRAME_ERROR)
dev_err(dev, "Previous SPI Frame was corrupt\n");
error_ret:
mutex_unlock(&st->lock);
return ret;
}
#endif /* SCA3000_DEBUG */
/**
* sca3000_show_rev() - sysfs interface to read the chip revision number
**/
@ -459,6 +432,8 @@ static const struct iio_chan_spec sca3000_channels_with_temp[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
/* No buffer support */
.scan_index = -1,
},
};
@ -1154,17 +1129,6 @@ static int sca3000_probe(struct spi_device *spi)
if (ret < 0)
return ret;
ret = iio_buffer_register(indio_dev,
sca3000_channels,
ARRAY_SIZE(sca3000_channels));
if (ret < 0)
goto error_unregister_dev;
if (indio_dev->buffer) {
iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
iio_scan_mask_set(indio_dev, indio_dev->buffer, 2);
}
if (spi->irq) {
ret = request_threaded_irq(spi->irq,
NULL,
@ -1173,7 +1137,7 @@ static int sca3000_probe(struct spi_device *spi)
"sca3000",
indio_dev);
if (ret)
goto error_unregister_ring;
goto error_unregister_dev;
}
sca3000_register_ring_funcs(indio_dev);
ret = sca3000_clean_setup(st);
@ -1184,8 +1148,6 @@ static int sca3000_probe(struct spi_device *spi)
error_free_irq:
if (spi->irq)
free_irq(spi->irq, indio_dev);
error_unregister_ring:
iio_buffer_unregister(indio_dev);
error_unregister_dev:
iio_device_unregister(indio_dev);
return ret;
@ -1219,7 +1181,6 @@ static int sca3000_remove(struct spi_device *spi)
if (spi->irq)
free_irq(spi->irq, indio_dev);
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
sca3000_unconfigure_ring(indio_dev);
return 0;

View File

@ -129,26 +129,11 @@ error_ret:
return ret ? ret : num_read;
}
/* This is only valid with all 3 elements enabled */
static int sca3000_ring_get_length(struct iio_buffer *r)
{
return 64;
}
/* only valid if resolution is kept at 11bits */
static int sca3000_ring_get_bytes_per_datum(struct iio_buffer *r)
{
return 6;
}
static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
{
return r->stufftoread;
}
static IIO_BUFFER_ENABLE_ATTR;
static IIO_BUFFER_LENGTH_ATTR;
/**
* sca3000_query_ring_int() is the hardware ring status interrupt enabled
**/
@ -238,20 +223,13 @@ static IIO_DEVICE_ATTR(in_accel_scale,
* only apply to the ring buffer. At all times full rate and accuracy
* is available via direct reading from registers.
*/
static struct attribute *sca3000_ring_attributes[] = {
&dev_attr_length.attr,
&dev_attr_enable.attr,
static const struct attribute *sca3000_ring_attributes[] = {
&iio_dev_attr_50_percent.dev_attr.attr,
&iio_dev_attr_75_percent.dev_attr.attr,
&iio_dev_attr_in_accel_scale.dev_attr.attr,
NULL,
};
static struct attribute_group sca3000_ring_attr = {
.attrs = sca3000_ring_attributes,
.name = "buffer",
};
static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
{
struct iio_buffer *buf;
@ -264,7 +242,8 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
ring->private = indio_dev;
buf = &ring->buf;
buf->stufftoread = 0;
buf->attrs = &sca3000_ring_attr;
buf->length = 64;
buf->attrs = sca3000_ring_attributes;
iio_buffer_init(buf);
return buf;
@ -277,8 +256,6 @@ static void sca3000_ring_release(struct iio_buffer *r)
static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = {
.read_first_n = &sca3000_read_first_n_hw_rb,
.get_length = &sca3000_ring_get_length,
.get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum,
.data_available = sca3000_ring_buf_data_available,
.release = sca3000_ring_release,
};

View File

@ -612,7 +612,7 @@ static int ad7192_probe(struct spi_device *spi)
const struct ad7192_platform_data *pdata = spi->dev.platform_data;
struct ad7192_state *st;
struct iio_dev *indio_dev;
int ret , voltage_uv = 0;
int ret, voltage_uv = 0;
if (!pdata) {
dev_err(&spi->dev, "no platform data?\n");

View File

@ -436,7 +436,14 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
*/
mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch));
/* prepare the delay/loop unit according to the oversampling count */
/*
* prepare the delay/loop unit according to the oversampling count
*
* from the datasheet:
* "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
* HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
* the LRADC will not trigger the delay group."
*/
mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch) |
LRADC_DELAY_TRIGGER_DELAYS(0) |
LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) |
@ -1495,20 +1502,38 @@ static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
return -EINVAL;
}
lradc->over_sample_cnt = 4;
ret = of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt);
if (ret == 0)
if (of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt)) {
lradc->over_sample_cnt = 4;
} else {
if (adapt < 1 || adapt > 32) {
dev_err(lradc->dev, "Invalid sample count (%u)\n",
adapt);
return -EINVAL;
}
lradc->over_sample_cnt = adapt;
}
lradc->over_sample_delay = 2;
ret = of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt);
if (ret == 0)
if (of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt)) {
lradc->over_sample_delay = 2;
} else {
if (adapt < 2 || adapt > LRADC_DELAY_DELAY_MASK + 1) {
dev_err(lradc->dev, "Invalid sample delay (%u)\n",
adapt);
return -EINVAL;
}
lradc->over_sample_delay = adapt;
}
lradc->settling_delay = 10;
ret = of_property_read_u32(lradc_node, "fsl,settling", &adapt);
if (ret == 0)
if (of_property_read_u32(lradc_node, "fsl,settling", &adapt)) {
lradc->settling_delay = 10;
} else {
if (adapt < 1 || adapt > LRADC_DELAY_DELAY_MASK) {
dev_err(lradc->dev, "Invalid settling delay (%u)\n",
adapt);
return -EINVAL;
}
lradc->settling_delay = adapt;
}
return 0;
}

View File

@ -33,6 +33,7 @@
* @base: base of irq range
* @enabled: mask of which irqs are enabled
* @inuse: mask of which irqs are connected
* @regs: irq regs we are faking
* @lock: protect the evgen state
*/
struct iio_dummy_eventgen {
@ -40,6 +41,7 @@ struct iio_dummy_eventgen {
int base;
bool enabled[IIO_EVENTGEN_NO];
bool inuse[IIO_EVENTGEN_NO];
struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock;
};
@ -136,6 +138,12 @@ int iio_dummy_evgen_release_irq(int irq)
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
{
return &iio_evgen->regs[irq - iio_evgen->base];
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
static void iio_dummy_evgen_free(void)
{
irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
@ -153,6 +161,15 @@ static ssize_t iio_evgen_poke(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long event;
int ret;
ret = kstrtoul(buf, 10, &event);
if (ret)
return ret;
iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
iio_evgen->regs[this_attr->address].reg_data = event;
if (iio_evgen->enabled[this_attr->address])
handle_nested_irq(iio_evgen->base + this_attr->address);

View File

@ -1,6 +1,12 @@
#ifndef _IIO_DUMMY_EVGEN_H_
#define _IIO_DUMMY_EVGEN_H_
struct iio_dummy_regs {
u32 reg_id;
u32 reg_data;
};
struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
int iio_dummy_evgen_get_irq(void);
int iio_dummy_evgen_release_irq(int irq);

View File

@ -69,6 +69,34 @@ static const struct iio_event_spec iio_dummy_event = {
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
};
/*
* simple step detect event - triggered when a step is detected
*/
static const struct iio_event_spec step_detect_event = {
.type = IIO_EV_TYPE_INSTANCE,
.dir = IIO_EV_DIR_NONE,
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
};
/*
* simple transition event - triggered when the reported running confidence
* value rises above a threshold value
*/
static const struct iio_event_spec iio_running_event = {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
};
/*
* simple transition event - triggered when the reported walking confidence
* value falls under a threshold value
*/
static const struct iio_event_spec iio_walking_event = {
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
};
#endif
/*
@ -211,10 +239,44 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.scan_index = -1, /* No buffer support */
.output = 1,
.indexed = 1,
.channel = 0,
},
{
.type = IIO_STEPS,
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
BIT(IIO_CHAN_INFO_CALIBHEIGHT),
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = -1, /* No buffer support */
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
.event_spec = &step_detect_event,
.num_event_specs = 1,
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
},
{
.type = IIO_ACTIVITY,
.modified = 1,
.channel2 = IIO_MOD_RUNNING,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = -1, /* No buffer support */
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
.event_spec = &iio_running_event,
.num_event_specs = 1,
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
},
{
.type = IIO_ACTIVITY,
.modified = 1,
.channel2 = IIO_MOD_WALKING,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.scan_index = -1, /* No buffer support */
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
.event_spec = &iio_walking_event,
.num_event_specs = 1,
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
},
};
/**
@ -263,24 +325,55 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
break;
}
break;
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_STEPS:
*val = st->steps;
ret = IIO_VAL_INT;
break;
case IIO_ACTIVITY:
switch (chan->channel2) {
case IIO_MOD_RUNNING:
*val = st->activity_running;
ret = IIO_VAL_INT;
break;
case IIO_MOD_WALKING:
*val = st->activity_walking;
ret = IIO_VAL_INT;
break;
default:
break;
}
break;
default:
break;
}
break;
case IIO_CHAN_INFO_OFFSET:
/* only single ended adc -> 7 */
*val = 7;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
switch (chan->differential) {
case 0:
/* only single ended adc -> 0.001333 */
*val = 0;
*val2 = 1333;
ret = IIO_VAL_INT_PLUS_MICRO;
switch (chan->type) {
case IIO_VOLTAGE:
switch (chan->differential) {
case 0:
/* only single ended adc -> 0.001333 */
*val = 0;
*val2 = 1333;
ret = IIO_VAL_INT_PLUS_MICRO;
break;
case 1:
/* all differential adc channels ->
* 0.000001344 */
*val = 0;
*val2 = 1344;
ret = IIO_VAL_INT_PLUS_NANO;
}
break;
default:
break;
case 1:
/* all differential adc channels -> 0.000001344 */
*val = 0;
*val2 = 1344;
ret = IIO_VAL_INT_PLUS_NANO;
}
break;
case IIO_CHAN_INFO_CALIBBIAS:
@ -298,6 +391,27 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
*val2 = 33;
ret = IIO_VAL_INT_PLUS_NANO;
break;
case IIO_CHAN_INFO_ENABLE:
switch (chan->type) {
case IIO_STEPS:
*val = st->steps_enabled;
ret = IIO_VAL_INT;
break;
default:
break;
}
break;
case IIO_CHAN_INFO_CALIBHEIGHT:
switch (chan->type) {
case IIO_STEPS:
*val = st->height;
ret = IIO_VAL_INT;
break;
default:
break;
}
break;
default:
break;
}
@ -330,14 +444,45 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (chan->output == 0)
return -EINVAL;
switch (chan->type) {
case IIO_VOLTAGE:
if (chan->output == 0)
return -EINVAL;
/* Locking not required as writing single value */
mutex_lock(&st->lock);
st->dac_val = val;
mutex_unlock(&st->lock);
return 0;
/* Locking not required as writing single value */
mutex_lock(&st->lock);
st->dac_val = val;
mutex_unlock(&st->lock);
return 0;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_STEPS:
mutex_lock(&st->lock);
st->steps = val;
mutex_unlock(&st->lock);
return 0;
case IIO_ACTIVITY:
if (val < 0)
val = 0;
if (val > 100)
val = 100;
switch (chan->channel2) {
case IIO_MOD_RUNNING:
st->activity_running = val;
return 0;
case IIO_MOD_WALKING:
st->activity_walking = val;
return 0;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBSCALE:
mutex_lock(&st->lock);
/* Compare against table - hard matching here */
@ -356,6 +501,24 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
st->accel_calibbias = val;
mutex_unlock(&st->lock);
return 0;
case IIO_CHAN_INFO_ENABLE:
switch (chan->type) {
case IIO_STEPS:
mutex_lock(&st->lock);
st->steps_enabled = val;
mutex_unlock(&st->lock);
return 0;
default:
return -EINVAL;
}
case IIO_CHAN_INFO_CALIBHEIGHT:
switch (chan->type) {
case IIO_STEPS:
st->height = val;
return 0;
default:
return -EINVAL;
}
default:
return -EINVAL;
@ -395,6 +558,9 @@ static int iio_dummy_init_device(struct iio_dev *indio_dev)
st->accel_val = 34;
st->accel_calibbias = -7;
st->accel_calibscale = &dummy_scales[0];
st->steps = 47;
st->activity_running = 98;
st->activity_walking = 4;
return 0;
}
@ -475,13 +641,7 @@ static int iio_dummy_probe(int index)
if (ret < 0)
goto error_free_device;
/*
* Configure buffered capture support and register the channels with the
* buffer, but avoid the output channel being registered by reducing the
* number of channels by 1.
*/
ret = iio_simple_dummy_configure_buffer(indio_dev,
iio_dummy_channels, 5);
ret = iio_simple_dummy_configure_buffer(indio_dev);
if (ret < 0)
goto error_unregister_events;

View File

@ -13,6 +13,7 @@
#include <linux/kernel.h>
struct iio_dummy_accel_calibscale;
struct iio_dummy_regs;
/**
* struct iio_dummy_state - device instance specific state.
@ -33,8 +34,14 @@ struct iio_dummy_state {
int differential_adc_val[2];
int accel_val;
int accel_calibbias;
int activity_running;
int activity_walking;
const struct iio_dummy_accel_calibscale *accel_calibscale;
struct mutex lock;
struct iio_dummy_regs *regs;
int steps_enabled;
int steps;
int height;
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
int event_irq;
int event_val;
@ -107,12 +114,10 @@ enum iio_simple_dummy_scan_elements {
};
#ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels, unsigned int num_channels);
int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
#else
static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels, unsigned int num_channels)
static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
return 0;
};

View File

@ -115,14 +115,13 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
.predisable = &iio_triggered_buffer_predisable,
};
int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels, unsigned int num_channels)
int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
int ret;
struct iio_buffer *buffer;
/* Allocate a buffer to use - here a kfifo */
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (buffer == NULL) {
ret = -ENOMEM;
goto error_ret;
@ -173,14 +172,8 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
*/
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
ret = iio_buffer_register(indio_dev, channels, num_channels);
if (ret)
goto error_dealloc_pollfunc;
return 0;
error_dealloc_pollfunc:
iio_dealloc_pollfunc(indio_dev->pollfunc);
error_free_buffer:
iio_kfifo_free(indio_dev->buffer);
error_ret:
@ -194,7 +187,6 @@ error_ret:
*/
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
{
iio_buffer_unregister(indio_dev);
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_kfifo_free(indio_dev->buffer);
}

View File

@ -72,6 +72,22 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
st->event_en = state;
else
return -EINVAL;
default:
return -EINVAL;
}
break;
case IIO_ACTIVITY:
switch (type) {
case IIO_EV_TYPE_THRESH:
st->event_en = state;
break;
default:
return -EINVAL;
}
case IIO_STEPS:
switch (type) {
case IIO_EV_TYPE_INSTANCE:
st->event_en = state;
break;
default:
return -EINVAL;
@ -148,12 +164,50 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
struct iio_dummy_state *st = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "id %x event %x\n",
st->regs->reg_id, st->regs->reg_data);
switch (st->regs->reg_data) {
case 0:
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0, 0),
iio_get_time_ns());
break;
case 1:
if (st->activity_running > st->event_val)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_RUNNING,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH,
0, 0, 0),
iio_get_time_ns());
break;
case 2:
if (st->activity_walking < st->event_val)
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_ACTIVITY, 0,
IIO_MOD_WALKING,
IIO_EV_DIR_FALLING,
IIO_EV_TYPE_THRESH,
0, 0, 0),
iio_get_time_ns());
break;
case 3:
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
IIO_EV_DIR_NONE,
IIO_EV_TYPE_INSTANCE, 0, 0, 0),
iio_get_time_ns());
break;
default:
break;
}
iio_push_event(indio_dev,
IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
IIO_EV_DIR_RISING,
IIO_EV_TYPE_THRESH, 0, 0, 0),
iio_get_time_ns());
return IRQ_HANDLED;
}
@ -179,6 +233,8 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
ret = st->event_irq;
goto error_ret;
}
st->regs = iio_dummy_evgen_get_regs(st->event_irq);
ret = request_threaded_irq(st->event_irq,
NULL,
&iio_simple_dummy_event_handler,

View File

@ -89,7 +89,6 @@
struct ad5933_state {
struct i2c_client *client;
struct regulator *reg;
struct ad5933_platform_data *pdata;
struct delayed_work work;
unsigned long mclk_hz;
unsigned char ctrl_hb;
@ -113,7 +112,8 @@ static const struct iio_chan_spec ad5933_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
.address = AD5933_REG_TEMP_DATA,
.scan_index = -1,
.scan_type = {
@ -520,12 +520,11 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
{
struct ad5933_state *st = iio_priv(indio_dev);
__be16 dat;
int ret = -EINVAL;
int ret;
mutex_lock(&indio_dev->mlock);
switch (m) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto out;
@ -543,16 +542,16 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
goto out;
mutex_unlock(&indio_dev->mlock);
ret = be16_to_cpu(dat);
/* Temp in Milli degrees Celsius */
if (ret < 8192)
*val = ret * 1000 / 32;
else
*val = (ret - 16384) * 1000 / 32;
*val = sign_extend32(be16_to_cpu(dat), 13);
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 1000;
*val2 = 5;
return IIO_VAL_FRACTIONAL_LOG2;
}
return -EINVAL;
out:
mutex_unlock(&indio_dev->mlock);
return ret;
@ -626,7 +625,7 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
struct iio_buffer *buffer;
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
@ -712,9 +711,7 @@ static int ad5933_probe(struct i2c_client *client,
st->client = client;
if (!pdata)
st->pdata = &ad5933_default_pdata;
else
st->pdata = pdata;
pdata = &ad5933_default_pdata;
st->reg = devm_regulator_get(&client->dev, "vcc");
if (!IS_ERR(st->reg)) {
@ -727,10 +724,10 @@ static int ad5933_probe(struct i2c_client *client,
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
st->vref_mv = st->pdata->vref_mv;
st->vref_mv = pdata->vref_mv;
if (st->pdata->ext_clk_Hz) {
st->mclk_hz = st->pdata->ext_clk_Hz;
if (pdata->ext_clk_Hz) {
st->mclk_hz = pdata->ext_clk_Hz;
st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK;
} else {
st->mclk_hz = AD5933_INT_OSC_FREQ_Hz;
@ -752,27 +749,16 @@ static int ad5933_probe(struct i2c_client *client,
if (ret)
goto error_disable_reg;
ret = iio_buffer_register(indio_dev, ad5933_channels,
ARRAY_SIZE(ad5933_channels));
ret = ad5933_setup(st);
if (ret)
goto error_unreg_ring;
/* enable both REAL and IMAG channels by default */
iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
ret = ad5933_setup(st);
if (ret)
goto error_uninitialize_ring;
ret = iio_device_register(indio_dev);
if (ret)
goto error_uninitialize_ring;
goto error_unreg_ring;
return 0;
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring:
iio_kfifo_free(indio_dev->buffer);
error_disable_reg:
@ -788,7 +774,6 @@ static int ad5933_remove(struct i2c_client *client)
struct ad5933_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
iio_kfifo_free(indio_dev->buffer);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);

View File

@ -145,7 +145,6 @@ ssize_t ade7758_read_data_from_ring(struct device *dev,
int ade7758_configure_ring(struct iio_dev *indio_dev);
void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
void ade7758_uninitialize_ring(struct iio_dev *indio_dev);
int ade7758_set_irq(struct device *dev, bool enable);
int ade7758_spi_write_reg_8(struct device *dev,

View File

@ -850,23 +850,15 @@ static int ade7758_probe(struct spi_device *spi)
if (ret)
goto error_free_tx;
ret = iio_buffer_register(indio_dev,
&ade7758_channels[0],
ARRAY_SIZE(ade7758_channels));
if (ret) {
dev_err(&spi->dev, "failed to initialize the ring\n");
goto error_unreg_ring_funcs;
}
/* Get the device into a sane initial state */
ret = ade7758_initial_setup(indio_dev);
if (ret)
goto error_uninitialize_ring;
goto error_unreg_ring_funcs;
if (spi->irq) {
ret = ade7758_probe_trigger(indio_dev);
if (ret)
goto error_uninitialize_ring;
goto error_unreg_ring_funcs;
}
ret = iio_device_register(indio_dev);
@ -878,8 +870,6 @@ static int ade7758_probe(struct spi_device *spi)
error_remove_trigger:
if (spi->irq)
ade7758_remove_trigger(indio_dev);
error_uninitialize_ring:
ade7758_uninitialize_ring(indio_dev);
error_unreg_ring_funcs:
ade7758_unconfigure_ring(indio_dev);
error_free_tx:
@ -897,7 +887,6 @@ static int ade7758_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
ade7758_stop_device(&indio_dev->dev);
ade7758_remove_trigger(indio_dev);
ade7758_uninitialize_ring(indio_dev);
ade7758_unconfigure_ring(indio_dev);
kfree(st->tx);
kfree(st->rx);

View File

@ -118,7 +118,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev)
struct iio_buffer *buffer;
int ret = 0;
buffer = iio_kfifo_allocate(indio_dev);
buffer = iio_kfifo_allocate();
if (!buffer) {
ret = -ENOMEM;
return ret;
@ -180,8 +180,3 @@ error_iio_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
}
void ade7758_uninitialize_ring(struct iio_dev *indio_dev)
{
iio_buffer_unregister(indio_dev);
}

View File

@ -116,7 +116,7 @@ static int ade7759_spi_read_reg_40(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7759_READ_REG(reg_address);
memset(&st->tx[1], 0 , 5);
memset(&st->tx[1], 0, 5);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {

View File

@ -25,9 +25,7 @@ struct iio_buffer;
* available.
* @request_update: if a parameter change has been marked, update underlying
* storage.
* @get_bytes_per_datum:get current bytes per datum
* @set_bytes_per_datum:set number of bytes per datum
* @get_length: get number of datums in buffer
* @set_length: set number of datums in buffer
* @release: called when the last reference to the buffer is dropped,
* should free all resources allocated by the buffer.
@ -49,9 +47,7 @@ struct iio_buffer_access_funcs {
int (*request_update)(struct iio_buffer *buffer);
int (*get_bytes_per_datum)(struct iio_buffer *buffer);
int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
int (*get_length)(struct iio_buffer *buffer);
int (*set_length)(struct iio_buffer *buffer, int length);
void (*release)(struct iio_buffer *buffer);
@ -85,10 +81,11 @@ struct iio_buffer {
bool scan_timestamp;
const struct iio_buffer_access_funcs *access;
struct list_head scan_el_dev_attr_list;
struct attribute_group buffer_group;
struct attribute_group scan_el_group;
wait_queue_head_t pollq;
bool stufftoread;
const struct attribute_group *attrs;
const struct attribute **attrs;
struct list_head demux_list;
void *demux_bounce;
struct list_head buffer_list;
@ -116,15 +113,6 @@ void iio_buffer_init(struct iio_buffer *buffer);
int iio_scan_mask_query(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
* iio_scan_mask_set() - set particular bit in the scan mask
* @indio_dev IIO device structure
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
**/
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
* iio_push_to_buffers() - push to a registered buffer.
* @indio_dev: iio_dev structure for device.
@ -159,56 +147,6 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
int iio_update_demux(struct iio_dev *indio_dev);
/**
* iio_buffer_register() - register the buffer with IIO core
* @indio_dev: device with the buffer to be registered
* @channels: the channel descriptions used to construct buffer
* @num_channels: the number of channels
**/
int iio_buffer_register(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels,
int num_channels);
/**
* iio_buffer_unregister() - unregister the buffer from IIO core
* @indio_dev: the device with the buffer to be unregistered
**/
void iio_buffer_unregister(struct iio_dev *indio_dev);
/**
* iio_buffer_read_length() - attr func to get number of datums in the buffer
**/
ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf);
/**
* iio_buffer_write_length() - attr func to set number of datums in the buffer
**/
ssize_t iio_buffer_write_length(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len);
/**
* iio_buffer_store_enable() - attr to turn the buffer on
**/
ssize_t iio_buffer_store_enable(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t len);
/**
* iio_buffer_show_enable() - attr to see if the buffer is on
**/
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf);
#define IIO_BUFFER_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR, \
iio_buffer_read_length, \
iio_buffer_write_length)
#define IIO_BUFFER_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, \
iio_buffer_show_enable, \
iio_buffer_store_enable)
bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
const unsigned long *mask);
@ -232,16 +170,6 @@ static inline void iio_device_attach_buffer(struct iio_dev *indio_dev,
#else /* CONFIG_IIO_BUFFER */
static inline int iio_buffer_register(struct iio_dev *indio_dev,
const struct iio_chan_spec *channels,
int num_channels)
{
return 0;
}
static inline void iio_buffer_unregister(struct iio_dev *indio_dev)
{}
static inline void iio_buffer_get(struct iio_buffer *buffer) {}
static inline void iio_buffer_put(struct iio_buffer *buffer) {}

View File

@ -150,6 +150,16 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val);
*/
int iio_read_channel_processed(struct iio_channel *chan, int *val);
/**
* iio_write_channel_raw() - write to a given channel
* @chan: The channel being queried.
* @val: Value being written.
*
* Note raw writes to iio channels are in dac counts and hence
* scale will need to be applied if standard units required.
*/
int iio_write_channel_raw(struct iio_channel *chan, int val);
/**
* iio_get_channel_type() - get the type of a channel
* @channel: The channel being queried.
@ -191,7 +201,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
* The scale factor allows to increase the precession of the returned value. For
* a scale factor of 1 the function will return the result in the normal IIO
* unit for the channel type. E.g. millivolt for voltage channels, if you want
* nanovolts instead pass 1000 as the scale factor.
* nanovolts instead pass 1000000 as the scale factor.
*/
int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
int *processed, unsigned int scale);

View File

@ -38,6 +38,8 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_HARDWAREGAIN,
IIO_CHAN_INFO_HYSTERESIS,
IIO_CHAN_INFO_INT_TIME,
IIO_CHAN_INFO_ENABLE,
IIO_CHAN_INFO_CALIBHEIGHT,
};
enum iio_shared_by {

View File

@ -5,7 +5,10 @@
#include <linux/iio/iio.h>
#include <linux/iio/buffer.h>
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
struct iio_buffer *iio_kfifo_allocate(void);
void iio_kfifo_free(struct iio_buffer *r);
struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev);
void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r);
#endif

View File

@ -30,6 +30,8 @@ enum iio_chan_type {
IIO_CCT,
IIO_PRESSURE,
IIO_HUMIDITYRELATIVE,
IIO_ACTIVITY,
IIO_STEPS,
};
enum iio_modifier {
@ -59,7 +61,11 @@ enum iio_modifier {
IIO_MOD_NORTH_MAGN,
IIO_MOD_NORTH_TRUE,
IIO_MOD_NORTH_MAGN_TILT_COMP,
IIO_MOD_NORTH_TRUE_TILT_COMP
IIO_MOD_NORTH_TRUE_TILT_COMP,
IIO_MOD_RUNNING,
IIO_MOD_JOGGING,
IIO_MOD_WALKING,
IIO_MOD_STILL,
};
enum iio_event_type {
@ -68,6 +74,7 @@ enum iio_event_type {
IIO_EV_TYPE_ROC,
IIO_EV_TYPE_THRESH_ADAPTIVE,
IIO_EV_TYPE_MAG_ADAPTIVE,
IIO_EV_TYPE_INSTANCE,
};
enum iio_event_info {
@ -81,6 +88,7 @@ enum iio_event_direction {
IIO_EV_DIR_EITHER,
IIO_EV_DIR_RISING,
IIO_EV_DIR_FALLING,
IIO_EV_DIR_NONE,
};
#define IIO_VAL_INT 1