diff options
40 files changed, 2756 insertions, 1270 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-accel-bmc150 b/Documentation/ABI/testing/sysfs-bus-iio-accel-bmc150 new file mode 100644 index 0000000..99847a9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-accel-bmc150 @@ -0,0 +1,7 @@ +What: /sys/bus/iio/devices/triggerX/name = "bmc150_accel-any-motion-devX" +KernelVersion: 3.17 +Contact: linux-iio@vger.kernel.org +Description: + The BMC150 accelerometer kernel module provides an additional trigger, + which sets driver in a mode, where data is pushed to the buffer + only when there is any motion. diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt index adc61b0..709efaa 100644 --- a/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt +++ b/Documentation/devicetree/bindings/arm/samsung/exynos-adc.txt @@ -11,13 +11,25 @@ New driver handles the following Required properties: - compatible: Must be "samsung,exynos-adc-v1" - for exynos4412/5250 controllers. + for exynos4412/5250 and s5pv210 controllers. Must be "samsung,exynos-adc-v2" for future controllers. Must be "samsung,exynos3250-adc" for controllers compatible with ADC of Exynos3250. -- reg: Contains ADC register address range (base address and - length) and the address of the phy enable register. + Must be "samsung,s3c2410-adc" for + the ADC in s3c2410 and compatibles + Must be "samsung,s3c2416-adc" for + the ADC in s3c2416 and compatibles + Must be "samsung,s3c2440-adc" for + the ADC in s3c2440 and compatibles + Must be "samsung,s3c2443-adc" for + the ADC in s3c2443 and compatibles + Must be "samsung,s3c6410-adc" for + the ADC in s3c6410 and compatibles +- reg: List of ADC register address range + - The base address and range of ADC register + - The base address and range of ADC_PHY register (every + SoC except for s3c24xx/s3c64xx ADC) - interrupts: Contains the interrupt information for the timer. The format is being dependent on which interrupt controller the Samsung device uses. diff --git a/Documentation/devicetree/bindings/iio/dac/max5821.txt b/Documentation/devicetree/bindings/iio/dac/max5821.txt new file mode 100644 index 0000000..54276ce --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/max5821.txt @@ -0,0 +1,14 @@ +Maxim max5821 DAC device driver + +Required properties: + - compatible: Must be "maxim,max5821" + - reg: Should contain the DAC I2C address + - vref-supply: Phandle to the vref power supply + +Example: + + max5821@38 { + compatible = "maxim,max5821"; + reg = <0x38>; + vref-supply = <®_max5821>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index aefa948..1c04709 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -685,6 +685,17 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) W: http://blackfin.uclinux.org/ S: Supported F: sound/soc/blackfin/* + +ANALOG DEVICES INC IIO DRIVERS +M: Lars-Peter Clausen <lars@metafoo.de> +M: Michael Hennerich <Michael.Hennerich@analog.com> +W: http://wiki.analog.com/ +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/iio/*/ad* +X: drivers/iio/*/adjd* +F: drivers/staging/iio/*/ad* +F: staging/iio/trigger/iio-trig-bfin-timer.c AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg <johannes@sipsolutions.net> @@ -4580,6 +4591,9 @@ F: drivers/media/rc/iguanair.c IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron <jic23@kernel.org> +R: Hartmut Knaack <knaack.h@gmx.de> +R: Lars-Peter Clausen <lars@metafoo.de> +R: Peter Meerwald <pmeerw@pmeerw.net> L: linux-iio@vger.kernel.org S: Maintained F: drivers/iio/ diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index e244e44..2ac2576 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -604,9 +604,9 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = -EINVAL; goto err_stop_hw; } - sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * - sizeof(struct mfd_cell), - GFP_KERNEL); + sd->hid_sensor_hub_client_devs = devm_kzalloc(&hdev->dev, dev_cnt * + sizeof(struct mfd_cell), + GFP_KERNEL); if (sd->hid_sensor_hub_client_devs == NULL) { hid_err(hdev, "Failed to allocate memory for mfd cells\n"); ret = -ENOMEM; @@ -618,11 +618,12 @@ static int sensor_hub_probe(struct hid_device *hdev, if (collection->type == HID_COLLECTION_PHYSICAL) { - hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL); + hsdev = devm_kzalloc(&hdev->dev, sizeof(*hsdev), + GFP_KERNEL); if (!hsdev) { hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); ret = -ENOMEM; - goto err_no_mem; + goto err_stop_hw; } hsdev->hdev = hdev; hsdev->vendor_id = hdev->vendor; @@ -631,13 +632,13 @@ static int sensor_hub_probe(struct hid_device *hdev, if (last_hsdev) last_hsdev->end_collection_index = i; last_hsdev = hsdev; - name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", - collection->usage); + name = devm_kasprintf(&hdev->dev, GFP_KERNEL, + "HID-SENSOR-%x", + collection->usage); if (name == NULL) { hid_err(hdev, "Failed MFD device name\n"); ret = -ENOMEM; - kfree(hsdev); - goto err_no_mem; + goto err_stop_hw; } sd->hid_sensor_hub_client_devs[ sd->hid_sensor_client_cnt].id = @@ -661,16 +662,10 @@ static int sensor_hub_probe(struct hid_device *hdev, ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, sd->hid_sensor_client_cnt, NULL, 0, NULL); if (ret < 0) - goto err_no_mem; + goto err_stop_hw; return ret; -err_no_mem: - for (i = 0; i < sd->hid_sensor_client_cnt; ++i) { - kfree(sd->hid_sensor_hub_client_devs[i].name); - kfree(sd->hid_sensor_hub_client_devs[i].platform_data); - } - kfree(sd->hid_sensor_hub_client_devs); err_stop_hw: hid_hw_stop(hdev); @@ -681,7 +676,6 @@ static void sensor_hub_remove(struct hid_device *hdev) { struct sensor_hub_data *data = hid_get_drvdata(hdev); unsigned long flags; - int i; hid_dbg(hdev, " hardware removed\n"); hid_hw_close(hdev); @@ -691,11 +685,6 @@ static void sensor_hub_remove(struct hid_device *hdev) complete(&data->pending.ready); spin_unlock_irqrestore(&data->lock, flags); mfd_remove_devices(&hdev->dev); - for (i = 0; i < data->hid_sensor_client_cnt; ++i) { - kfree(data->hid_sensor_hub_client_devs[i].name); - kfree(data->hid_sensor_hub_client_devs[i].platform_data); - } - kfree(data->hid_sensor_hub_client_devs); hid_set_drvdata(hdev, NULL); mutex_destroy(&data->mutex); } diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 12addf2..5704d6b 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -17,6 +17,19 @@ config BMA180 To compile this driver as a module, choose M here: the module will be called bma180. +config BMC150_ACCEL + tristate "Bosch BMC150 Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Bosch BMC150 accelerometer. + Currently this only supports the device via an i2c interface. + + This is a combo module with both accelerometer and magnetometer. + This driver is only implementing accelerometer part, which has + its own address and register map. + config HID_SENSOR_ACCEL_3D depends on HID_SENSOR_HUB select IIO_BUFFER diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index 6578ca1..a593996 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -4,6 +4,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o +obj-$(CONFIG_BMC150_ACCEL) += bmc150-accel.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c new file mode 100644 index 0000000..23ae334 --- /dev/null +++ b/drivers/iio/accel/bmc150-accel.c @@ -0,0 +1,1307 @@ +/* + * BMC150 3-axis accelerometer 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/delay.h> +#include <linux/slab.h> +#include <linux/acpi.h> +#include <linux/gpio/consumer.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define BMC150_ACCEL_DRV_NAME "bmc150_accel" +#define BMC150_ACCEL_IRQ_NAME "bmc150_accel_event" +#define BMC150_ACCEL_GPIO_NAME "bmc150_accel_int" + +#define BMC150_ACCEL_REG_CHIP_ID 0x00 +#define BMC150_ACCEL_CHIP_ID_VAL 0xFA + +#define BMC150_ACCEL_REG_INT_STATUS_2 0x0B +#define BMC150_ACCEL_ANY_MOTION_MASK 0x07 +#define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) + +#define BMC150_ACCEL_REG_PMU_LPW 0x11 +#define BMC150_ACCEL_PMU_MODE_MASK 0xE0 +#define BMC150_ACCEL_PMU_MODE_SHIFT 5 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_MASK 0x17 +#define BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT 1 + +#define BMC150_ACCEL_REG_PMU_RANGE 0x0F + +#define BMC150_ACCEL_DEF_RANGE_2G 0x03 +#define BMC150_ACCEL_DEF_RANGE_4G 0x05 +#define BMC150_ACCEL_DEF_RANGE_8G 0x08 +#define BMC150_ACCEL_DEF_RANGE_16G 0x0C + +/* Default BW: 125Hz */ +#define BMC150_ACCEL_REG_PMU_BW 0x10 +#define BMC150_ACCEL_DEF_BW 125 + +#define BMC150_ACCEL_REG_INT_MAP_0 0x19 +#define BMC150_ACCEL_INT_MAP_0_BIT_SLOPE BIT(2) + +#define BMC150_ACCEL_REG_INT_MAP_1 0x1A +#define BMC150_ACCEL_INT_MAP_1_BIT_DATA BIT(0) + +#define BMC150_ACCEL_REG_INT_RST_LATCH 0x21 +#define BMC150_ACCEL_INT_MODE_LATCH_RESET 0x80 +#define BMC150_ACCEL_INT_MODE_LATCH_INT 0x0F +#define BMC150_ACCEL_INT_MODE_NON_LATCH_INT 0x00 + +#define BMC150_ACCEL_REG_INT_EN_0 0x16 +#define BMC150_ACCEL_INT_EN_BIT_SLP_X BIT(0) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Y BIT(1) +#define BMC150_ACCEL_INT_EN_BIT_SLP_Z BIT(2) + +#define BMC150_ACCEL_REG_INT_EN_1 0x17 +#define BMC150_ACCEL_INT_EN_BIT_DATA_EN BIT(4) + +#define BMC150_ACCEL_REG_INT_OUT_CTRL 0x20 +#define BMC150_ACCEL_INT_OUT_CTRL_INT1_LVL BIT(0) + +#define BMC150_ACCEL_REG_INT_5 0x27 +#define BMC150_ACCEL_SLOPE_DUR_MASK 0x03 + +#define BMC150_ACCEL_REG_INT_6 0x28 +#define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF + +/* Slope duration in terms of number of samples */ +#define BMC150_ACCEL_DEF_SLOPE_DURATION 2 +/* in terms of multiples of g's/LSB, based on range */ +#define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 5 + +#define BMC150_ACCEL_REG_XOUT_L 0x02 + +#define BMC150_ACCEL_MAX_STARTUP_TIME_MS 100 + +/* Sleep Duration values */ +#define BMC150_ACCEL_SLEEP_500_MICRO 0x05 +#define BMC150_ACCEL_SLEEP_1_MS 0x06 +#define BMC150_ACCEL_SLEEP_2_MS 0x07 +#define BMC150_ACCEL_SLEEP_4_MS 0x08 +#define BMC150_ACCEL_SLEEP_6_MS 0x09 +#define BMC150_ACCEL_SLEEP_10_MS 0x0A +#define BMC150_ACCEL_SLEEP_25_MS 0x0B +#define BMC150_ACCEL_SLEEP_50_MS 0x0C +#define BMC150_ACCEL_SLEEP_100_MS 0x0D +#define BMC150_ACCEL_SLEEP_500_MS 0x0E +#define BMC150_ACCEL_SLEEP_1_SEC 0x0F + +#define BMC150_ACCEL_REG_TEMP 0x08 +#define BMC150_ACCEL_TEMP_CENTER_VAL 24 + +#define BMC150_ACCEL_AXIS_TO_REG(axis) (BMC150_ACCEL_REG_XOUT_L + (axis * 2)) +#define BMC150_AUTO_SUSPEND_DELAY_MS 2000 + +enum bmc150_accel_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum bmc150_power_modes { + BMC150_ACCEL_SLEEP_MODE_NORMAL, + BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, + BMC150_ACCEL_SLEEP_MODE_LPM, + BMC150_ACCEL_SLEEP_MODE_SUSPEND = 0x04, +}; + +struct bmc150_accel_data { + struct i2c_client *client; + struct iio_trigger *dready_trig; + struct iio_trigger *motion_trig; + struct mutex mutex; + s16 buffer[8]; + u8 bw_bits; + u32 slope_dur; + u32 slope_thres; + u32 range; + int ev_enable_state; + bool dready_trigger_on; + bool motion_trigger_on; + int64_t timestamp; +}; + +static const struct { + int val; + int val2; + u8 bw_bits; +} bmc150_accel_samp_freq_table[] = { {7, 810000, 0x08}, + {15, 630000, 0x09}, + {31, 250000, 0x0A}, + {62, 500000, 0x0B}, + {125, 0, 0x0C}, + {250, 0, 0x0D}, + {500, 0, 0x0E}, + {1000, 0, 0x0F} }; + +static const struct { + int bw_bits; + int msec; +} bmc150_accel_sample_upd_time[] = { {0x08, 64}, + {0x09, 32}, + {0x0A, 16}, + {0x0B, 8}, + {0x0C, 4}, + {0x0D, 2}, + {0x0E, 1}, + {0x0F, 1} }; + +static const struct { + int scale; + int range; +} bmc150_accel_scale_table[] = { {9610, BMC150_ACCEL_DEF_RANGE_2G}, + {19122, BMC150_ACCEL_DEF_RANGE_4G}, + {38344, BMC150_ACCEL_DEF_RANGE_8G}, + {77057, BMC150_ACCEL_DEF_RANGE_16G} }; + +static const struct { + int sleep_dur; + int reg_value; +} bmc150_accel_sleep_value_table[] = { {0, 0}, + {500, BMC150_ACCEL_SLEEP_500_MICRO}, + {1000, BMC150_ACCEL_SLEEP_1_MS}, + {2000, BMC150_ACCEL_SLEEP_2_MS}, + {4000, BMC150_ACCEL_SLEEP_4_MS}, + {6000, BMC150_ACCEL_SLEEP_6_MS}, + {10000, BMC150_ACCEL_SLEEP_10_MS}, + {25000, BMC150_ACCEL_SLEEP_25_MS}, + {50000, BMC150_ACCEL_SLEEP_50_MS}, + {100000, BMC150_ACCEL_SLEEP_100_MS}, + {500000, BMC150_ACCEL_SLEEP_500_MS}, + {1000000, BMC150_ACCEL_SLEEP_1_SEC} }; + + +static int bmc150_accel_set_mode(struct bmc150_accel_data *data, + enum bmc150_power_modes mode, + int dur_us) +{ + int i; + int ret; + u8 lpw_bits; + int dur_val = -1; + + if (dur_us > 0) { + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sleep_value_table); + ++i) { + if (bmc150_accel_sleep_value_table[i].sleep_dur == + dur_us) + dur_val = + bmc150_accel_sleep_value_table[i].reg_value; + } + } else + dur_val = 0; + + if (dur_val < 0) + return -EINVAL; + + lpw_bits = mode << BMC150_ACCEL_PMU_MODE_SHIFT; + lpw_bits |= (dur_val << BMC150_ACCEL_PMU_BIT_SLEEP_DUR_SHIFT); + + dev_dbg(&data->client->dev, "Set Mode bits %x\n", lpw_bits); + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_LPW, lpw_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_lpw\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, + int val2) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].val == val && + bmc150_accel_samp_freq_table[i].val2 == val2) { + ret = i2c_smbus_write_byte_data( + data->client, + BMC150_ACCEL_REG_PMU_BW, + bmc150_accel_samp_freq_table[i].bw_bits); + if (ret < 0) + return ret; + + data->bw_bits = + bmc150_accel_samp_freq_table[i].bw_bits; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, + "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + if (ret != BMC150_ACCEL_CHIP_ID_VAL) { + dev_err(&data->client->dev, "Invalid chip %x\n", ret); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration */ + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_5\n"); + return ret; + } + data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_5, + data->slope_dur); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_5\n"); + return ret; + } + dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur); + + /* Set default slope thresholds */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_6, + BMC150_ACCEL_DEF_SLOPE_THRESHOLD); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_6\n"); + return ret; + } + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres); + + /* Set default as latched interrupts */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_setup_any_motion_interrupt( + struct bmc150_accel_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT1 mapping */ + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_0); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map_0\n"); + return ret; + } + if (status) + ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; + else + ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_0, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map_0\n"); + return ret; + } + + if (status) { + /* Set slope duration (no of samples) */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_5, + data->slope_dur); + if (ret < 0) { + dev_err(&data->client->dev, "Error write reg_int_5\n"); + return ret; + } + + /* Set slope thresholds */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_6, + data->slope_thres); + if (ret < 0) { + dev_err(&data->client->dev, "Error write reg_int_6\n"); + return ret; + } + + /* + * New data interrupt is always non-latched, + * which will have higher priority, so no need + * to set latched mode, we will be flooded anyway with INTR + */ + if (!data->dready_trigger_on) { + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_0, + BMC150_ACCEL_INT_EN_BIT_SLP_X | + BMC150_ACCEL_INT_EN_BIT_SLP_Y | + BMC150_ACCEL_INT_EN_BIT_SLP_Z); + } else + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_0, + 0); + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en_0\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data, + bool status) +{ + int ret; + + /* Enable/Disable INT1 mapping */ + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map_1\n"); + return ret; + } + if (status) + ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA; + else + ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA; + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_MAP_1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map_1\n"); + return ret; + } + + if (status) { + /* + * Set non latched mode interrupt and clear any latched + * interrupt + */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_NON_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_1, + BMC150_ACCEL_INT_EN_BIT_DATA_EN); + + } else { + /* Restore default interrupt mode */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_EN_1, + 0); + } + + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en_1\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, + int *val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_samp_freq_table); ++i) { + if (bmc150_accel_samp_freq_table[i].bw_bits == data->bw_bits) { + *val = bmc150_accel_samp_freq_table[i].val; + *val2 = bmc150_accel_samp_freq_table[i].val2; + return IIO_VAL_INT_PLUS_MICRO; + } + } + + return -EINVAL; +} + +static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_sample_upd_time); ++i) { + if (bmc150_accel_sample_upd_time[i].bw_bits == data->bw_bits) + return bmc150_accel_sample_upd_time[i].msec; + } + + return BMC150_ACCEL_MAX_STARTUP_TIME_MS; +} + +static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) +{ + int ret; + + if (on) + ret = pm_runtime_get_sync(&data->client->dev); + else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + if (ret < 0) { + dev_err(&data->client->dev, + "Failed: bmc150_accel_set_power_state for %d\n", on); + return ret; + } + + return 0; +} + +static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); ++i) { + if (bmc150_accel_scale_table[i].scale == val) { + ret = i2c_smbus_write_byte_data( + data->client, + BMC150_ACCEL_REG_PMU_RANGE, + bmc150_accel_scale_table[i].range); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing pmu_range\n"); + return ret; + } + + data->range = bmc150_accel_scale_table[i].range; + return 0; + } + } + + return -EINVAL; +} + +static int bmc150_accel_get_temp(struct bmc150_accel_data *data, int *val) +{ + int ret; + + mutex_lock(&data->mutex); + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_TEMP); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_temp\n"); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret, 7); + + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; +} + +static int bmc150_accel_get_axis(struct bmc150_accel_data *data, int axis, + int *val) +{ + int ret; + + mutex_lock(&data->mutex); + ret = bmc150_accel_set_power_state(data, true); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = i2c_smbus_read_word_data(data->client, + BMC150_ACCEL_AXIS_TO_REG(axis)); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading axis %d\n", axis); + bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret >> 4, 11); + ret = bmc150_accel_set_power_state(data, false); + mutex_unlock(&data->mutex); + if (ret < 0) + return ret; + + return IIO_VAL_INT; +} + +static int bmc150_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_TEMP: + return bmc150_accel_get_temp(data, val); + case IIO_ACCEL: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + else + return bmc150_accel_get_axis(data, + chan->scan_index, + val); + default: + return -EINVAL; + } + case IIO_CHAN_INFO_OFFSET: + if (chan->type == IIO_TEMP) { + *val = BMC150_ACCEL_TEMP_CENTER_VAL; + return IIO_VAL_INT; + } else + return -EINVAL; + case IIO_CHAN_INFO_SCALE: + *val = 0; + switch (chan->type) { + case IIO_TEMP: + *val2 = 500000; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_ACCEL: + { + int i; + + for (i = 0; i < ARRAY_SIZE(bmc150_accel_scale_table); + ++i) { + if (bmc150_accel_scale_table[i].range == + data->range) { + *val2 = + bmc150_accel_scale_table[i].scale; + return IIO_VAL_INT_PLUS_MICRO; + } + } + return -EINVAL; + } + default: + return -EINVAL; + } + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_get_bw(data, val, val2); + mutex_unlock(&data->mutex); + return ret; + default: + return -EINVAL; + } +} + +static int bmc150_accel_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = bmc150_accel_set_bw(data, val, val2); + mutex_unlock(&data->mutex); + break; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = bmc150_accel_set_scale(data, val2); + mutex_unlock(&data->mutex); + return ret; + default: + ret = -EINVAL; + } + + return ret; +} + +static int bmc150_accel_read_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + *val2 = 0; + switch (info) { + case IIO_EV_INFO_VALUE: + *val = data->slope_thres; + break; + case IIO_EV_INFO_PERIOD: + *val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK; + break; + default: + return -EINVAL; + } + + return IIO_VAL_INT; +} + +static int bmc150_accel_write_event(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + if (data->ev_enable_state) + return -EBUSY; + + switch (info) { + case IIO_EV_INFO_VALUE: + data->slope_thres = val; + break; + case IIO_EV_INFO_PERIOD: + data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK; + data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + + return data->ev_enable_state; +} + +static int bmc150_accel_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 bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + if (state && data->ev_enable_state) + return 0; + + mutex_lock(&data->mutex); + + if (!state && data->motion_trigger_on) { + data->ev_enable_state = 0; + mutex_unlock(&data->mutex); + return 0; + } + + /* + * We will expect the enable and disable to do operation in + * in reverse order. This will happen here anyway as our + * resume operation uses sync mode runtime pm calls, the + * suspend operation will be delayed by autosuspend delay + * So the disable operation will still happen in reverse of + * enable operation. When runtime pm is disabled the mode + * is always on so sequence doesn't matter + */ + + ret = bmc150_accel_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + ret = bmc150_accel_setup_any_motion_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + + data->ev_enable_state = state; + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct bmc150_accel_data *data = iio_priv(indio_dev); + + if (data->dready_trig != trig && data->motion_trig != trig) + return -EINVAL; + + return 0; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "7.810000 15.630000 31.250000 62.500000 125 250 500 1000"); + +static struct attribute *bmc150_accel_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group bmc150_accel_attrs_group = { + .attrs = bmc150_accel_attributes, +}; + +static const struct iio_event_spec bmc150_accel_event = { + .type = IIO_EV_TYPE_ROC, + .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_PERIOD) +}; + +#define BMC150_ACCEL_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + }, \ + .event_spec = &bmc150_accel_event, \ + .num_event_specs = 1 \ +} + +static const struct iio_chan_spec bmc150_accel_channels[] = { + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = -1, + }, + BMC150_ACCEL_CHANNEL(X), + BMC150_ACCEL_CHANNEL(Y), + BMC150_ACCEL_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_info bmc150_accel_info = { + .attrs = &bmc150_accel_attrs_group, + .read_raw = bmc150_accel_read_raw, + .write_raw = bmc150_accel_write_raw, + .read_event_value = bmc150_accel_read_event, + .write_event_value = bmc150_accel_write_event, + .write_event_config = bmc150_accel_write_event_config, + .read_event_config = bmc150_accel_read_event_config, + .validate_trigger = bmc150_accel_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t bmc150_accel_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct bmc150_accel_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + for_each_set_bit(bit, indio_dev->buffer->scan_mask, + indio_dev->masklength) { + ret = i2c_smbus_read_word_data(data->client, + BMC150_ACCEL_AXIS_TO_REG(bit)); + if (ret < 0) { + mutex_unlock(&data->mutex); + goto err_read; + } + data->buffer[i++] = ret; + } + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + data->timestamp); +err_read: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + /* new data interrupts don't need ack */ + if (data->dready_trigger_on) + return 0; + + mutex_lock(&data->mutex); + /* clear any latched interrupt */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + mutex_unlock(&data->mutex); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + +static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + + if (!state && data->ev_enable_state && data->motion_trigger_on) { + data->motion_trigger_on = false; + mutex_unlock(&data->mutex); + return 0; + } + + /* + * Refer to comment in bmc150_accel_write_event_config for + * enable/disable operation order + */ + ret = bmc150_accel_set_power_state(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + ret = bmc150_accel_setup_any_motion_interrupt(data, state); + else + ret = bmc150_accel_setup_new_data_interrupt(data, state); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + if (data->motion_trig == trig) + data->motion_trigger_on = state; + else + data->dready_trigger_on = state; + + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops bmc150_accel_trigger_ops = { + .set_trigger_state = bmc150_accel_data_rdy_trigger_set_state, + .try_reenable = bmc150_accel_trig_try_reen, + .owner = THIS_MODULE, +}; + +static irqreturn_t bmc150_accel_event_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + int dir; + + ret = i2c_smbus_read_byte_data(data->client, + BMC150_ACCEL_REG_INT_STATUS_2); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_status_2\n"); + goto ack_intr_status; + } + + if (ret & BMC150_ACCEL_ANY_MOTION_BIT_SIGN) + dir = IIO_EV_DIR_FALLING; + else + dir = IIO_EV_DIR_RISING; + + if (ret & BMC150_ACCEL_ANY_MOTION_MASK) + iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X_OR_Y_OR_Z, + IIO_EV_TYPE_ROC, + IIO_EV_DIR_EITHER), + data->timestamp); +ack_intr_status: + if (!data->dready_trigger_on) + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + + return IRQ_HANDLED; +} + +static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct bmc150_accel_data *data = iio_priv(indio_dev); + + data->timestamp = iio_get_time_ns(); + + if (data->dready_trigger_on) + iio_trigger_poll(data->dready_trig); + else if (data->motion_trigger_on) + iio_trigger_poll(data->motion_trig); + + if (data->ev_enable_state) + return IRQ_WAKE_THREAD; + else + return IRQ_HANDLED; +} + +static int bmc150_accel_acpi_gpio_probe(struct i2c_client *client, + struct bmc150_accel_data *data) +{ + const struct acpi_device_id *id; + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + if (!ACPI_HANDLE(dev)) + return -ENODEV; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0); + if (IS_ERR(gpio)) { + dev_err(dev, "Failed: acpi gpio get index\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 bmc150_accel_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct bmc150_accel_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + ret = bmc150_accel_chip_init(data); + if (ret < 0) + return ret; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = bmc150_accel_channels; + indio_dev->num_channels = ARRAY_SIZE(bmc150_accel_channels); + indio_dev->name = BMC150_ACCEL_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &bmc150_accel_info; + + if (client->irq < 0) + client->irq = bmc150_accel_acpi_gpio_probe(client, data); + + if (client->irq >= 0) { + ret = devm_request_threaded_irq( + &client->dev, client->irq, + bmc150_accel_data_rdy_trig_poll, + bmc150_accel_event_handler, + IRQF_TRIGGER_RISING, + BMC150_ACCEL_IRQ_NAME, + indio_dev); + if (ret) + return ret; + + data->dready_trig = devm_iio_trigger_alloc(&client->dev, + "%s-dev%d", + indio_dev->name, + indio_dev->id); + if (!data->dready_trig) + return -ENOMEM; + + 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; + + data->dready_trig->dev.parent = &client->dev; + data->dready_trig->ops = &bmc150_accel_trigger_ops; + iio_trigger_set_drvdata(data->dready_trig, indio_dev); + ret = iio_trigger_register(data->dready_trig); + if (ret) + return ret; + + data->motion_trig->dev.parent = &client->dev; + data->motion_trig->ops = &bmc150_accel_trigger_ops; + iio_trigger_set_drvdata(data->motion_trig, indio_dev); + ret = iio_trigger_register(data->motion_trig); + if (ret) { + data->motion_trig = NULL; + goto err_trigger_unregister; + } + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + bmc150_accel_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "Failed: iio triggered buffer setup\n"); + goto err_trigger_unregister; + } + } + + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "Unable to register iio device\n"); + goto err_buffer_cleanup; + } + + ret = pm_runtime_set_active(&client->dev); + if (ret) + goto err_iio_unregister; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + BMC150_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return 0; + +err_iio_unregister: + iio_device_unregister(indio_dev); +err_buffer_cleanup: + if (data->dready_trig) + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->dready_trig) + iio_trigger_unregister(data->dready_trig); + if (data->motion_trig) + iio_trigger_unregister(data->motion_trig); + + return ret; +} + +static int bmc150_accel_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + iio_device_unregister(indio_dev); + + if (data->dready_trig) { + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->dready_trig); + iio_trigger_unregister(data->motion_trig); + } + + mutex_lock(&data->mutex); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bmc150_accel_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); + mutex_unlock(&data->mutex); + + return 0; +} + +static int bmc150_accel_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (data->dready_trigger_on || data->motion_trigger_on || + data->ev_enable_state) + bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + mutex_unlock(&data->mutex); + + return 0; +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int bmc150_accel_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + + dev_dbg(&data->client->dev, __func__); + + return bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); +} + +static int bmc150_accel_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct bmc150_accel_data *data = iio_priv(indio_dev); + int ret; + int sleep_val; + + dev_dbg(&data->client->dev, __func__); + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + sleep_val = bmc150_accel_get_startup_times(data); + if (sleep_val < 20) + usleep_range(sleep_val * 1000, 20000); + else + msleep_interruptible(sleep_val); + + return 0; +} +#endif + +static const struct dev_pm_ops bmc150_accel_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bmc150_accel_suspend, bmc150_accel_resume) + SET_RUNTIME_PM_OPS(bmc150_accel_runtime_suspend, + bmc150_accel_runtime_resume, NULL) +}; + +static const struct acpi_device_id bmc150_accel_acpi_match[] = { + {"BSBA0150", 0}, + {"BMC150A", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, bmc150_accel_acpi_match); + +static const struct i2c_device_id bmc150_accel_id[] = { + {"bmc150_accel", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, bmc150_accel_id); + +static struct i2c_driver bmc150_accel_driver = { + .driver = { + .name = BMC150_ACCEL_DRV_NAME, + .acpi_match_table = ACPI_PTR(bmc150_accel_acpi_match), + .pm = &bmc150_accel_pm_ops, + }, + .probe = bmc150_accel_probe, + .remove = bmc150_accel_remove, + .id_table = bmc150_accel_id, +}; +module_i2c_driver(bmc150_accel_driver); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("BMC150 accelerometer driver"); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 7941cf2..57c515b 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -21,6 +21,8 @@ #include <linux/string.h> #include <linux/acpi.h> #include <linux/gpio/consumer.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> @@ -71,15 +73,18 @@ #define KXCJK1013_DATA_MASK_12_BIT 0x0FFF #define KXCJK1013_MAX_STARTUP_TIME_US 100000 +#define KXCJK1013_SLEEP_DELAY_MS 2000 + struct kxcjk1013_data { struct i2c_client *client; struct iio_trigger *trig; bool trig_mode; struct mutex mutex; s16 buffer[8]; - int power_state; u8 odr_bits; + u8 range; bool active_high_intr; + bool trigger_on; }; enum kxcjk1013_axis { @@ -93,6 +98,12 @@ enum kxcjk1013_mode { OPERATION, }; +enum kxcjk1013_range { + KXCJK1013_RANGE_2G, + KXCJK1013_RANGE_4G, + KXCJK1013_RANGE_8G, +}; + static const struct { int val; int val2; @@ -112,6 +123,14 @@ static const struct { {0x02, 21000}, {0x03, 11000}, {0x04, 6400}, {0x05, 3900}, {0x06, 2700}, {0x07, 2100} }; +static const struct { + u16 scale; + u8 gsel_0; + u8 gsel_1; +} KXCJK1013_scale_table[] = { {9582, 0, 0}, + {19163, 1, 0}, + {38326, 0, 1} }; + static int kxcjk1013_set_mode(struct kxcjk1013_data *data, enum kxcjk1013_mode mode) { @@ -138,6 +157,51 @@ static int kxcjk1013_set_mode(struct kxcjk1013_data *data, return 0; } +static int kxcjk1013_get_mode(struct kxcjk1013_data *data, + enum kxcjk1013_mode *mode) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (ret & KXCJK1013_REG_CTRL1_BIT_PC1) + *mode = OPERATION; + else + *mode = STANDBY; + + return 0; +} + +static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); + ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + data->range = range_index; + + return 0; +} + static int kxcjk1013_chip_init(struct kxcjk1013_data *data) { int ret; @@ -160,10 +224,6 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } - /* Setting range to 4G */ - ret |= KXCJK1013_REG_CTRL1_BIT_GSEL0; - ret &= ~KXCJK1013_REG_CTRL1_BIT_GSEL1; - /* Set 12 bit mode */ ret |= KXCJK1013_REG_CTRL1_BIT_RES; @@ -174,6 +234,14 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } + /* Setting range to 4G */ + ret = kxcjk1013_set_range(data, KXCJK1013_RANGE_4G); + if (ret < 0) + return ret; + + data->range = KXCJK1013_RANGE_4G; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); if (ret < 0) { dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); @@ -201,6 +269,41 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data) return ret; } + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + + return 0; +} + +static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) { + if (odr_start_up_times[i].odr_bits == data->odr_bits) + return odr_start_up_times[i].usec; + } + + return KXCJK1013_MAX_STARTUP_TIME_US; +} + +static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on) +{ + int ret; + + if (on) + ret = pm_runtime_get_sync(&data->client->dev); + else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + if (ret < 0) { + dev_err(&data->client->dev, + "Failed: kxcjk1013_set_power_state for %d\n", on); + return ret; + } + return 0; } @@ -208,6 +311,11 @@ static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, bool status) { int ret; + enum kxcjk1013_mode store_mode; + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; /* This is requirement by spec to change state to STANDBY */ ret = kxcjk1013_set_mode(data, STANDBY); @@ -250,7 +358,13 @@ static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, return ret; } - return ret; + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; } static int kxcjk1013_convert_freq_to_bit(int val, int val2) @@ -271,6 +385,11 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) { int ret; int odr_bits; + enum kxcjk1013_mode store_mode; + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; odr_bits = kxcjk1013_convert_freq_to_bit(val, val2); if (odr_bits < 0) @@ -290,9 +409,7 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) data->odr_bits = odr_bits; - /* Check, if the ODR is changed after data enable */ - if (data->power_state) { - /* Set the state back to operation */ + if (store_mode == OPERATION) { ret = kxcjk1013_set_mode(data, OPERATION); if (ret < 0) return ret; @@ -331,16 +448,38 @@ static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis) return ret; } -static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) +static int kxcjk1013_set_scale(struct kxcjk1013_data *data, int val) { - int i; + int ret, i; + enum kxcjk1013_mode store_mode; - for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) { - if (odr_start_up_times[i].odr_bits == data->odr_bits) - return odr_start_up_times[i].usec; + + for (i = 0; i < ARRAY_SIZE(KXCJK1013_scale_table); ++i) { + if (KXCJK1013_scale_table[i].scale == val) { + + ret = kxcjk1013_get_mode(data, &store_mode); + if (ret < 0) + return ret; + + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = kxcjk1013_set_range(data, i); + if (ret < 0) + return ret; + + if (store_mode == OPERATION) { + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret) + return ret; + } + + return 0; + } } - return KXCJK1013_MAX_STARTUP_TIME_US; + return -EINVAL; } static int kxcjk1013_read_raw(struct iio_dev *indio_dev, @@ -356,34 +495,30 @@ static int kxcjk1013_read_raw(struct iio_dev *indio_dev, if (iio_buffer_enabled(indio_dev)) ret = -EBUSY; else { - int sleep_val; - - ret = kxcjk1013_set_mode(data, OPERATION); + ret = kxcjk1013_set_power_state(data, true); if (ret < 0) { mutex_unlock(&data->mutex); return ret; } - ++data->power_state; - sleep_val = kxcjk1013_get_startup_times(data); - if (sleep_val < 20000) - usleep_range(sleep_val, 20000); - else - msleep_interruptible(sleep_val/1000); ret = kxcjk1013_get_acc_reg(data, chan->scan_index); - if (--data->power_state == 0) - kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) { + kxcjk1013_set_power_state(data, false); + mutex_unlock(&data->mutex); + return ret; + } + *val = sign_extend32(ret >> 4, 11); + ret = kxcjk1013_set_power_state(data, false); } mutex_unlock(&data->mutex); if (ret < 0) return ret; - *val = sign_extend32(ret >> 4, 11); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = 0; - *val2 = 19163; /* range +-4g (4/2047*9.806650) */ + *val2 = KXCJK1013_scale_table[data->range].scale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: @@ -410,6 +545,14 @@ static int kxcjk1013_write_raw(struct iio_dev *indio_dev, ret = kxcjk1013_set_odr(data, val, val2); mutex_unlock(&data->mutex); break; + case IIO_CHAN_INFO_SCALE: + if (val) + return -EINVAL; + + mutex_lock(&data->mutex); + ret = kxcjk1013_set_scale(data, val2); + mutex_unlock(&data->mutex); + break; default: ret = -EINVAL; } @@ -431,8 +574,11 @@ static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev, static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600"); +static IIO_CONST_ATTR(in_accel_scale_available, "0.009582 0.019163 0.038326"); + static struct attribute *kxcjk1013_attributes[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, NULL, }; @@ -520,20 +666,21 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, { struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + if (state && data->trigger_on) + return 0; mutex_lock(&data->mutex); - if (state) { - kxcjk1013_chip_setup_interrupt(data, true); - kxcjk1013_set_mode(data, OPERATION); - ++data->power_state; - } else { - if (--data->power_state) { + ret = kxcjk1013_chip_setup_interrupt(data, state); + if (!ret) { + ret = kxcjk1013_set_power_state(data, state); + if (ret < 0) { mutex_unlock(&data->mutex); - return 0; + return ret; } - kxcjk1013_chip_setup_interrupt(data, false); - kxcjk1013_set_mode(data, STANDBY); } + data->trigger_on = state; mutex_unlock(&data->mutex); return 0; @@ -661,14 +808,25 @@ static int kxcjk1013_probe(struct i2c_client *client, } } - ret = devm_iio_device_register(&client->dev, indio_dev); + ret = iio_device_register(indio_dev); if (ret < 0) { dev_err(&client->dev, "unable to register iio device\n"); goto err_buffer_cleanup; } + ret = pm_runtime_set_active(&client->dev); + if (ret) + goto err_iio_unregister; + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + KXCJK1013_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + return 0; +err_iio_unregister: + iio_device_unregister(indio_dev); err_buffer_cleanup: if (data->trig_mode) iio_triggered_buffer_cleanup(indio_dev); @@ -687,6 +845,12 @@ static int kxcjk1013_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct kxcjk1013_data *data = iio_priv(indio_dev); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + iio_device_unregister(indio_dev); + if (data->trig_mode) { iio_triggered_buffer_cleanup(indio_dev); iio_trigger_unregister(data->trig); @@ -705,35 +869,67 @@ static int kxcjk1013_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; mutex_lock(&data->mutex); - kxcjk1013_set_mode(data, STANDBY); + ret = kxcjk1013_set_mode(data, STANDBY); mutex_unlock(&data->mutex); - return 0; + return ret; } static int kxcjk1013_resume(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 = 0; mutex_lock(&data->mutex); + /* Check, if the suspend occured while active */ + if (data->trigger_on) + ret = kxcjk1013_set_mode(data, OPERATION); + mutex_unlock(&data->mutex); - if (data->power_state) - kxcjk1013_set_mode(data, OPERATION); + return ret; +} +#endif - mutex_unlock(&data->mutex); +#ifdef CONFIG_PM_RUNTIME +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); - return 0; + return kxcjk1013_set_mode(data, STANDBY); } -static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend, kxcjk1013_resume); -#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops) -#else -#define KXCJK1013_PM_OPS NULL +static int kxcjk1013_runtime_resume(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; + int sleep_val; + + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + + sleep_val = kxcjk1013_get_startup_times(data); + if (sleep_val < 20000) + usleep_range(sleep_val, 20000); + else + msleep_interruptible(sleep_val/1000); + + return 0; +} #endif +static const struct dev_pm_ops kxcjk1013_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(kxcjk1013_suspend, kxcjk1013_resume) + SET_RUNTIME_PM_OPS(kxcjk1013_runtime_suspend, + kxcjk1013_runtime_resume, NULL) +}; + static const struct acpi_device_id kx_acpi_match[] = { {"KXCJ1013", 0}, { }, @@ -751,7 +947,7 @@ static struct i2c_driver kxcjk1013_driver = { .driver = { .name = KXCJK1013_DRV_NAME, .acpi_match_table = ACPI_PTR(kx_acpi_match), - .pm = KXCJK1013_PM_OPS, + .pm = &kxcjk1013_pm_ops, }, .probe = kxcjk1013_probe, .remove = kxcjk1013_remove, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 11b048a..88bdc8f 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -129,7 +129,7 @@ config AT91_ADC config EXYNOS_ADC tristate "Exynos ADC driver support" - depends on ARCH_EXYNOS || (OF && COMPILE_TEST) + depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) help Core support for the ADC block found in the Samsung EXYNOS series of SoCs for drivers such as the touchscreen and hwmon to use to share @@ -206,6 +206,16 @@ config NAU7802 To compile this driver as a module, choose M here: the module will be called nau7802. +config ROCKCHIP_SARADC + tristate "Rockchip SARADC driver" + depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) + help + Say yes here to build support for the SARADC found in SoCs from + Rockchip. + + To compile this driver as a module, choose M here: the + module will be called rockchip_saradc. + config TI_ADC081C tristate "Texas Instruments ADC081C021/027" depends on I2C @@ -216,6 +226,16 @@ config TI_ADC081C This driver can also be built as a module. If so, the module will be called ti-adc081c. +config TI_ADC128S052 + tristate "Texas Instruments ADC128S052" + depends on SPI + help + If you say yes here you get support for Texas Instruments ADC128S052 + chip. + + This driver can also be built as a module. If so, the module will be + called ti-adc128s052. + config TI_AM335X_ADC tristate "TI's AM335X ADC driver" depends on MFD_TI_AM335X_TSCADC diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ad81b51..cb88a6a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -22,7 +22,9 @@ obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_NAU7802) += nau7802.o +obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o +obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index fc9dfc2..c59012d 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -40,13 +40,16 @@ #include <linux/iio/machine.h> #include <linux/iio/driver.h> -/* EXYNOS4412/5250 ADC_V1 registers definitions */ +/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */ #define ADC_V1_CON(x) ((x) + 0x00) #define ADC_V1_DLY(x) ((x) + 0x08) #define ADC_V1_DATX(x) ((x) + 0x0C) #define ADC_V1_INTCLR(x) ((x) + 0x18) #define ADC_V1_MUX(x) ((x) + 0x1c) +/* S3C2410 ADC registers definitions */ +#define ADC_S3C2410_MUX(x) ((x) + 0x18) + /* Future ADC_V2 registers definitions */ #define ADC_V2_CON1(x) ((x) + 0x00) #define ADC_V2_CON2(x) ((x) + 0x04) @@ -61,6 +64,11 @@ #define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) #define ADC_V1_CON_STANDBY (1u << 2) +/* Bit definitions for S3C2410 ADC */ +#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3) +#define ADC_S3C2410_DATX_MASK 0x3FF +#define ADC_S3C2416_CON_RES_SEL (1u << 3) + /* Bit definitions for ADC_V2 */ #define ADC_V2_CON1_SOFT_RESET (1u << 2) @@ -77,6 +85,7 @@ /* Bit definitions common for ADC_V1 and ADC_V2 */ #define ADC_CON_EN_START (1u << 0) +#define ADC_CON_EN_START_MASK (0x3 << 0) #define ADC_DATX_MASK 0xFFF #define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) @@ -100,6 +109,8 @@ struct exynos_adc { struct exynos_adc_data { int num_channels; bool needs_sclk; + bool needs_adc_phy; + u32 mask; void (*init_hw)(struct exynos_adc *info); void (*exit_hw)(struct exynos_adc *info); @@ -171,7 +182,8 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info) { u32 con1; - writel(1, info->enable_reg); + if (info->data->needs_adc_phy) + writel(1, info->enable_reg); /* set default prescaler values and Enable prescaler */ con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; @@ -185,7 +197,8 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info) { u32 con; - writel(0, info->enable_reg); + if (info->data->needs_adc_phy) + writel(0, info->enable_reg); con = readl(ADC_V1_CON(info->regs)); con |= ADC_V1_CON_STANDBY; @@ -210,6 +223,8 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info, static const struct exynos_adc_data exynos_adc_v1_data = { .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + .needs_adc_phy = true, .init_hw = exynos_adc_v1_init_hw, .exit_hw = exynos_adc_v1_exit_hw, @@ -217,11 +232,89 @@ static const struct exynos_adc_data exynos_adc_v1_data = { .start_conv = exynos_adc_v1_start_conv, }; +static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + /* Enable 12 bit ADC resolution */ + con1 = readl(ADC_V1_CON(info->regs)); + con1 |= ADC_S3C2416_CON_RES_SEL; + writel(con1, ADC_V1_CON(info->regs)); + + /* Select channel for S3C2416 */ + writel(addr, ADC_S3C2410_MUX(info->regs)); + + con1 = readl(ADC_V1_CON(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c2416_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c2416_start_conv, +}; + +static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + /* Select channel for S3C2433 */ + writel(addr, ADC_S3C2410_MUX(info->regs)); + + con1 = readl(ADC_V1_CON(info->regs)); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c2443_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c2443_start_conv, +}; + +static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info, + unsigned long addr) +{ + u32 con1; + + con1 = readl(ADC_V1_CON(info->regs)); + con1 &= ~ADC_S3C2410_CON_SELMUX(0x7); + con1 |= ADC_S3C2410_CON_SELMUX(addr); + writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs)); +} + +static struct exynos_adc_data const exynos_adc_s3c24xx_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .start_conv = exynos_adc_s3c64xx_start_conv, +}; + +static struct exynos_adc_data const exynos_adc_s3c64xx_data = { + .num_channels = MAX_ADC_V1_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .clear_irq = exynos_adc_v1_clear_irq, + .start_conv = exynos_adc_s3c64xx_start_conv, +}; + static void exynos_adc_v2_init_hw(struct exynos_adc *info) { u32 con1, con2; - writel(1, info->enable_reg); + if (info->data->needs_adc_phy) + writel(1, info->enable_reg); con1 = ADC_V2_CON1_SOFT_RESET; writel(con1, ADC_V2_CON1(info->regs)); @@ -238,7 +331,8 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info) { u32 con; - writel(0, info->enable_reg); + if (info->data->needs_adc_phy) + writel(0, info->enable_reg); con = readl(ADC_V2_CON1(info->regs)); con &= ~ADC_CON_EN_START; @@ -266,6 +360,8 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info, static const struct exynos_adc_data exynos_adc_v2_data = { .num_channels = MAX_ADC_V2_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + .needs_adc_phy = true, .init_hw = exynos_adc_v2_init_hw, .exit_hw = exynos_adc_v2_exit_hw, @@ -275,7 +371,9 @@ static const struct exynos_adc_data exynos_adc_v2_data = { static const struct exynos_adc_data exynos3250_adc_data = { .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ .needs_sclk = true, + .needs_adc_phy = true, .init_hw = exynos_adc_v2_init_hw, .exit_hw = exynos_adc_v2_exit_hw, @@ -285,6 +383,21 @@ static const struct exynos_adc_data exynos3250_adc_data = { static const struct of_device_id exynos_adc_match[] = { { + .compatible = "samsung,s3c2410-adc", + .data = &exynos_adc_s3c24xx_data, + }, { + .compatible = "samsung,s3c2416-adc", + .data = &exynos_adc_s3c2416_data, + }, { + .compatible = "samsung,s3c2440-adc", + .data = &exynos_adc_s3c24xx_data, + }, { + .compatible = "samsung,s3c2443-adc", + .data = &exynos_adc_s3c2443_data, + }, { + .compatible = "samsung,s3c6410-adc", + .data = &exynos_adc_s3c64xx_data, + }, { .compatible = "samsung,exynos-adc-v1", .data = &exynos_adc_v1_data, }, { @@ -347,9 +460,10 @@ static int exynos_read_raw(struct iio_dev *indio_dev, static irqreturn_t exynos_adc_isr(int irq, void *dev_id) { struct exynos_adc *info = (struct exynos_adc *)dev_id; + u32 mask = info->data->mask; /* Read value */ - info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; + info->value = readl(ADC_V1_DATX(info->regs)) & mask; /* clear irq */ if (info->data->clear_irq) @@ -442,10 +556,13 @@ static int exynos_adc_probe(struct platform_device *pdev) if (IS_ERR(info->regs)) return PTR_ERR(info->regs); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(info->enable_reg)) - return PTR_ERR(info->enable_reg); + + if (info->data->needs_adc_phy) { + mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->enable_reg)) + return PTR_ERR(info->enable_reg); + } irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c new file mode 100644 index 0000000..1fad964 --- /dev/null +++ b/drivers/iio/adc/rockchip_saradc.c @@ -0,0 +1,317 @@ +/* + * Rockchip Successive Approximation Register (SAR) A/D Converter + * Copyright (C) 2014 ROCKCHIP, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/regulator/consumer.h> +#include <linux/iio/iio.h> + +#define SARADC_DATA 0x00 +#define SARADC_DATA_MASK 0x3ff + +#define SARADC_STAS 0x04 +#define SARADC_STAS_BUSY BIT(0) + +#define SARADC_CTRL 0x08 +#define SARADC_CTRL_IRQ_STATUS BIT(6) +#define SARADC_CTRL_IRQ_ENABLE BIT(5) +#define SARADC_CTRL_POWER_CTRL BIT(3) +#define SARADC_CTRL_CHN_MASK 0x7 + +#define SARADC_DLY_PU_SOC 0x0c +#define SARADC_DLY_PU_SOC_MASK 0x3f + +#define SARADC_BITS 10 +#define SARADC_TIMEOUT msecs_to_jiffies(100) + +struct rockchip_saradc { + void __iomem *regs; + struct clk *pclk; + struct clk *clk; + struct completion completion; + struct regulator *vref; + u16 last_val; +}; + +static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct rockchip_saradc *info = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&indio_dev->mlock); + + reinit_completion(&info->completion); + + /* 8 clock periods as delay between power up and start cmd */ + writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); + + /* Select the channel to be used and trigger conversion */ + writel(SARADC_CTRL_POWER_CTRL + | (chan->channel & SARADC_CTRL_CHN_MASK) + | SARADC_CTRL_IRQ_ENABLE, + info->regs + SARADC_CTRL); + + if (!wait_for_completion_timeout(&info->completion, + SARADC_TIMEOUT)) { + writel_relaxed(0, info->regs + SARADC_CTRL); + mutex_unlock(&indio_dev->mlock); + return -ETIMEDOUT; + } + + *val = info->last_val; + mutex_unlock(&indio_dev->mlock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(info->vref); + if (ret < 0) { + dev_err(&indio_dev->dev, "failed to get voltage\n"); + return ret; + } + + *val = ret / 1000; + *val2 = SARADC_BITS; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) +{ + struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id; + + /* Read value */ + info->last_val = readl_relaxed(info->regs + SARADC_DATA); + info->last_val &= SARADC_DATA_MASK; + + /* Clear irq & power down adc */ + writel_relaxed(0, info->regs + SARADC_CTRL); + + complete(&info->completion); + + return IRQ_HANDLED; +} + +static const struct iio_info rockchip_saradc_iio_info = { + .read_raw = rockchip_saradc_read_raw, + .driver_module = THIS_MODULE, +}; + +#define ADC_CHANNEL(_index, _id) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .datasheet_name = _id, \ +} + +static const struct iio_chan_spec rockchip_saradc_iio_channels[] = { + ADC_CHANNEL(0, "adc0"), + ADC_CHANNEL(1, "adc1"), + ADC_CHANNEL(2, "adc2"), +}; + +static int rockchip_saradc_probe(struct platform_device *pdev) +{ + struct rockchip_saradc *info = NULL; + struct device_node *np = pdev->dev.of_node; + struct iio_dev *indio_dev = NULL; + struct resource *mem; + int ret; + int irq; + u32 rate; + + if (!np) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + info = iio_priv(indio_dev); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(info->regs)) + return PTR_ERR(info->regs); + + init_completion(&info->completion); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, + 0, dev_name(&pdev->dev), info); + if (ret < 0) { + dev_err(&pdev->dev, "failed requesting irq %d\n", irq); + return ret; + } + + info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); + if (IS_ERR(info->pclk)) { + dev_err(&pdev->dev, "failed to get pclk\n"); + return PTR_ERR(info->pclk); + } + + info->clk = devm_clk_get(&pdev->dev, "saradc"); + if (IS_ERR(info->clk)) { + dev_err(&pdev->dev, "failed to get adc clock\n"); + return PTR_ERR(info->clk); + } + + info->vref = devm_regulator_get(&pdev->dev, "vref"); + if (IS_ERR(info->vref)) { + dev_err(&pdev->dev, "failed to get regulator, %ld\n", + PTR_ERR(info->vref)); + return PTR_ERR(info->vref); + } + + /* + * Use a default of 1MHz for the converter clock. + * This may become user-configurable in the future. + */ + ret = clk_set_rate(info->clk, 1000000); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); + return ret; + } + + ret = regulator_enable(info->vref); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable vref regulator\n"); + return ret; + } + + ret = clk_prepare_enable(info->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable pclk\n"); + goto err_reg_voltage; + } + + ret = clk_prepare_enable(info->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable converter clock\n"); + goto err_pclk; + } + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->info = &rockchip_saradc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + indio_dev->channels = rockchip_saradc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_clk; + + return 0; + +err_clk: + clk_disable_unprepare(info->clk); +err_pclk: + clk_disable_unprepare(info->pclk); +err_reg_voltage: + regulator_disable(info->vref); + return ret; +} + +static int rockchip_saradc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct rockchip_saradc *info = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->pclk); + regulator_disable(info->vref); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int rockchip_saradc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rockchip_saradc *info = iio_priv(indio_dev); + + clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->pclk); + regulator_disable(info->vref); + + return 0; +} + +static int rockchip_saradc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct rockchip_saradc *info = iio_priv(indio_dev); + int ret; + + ret = regulator_enable(info->vref); + if (ret) + return ret; + + ret = clk_prepare_enable(info->pclk); + if (ret) + return ret; + + ret = clk_prepare_enable(info->clk); + if (ret) + return ret; + + return ret; +} +#endif + +static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, + rockchip_saradc_suspend, rockchip_saradc_resume); + +static const struct of_device_id rockchip_saradc_match[] = { + { .compatible = "rockchip,saradc" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rockchip_saradc_match); + +static struct platform_driver rockchip_saradc_driver = { + .probe = rockchip_saradc_probe, + .remove = rockchip_saradc_remove, + .driver = { + .name = "rockchip-saradc", + .owner = THIS_MODULE, + .of_match_table = rockchip_saradc_match, + .pm = &rockchip_saradc_pm_ops, + }, +}; + +module_platform_driver(rockchip_saradc_driver); diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c new file mode 100644 index 0000000..655cb56 --- /dev/null +++ b/drivers/iio/adc/ti-adc128s052.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2014 Angelo Compagnucci <angelo.compagnucci@gmail.com> + * + * Driver for Texas Instruments' ADC128S052 ADC chip. + * Datasheet can be found here: + * http://www.ti.com/lit/ds/symlink/adc128s052.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/err.h> +#include <linux/spi/spi.h> +#include <linux/module.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +struct adc128 { + struct spi_device *spi; + + struct regulator *reg; + struct mutex lock; + + u8 buffer[2] ____cacheline_aligned; +}; + +static int adc128_adc_conversion(struct adc128 *adc, u8 channel) +{ + int ret; + + mutex_lock(&adc->lock); + + adc->buffer[0] = channel << 3; + adc->buffer[1] = 0; + + ret = spi_write(adc->spi, &adc->buffer, 2); + if (ret < 0) { + mutex_unlock(&adc->lock); + return ret; + } + + ret = spi_read(adc->spi, &adc->buffer, 2); + + mutex_unlock(&adc->lock); + + if (ret < 0) + return ret; + + return ((adc->buffer[0] << 8 | adc->buffer[1]) & 0xFFF); +} + +static int adc128_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *channel, int *val, + int *val2, long mask) +{ + struct adc128 *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + + ret = adc128_adc_conversion(adc, channel->channel); + if (ret < 0) + return ret; + + *val = ret; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + + ret = regulator_get_voltage(adc->reg); + if (ret < 0) + return ret; + + *val = ret / 1000; + *val2 = 12; + return IIO_VAL_FRACTIONAL_LOG2; + + default: + return -EINVAL; + } + +} + +#define ADC128_VOLTAGE_CHANNEL(num) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (num), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + } + +static const struct iio_chan_spec adc128_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), + ADC128_VOLTAGE_CHANNEL(1), + ADC128_VOLTAGE_CHANNEL(2), + ADC128_VOLTAGE_CHANNEL(3), + ADC128_VOLTAGE_CHANNEL(4), + ADC128_VOLTAGE_CHANNEL(5), + ADC128_VOLTAGE_CHANNEL(6), + ADC128_VOLTAGE_CHANNEL(7), +}; + +static const struct iio_info adc128_info = { + .read_raw = adc128_read_raw, + .driver_module = THIS_MODULE, +}; + +static int adc128_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adc128 *adc; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + + spi_set_drvdata(spi, indio_dev); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &adc128_info; + + indio_dev->channels = adc128_channels; + indio_dev->num_channels = ARRAY_SIZE(adc128_channels); + + adc->reg = devm_regulator_get(&spi->dev, "vref"); + if (IS_ERR(adc->reg)) + return PTR_ERR(adc->reg); + + ret = regulator_enable(adc->reg); + if (ret < 0) + return ret; + + mutex_init(&adc->lock); + + ret = iio_device_register(indio_dev); + + return ret; +} + +static int adc128_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adc128 *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(adc->reg); + + return 0; +} + +static const struct spi_device_id adc128_id[] = { + { "adc128s052", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, adc128_id); + +static struct spi_driver adc128_driver = { + .driver = { + .name = "adc128s052", + .owner = THIS_MODULE, + }, + .probe = adc128_probe, + .remove = adc128_remove, + .id_table = adc128_id, +}; +module_spi_driver(adc128_driver); + +MODULE_AUTHOR("Angelo Compagnucci <angelo.compagnucci@gmail.com>"); +MODULE_DESCRIPTION("Texas Instruments ADC128S052"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index fd2745c..5d52a31 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1201,12 +1201,16 @@ static int xadc_probe(struct platform_device *pdev) goto err_device_free; xadc->convst_trigger = xadc_alloc_trigger(indio_dev, "convst"); - if (IS_ERR(xadc->convst_trigger)) + if (IS_ERR(xadc->convst_trigger)) { + ret = PTR_ERR(xadc->convst_trigger); goto err_triggered_buffer_cleanup; + } xadc->samplerate_trigger = xadc_alloc_trigger(indio_dev, "samplerate"); - if (IS_ERR(xadc->samplerate_trigger)) + if (IS_ERR(xadc->samplerate_trigger)) { + ret = PTR_ERR(xadc->samplerate_trigger); goto err_free_convst_trigger; + } } xadc->clk = devm_clk_get(&pdev->dev, NULL); @@ -1322,7 +1326,6 @@ static struct platform_driver xadc_driver = { .remove = xadc_remove, .driver = { .name = "xadc", - .owner = THIS_MODULE, .of_match_table = xadc_of_match_table, }, }; diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index f278eff..2236ea2 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -152,6 +152,14 @@ config MAX517 This driver can also be built as a module. If so, the module will be called max517. +config MAX5821 + tristate "Maxim MAX5821 DAC driver" + depends on I2C + depends on OF + help + Say yes here to build support for Maxim MAX5821 + 10 bits DAC. + config MCP4725 tristate "MCP4725 DAC driver" depends on I2C diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 1010764..52be7e1 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -17,5 +17,6 @@ obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD7303) += ad7303.o obj-$(CONFIG_MAX517) += max517.o +obj-$(CONFIG_MAX5821) += max5821.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4922) += mcp4922.o diff --git a/drivers/iio/dac/max5821.c b/drivers/iio/dac/max5821.c new file mode 100644 index 0000000..6e91449 --- /dev/null +++ b/drivers/iio/dac/max5821.c @@ -0,0 +1,405 @@ + /* + * iio/dac/max5821.c + * Copyright (C) 2014 Philippe Reynes + * + * 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/module.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/regulator/consumer.h> + +#define MAX5821_MAX_DAC_CHANNELS 2 + +/* command bytes */ +#define MAX5821_LOAD_DAC_A_IN_REG_B 0x00 +#define MAX5821_LOAD_DAC_B_IN_REG_A 0x10 +#define MAX5821_EXTENDED_COMMAND_MODE 0xf0 +#define MAX5821_READ_DAC_A_COMMAND 0xf1 +#define MAX5821_READ_DAC_B_COMMAND 0xf2 + +#define MAX5821_EXTENDED_POWER_UP 0x00 +#define MAX5821_EXTENDED_POWER_DOWN_MODE0 0x01 +#define MAX5821_EXTENDED_POWER_DOWN_MODE1 0x02 +#define MAX5821_EXTENDED_POWER_DOWN_MODE2 0x03 +#define MAX5821_EXTENDED_DAC_A 0x04 +#define MAX5821_EXTENDED_DAC_B 0x08 + +enum max5821_device_ids { + ID_MAX5821, +}; + +struct max5821_data { + struct i2c_client *client; + struct regulator *vref_reg; + unsigned short vref_mv; + bool powerdown[MAX5821_MAX_DAC_CHANNELS]; + u8 powerdown_mode[MAX5821_MAX_DAC_CHANNELS]; + struct mutex lock; +}; + +static const char * const max5821_powerdown_modes[] = { + "three_state", + "1kohm_to_gnd", + "100kohm_to_gnd", +}; + +enum { + MAX5821_THREE_STATE, + MAX5821_1KOHM_TO_GND, + MAX5821_100KOHM_TO_GND +}; + +static int max5821_get_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct max5821_data *st = iio_priv(indio_dev); + + return st->powerdown_mode[chan->channel]; +} + +static int max5821_set_powerdown_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct max5821_data *st = iio_priv(indio_dev); + + st->powerdown_mode[chan->channel] = mode; + + return 0; +} + +static const struct iio_enum max5821_powerdown_mode_enum = { + .items = max5821_powerdown_modes, + .num_items = ARRAY_SIZE(max5821_powerdown_modes), + .get = max5821_get_powerdown_mode, + .set = max5821_set_powerdown_mode, +}; + +static ssize_t max5821_read_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + char *buf) +{ + struct max5821_data *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", st->powerdown[chan->channel]); +} + +static int max5821_sync_powerdown_mode(struct max5821_data *data, + const struct iio_chan_spec *chan) +{ + u8 outbuf[2]; + + outbuf[0] = MAX5821_EXTENDED_COMMAND_MODE; + + if (chan->channel == 0) + outbuf[1] = MAX5821_EXTENDED_DAC_A; + else + outbuf[1] = MAX5821_EXTENDED_DAC_B; + + if (data->powerdown[chan->channel]) + outbuf[1] |= data->powerdown_mode[chan->channel] + 1; + else + outbuf[1] |= MAX5821_EXTENDED_POWER_UP; + + return i2c_master_send(data->client, outbuf, 2); +} + +static ssize_t max5821_write_dac_powerdown(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct max5821_data *data = iio_priv(indio_dev); + bool powerdown; + int ret; + + ret = strtobool(buf, &powerdown); + if (ret) + return ret; + + data->powerdown[chan->channel] = powerdown; + + ret = max5821_sync_powerdown_mode(data, chan); + if (ret < 0) + return ret; + + return len; +} + +static const struct iio_chan_spec_ext_info max5821_ext_info[] = { + { + .name = "powerdown", + .read = max5821_read_dac_powerdown, + .write = max5821_write_dac_powerdown, + .shared = IIO_SEPARATE, + }, + IIO_ENUM("powerdown_mode", IIO_SEPARATE, &max5821_powerdown_mode_enum), + IIO_ENUM_AVAILABLE("powerdown_mode", &max5821_powerdown_mode_enum), + { }, +}; + +#define MAX5821_CHANNEL(chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (chan), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE), \ + .ext_info = max5821_ext_info, \ +} + +static const struct iio_chan_spec max5821_channels[] = { + MAX5821_CHANNEL(0), + MAX5821_CHANNEL(1) +}; + +static const u8 max5821_read_dac_command[] = { + MAX5821_READ_DAC_A_COMMAND, + MAX5821_READ_DAC_B_COMMAND +}; + +static const u8 max5821_load_dac_command[] = { + MAX5821_LOAD_DAC_A_IN_REG_B, + MAX5821_LOAD_DAC_B_IN_REG_A +}; + +static int max5821_get_value(struct iio_dev *indio_dev, + int *val, int channel) +{ + struct max5821_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + u8 outbuf[1]; + u8 inbuf[2]; + int ret; + + if ((channel != 0) && (channel != 1)) + return -EINVAL; + + outbuf[0] = max5821_read_dac_command[channel]; + + mutex_lock(&data->lock); + + ret = i2c_master_send(client, outbuf, 1); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret != 1) { + mutex_unlock(&data->lock); + return -EIO; + } + + ret = i2c_master_recv(client, inbuf, 2); + if (ret < 0) { + mutex_unlock(&data->lock); + return ret; + } else if (ret != 2) { + mutex_unlock(&data->lock); + return -EIO; + } + + mutex_unlock(&data->lock); + + *val = ((inbuf[0] & 0x0f) << 6) | (inbuf[1] >> 2); + + return IIO_VAL_INT; +} + +static int max5821_set_value(struct iio_dev *indio_dev, + int val, int channel) +{ + struct max5821_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + u8 outbuf[2]; + int ret; + + if ((val < 0) || (val > 1023)) + return -EINVAL; + + if ((channel != 0) && (channel != 1)) + return -EINVAL; + + outbuf[0] = max5821_load_dac_command[channel]; + outbuf[0] |= val >> 6; + outbuf[1] = (val & 0x3f) << 2; + + ret = i2c_master_send(client, outbuf, 2); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + else + return 0; +} + +static int max5821_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct max5821_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return max5821_get_value(indio_dev, val, chan->channel); + case IIO_CHAN_INFO_SCALE: + *val = data->vref_mv; + *val2 = 10; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static int max5821_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + if (val2 != 0) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return max5821_set_value(indio_dev, val, chan->channel); + default: + return -EINVAL; + } +} + +#ifdef CONFIG_PM_SLEEP +static int max5821_suspend(struct device *dev) +{ + u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE, + MAX5821_EXTENDED_DAC_A | + MAX5821_EXTENDED_DAC_B | + MAX5821_EXTENDED_POWER_DOWN_MODE2 }; + + return i2c_master_send(to_i2c_client(dev), outbuf, 2); +} + +static int max5821_resume(struct device *dev) +{ + u8 outbuf[2] = { MAX5821_EXTENDED_COMMAND_MODE, + MAX5821_EXTENDED_DAC_A | + MAX5821_EXTENDED_DAC_B | + MAX5821_EXTENDED_POWER_UP }; + + return i2c_master_send(to_i2c_client(dev), outbuf, 2); +} + +static SIMPLE_DEV_PM_OPS(max5821_pm_ops, max5821_suspend, max5821_resume); +#define MAX5821_PM_OPS (&max5821_pm_ops) +#else +#define MAX5821_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static const struct iio_info max5821_info = { + .read_raw = max5821_read_raw, + .write_raw = max5821_write_raw, + .driver_module = THIS_MODULE, +}; + +static int max5821_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct max5821_data *data; + struct iio_dev *indio_dev; + u32 tmp; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + mutex_init(&data->lock); + + /* max5821 start in powerdown mode 100Kohm to ground */ + for (tmp = 0; tmp < MAX5821_MAX_DAC_CHANNELS; tmp++) { + data->powerdown[tmp] = true; + data->powerdown_mode[tmp] = MAX5821_100KOHM_TO_GND; + } + + data->vref_reg = devm_regulator_get(&client->dev, "vref"); + if (IS_ERR(data->vref_reg)) { + ret = PTR_ERR(data->vref_reg); + dev_err(&client->dev, + "Failed to get vref regulator: %d\n", ret); + goto error_free_reg; + } + + ret = regulator_enable(data->vref_reg); + if (ret) { + dev_err(&client->dev, + "Failed to enable vref regulator: %d\n", ret); + goto error_free_reg; + } + + ret = regulator_get_voltage(data->vref_reg); + if (ret < 0) { + dev_err(&client->dev, + "Failed to get voltage on regulator: %d\n", ret); + goto error_disable_reg; + } + + data->vref_mv = ret / 1000; + + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->num_channels = ARRAY_SIZE(max5821_channels); + indio_dev->channels = max5821_channels; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &max5821_info; + + return iio_device_register(indio_dev); + +error_disable_reg: + regulator_disable(data->vref_reg); + +error_free_reg: + + return ret; +} + +static int max5821_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct max5821_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + regulator_disable(data->vref_reg); + + return 0; +} + +static const struct i2c_device_id max5821_id[] = { + { "max5821", ID_MAX5821 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max5821_id); + +static const struct of_device_id max5821_of_match[] = { + { .compatible = "maxim,max5821" }, + { } +}; + +static struct i2c_driver max5821_driver = { + .driver = { + .name = "max5821", + .pm = MAX5821_PM_OPS, + .owner = THIS_MODULE, + }, + .probe = max5821_probe, + .remove = max5821_remove, + .id_table = max5821_id, +}; +module_i2c_driver(max5821_driver); + +MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>"); +MODULE_DESCRIPTION("MAX5821 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 0472ee2..f971f79 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -942,13 +942,34 @@ int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data) } EXPORT_SYMBOL_GPL(iio_push_to_buffers); +static int iio_buffer_add_demux(struct iio_buffer *buffer, + struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc, + unsigned int length) +{ + + if (*p && (*p)->from + (*p)->length == in_loc && + (*p)->to + (*p)->length == out_loc) { + (*p)->length += length; + } else { + *p = kmalloc(sizeof(**p), GFP_KERNEL); + if (*p == NULL) + return -ENOMEM; + (*p)->from = in_loc; + (*p)->to = out_loc; + (*p)->length = length; + list_add_tail(&(*p)->l, &buffer->demux_list); + } + + return 0; +} + static int iio_buffer_update_demux(struct iio_dev *indio_dev, struct iio_buffer *buffer) { const struct iio_chan_spec *ch; int ret, in_ind = -1, out_ind, length; unsigned in_loc = 0, out_loc = 0; - struct iio_demux_table *p; + struct iio_demux_table *p = NULL; /* Clear out any old demux */ iio_buffer_demux_free(buffer); @@ -979,14 +1000,7 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, else length = ch->scan_type.storagebits / 8; /* Make sure we are aligned */ - in_loc += length; - if (in_loc % length) - in_loc += length - in_loc % length; - } - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - ret = -ENOMEM; - goto error_clear_mux_table; + in_loc = roundup(in_loc, length) + length; } ch = iio_find_channel_from_si(indio_dev, in_ind); if (ch->scan_type.repeat > 1) @@ -994,24 +1008,16 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ch->scan_type.repeat; else length = ch->scan_type.storagebits / 8; - if (out_loc % length) - out_loc += length - out_loc % length; - if (in_loc % length) - in_loc += length - in_loc % length; - p->from = in_loc; - p->to = out_loc; - p->length = length; - list_add_tail(&p->l, &buffer->demux_list); + out_loc = roundup(out_loc, length); + in_loc = roundup(in_loc, length); + ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); + if (ret) + goto error_clear_mux_table; out_loc += length; in_loc += length; } /* Relies on scan_timestamp being last */ if (buffer->scan_timestamp) { - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (p == NULL) { - ret = -ENOMEM; - goto error_clear_mux_table; - } ch = iio_find_channel_from_si(indio_dev, indio_dev->scan_index_timestamp); if (ch->scan_type.repeat > 1) @@ -1019,14 +1025,11 @@ static int iio_buffer_update_demux(struct iio_dev *indio_dev, ch->scan_type.repeat; else length = ch->scan_type.storagebits / 8; - if (out_loc % length) - out_loc += length - out_loc % length; - if (in_loc % length) - in_loc += length - in_loc % length; - p->from = in_loc; - p->to = out_loc; - p->length = length; - list_add_tail(&p->l, &buffer->demux_list); + out_loc = roundup(out_loc, length); + in_loc = roundup(in_loc, length); + ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length); + if (ret) + goto error_clear_mux_table; out_loc += length; in_loc += length; } diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 3ec777a..1e717c7 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -246,8 +246,7 @@ static const struct iio_info magn_3d_info = { }; /* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); iio_push_to_buffers(indio_dev, data); @@ -263,9 +262,7 @@ static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); if (atomic_read(&magn_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - magn_state->iio_vals, - sizeof(magn_state->iio_vals)); + hid_sensor_push_data(indio_dev, magn_state->iio_vals); return 0; } diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c index 50ba1fa..7eae5fd 100644 --- a/drivers/staging/iio/accel/adis16201_core.c +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -111,6 +111,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, int bits; s16 val16; u8 addr; + switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { @@ -131,8 +132,8 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, } static const struct iio_chan_spec adis16201_channels[] = { - ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12), - ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12), + ADIS_SUPPLY_CHAN(ADIS16201_SUPPLY_OUT, ADIS16201_SCAN_SUPPLY, 0, 12), + ADIS_TEMP_CHAN(ADIS16201_TEMP_OUT, ADIS16201_SCAN_TEMP, 0, 12), ADIS_ACCEL_CHAN(X, ADIS16201_XACCL_OUT, ADIS16201_SCAN_ACC_X, BIT(IIO_CHAN_INFO_CALIBBIAS), 0, 14), ADIS_ACCEL_CHAN(Y, ADIS16201_YACCL_OUT, ADIS16201_SCAN_ACC_Y, diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c index f472137..fbbe93f 100644 --- a/drivers/staging/iio/accel/adis16203_core.c +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -37,6 +37,7 @@ static int adis16203_write_raw(struct iio_dev *indio_dev, struct adis *st = iio_priv(indio_dev); /* currently only one writable parameter which keeps this simple */ u8 addr = adis16203_addresses[chan->scan_index]; + return adis_write_reg_16(st, addr, val & 0x3FFF); } @@ -50,6 +51,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, int bits; u8 addr; s16 val16; + switch (mask) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c index 19eaebc..4c8acbc 100644 --- a/drivers/staging/iio/accel/adis16204_core.c +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -119,6 +119,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, int bits; s16 val16; u8 addr; + switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index 374dc6e..b2c7aed 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -44,6 +44,7 @@ static int adis16209_write_raw(struct iio_dev *indio_dev, int bits; s16 val16; u8 addr; + switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: switch (chan->type) { diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index 74ace2a..205d6d0 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -163,6 +163,7 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, int bits = 10; s16 val16; u8 addr; + switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: val16 = val & ((1 << bits) - 1); diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 898653c..f5e145c 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -212,6 +212,7 @@ static int lis3l02dq_write_thresh(struct iio_dev *indio_dev, int val, int val2) { u16 value = val; + return lis3l02dq_spi_write_reg_s16(indio_dev, LIS3L02DQ_REG_THS_L_ADDR, value); @@ -226,6 +227,7 @@ static int lis3l02dq_write_raw(struct iio_dev *indio_dev, int ret = -EINVAL, reg; u8 uval; s8 sval; + switch (mask) { case IIO_CHAN_INFO_CALIBBIAS: if (val > 255 || val < -256) @@ -302,6 +304,7 @@ static ssize_t lis3l02dq_read_frequency(struct device *dev, struct iio_dev *indio_dev = dev_to_iio_dev(dev); int ret, len = 0; s8 t; + ret = lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_CTRL_1_ADDR, (u8 *)&t); @@ -565,6 +568,7 @@ static int lis3l02dq_read_event_config(struct iio_dev *indio_dev, u8 val; int ret; u8 mask = (1 << (chan->channel2*2 + (dir == IIO_EV_DIR_RISING))); + ret = lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_WAKE_UP_CFG_ADDR, &val); diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index bf33fde..1d934ee 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -19,6 +19,7 @@ static inline u16 combine_8_to_16(u8 lower, u8 upper) { u16 _lower = lower; u16 _upper = upper; + return _lower | (_upper << 8); } diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index ed30e32..e4e5639 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -506,7 +506,8 @@ static int sca3000_read_raw(struct iio_dev *indio_dev, mutex_unlock(&st->lock); return ret; } - *val = ((st->rx[0] & 0x3F) << 3) | ((st->rx[1] & 0xE0) >> 5); + *val = ((st->rx[0] & 0x3F) << 3) | + ((st->rx[1] & 0xE0) >> 5); } mutex_unlock(&st->lock); return IIO_VAL_INT; @@ -713,6 +714,7 @@ static int sca3000_read_thresh(struct iio_dev *indio_dev, int ret, i; struct sca3000_state *st = iio_priv(indio_dev); int num = chan->channel2; + mutex_lock(&st->lock); ret = sca3000_read_ctrl_reg(st, sca3000_addresses[num][1]); mutex_unlock(&st->lock); diff --git a/drivers/staging/iio/frequency/Kconfig b/drivers/staging/iio/frequency/Kconfig index 93b7141..fc726d3 100644 --- a/drivers/staging/iio/frequency/Kconfig +++ b/drivers/staging/iio/frequency/Kconfig @@ -3,13 +3,6 @@ # menu "Direct Digital Synthesis" -config AD5930 - tristate "Analog Devices ad5930/5932 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - ad5930/ad5932, provides direct access via sysfs. - config AD9832 tristate "Analog Devices ad9832/5 driver" depends on SPI @@ -30,32 +23,4 @@ config AD9834 To compile this driver as a module, choose M here: the module will be called ad9834. -config AD9850 - tristate "Analog Devices ad9850/1 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - ad9850/1, provides direct access via sysfs. - -config AD9852 - tristate "Analog Devices ad9852/4 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - ad9852/4, provides direct access via sysfs. - -config AD9910 - tristate "Analog Devices ad9910 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - ad9910, provides direct access via sysfs. - -config AD9951 - tristate "Analog Devices ad9951 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - ad9951, provides direct access via sysfs. - endmenu diff --git a/drivers/staging/iio/frequency/Makefile b/drivers/staging/iio/frequency/Makefile index 1477461..e5dbcfc 100644 --- a/drivers/staging/iio/frequency/Makefile +++ b/drivers/staging/iio/frequency/Makefile @@ -2,10 +2,5 @@ # Makefile for Direct Digital Synthesis drivers # -obj-$(CONFIG_AD5930) += ad5930.o obj-$(CONFIG_AD9832) += ad9832.o obj-$(CONFIG_AD9834) += ad9834.o -obj-$(CONFIG_AD9850) += ad9850.o -obj-$(CONFIG_AD9852) += ad9852.o -obj-$(CONFIG_AD9910) += ad9910.o -obj-$(CONFIG_AD9951) += ad9951.o diff --git a/drivers/staging/iio/frequency/ad5930.c b/drivers/staging/iio/frequency/ad5930.c deleted file mode 100644 index a4aeee6..0000000 --- a/drivers/staging/iio/frequency/ad5930.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Driver for ADI Direct Digital Synthesis ad5930 - * - * Copyright (c) 2010-2010 Analog Devices Inc. - * - * 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/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define DRV_NAME "ad5930" - -#define value_mask (u16)0xf000 -#define addr_shift 12 - -/* Register format: 4 bits addr + 12 bits value */ -struct ad5903_config { - u16 control; - u16 incnum; - u16 frqdelt[2]; - u16 incitvl; - u16 buritvl; - u16 strtfrq[2]; -}; - -struct ad5930_state { - struct mutex lock; - struct spi_device *sdev; -}; - -static ssize_t ad5930_set_parameter(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct spi_transfer xfer; - int ret; - struct ad5903_config *config = (struct ad5903_config *)buf; - struct iio_dev *idev = dev_to_iio_dev(dev); - struct ad5930_state *st = iio_priv(idev); - - config->control = (config->control & ~value_mask); - config->incnum = (config->control & ~value_mask) | (1 << addr_shift); - config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift); - config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift; - config->incitvl = (config->control & ~value_mask) | 4 << addr_shift; - config->buritvl = (config->control & ~value_mask) | 8 << addr_shift; - config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift; - config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift; - - xfer.len = len; - xfer.tx_buf = config; - mutex_lock(&st->lock); - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0); - -static struct attribute *ad5930_attributes[] = { - &iio_dev_attr_dds.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad5930_attribute_group = { - .attrs = ad5930_attributes, -}; - -static const struct iio_info ad5930_info = { - .attrs = &ad5930_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int ad5930_probe(struct spi_device *spi) -{ - struct ad5930_state *st; - struct iio_dev *idev; - int ret = 0; - - idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!idev) - return -ENOMEM; - spi_set_drvdata(spi, idev); - st = iio_priv(idev); - - mutex_init(&st->lock); - st->sdev = spi; - idev->dev.parent = &spi->dev; - idev->info = &ad5930_info; - idev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(idev); - if (ret) - return ret; - spi->max_speed_hz = 2000000; - spi->mode = SPI_MODE_3; - spi->bits_per_word = 16; - spi_setup(spi); - - return 0; -} - -static int ad5930_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver ad5930_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = ad5930_probe, - .remove = ad5930_remove, -}; -module_spi_driver(ad5930_driver); - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION("Analog Devices ad5930 driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9850.c b/drivers/staging/iio/frequency/ad9850.c deleted file mode 100644 index 8727933..0000000 --- a/drivers/staging/iio/frequency/ad9850.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Driver for ADI Direct Digital Synthesis ad9850 - * - * Copyright (c) 2010-2010 Analog Devices Inc. - * - * 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/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define DRV_NAME "ad9850" - -/* Register format: 4 bits addr + 12 bits value */ -struct ad9850_config { - u8 control[5]; -}; - -struct ad9850_state { - struct mutex lock; - struct spi_device *sdev; -}; - -static ssize_t ad9850_set_parameter(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct spi_transfer xfer; - int ret; - struct ad9850_config *config = (struct ad9850_config *)buf; - struct iio_dev *idev = dev_to_iio_dev(dev); - struct ad9850_state *st = iio_priv(idev); - - xfer.len = len; - xfer.tx_buf = config; - mutex_lock(&st->lock); - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0); - -static struct attribute *ad9850_attributes[] = { - &iio_dev_attr_dds.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad9850_attribute_group = { - .attrs = ad9850_attributes, -}; - -static const struct iio_info ad9850_info = { - .attrs = &ad9850_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int ad9850_probe(struct spi_device *spi) -{ - struct ad9850_state *st; - struct iio_dev *idev; - int ret = 0; - - idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!idev) - return -ENOMEM; - spi_set_drvdata(spi, idev); - st = iio_priv(idev); - mutex_init(&st->lock); - st->sdev = spi; - - idev->dev.parent = &spi->dev; - idev->info = &ad9850_info; - idev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(idev); - if (ret) - return ret; - spi->max_speed_hz = 2000000; - spi->mode = SPI_MODE_3; - spi->bits_per_word = 16; - spi_setup(spi); - - return 0; -} - -static int ad9850_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver ad9850_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = ad9850_probe, - .remove = ad9850_remove, -}; -module_spi_driver(ad9850_driver); - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION("Analog Devices ad9850 driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9852.c b/drivers/staging/iio/frequency/ad9852.c deleted file mode 100644 index 11e4367..0000000 --- a/drivers/staging/iio/frequency/ad9852.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Driver for ADI Direct Digital Synthesis ad9852 - * - * Copyright (c) 2010 Analog Devices Inc. - * - * 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/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define DRV_NAME "ad9852" - -#define addr_phaad1 0x0 -#define addr_phaad2 0x1 -#define addr_fretu1 0x2 -#define addr_fretu2 0x3 -#define addr_delfre 0x4 -#define addr_updclk 0x5 -#define addr_ramclk 0x6 -#define addr_contrl 0x7 -#define addr_optskm 0x8 -#define addr_optskr 0xa -#define addr_dacctl 0xb - -#define COMPPD (1 << 4) -#define REFMULT2 (1 << 2) -#define BYPPLL (1 << 5) -#define PLLRANG (1 << 6) -#define IEUPCLK (1) -#define OSKEN (1 << 5) - -#define read_bit (1 << 7) - -/* Register format: 1 byte addr + value */ -struct ad9852_config { - u8 phajst0[3]; - u8 phajst1[3]; - u8 fretun1[6]; - u8 fretun2[6]; - u8 dltafre[6]; - u8 updtclk[5]; - u8 ramprat[4]; - u8 control[5]; - u8 outpskm[3]; - u8 outpskr[2]; - u8 daccntl[3]; -}; - -struct ad9852_state { - struct mutex lock; - struct spi_device *sdev; -}; - -static ssize_t ad9852_set_parameter(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct spi_transfer xfer; - int ret; - struct ad9852_config *config = (struct ad9852_config *)buf; - struct iio_dev *idev = dev_to_iio_dev(dev); - struct ad9852_state *st = iio_priv(idev); - - xfer.len = 3; - xfer.tx_buf = &config->phajst0[0]; - mutex_lock(&st->lock); - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 3; - xfer.tx_buf = &config->phajst1[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 6; - xfer.tx_buf = &config->fretun1[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 6; - xfer.tx_buf = &config->fretun2[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 6; - xfer.tx_buf = &config->dltafre[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->updtclk[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 4; - xfer.tx_buf = &config->ramprat[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->control[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 3; - xfer.tx_buf = &config->outpskm[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 2; - xfer.tx_buf = &config->outpskr[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 3; - xfer.tx_buf = &config->daccntl[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); - -static void ad9852_init(struct ad9852_state *st) -{ - struct spi_transfer xfer; - int ret; - u8 config[5]; - - config[0] = addr_contrl; - config[1] = COMPPD; - config[2] = REFMULT2 | BYPPLL | PLLRANG; - config[3] = IEUPCLK; - config[4] = OSKEN; - - mutex_lock(&st->lock); - - xfer.len = 5; - xfer.tx_buf = &config; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - -error_ret: - mutex_unlock(&st->lock); - - - -} - -static struct attribute *ad9852_attributes[] = { - &iio_dev_attr_dds.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad9852_attribute_group = { - .attrs = ad9852_attributes, -}; - -static const struct iio_info ad9852_info = { - .attrs = &ad9852_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int ad9852_probe(struct spi_device *spi) -{ - struct ad9852_state *st; - struct iio_dev *idev; - int ret = 0; - - idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!idev) - return -ENOMEM; - st = iio_priv(idev); - spi_set_drvdata(spi, idev); - mutex_init(&st->lock); - st->sdev = spi; - - idev->dev.parent = &spi->dev; - idev->info = &ad9852_info; - idev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(idev); - if (ret) - return ret; - spi->max_speed_hz = 2000000; - spi->mode = SPI_MODE_3; - spi->bits_per_word = 8; - spi_setup(spi); - ad9852_init(st); - - return 0; -} - -static int ad9852_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver ad9852_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = ad9852_probe, - .remove = ad9852_remove, -}; -module_spi_driver(ad9852_driver); - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION("Analog Devices ad9852 driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9910.c b/drivers/staging/iio/frequency/ad9910.c deleted file mode 100644 index 755e048..0000000 --- a/drivers/staging/iio/frequency/ad9910.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Driver for ADI Direct Digital Synthesis ad9910 - * - * Copyright (c) 2010 Analog Devices Inc. - * - * 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/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define DRV_NAME "ad9910" - -#define CFR1 0x0 -#define CFR2 0x1 -#define CFR3 0x2 - -#define AUXDAC 0x3 -#define IOUPD 0x4 -#define FTW 0x7 -#define POW 0x8 -#define ASF 0x9 -#define MULTC 0x0A -#define DIG_RAMPL 0x0B -#define DIG_RAMPS 0x0C -#define DIG_RAMPR 0x0D -#define SIN_TONEP0 0x0E -#define SIN_TONEP1 0x0F -#define SIN_TONEP2 0x10 -#define SIN_TONEP3 0x11 -#define SIN_TONEP4 0x12 -#define SIN_TONEP5 0x13 -#define SIN_TONEP6 0x14 -#define SIN_TONEP7 0x15 - -#define RAM_ENABLE (1 << 7) - -#define MANUAL_OSK (1 << 7) -#define INVSIC (1 << 6) -#define DDS_SINEOP (1) - -#define AUTO_OSK (1) -#define OSKEN (1 << 1) -#define LOAD_ARR (1 << 2) -#define CLR_PHA (1 << 3) -#define CLR_DIG (1 << 4) -#define ACLR_PHA (1 << 5) -#define ACLR_DIG (1 << 6) -#define LOAD_LRR (1 << 7) - -#define LSB_FST (1) -#define SDIO_IPT (1 << 1) -#define EXT_PWD (1 << 3) -#define ADAC_PWD (1 << 4) -#define REFCLK_PWD (1 << 5) -#define DAC_PWD (1 << 6) -#define DIG_PWD (1 << 7) - -#define ENA_AMP (1) -#define READ_FTW (1) -#define DIGR_LOW (1 << 1) -#define DIGR_HIGH (1 << 2) -#define DIGR_ENA (1 << 3) -#define SYNCCLK_ENA (1 << 6) -#define ITER_IOUPD (1 << 7) - -#define TX_ENA (1 << 1) -#define PDCLK_INV (1 << 2) -#define PDCLK_ENB (1 << 3) - -#define PARA_ENA (1 << 4) -#define SYNC_DIS (1 << 5) -#define DATA_ASS (1 << 6) -#define MATCH_ENA (1 << 7) - -#define PLL_ENA (1) -#define PFD_RST (1 << 2) -#define REFCLK_RST (1 << 6) -#define REFCLK_BYP (1 << 7) - -/* Register format: 1 byte addr + value */ -struct ad9910_config { - u8 auxdac[5]; - u8 ioupd[5]; - u8 ftw[5]; - u8 pow[3]; - u8 asf[5]; - u8 multc[5]; - u8 dig_rampl[9]; - u8 dig_ramps[9]; - u8 dig_rampr[5]; - u8 sin_tonep0[9]; - u8 sin_tonep1[9]; - u8 sin_tonep2[9]; - u8 sin_tonep3[9]; - u8 sin_tonep4[9]; - u8 sin_tonep5[9]; - u8 sin_tonep6[9]; - u8 sin_tonep7[9]; -}; - -struct ad9910_state { - struct mutex lock; - struct spi_device *sdev; -}; - -static ssize_t ad9910_set_parameter(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct spi_transfer xfer; - int ret; - struct ad9910_config *config = (struct ad9910_config *)buf; - struct iio_dev *idev = dev_to_iio_dev(dev); - struct ad9910_state *st = iio_priv(idev); - - xfer.len = 5; - xfer.tx_buf = &config->auxdac[0]; - mutex_lock(&st->lock); - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->ioupd[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->ftw[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 3; - xfer.tx_buf = &config->pow[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->asf[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->multc[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->dig_rampl[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->dig_ramps[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->dig_rampr[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep0[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep1[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep2[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep3[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep4[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep5[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep6[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 9; - xfer.tx_buf = &config->sin_tonep7[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0); - -static void ad9910_init(struct ad9910_state *st) -{ - struct spi_transfer xfer; - int ret; - u8 cfr[5]; - - cfr[0] = CFR1; - cfr[1] = 0; - cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP; - cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR; - cfr[4] = 0; - - mutex_lock(&st->lock); - - xfer.len = 5; - xfer.tx_buf = 𝔠 - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - cfr[0] = CFR2; - cfr[1] = ENA_AMP; - cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD; - cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB; - cfr[4] = PARA_ENA; - - xfer.len = 5; - xfer.tx_buf = 𝔠 - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - cfr[0] = CFR3; - cfr[1] = PLL_ENA; - cfr[2] = 0; - cfr[3] = REFCLK_RST | REFCLK_BYP; - cfr[4] = 0; - - xfer.len = 5; - xfer.tx_buf = 𝔠 - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - -error_ret: - mutex_unlock(&st->lock); - - - -} - -static struct attribute *ad9910_attributes[] = { - &iio_dev_attr_dds.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad9910_attribute_group = { - .attrs = ad9910_attributes, -}; - -static const struct iio_info ad9910_info = { - .attrs = &ad9910_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int ad9910_probe(struct spi_device *spi) -{ - struct ad9910_state *st; - struct iio_dev *idev; - int ret = 0; - - idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!idev) - return -ENOMEM; - spi_set_drvdata(spi, idev); - st = iio_priv(idev); - mutex_init(&st->lock); - st->sdev = spi; - - idev->dev.parent = &spi->dev; - idev->info = &ad9910_info; - idev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(idev); - if (ret) - return ret; - spi->max_speed_hz = 2000000; - spi->mode = SPI_MODE_3; - spi->bits_per_word = 8; - spi_setup(spi); - ad9910_init(st); - return 0; -} - -static int ad9910_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver ad9910_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = ad9910_probe, - .remove = ad9910_remove, -}; -module_spi_driver(ad9910_driver); - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION("Analog Devices ad9910 driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/frequency/ad9951.c b/drivers/staging/iio/frequency/ad9951.c deleted file mode 100644 index 5e8990a..0000000 --- a/drivers/staging/iio/frequency/ad9951.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Driver for ADI Direct Digital Synthesis ad9951 - * - * Copyright (c) 2010 Analog Devices Inc. - * - * 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/types.h> -#include <linux/mutex.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/slab.h> -#include <linux/sysfs.h> -#include <linux/module.h> - -#include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> - -#define DRV_NAME "ad9951" - -#define CFR1 0x0 -#define CFR2 0x1 - -#define AUTO_OSK (1) -#define OSKEN (1 << 1) -#define LOAD_ARR (1 << 2) - -#define AUTO_SYNC (1 << 7) - -#define LSB_FST (1) -#define SDIO_IPT (1 << 1) -#define CLR_PHA (1 << 2) -#define SINE_OPT (1 << 4) -#define ACLR_PHA (1 << 5) - -#define VCO_RANGE (1 << 2) - -#define CRS_OPT (1 << 1) -#define HMANU_SYNC (1 << 2) -#define HSPD_SYNC (1 << 3) - -/* Register format: 1 byte addr + value */ -struct ad9951_config { - u8 asf[3]; - u8 arr[2]; - u8 ftw0[5]; - u8 ftw1[3]; -}; - -struct ad9951_state { - struct mutex lock; - struct spi_device *sdev; -}; - -static ssize_t ad9951_set_parameter(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t len) -{ - struct spi_transfer xfer; - int ret; - struct ad9951_config *config = (struct ad9951_config *)buf; - struct iio_dev *idev = dev_to_iio_dev(dev); - struct ad9951_state *st = iio_priv(idev); - - xfer.len = 3; - xfer.tx_buf = &config->asf[0]; - mutex_lock(&st->lock); - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 2; - xfer.tx_buf = &config->arr[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 5; - xfer.tx_buf = &config->ftw0[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - xfer.len = 3; - xfer.tx_buf = &config->ftw1[0]; - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; -error_ret: - mutex_unlock(&st->lock); - - return ret ? ret : len; -} - -static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0); - -static void ad9951_init(struct ad9951_state *st) -{ - struct spi_transfer xfer; - int ret; - u8 cfr[5]; - - cfr[0] = CFR1; - cfr[1] = 0; - cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA; - cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR; - cfr[4] = 0; - - mutex_lock(&st->lock); - - xfer.len = 5; - xfer.tx_buf = 𝔠 - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - - cfr[0] = CFR2; - cfr[1] = VCO_RANGE; - cfr[2] = HSPD_SYNC; - cfr[3] = 0; - - xfer.len = 4; - xfer.tx_buf = 𝔠 - - ret = spi_sync_transfer(st->sdev, &xfer, 1); - if (ret) - goto error_ret; - -error_ret: - mutex_unlock(&st->lock); - - - -} - -static struct attribute *ad9951_attributes[] = { - &iio_dev_attr_dds.dev_attr.attr, - NULL, -}; - -static const struct attribute_group ad9951_attribute_group = { - .attrs = ad9951_attributes, -}; - -static const struct iio_info ad9951_info = { - .attrs = &ad9951_attribute_group, - .driver_module = THIS_MODULE, -}; - -static int ad9951_probe(struct spi_device *spi) -{ - struct ad9951_state *st; - struct iio_dev *idev; - int ret = 0; - - idev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); - if (!idev) - return -ENOMEM; - spi_set_drvdata(spi, idev); - st = iio_priv(idev); - mutex_init(&st->lock); - st->sdev = spi; - - idev->dev.parent = &spi->dev; - - idev->info = &ad9951_info; - idev->modes = INDIO_DIRECT_MODE; - - ret = iio_device_register(idev); - if (ret) - return ret; - spi->max_speed_hz = 2000000; - spi->mode = SPI_MODE_3; - spi->bits_per_word = 8; - spi_setup(spi); - ad9951_init(st); - return 0; -} - -static int ad9951_remove(struct spi_device *spi) -{ - iio_device_unregister(spi_get_drvdata(spi)); - - return 0; -} - -static struct spi_driver ad9951_driver = { - .driver = { - .name = DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = ad9951_probe, - .remove = ad9951_remove, -}; -module_spi_driver(ad9951_driver); - -MODULE_AUTHOR("Cliff Cai"); -MODULE_DESCRIPTION("Analog Devices ad9951 driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("spi:" DRV_NAME); diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index d5d395c..4c5869d 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -180,6 +180,7 @@ static int adis16060_w_probe(struct spi_device *spi) int ret; struct iio_dev *indio_dev = adis16060_iio_dev; struct adis16060_state *st; + if (!indio_dev) { ret = -ENODEV; goto error_ret; diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 2b96665..2cef4b9 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -220,7 +220,7 @@ static int ad5933_set_freq(struct ad5933_state *st, { unsigned long long freqreg; union { - u32 d32; + __be32 d32; u8 d8[4]; } dat; @@ -244,7 +244,7 @@ static int ad5933_set_freq(struct ad5933_state *st, static int ad5933_setup(struct ad5933_state *st) { - unsigned short dat; + __be16 dat; int ret; ret = ad5933_reset(st); @@ -297,7 +297,7 @@ static ssize_t ad5933_show_frequency(struct device *dev, int ret; unsigned long long freqreg; union { - u32 d32; + __be32 d32; u8 d8[4]; } dat; @@ -402,7 +402,7 @@ static ssize_t ad5933_store(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); u16 val; int i, ret = 0; - unsigned short dat; + __be16 dat; if (this_attr->address != AD5933_IN_PGA_GAIN) { ret = kstrtou16(buf, 10, &val); @@ -521,7 +521,7 @@ static int ad5933_read_raw(struct iio_dev *indio_dev, long m) { struct ad5933_state *st = iio_priv(indio_dev); - unsigned short dat; + __be16 dat; int ret = -EINVAL; mutex_lock(&indio_dev->mlock); diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 3660a43..86cc8f9 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -454,7 +454,7 @@ static const struct attribute_group isl29108_group = { static int isl29018_chip_init(struct isl29018_chip *chip) { int status; - int new_adc_bit; + unsigned int new_adc_bit; unsigned int new_range; /* Code added per Intersil Application Note 1534: diff --git a/drivers/staging/iio/magnetometer/hmc5843_core.c b/drivers/staging/iio/magnetometer/hmc5843_core.c index 914ae1a..fd171d8 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_core.c +++ b/drivers/staging/iio/magnetometer/hmc5843_core.c @@ -131,7 +131,7 @@ static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) static int hmc5843_wait_measurement(struct hmc5843_data *data) { int tries = 150; - int val; + unsigned int val; int ret; while (tries-- > 0) { @@ -209,7 +209,7 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev, char *buf) { struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); - int val; + unsigned int val; int ret; ret = regmap_read(data->regmap, HMC5843_CONFIG_REG_A, &val); @@ -344,7 +344,7 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct hmc5843_data *data = iio_priv(indio_dev); - int rval; + unsigned int rval; int ret; switch (mask) { diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index 7fbaba4..1360099 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -491,7 +491,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_ANGL: - pos = be16_to_cpup((u16 *)st->rx); + pos = be16_to_cpup((__be16 *) st->rx); if (st->hysteresis) pos >>= 16 - st->resolution; *val = pos; @@ -499,7 +499,7 @@ static int ad2s1210_read_raw(struct iio_dev *indio_dev, break; case IIO_ANGL_VEL: negative = st->rx[0] & 0x80; - vel = be16_to_cpup((s16 *)st->rx); + vel = be16_to_cpup((__be16 *) st->rx); vel >>= 16 - st->resolution; if (vel & 0x8000) { negative = (0xffff >> st->resolution) << st->resolution; |