From 9ff88edc5e7bad08bdd79a20f14533a5cf44b865 Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Sun, 7 May 2017 18:24:24 +0800 Subject: iio: hid-sensor-rotation: Add relative orientation sensor hid support Relative orientation(AG) sensor is a 6dof orientation sensor, it depends on acceleration and gyroscope sensor data. It gives a quaternion describing the orientation of the device relative to an initial orientation. It is a standard HID sensor. More information can be found in: http://www.usb.org/developers/hidpage/HUTRR59_-_Usages_for_Wearables.pdf Relative orientation(AG) sensor and dev rotation sensor have same channels and share channel usage id. So the most of the code for relative orientation sensor can be reused. Signed-off-by: Song Hongyan Reviewed-by: Andy Shevchenko Reviewed-by: Xu Even Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- include/linux/hid-sensor-ids.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 761f86242473..b5469e878e99 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -90,6 +90,7 @@ #define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481 #define HID_USAGE_SENSOR_DEVICE_ORIENTATION 0x20008A +#define HID_USAGE_SENSOR_RELATIVE_ORIENTATION 0x20008E #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 -- cgit v1.2.3 From 00907c7a3282053dd4782e02c3101809608e7ea7 Mon Sep 17 00:00:00 2001 From: Song Hongyan Date: Sun, 7 May 2017 18:24:25 +0800 Subject: iio: hid-sensor-rotation: Add geomagnetic orientation sensor hid support. Geomagnetic orientation(AM) sensor is one kind of orientation 6dof sensor. It gives the device rotation in respect to the earth center and the magnetic north. The sensor is implemented through use of an accelerometer and magnetometer do not use gyroscope. It is a standard HID sensor. More information can be found in: http://www.usb.org/developers/hidpage/HUTRR59_-_Usages_for_Wearables.pdf Geomagnetic orientation(AM) sensor and dev rotation sensor have same channel and share channel usage id. So the most of the code for relative orientation sensor can be reused. Signed-off-by: Song Hongyan Signed-off-by: Jonathan Cameron --- drivers/iio/orientation/hid-sensor-rotation.c | 7 +++++++ include/linux/hid-sensor-ids.h | 1 + 2 files changed, 8 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 4d953c26325f..60d3517a78af 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -241,6 +241,9 @@ static int hid_dev_rot_probe(struct platform_device *pdev) case HID_USAGE_SENSOR_RELATIVE_ORIENTATION: name = "relative_orientation"; break; + case HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION: + name = "geomagnetic_orientation"; + break; default: return -EINVAL; } @@ -339,6 +342,10 @@ static const struct platform_device_id hid_dev_rot_ids[] = { /* Relative orientation(AG) sensor */ .name = "HID-SENSOR-20008e", }, + { + /* Geomagnetic orientation(AM) sensor */ + .name = "HID-SENSOR-2000c1", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, hid_dev_rot_ids); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index b5469e878e99..5af62c7e49f3 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -91,6 +91,7 @@ #define HID_USAGE_SENSOR_DEVICE_ORIENTATION 0x20008A #define HID_USAGE_SENSOR_RELATIVE_ORIENTATION 0x20008E +#define HID_USAGE_SENSOR_GEOMAGNETIC_ORIENTATION 0x2000C1 #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 -- cgit v1.2.3 From 6fb34812c2a2a4cdcdad4452b9634892812fa97b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 2 May 2017 14:33:45 +0200 Subject: iio: stm32 trigger: Add support for TRGO2 triggers Add support for TRGO2 trigger that can be found on STM32F7. Add additional master modes supported by TRGO2. Register additional "tim[1/8]_trgo2" triggers for timer1 & timer8. Detect TRGO2 timer capability (master mode selection 2). Signed-off-by: Fabrice Gasnier Acked-by: Benjamin Gaignard Signed-off-by: Jonathan Cameron --- .../ABI/testing/sysfs-bus-iio-timer-stm32 | 48 +++++++++ drivers/iio/trigger/stm32-timer-trigger.c | 113 ++++++++++++++++++--- include/linux/iio/timer/stm32-timer-trigger.h | 2 + include/linux/mfd/stm32-timers.h | 2 + 4 files changed, 151 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 index 230020e06677..deb015935683 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 @@ -16,6 +16,54 @@ Description: - "OC2REF" : OC2REF signal is used as trigger output. - "OC3REF" : OC3REF signal is used as trigger output. - "OC4REF" : OC4REF signal is used as trigger output. + Additional modes (on TRGO2 only): + - "OC5REF" : OC5REF signal is used as trigger output. + - "OC6REF" : OC6REF signal is used as trigger output. + - "compare_pulse_OC4REF": + OC4REF rising or falling edges generate pulses. + - "compare_pulse_OC6REF": + OC6REF rising or falling edges generate pulses. + - "compare_pulse_OC4REF_r_or_OC6REF_r": + OC4REF or OC6REF rising edges generate pulses. + - "compare_pulse_OC4REF_r_or_OC6REF_f": + OC4REF rising or OC6REF falling edges generate pulses. + - "compare_pulse_OC5REF_r_or_OC6REF_r": + OC5REF or OC6REF rising edges generate pulses. + - "compare_pulse_OC5REF_r_or_OC6REF_f": + OC5REF rising or OC6REF falling edges generate pulses. + + +-----------+ +-------------+ +---------+ + | Prescaler +-> | Counter | +-> | Master | TRGO(2) + +-----------+ +--+--------+-+ |-> | Control +--> + | | || +---------+ + +--v--------+-+ OCxREF || +---------+ + | Chx compare +----------> | Output | ChX + +-----------+-+ | | Control +--> + . | | +---------+ + . | | . + +-----------v-+ OC6REF | . + | Ch6 compare +---------+> + +-------------+ + + Example with: "compare_pulse_OC4REF_r_or_OC6REF_r": + + X + X X + X . . X + X . . X + X . . X + count X . . . . X + . . . . + . . . . + +---------------+ + OC4REF | . . | + +-+ . . +-+ + . +---+ . + OC6REF . | | . + +-------+ +-------+ + +-+ +-+ + TRGO2 | | | | + +-+ +---+ +---------+ What: /sys/bus/iio/devices/triggerX/master_mode KernelVersion: 4.11 diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 25248d644e7c..0797f2fe584f 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -14,19 +14,19 @@ #include #include -#define MAX_TRIGGERS 6 +#define MAX_TRIGGERS 7 #define MAX_VALIDS 5 /* List the triggers created by each timer */ static const void *triggers_table[][MAX_TRIGGERS] = { - { TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, + { TIM1_TRGO, TIM1_TRGO2, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,}, { TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,}, { TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,}, { TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,}, { TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,}, { TIM6_TRGO,}, { TIM7_TRGO,}, - { TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, + { TIM8_TRGO, TIM8_TRGO2, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,}, { TIM9_TRGO, TIM9_CH1, TIM9_CH2,}, { }, /* timer 10 */ { }, /* timer 11 */ @@ -56,9 +56,16 @@ struct stm32_timer_trigger { u32 max_arr; const void *triggers; const void *valids; + bool has_trgo2; }; +static bool stm32_timer_is_trgo2_name(const char *name) +{ + return !!strstr(name, "trgo2"); +} + static int stm32_timer_start(struct stm32_timer_trigger *priv, + struct iio_trigger *trig, unsigned int frequency) { unsigned long long prd, div; @@ -102,7 +109,12 @@ static int stm32_timer_start(struct stm32_timer_trigger *priv, regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE); /* Force master mode to update mode */ - regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20); + if (stm32_timer_is_trgo2_name(trig->name)) + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, + 0x2 << TIM_CR2_MMS2_SHIFT); + else + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, + 0x2 << TIM_CR2_MMS_SHIFT); /* Make sure that registers are updated */ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); @@ -150,7 +162,7 @@ static ssize_t stm32_tt_store_frequency(struct device *dev, if (freq == 0) { stm32_timer_stop(priv); } else { - ret = stm32_timer_start(priv, freq); + ret = stm32_timer_start(priv, trig, freq); if (ret) return ret; } @@ -183,6 +195,9 @@ static IIO_DEV_ATTR_SAMP_FREQ(0660, stm32_tt_read_frequency, stm32_tt_store_frequency); +#define MASTER_MODE_MAX 7 +#define MASTER_MODE2_MAX 15 + static char *master_mode_table[] = { "reset", "enable", @@ -191,7 +206,16 @@ static char *master_mode_table[] = { "OC1REF", "OC2REF", "OC3REF", - "OC4REF" + "OC4REF", + /* Master mode selection 2 only */ + "OC5REF", + "OC6REF", + "compare_pulse_OC4REF", + "compare_pulse_OC6REF", + "compare_pulse_OC4REF_r_or_OC6REF_r", + "compare_pulse_OC4REF_r_or_OC6REF_f", + "compare_pulse_OC5REF_r_or_OC6REF_r", + "compare_pulse_OC5REF_r_or_OC6REF_f", }; static ssize_t stm32_tt_show_master_mode(struct device *dev, @@ -199,10 +223,15 @@ static ssize_t stm32_tt_show_master_mode(struct device *dev, char *buf) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); + struct iio_trigger *trig = to_iio_trigger(dev); u32 cr2; regmap_read(priv->regmap, TIM_CR2, &cr2); - cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; + + if (stm32_timer_is_trgo2_name(trig->name)) + cr2 = (cr2 & TIM_CR2_MMS2) >> TIM_CR2_MMS2_SHIFT; + else + cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT; return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]); } @@ -212,13 +241,25 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, const char *buf, size_t len) { struct stm32_timer_trigger *priv = dev_get_drvdata(dev); + struct iio_trigger *trig = to_iio_trigger(dev); + u32 mask, shift, master_mode_max; int i; - for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) { + if (stm32_timer_is_trgo2_name(trig->name)) { + mask = TIM_CR2_MMS2; + shift = TIM_CR2_MMS2_SHIFT; + master_mode_max = MASTER_MODE2_MAX; + } else { + mask = TIM_CR2_MMS; + shift = TIM_CR2_MMS_SHIFT; + master_mode_max = MASTER_MODE_MAX; + } + + for (i = 0; i <= master_mode_max; i++) { if (!strncmp(master_mode_table[i], buf, strlen(master_mode_table[i]))) { - regmap_update_bits(priv->regmap, TIM_CR2, - TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT); + regmap_update_bits(priv->regmap, TIM_CR2, mask, + i << shift); /* Make sure that registers are updated */ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG); @@ -229,8 +270,31 @@ static ssize_t stm32_tt_store_master_mode(struct device *dev, return -EINVAL; } -static IIO_CONST_ATTR(master_mode_available, - "reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF"); +static ssize_t stm32_tt_show_master_mode_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_trigger *trig = to_iio_trigger(dev); + unsigned int i, master_mode_max; + size_t len = 0; + + if (stm32_timer_is_trgo2_name(trig->name)) + master_mode_max = MASTER_MODE2_MAX; + else + master_mode_max = MASTER_MODE_MAX; + + for (i = 0; i <= master_mode_max; i++) + len += scnprintf(buf + len, PAGE_SIZE - len, + "%s ", master_mode_table[i]); + + /* replace trailing space by newline */ + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR(master_mode_available, 0444, + stm32_tt_show_master_mode_avail, NULL, 0); static IIO_DEVICE_ATTR(master_mode, 0660, stm32_tt_show_master_mode, @@ -240,7 +304,7 @@ static IIO_DEVICE_ATTR(master_mode, 0660, static struct attribute *stm32_trigger_attrs[] = { &iio_dev_attr_sampling_frequency.dev_attr.attr, &iio_dev_attr_master_mode.dev_attr.attr, - &iio_const_attr_master_mode_available.dev_attr.attr, + &iio_dev_attr_master_mode_available.dev_attr.attr, NULL, }; @@ -264,6 +328,12 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) while (cur && *cur) { struct iio_trigger *trig; + bool cur_is_trgo2 = stm32_timer_is_trgo2_name(*cur); + + if (cur_is_trgo2 && !priv->has_trgo2) { + cur++; + continue; + } trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur); if (!trig) @@ -277,7 +347,7 @@ static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv) * should only be available on trgo trigger which * is always the first in the list. */ - if (cur == priv->triggers) + if (cur == priv->triggers || cur_is_trgo2) trig->dev.groups = stm32_trigger_attr_groups; iio_trigger_set_drvdata(trig, priv); @@ -584,6 +654,20 @@ bool is_stm32_timer_trigger(struct iio_trigger *trig) } EXPORT_SYMBOL(is_stm32_timer_trigger); +static void stm32_timer_detect_trgo2(struct stm32_timer_trigger *priv) +{ + u32 val; + + /* + * Master mode selection 2 bits can only be written and read back when + * timer supports it. + */ + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, TIM_CR2_MMS2); + regmap_read(priv->regmap, TIM_CR2, &val); + regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS2, 0); + priv->has_trgo2 = !!val; +} + static int stm32_timer_trigger_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -614,6 +698,7 @@ static int stm32_timer_trigger_probe(struct platform_device *pdev) priv->max_arr = ddata->max_arr; priv->triggers = triggers_table[index]; priv->valids = valids_table[index]; + stm32_timer_detect_trgo2(priv); ret = stm32_setup_iio_triggers(priv); if (ret) diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h index 55535aef2e6c..fa7d786ed99e 100644 --- a/include/linux/iio/timer/stm32-timer-trigger.h +++ b/include/linux/iio/timer/stm32-timer-trigger.h @@ -10,6 +10,7 @@ #define _STM32_TIMER_TRIGGER_H_ #define TIM1_TRGO "tim1_trgo" +#define TIM1_TRGO2 "tim1_trgo2" #define TIM1_CH1 "tim1_ch1" #define TIM1_CH2 "tim1_ch2" #define TIM1_CH3 "tim1_ch3" @@ -44,6 +45,7 @@ #define TIM7_TRGO "tim7_trgo" #define TIM8_TRGO "tim8_trgo" +#define TIM8_TRGO2 "tim8_trgo2" #define TIM8_CH1 "tim8_ch1" #define TIM8_CH2 "tim8_ch2" #define TIM8_CH3 "tim8_ch3" diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index 4a0abbc10ef6..ce7346e7f77a 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -34,6 +34,7 @@ #define TIM_CR1_DIR BIT(4) /* Counter Direction */ #define TIM_CR1_ARPE BIT(7) /* Auto-reload Preload Ena */ #define TIM_CR2_MMS (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */ +#define TIM_CR2_MMS2 GENMASK(23, 20) /* Master mode selection 2 */ #define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */ #define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */ #define TIM_DIER_UIE BIT(0) /* Update interrupt */ @@ -60,6 +61,7 @@ #define MAX_TIM_PSC 0xFFFF #define TIM_CR2_MMS_SHIFT 4 +#define TIM_CR2_MMS2_SHIFT 20 #define TIM_SMCR_TS_SHIFT 4 #define TIM_BDTR_BKF_MASK 0xF #define TIM_BDTR_BKF_SHIFT 16 -- cgit v1.2.3 From 12e84c71b7d4ee38d51377fd494ac748ee4e6912 Mon Sep 17 00:00:00 2001 From: Okash Khawaja Date: Mon, 15 May 2017 18:45:32 +0100 Subject: tty: export tty_open_by_driver This exports tty_open_by_driver so that it can be called from other places inside the kernel. The checks for null file pointer are based on Alan Cox's patch here: http://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1215095.html. Description below is quoted from it: "[RFC] tty_port: allow a port to be opened with a tty that has no file handle Let us create tty objects entirely in kernel space. Untested proposal to show why all the ideas around rewriting half the uart stack are not needed. With this a kernel created non file backed tty object could be used to handle data, and set terminal modes. Not all ldiscs can cope with this as N_TTY in particular has to work back to the fs/tty layer. The tty_port code is however otherwise clean of file handles as far as I can tell as is the low level tty port write path used by the ldisc, the configuration low level interfaces and most of the ldiscs. Currently you don't have any exposure to see tty hangups because those are built around the file layer. However a) it's a fixed port so you probably don't care about that b) if you do we can add a callback and c) you almost certainly don't want the userspace tear down/rebuild behaviour anyway. This should however be sufficient if we wanted for example to enumerate all the bluetooth bound fixed ports via ACPI and make them directly available. It doesn't deal with the case of a user opening a port that's also kernel opened and that would need some locking out (so it returned EBUSY if bound to a kernel device of some kind). That needs resolving along with how you "up" or "down" your new bluetooth device, or enumerate it while providing the existing tty API to avoid regressions (and to debug)." The exported funtion is used later in this patch set to gain access to tty_struct. [changed export symbol level - gkh] Signed-off-by: Okash Khawaja Reviewed-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 10 +++++++--- include/linux/tty.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 0c150b5a9dd6..49abf04c90b2 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1083,7 +1083,10 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct tty_struct *tty; if (driver->ops->lookup) - tty = driver->ops->lookup(driver, file, idx); + if (!file) + tty = ERR_PTR(-EIO); + else + tty = driver->ops->lookup(driver, file, idx); else tty = driver->ttys[idx]; @@ -1715,7 +1718,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, struct tty_driver *console_driver = console_device(index); if (console_driver) { driver = tty_driver_kref_get(console_driver); - if (driver) { + if (driver && filp) { /* Don't let /dev/console block */ filp->f_flags |= O_NONBLOCK; break; @@ -1748,7 +1751,7 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, * - concurrent tty driver removal w/ lookup * - concurrent tty removal from driver table */ -static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, +struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, struct file *filp) { struct tty_struct *tty; @@ -1793,6 +1796,7 @@ out: tty_driver_kref_put(driver); return tty; } +EXPORT_SYMBOL_GPL(tty_open_by_driver); /** * tty_open - open a tty device diff --git a/include/linux/tty.h b/include/linux/tty.h index d07cd2105a6c..c9f9fd2c4eef 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -400,6 +400,8 @@ extern struct tty_struct *get_current_tty(void); /* tty_io.c */ extern int __init tty_init(void); extern const char *tty_name(const struct tty_struct *tty); +extern struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, + struct file *filp); #else static inline void tty_kref_put(struct tty_struct *tty) { } -- cgit v1.2.3 From 138bc7969c24c6cbba28e919c2376ad10a46fc60 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 7 Apr 2017 19:22:06 -0700 Subject: iio: hid-sensor-hub: Implement batch mode HID sensor hubs using Integrated Senor Hub (ISH) has added capability to support batch mode. This allows host processor to go to sleep for extended duration, while the sensor hub is storing samples in its internal buffers. 'Commit f4f4673b7535 ("iio: add support for hardware fifo")' implements feature in IIO core to implement such feature. This feature is used in bmc150-accel-core.c to implement batch mode. This implementation allows software device buffer watermark to be used as a hint to adjust hardware FIFO. But HID sensor hubs don't allow to change internal buffer size of FIFOs. Instead an additional usage id to set "maximum report latency" is defined. This allows host to go to sleep upto this latency period without getting any report. Since there is no ABI to set this latency, a new attribute "hwfifo_timeout" is added so that user mode can specify a latency. This change checks presence of usage id to get/set maximum report latency and if present, it will expose hwfifo_timeout. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 11 +++ .../iio/common/hid-sensors/hid-sensor-attributes.c | 44 ++++++++++++ .../iio/common/hid-sensors/hid-sensor-trigger.c | 80 ++++++++++++++++++++++ include/linux/hid-sensor-hub.h | 5 ++ include/linux/hid-sensor-ids.h | 3 + 5 files changed, 143 insertions(+) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 8c24d0892f61..2db2cdf42d54 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1425,6 +1425,17 @@ Description: guarantees that the hardware fifo is flushed to the device buffer. +What: /sys/bus/iio/devices/iio:device*/buffer/hwfifo_timeout +KernelVersion: 4.12 +Contact: linux-iio@vger.kernel.org +Description: + A read/write property to provide capability to delay reporting of + samples till a timeout is reached. This allows host processors to + sleep, while the sensor is storing samples in its internal fifo. + The maximum timeout in seconds can be specified by setting + hwfifo_timeout.The current delay can be read by reading + hwfifo_timeout. A value of 0 means that there is no timeout. + What: /sys/bus/iio/devices/iio:deviceX/buffer/hwfifo_watermark KernelVersion: 4.2 Contact: linux-iio@vger.kernel.org diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index 0e05f6d1e761..f5d4d786e193 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -410,6 +410,48 @@ int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev, } +static void hid_sensor_get_report_latency_info(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_common *st) +{ + sensor_hub_input_get_attribute_info(hsdev, HID_FEATURE_REPORT, + usage_id, + HID_USAGE_SENSOR_PROP_REPORT_LATENCY, + &st->report_latency); + + hid_dbg(hsdev->hdev, "Report latency attributes: %x:%x\n", + st->report_latency.index, st->report_latency.report_id); +} + +int hid_sensor_get_report_latency(struct hid_sensor_common *st) +{ + int ret; + int value; + + ret = sensor_hub_get_feature(st->hsdev, st->report_latency.report_id, + st->report_latency.index, sizeof(value), + &value); + if (ret < 0) + return ret; + + return value; +} +EXPORT_SYMBOL(hid_sensor_get_report_latency); + +int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency_ms) +{ + return sensor_hub_set_feature(st->hsdev, st->report_latency.report_id, + st->report_latency.index, + sizeof(latency_ms), &latency_ms); +} +EXPORT_SYMBOL(hid_sensor_set_report_latency); + +bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st) +{ + return st->report_latency.index > 0 && st->report_latency.report_id > 0; +} +EXPORT_SYMBOL(hid_sensor_batch_mode_supported); + int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, u32 usage_id, struct hid_sensor_common *st) @@ -451,6 +493,8 @@ int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, } else st->timestamp_ns_scale = 1000000000; + hid_sensor_get_report_latency_info(hsdev, usage_id, st); + hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n", st->poll.index, st->poll.report_id, st->report_state.index, st->report_state.report_id, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 0b5dea050239..16ade0a0327b 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -26,9 +26,84 @@ #include #include #include +#include #include #include "hid-sensor-trigger.h" +static ssize_t _hid_sensor_set_report_latency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int integer, fract, ret; + int latency; + + ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); + if (ret) + return ret; + + latency = integer * 1000 + fract / 1000; + ret = hid_sensor_set_report_latency(attrb, latency); + if (ret < 0) + return len; + + attrb->latency_ms = hid_sensor_get_report_latency(attrb); + + return len; +} + +static ssize_t _hid_sensor_get_report_latency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int latency; + + latency = hid_sensor_get_report_latency(attrb); + if (latency < 0) + return latency; + + return sprintf(buf, "%d.%06u\n", latency / 1000, (latency % 1000) * 1000); +} + +static ssize_t _hid_sensor_get_fifo_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev); + int latency; + + latency = hid_sensor_get_report_latency(attrb); + if (latency < 0) + return latency; + + return sprintf(buf, "%d\n", !!latency); +} + +static IIO_DEVICE_ATTR(hwfifo_timeout, 0644, + _hid_sensor_get_report_latency, + _hid_sensor_set_report_latency, 0); +static IIO_DEVICE_ATTR(hwfifo_enabled, 0444, + _hid_sensor_get_fifo_state, NULL, 0); + +static const struct attribute *hid_sensor_fifo_attributes[] = { + &iio_dev_attr_hwfifo_timeout.dev_attr.attr, + &iio_dev_attr_hwfifo_enabled.dev_attr.attr, + NULL, +}; + +static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev, + struct hid_sensor_common *st) +{ + if (!hid_sensor_batch_mode_supported(st)) + return; + + iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes); +} + static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) { int state_val; @@ -141,6 +216,9 @@ static void hid_sensor_set_power_work(struct work_struct *work) sizeof(attrb->raw_hystersis), &attrb->raw_hystersis); + if (attrb->latency_ms > 0) + hid_sensor_set_report_latency(attrb, attrb->latency_ms); + _hid_sensor_power_state(attrb, true); } @@ -192,6 +270,8 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, attrb->trigger = trig; indio_dev->trig = iio_trigger_get(trig); + hid_sensor_setup_batch_mode(indio_dev, attrb); + ret = pm_runtime_set_active(&indio_dev->dev); if (ret) goto error_unreg_trigger; diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h index f32d7c392c1e..fc7aae64dcde 100644 --- a/include/linux/hid-sensor-hub.h +++ b/include/linux/hid-sensor-hub.h @@ -233,12 +233,14 @@ struct hid_sensor_common { atomic_t user_requested_state; int poll_interval; int raw_hystersis; + int latency_ms; struct iio_trigger *trigger; int timestamp_ns_scale; struct hid_sensor_hub_attribute_info poll; struct hid_sensor_hub_attribute_info report_state; struct hid_sensor_hub_attribute_info power_state; struct hid_sensor_hub_attribute_info sensitivity; + struct hid_sensor_hub_attribute_info report_latency; struct work_struct work; }; @@ -276,5 +278,8 @@ s32 hid_sensor_read_poll_value(struct hid_sensor_common *st); int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st, int64_t raw_value); +bool hid_sensor_batch_mode_supported(struct hid_sensor_common *st); +int hid_sensor_set_report_latency(struct hid_sensor_common *st, int latency); +int hid_sensor_get_report_latency(struct hid_sensor_common *st); #endif diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 5af62c7e49f3..76033e0420a7 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -152,6 +152,9 @@ #define HID_USAGE_SENSOR_PROP_REPORT_STATE 0x200316 #define HID_USAGE_SENSOR_PROY_POWER_STATE 0x200319 +/* Batch mode selectors */ +#define HID_USAGE_SENSOR_PROP_REPORT_LATENCY 0x20031B + /* Per data field properties */ #define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00 #define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 -- cgit v1.2.3 From 6576ff740f5c1e6705d33b9d6a922526f20fa0dc Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 27 Apr 2017 17:30:08 +0200 Subject: iio: adc: twl4030: Drop twl4030_get_madc_conversion() Drop legacy twl4030_get_madc_conversion() method. It has been used by drivers to get madc data before it conversion to IIO API. There are no users in the mainline kernel anymore. Signed-off-by: Sebastian Reichel Acked-by: Wolfram Sang Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 21 --------------------- include/linux/i2c/twl4030-madc.h | 1 - 2 files changed, 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 0c74869a540a..88e44066ef82 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -642,27 +642,6 @@ out: } EXPORT_SYMBOL_GPL(twl4030_madc_conversion); -int twl4030_get_madc_conversion(int channel_no) -{ - struct twl4030_madc_request req; - int temp = 0; - int ret; - - req.channels = (1 << channel_no); - req.method = TWL4030_MADC_SW2; - req.active = 0; - req.raw = 0; - req.func_cb = NULL; - ret = twl4030_madc_conversion(&req); - if (ret < 0) - return ret; - if (req.rbuf[channel_no] > 0) - temp = req.rbuf[channel_no]; - - return temp; -} -EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); - /** * twl4030_madc_set_current_generator() - setup bias current * diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index 1c0134dd3271..0c919ebb31e0 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -143,5 +143,4 @@ struct twl4030_madc_user_parms { }; int twl4030_madc_conversion(struct twl4030_madc_request *conv); -int twl4030_get_madc_conversion(int channel_no); #endif -- cgit v1.2.3 From 42ab9278eb3abfe8b500abe6681c8549c408ec8f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 27 Apr 2017 17:30:09 +0200 Subject: iio: adc: twl4030: Unexport twl4030_madc_conversion() All madc users have been converted to IIO API, so drop the legacy API. The function is still used inside of the driver. Signed-off-by: Sebastian Reichel Acked-by: Wolfram Sang Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 5 +++-- include/linux/i2c/twl4030-madc.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 88e44066ef82..be60f76d1a50 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -72,6 +72,8 @@ struct twl4030_madc_data { u8 isr; }; +static int twl4030_madc_conversion(struct twl4030_madc_request *req); + static int twl4030_madc_read(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long mask) @@ -568,7 +570,7 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc, * be a negative error value in the corresponding array element. * returns 0 if succeeds else error value */ -int twl4030_madc_conversion(struct twl4030_madc_request *req) +static int twl4030_madc_conversion(struct twl4030_madc_request *req) { const struct twl4030_madc_conversion_method *method; int ret; @@ -640,7 +642,6 @@ out: return ret; } -EXPORT_SYMBOL_GPL(twl4030_madc_conversion); /** * twl4030_madc_set_current_generator() - setup bias current diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index 0c919ebb31e0..be9260e261ac 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -141,6 +141,4 @@ struct twl4030_madc_user_parms { int status; u16 result; }; - -int twl4030_madc_conversion(struct twl4030_madc_request *conv); #endif -- cgit v1.2.3 From 1adf5a3c0d60ad76a873e90a25a456fd51971774 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 27 Apr 2017 17:30:10 +0200 Subject: iio: adc: twl4030: Drop struct twl4030_madc_user_parms This struct is no longer used by anything in the kernel. Signed-off-by: Sebastian Reichel Acked-by: Wolfram Sang Signed-off-by: Jonathan Cameron --- include/linux/i2c/twl4030-madc.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index be9260e261ac..f395700fb933 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -135,10 +135,4 @@ enum sample_type { #define TWL4030_REG_GPBR1 0x0c #define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7) -struct twl4030_madc_user_parms { - int channel; - int average; - int status; - u16 result; -}; #endif -- cgit v1.2.3 From 842eb60b044454f186b4e1da87a4333a9827b62f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 27 Apr 2017 17:30:11 +0200 Subject: iio: adc: twl4030: Remove twl4030_madc_request.func_cb This functionality is not used by the IIO subsystem. Due to removal of legacy API it can also be removed. Signed-off-by: Sebastian Reichel Acked-by: Wolfram Sang Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 70 ---------------------------------------- include/linux/i2c/twl4030-madc.h | 1 - 2 files changed, 71 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index be60f76d1a50..21df5b932bd1 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -86,7 +86,6 @@ static int twl4030_madc_read(struct iio_dev *iio_dev, req.channels = BIT(chan->channel); req.active = false; - req.func_cb = NULL; req.type = TWL4030_MADC_WAIT; req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); @@ -342,37 +341,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, return count; } -/* - * Enables irq. - * @madc - pointer to twl4030_madc_data struct - * @id - irq number to be enabled - * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2 - * corresponding to RT, SW1, SW2 conversion requests. - * If the i2c read fails it returns an error else returns 0. - */ -static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id) -{ - u8 val; - int ret; - - ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr); - if (ret) { - dev_err(madc->dev, "unable to read imr register 0x%X\n", - madc->imr); - return ret; - } - - val &= ~(1 << id); - ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr); - if (ret) { - dev_err(madc->dev, - "unable to write imr register 0x%X\n", madc->imr); - return ret; - } - - return 0; -} - /* * Disables irq. * @madc - pointer to twl4030_madc_data struct @@ -442,11 +410,6 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) /* Read results */ len = twl4030_madc_read_channels(madc, method->rbase, r->channels, r->rbuf, r->raw); - /* Return results to caller */ - if (r->func_cb != NULL) { - r->func_cb(len, r->channels, r->rbuf); - r->func_cb = NULL; - } /* Free request */ r->result_pending = 0; r->active = 0; @@ -468,11 +431,6 @@ err_i2c: /* Read results */ len = twl4030_madc_read_channels(madc, method->rbase, r->channels, r->rbuf, r->raw); - /* Return results to caller */ - if (r->func_cb != NULL) { - r->func_cb(len, r->channels, r->rbuf); - r->func_cb = NULL; - } /* Free request */ r->result_pending = 0; r->active = 0; @@ -482,23 +440,6 @@ err_i2c: return IRQ_HANDLED; } -static int twl4030_madc_set_irq(struct twl4030_madc_data *madc, - struct twl4030_madc_request *req) -{ - struct twl4030_madc_request *p; - int ret; - - p = &madc->requests[req->method]; - memcpy(p, req, sizeof(*req)); - ret = twl4030_madc_enable_irq(madc, req->method); - if (ret < 0) { - dev_err(madc->dev, "enable irq failed!!\n"); - return ret; - } - - return 0; -} - /* * Function which enables the madc conversion * by writing to the control register. @@ -607,17 +548,6 @@ static int twl4030_madc_conversion(struct twl4030_madc_request *req) goto out; } } - if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { - ret = twl4030_madc_set_irq(twl4030_madc, req); - if (ret < 0) - goto out; - ret = twl4030_madc_start_conversion(twl4030_madc, req->method); - if (ret < 0) - goto out; - twl4030_madc->requests[req->method].active = 1; - ret = 0; - goto out; - } /* With RT method we should not be here anymore */ if (req->method == TWL4030_MADC_RT) { ret = -EINVAL; diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index f395700fb933..34e94747b61e 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -51,7 +51,6 @@ struct twl4030_madc_request { bool result_pending; bool raw; int rbuf[TWL4030_MADC_MAX_CHANNELS]; - void (*func_cb)(int len, int channels, int *buf); }; enum conversion_methods { -- cgit v1.2.3 From 7af1a06776da9e943126c2dd740a18710ecd66df Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 27 Apr 2017 17:30:12 +0200 Subject: iio: adc: twl4030: Fold twl4030-madc.h into driver twl4030-madc.h is no longer used by anything outside of the iio driver, so it can be merged into the driver. Signed-off-by: Sebastian Reichel Acked-by: Wolfram Sang Signed-off-by: Jonathan Cameron --- drivers/iio/adc/twl4030-madc.c | 113 +++++++++++++++++++++++++++++++- include/linux/i2c/twl4030-madc.h | 137 --------------------------------------- 2 files changed, 112 insertions(+), 138 deletions(-) delete mode 100644 include/linux/i2c/twl4030-madc.h (limited to 'include/linux') diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 21df5b932bd1..bd3d37fc2144 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -49,9 +48,121 @@ #include +#define TWL4030_MADC_MAX_CHANNELS 16 + +#define TWL4030_MADC_CTRL1 0x00 +#define TWL4030_MADC_CTRL2 0x01 + +#define TWL4030_MADC_RTSELECT_LSB 0x02 +#define TWL4030_MADC_SW1SELECT_LSB 0x06 +#define TWL4030_MADC_SW2SELECT_LSB 0x0A + +#define TWL4030_MADC_RTAVERAGE_LSB 0x04 +#define TWL4030_MADC_SW1AVERAGE_LSB 0x08 +#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C + +#define TWL4030_MADC_CTRL_SW1 0x12 +#define TWL4030_MADC_CTRL_SW2 0x13 + +#define TWL4030_MADC_RTCH0_LSB 0x17 +#define TWL4030_MADC_GPCH0_LSB 0x37 + +#define TWL4030_MADC_MADCON (1 << 0) /* MADC power on */ +#define TWL4030_MADC_BUSY (1 << 0) /* MADC busy */ +/* MADC conversion completion */ +#define TWL4030_MADC_EOC_SW (1 << 1) +/* MADC SWx start conversion */ +#define TWL4030_MADC_SW_START (1 << 5) +#define TWL4030_MADC_ADCIN0 (1 << 0) +#define TWL4030_MADC_ADCIN1 (1 << 1) +#define TWL4030_MADC_ADCIN2 (1 << 2) +#define TWL4030_MADC_ADCIN3 (1 << 3) +#define TWL4030_MADC_ADCIN4 (1 << 4) +#define TWL4030_MADC_ADCIN5 (1 << 5) +#define TWL4030_MADC_ADCIN6 (1 << 6) +#define TWL4030_MADC_ADCIN7 (1 << 7) +#define TWL4030_MADC_ADCIN8 (1 << 8) +#define TWL4030_MADC_ADCIN9 (1 << 9) +#define TWL4030_MADC_ADCIN10 (1 << 10) +#define TWL4030_MADC_ADCIN11 (1 << 11) +#define TWL4030_MADC_ADCIN12 (1 << 12) +#define TWL4030_MADC_ADCIN13 (1 << 13) +#define TWL4030_MADC_ADCIN14 (1 << 14) +#define TWL4030_MADC_ADCIN15 (1 << 15) + +/* Fixed channels */ +#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1 +#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8 +#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9 +#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10 +#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11 +#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12 + +/* Step size and prescaler ratio */ +#define TEMP_STEP_SIZE 147 +#define TEMP_PSR_R 100 +#define CURR_STEP_SIZE 147 +#define CURR_PSR_R1 44 +#define CURR_PSR_R2 88 + +#define TWL4030_BCI_BCICTL1 0x23 +#define TWL4030_BCI_CGAIN 0x020 +#define TWL4030_BCI_MESBAT (1 << 1) +#define TWL4030_BCI_TYPEN (1 << 4) +#define TWL4030_BCI_ITHEN (1 << 3) + +#define REG_BCICTL2 0x024 +#define TWL4030_BCI_ITHSENS 0x007 + +/* Register and bits for GPBR1 register */ +#define TWL4030_REG_GPBR1 0x0c +#define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7) + #define TWL4030_USB_SEL_MADC_MCPC (1<<3) #define TWL4030_USB_CARKIT_ANA_CTRL 0xBB +struct twl4030_madc_conversion_method { + u8 sel; + u8 avg; + u8 rbase; + u8 ctrl; +}; + +/** + * struct twl4030_madc_request - madc request packet for channel conversion + * @channels: 16 bit bitmap for individual channels + * @do_avg: sample the input channel for 4 consecutive cycles + * @method: RT, SW1, SW2 + * @type: Polling or interrupt based method + * @active: Flag if request is active + * @result_pending: Flag from irq handler, that result is ready + * @raw: Return raw value, do not convert it + * @rbuf: Result buffer + */ +struct twl4030_madc_request { + unsigned long channels; + bool do_avg; + u16 method; + u16 type; + bool active; + bool result_pending; + bool raw; + int rbuf[TWL4030_MADC_MAX_CHANNELS]; +}; + +enum conversion_methods { + TWL4030_MADC_RT, + TWL4030_MADC_SW1, + TWL4030_MADC_SW2, + TWL4030_MADC_NUM_METHODS +}; + +enum sample_type { + TWL4030_MADC_WAIT, + TWL4030_MADC_IRQ_ONESHOT, + TWL4030_MADC_IRQ_REARM +}; + /** * struct twl4030_madc_data - a container for madc info * @dev: Pointer to device structure for madc diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h deleted file mode 100644 index 34e94747b61e..000000000000 --- a/include/linux/i2c/twl4030-madc.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * twl4030_madc.h - Header for TWL4030 MADC - * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ - * J Keerthy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - * - */ - -#ifndef _TWL4030_MADC_H -#define _TWL4030_MADC_H - -struct twl4030_madc_conversion_method { - u8 sel; - u8 avg; - u8 rbase; - u8 ctrl; -}; - -#define TWL4030_MADC_MAX_CHANNELS 16 - - -/* - * twl4030_madc_request- madc request packet for channel conversion - * @channels: 16 bit bitmap for individual channels - * @do_avgP: sample the input channel for 4 consecutive cycles - * @method: RT, SW1, SW2 - * @type: Polling or interrupt based method - * @raw: Return raw value, do not convert it - */ - -struct twl4030_madc_request { - unsigned long channels; - bool do_avg; - u16 method; - u16 type; - bool active; - bool result_pending; - bool raw; - int rbuf[TWL4030_MADC_MAX_CHANNELS]; -}; - -enum conversion_methods { - TWL4030_MADC_RT, - TWL4030_MADC_SW1, - TWL4030_MADC_SW2, - TWL4030_MADC_NUM_METHODS -}; - -enum sample_type { - TWL4030_MADC_WAIT, - TWL4030_MADC_IRQ_ONESHOT, - TWL4030_MADC_IRQ_REARM -}; - -#define TWL4030_MADC_CTRL1 0x00 -#define TWL4030_MADC_CTRL2 0x01 - -#define TWL4030_MADC_RTSELECT_LSB 0x02 -#define TWL4030_MADC_SW1SELECT_LSB 0x06 -#define TWL4030_MADC_SW2SELECT_LSB 0x0A - -#define TWL4030_MADC_RTAVERAGE_LSB 0x04 -#define TWL4030_MADC_SW1AVERAGE_LSB 0x08 -#define TWL4030_MADC_SW2AVERAGE_LSB 0x0C - -#define TWL4030_MADC_CTRL_SW1 0x12 -#define TWL4030_MADC_CTRL_SW2 0x13 - -#define TWL4030_MADC_RTCH0_LSB 0x17 -#define TWL4030_MADC_GPCH0_LSB 0x37 - -#define TWL4030_MADC_MADCON (1 << 0) /* MADC power on */ -#define TWL4030_MADC_BUSY (1 << 0) /* MADC busy */ -/* MADC conversion completion */ -#define TWL4030_MADC_EOC_SW (1 << 1) -/* MADC SWx start conversion */ -#define TWL4030_MADC_SW_START (1 << 5) -#define TWL4030_MADC_ADCIN0 (1 << 0) -#define TWL4030_MADC_ADCIN1 (1 << 1) -#define TWL4030_MADC_ADCIN2 (1 << 2) -#define TWL4030_MADC_ADCIN3 (1 << 3) -#define TWL4030_MADC_ADCIN4 (1 << 4) -#define TWL4030_MADC_ADCIN5 (1 << 5) -#define TWL4030_MADC_ADCIN6 (1 << 6) -#define TWL4030_MADC_ADCIN7 (1 << 7) -#define TWL4030_MADC_ADCIN8 (1 << 8) -#define TWL4030_MADC_ADCIN9 (1 << 9) -#define TWL4030_MADC_ADCIN10 (1 << 10) -#define TWL4030_MADC_ADCIN11 (1 << 11) -#define TWL4030_MADC_ADCIN12 (1 << 12) -#define TWL4030_MADC_ADCIN13 (1 << 13) -#define TWL4030_MADC_ADCIN14 (1 << 14) -#define TWL4030_MADC_ADCIN15 (1 << 15) - -/* Fixed channels */ -#define TWL4030_MADC_BTEMP TWL4030_MADC_ADCIN1 -#define TWL4030_MADC_VBUS TWL4030_MADC_ADCIN8 -#define TWL4030_MADC_VBKB TWL4030_MADC_ADCIN9 -#define TWL4030_MADC_ICHG TWL4030_MADC_ADCIN10 -#define TWL4030_MADC_VCHG TWL4030_MADC_ADCIN11 -#define TWL4030_MADC_VBAT TWL4030_MADC_ADCIN12 - -/* Step size and prescaler ratio */ -#define TEMP_STEP_SIZE 147 -#define TEMP_PSR_R 100 -#define CURR_STEP_SIZE 147 -#define CURR_PSR_R1 44 -#define CURR_PSR_R2 88 - -#define TWL4030_BCI_BCICTL1 0x23 -#define TWL4030_BCI_CGAIN 0x020 -#define TWL4030_BCI_MESBAT (1 << 1) -#define TWL4030_BCI_TYPEN (1 << 4) -#define TWL4030_BCI_ITHEN (1 << 3) - -#define REG_BCICTL2 0x024 -#define TWL4030_BCI_ITHSENS 0x007 - -/* Register and bits for GPBR1 register */ -#define TWL4030_REG_GPBR1 0x0c -#define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7) - -#endif -- cgit v1.2.3 From d89e119a088ec83881eda5645307ae252ecea33a Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Thu, 27 Apr 2017 15:29:15 +0200 Subject: iio: add hardware triggered operating mode Devices, like stm32 timer, could be triggered by hardware events which are not buffer or software events. However it could be necessary to validate the triggers like it is done for buffer or event triggered modes. This patch add a new INDIO_HARDWARE_TRIGGERED operating mode for this kind of devices and allow this mode to register trigger consumer. Signed-off-by: Benjamin Gaignard Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 4 ++-- include/linux/iio/iio.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 15c86a8cd704..17ec4cee51dc 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1423,7 +1423,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev) static void iio_dev_release(struct device *device) { struct iio_dev *indio_dev = dev_to_iio_dev(device); - if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) + if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES) iio_device_unregister_trigger_consumer(indio_dev); iio_device_unregister_eventset(indio_dev); iio_device_unregister_sysfs(indio_dev); @@ -1705,7 +1705,7 @@ int iio_device_register(struct iio_dev *indio_dev) "Failed to register event set\n"); goto error_free_sysfs; } - if (indio_dev->modes & (INDIO_BUFFER_TRIGGERED | INDIO_EVENT_TRIGGERED)) + if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES) iio_device_register_trigger_consumer(indio_dev); if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) && diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 3f5ea2e9a39e..d68bec297a45 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -352,10 +352,16 @@ unsigned int iio_get_time_res(const struct iio_dev *indio_dev); #define INDIO_BUFFER_SOFTWARE 0x04 #define INDIO_BUFFER_HARDWARE 0x08 #define INDIO_EVENT_TRIGGERED 0x10 +#define INDIO_HARDWARE_TRIGGERED 0x20 #define INDIO_ALL_BUFFER_MODES \ (INDIO_BUFFER_TRIGGERED | INDIO_BUFFER_HARDWARE | INDIO_BUFFER_SOFTWARE) +#define INDIO_ALL_TRIGGERED_MODES \ + (INDIO_BUFFER_TRIGGERED \ + | INDIO_EVENT_TRIGGERED \ + | INDIO_HARDWARE_TRIGGERED) + #define INDIO_MAX_RAW_ELEMENTS 4 struct iio_trigger; /* forward declaration */ -- cgit v1.2.3 From cbf4b3867875206aa548a8c6d7c886f3299d619e Mon Sep 17 00:00:00 2001 From: Okash Khawaja Date: Sat, 17 Jun 2017 22:32:55 +0100 Subject: tty: define tty_open_by_driver when CONFIG_TTY is not defined This patch adds definition of tty_open_by_driver when CONFIG_TTY is not defined. This was supposed to have been included in commit 12e84c71b7d4ee38d51377fd494ac748ee4e6912 ("tty: export tty_open_by_driver"). The patch follows convention for other such functions and returns NULL. Signed-off-by: Okash Khawaja Reviewed-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index 5c3f01f49b10..b75b2d51ba2b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -422,6 +422,9 @@ static inline int __init tty_init(void) { return 0; } static inline const char *tty_name(const struct tty_struct *tty) { return "(none)"; } +static inline struct tty_struct *tty_open_by_driver(dev_t device, + struct inode *inode, struct file *filp) +{ return NULL; } #endif extern struct ktermios tty_std_termios; -- cgit v1.2.3 From fc61ed51270e86440cf7cf84cbe1d86753592932 Mon Sep 17 00:00:00 2001 From: Okash Khawaja Date: Sun, 25 Jun 2017 19:40:00 +0100 Subject: tty: add function to convert device name to number The function converts strings like ttyS0 and ttyUSB0 to dev_t like (4, 64) and (188, 0). It does this by scanning tty_drivers list for corresponding device name and index. If the driver is not registered, this function returns -ENODEV. It also acquires tty_mutex. Signed-off-by: Okash Khawaja Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/tty.h | 3 +++ 2 files changed, 53 insertions(+) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 49abf04c90b2..974b13d24401 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -325,6 +325,56 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) return NULL; } +/** + * tty_dev_name_to_number - return dev_t for device name + * @name: user space name of device under /dev + * @number: pointer to dev_t that this function will populate + * + * This function converts device names like ttyS0 or ttyUSB1 into dev_t + * like (4, 64) or (188, 1). If no corresponding driver is registered then + * the function returns -ENODEV. + * + * Locking: this acquires tty_mutex to protect the tty_drivers list from + * being modified while we are traversing it, and makes sure to + * release it before exiting. + */ +int tty_dev_name_to_number(const char *name, dev_t *number) +{ + struct tty_driver *p; + int ret; + int index, prefix_length = 0; + const char *str; + + for (str = name; *str && !isdigit(*str); str++) + ; + + if (!*str) + return -EINVAL; + + ret = kstrtoint(str, 10, &index); + if (ret) + return ret; + + prefix_length = str - name; + mutex_lock(&tty_mutex); + + list_for_each_entry(p, &tty_drivers, tty_drivers) + if (prefix_length == strlen(p->name) && strncmp(name, + p->name, prefix_length) == 0) { + if (index < p->num) { + *number = MKDEV(p->major, p->minor_start + index); + goto out; + } + } + + /* if here then driver wasn't found */ + ret = -ENODEV; +out: + mutex_unlock(&tty_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(tty_dev_name_to_number); + #ifdef CONFIG_CONSOLE_POLL /** diff --git a/include/linux/tty.h b/include/linux/tty.h index b75b2d51ba2b..8156a9ee6fe6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -402,6 +402,7 @@ extern int __init tty_init(void); extern const char *tty_name(const struct tty_struct *tty); extern struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, struct file *filp); +extern int tty_dev_name_to_number(const char *name, dev_t *number); #else static inline void tty_kref_put(struct tty_struct *tty) { } @@ -425,6 +426,8 @@ static inline const char *tty_name(const struct tty_struct *tty) static inline struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, struct file *filp) { return NULL; } +static inline int tty_dev_name_to_number(const char *name, dev_t *number) +{ return -ENOTSUPP; } #endif extern struct ktermios tty_std_termios; -- cgit v1.2.3