public inbox for cip-dev@lists.cip-project.org
 help / color / mirror / Atom feed
* [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices
@ 2017-08-30 18:52 Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 1/8] stmmac: Add support for SIMATIC IOT2000 platform Jan Kiszka
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

This is the first of 3 chunks to enable the CIP kernel for the IOT2000
devices. It has the side effect of improving also the support of the
by now discontinued Galileo Gen 2 board.

Features added:
 - Ethernet MACs on IOT2000
 - TI ADC108S102 on IOT2000 and Galileo
 - I2C frequency tuning on IOT2000
 - GPIO support for pca9685 PWMs on IOT2000 and Galileo
 - interrupt support for PCAL9535 on IOT2000 and Galileo

Jan

Alison Schofield (1):
  iio: core: implement iio_device_{claim|release}_direct_mode()

Jan Kiszka (4):
  stmmac: Add support for SIMATIC IOT2000 platform
  iio: adc: Add support for TI ADC108S102 and ADC128S102
  mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving
    frequency
  mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform

Mika Westerberg (1):
  pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO

Sven Van Asbroeck (1):
  pwm: pca9685: Fix GPIO-only operation

Yong Li (1):
  gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2

 .../devicetree/bindings/iio/adc/ti-adc108s102.txt  |  18 ++
 drivers/gpio/gpio-pca953x.c                        |  42 ++-
 drivers/iio/adc/Kconfig                            |  12 +
 drivers/iio/adc/Makefile                           |   1 +
 drivers/iio/adc/ti-adc108s102.c                    | 348 +++++++++++++++++++++
 drivers/iio/industrialio-core.c                    |  39 +++
 drivers/mfd/intel_quark_i2c_gpio.c                 |  49 +--
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c   |  26 +-
 drivers/pwm/pwm-pca9685.c                          | 248 +++++++++++++--
 include/linux/iio/iio.h                            |   2 +
 10 files changed, 743 insertions(+), 42 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt
 create mode 100644 drivers/iio/adc/ti-adc108s102.c

-- 
2.12.3

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 1/8] stmmac: Add support for SIMATIC IOT2000 platform
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 2/8] iio: core: implement iio_device_{claim|release}_direct_mode() Jan Kiszka
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Jan Kiszka <jan.kiszka@siemens.com>

commit 212c7fd614377fef4415d94856a59e9f484aa439 upstream.

The IOT2000 is industrial controller platform, derived from the Intel
Galileo Gen2 board. The variant IOT2020 comes with one LAN port, the
IOT2040 has two of them. They can be told apart based on the board asset
tag in the DMI table.

Based on patch by Sascha Weisenberger.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Sascha Weisenberger <sascha.weisenberger@siemens.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c | 26 +++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index d71a721ea61c..3491e98bffc5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -36,6 +36,7 @@
  */
 struct stmmac_pci_dmi_data {
 	const char *name;
+	const char *asset_tag;
 	unsigned int func;
 	int phy_addr;
 };
@@ -50,6 +51,7 @@ struct stmmac_pci_info {
 static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
 {
 	const char *name = dmi_get_system_info(DMI_BOARD_NAME);
+	const char *asset_tag = dmi_get_system_info(DMI_BOARD_ASSET_TAG);
 	unsigned int func = PCI_FUNC(info->pdev->devfn);
 	struct stmmac_pci_dmi_data *dmi;
 
@@ -61,8 +63,12 @@ static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
 		return 1;
 
 	for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
-		if (!strcmp(dmi->name, name) && dmi->func == func)
+		if (!strcmp(dmi->name, name) && dmi->func == func) {
+			/* If asset tag is provided, match on it as well. */
+			if (dmi->asset_tag && strcmp(dmi->asset_tag, asset_tag))
+				continue;
 			return dmi->phy_addr;
+		}
 	}
 
 	return -ENODEV;
@@ -138,6 +144,24 @@ static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
 		.func = 6,
 		.phy_addr = 1,
 	},
+	{
+		.name = "SIMATIC IOT2000",
+		.asset_tag = "6ES7647-0AA00-0YA2",
+		.func = 6,
+		.phy_addr = 1,
+	},
+	{
+		.name = "SIMATIC IOT2000",
+		.asset_tag = "6ES7647-0AA00-1YA2",
+		.func = 6,
+		.phy_addr = 1,
+	},
+	{
+		.name = "SIMATIC IOT2000",
+		.asset_tag = "6ES7647-0AA00-1YA2",
+		.func = 7,
+		.phy_addr = 1,
+	},
 	{}
 };
 
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 2/8] iio: core: implement iio_device_{claim|release}_direct_mode()
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 1/8] stmmac: Add support for SIMATIC IOT2000 platform Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 3/8] iio: adc: Add support for TI ADC108S102 and ADC128S102 Jan Kiszka
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Alison Schofield <amsfield22@gmail.com>

commit 08a33805518e7845486f88287e8aace6f8439391 upstream.

It is often the case that the driver wants to be sure a device stays
in direct mode while it is executing a task or series of tasks.  To
accomplish this today, the driver performs this sequence: 1) take the
device state lock, 2) verify it is not in a buffered mode, 3) execute
some tasks, and 4) release that lock.

This patch introduces a pair of helper functions that simplify these
steps and make it more semantically expressive.

iio_device_claim_direct_mode()
        If the device is not in any buffered mode it is guaranteed
        to stay that way until iio_release_direct_mode() is called.

iio_device_release_direct_mode()
        Release the claim. Device is no longer guaranteed to stay
        in direct mode.

Signed-off-by: Alison Schofield <amsfield22@gmail.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
 drivers/iio/industrialio-core.c | 39 +++++++++++++++++++++++++++++++++++++++
 include/linux/iio/iio.h         |  2 ++
 2 files changed, 41 insertions(+)

diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 131b434af994..dc0701f0ab03 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/anon_inodes.h>
 #include <linux/debugfs.h>
+#include <linux/mutex.h>
 #include <linux/iio/iio.h>
 #include "iio_core.h"
 #include "iio_core_trigger.h"
@@ -1363,6 +1364,44 @@ void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev)
 }
 EXPORT_SYMBOL_GPL(devm_iio_device_unregister);
 
+/**
+ * iio_device_claim_direct_mode - Keep device in direct mode
+ * @indio_dev:	the iio_dev associated with the device
+ *
+ * If the device is in direct mode it is guaranteed to stay
+ * that way until iio_device_release_direct_mode() is called.
+ *
+ * Use with iio_device_release_direct_mode()
+ *
+ * Returns: 0 on success, -EBUSY on failure
+ */
+int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
+{
+	mutex_lock(&indio_dev->mlock);
+
+	if (iio_buffer_enabled(indio_dev)) {
+		mutex_unlock(&indio_dev->mlock);
+		return -EBUSY;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
+
+/**
+ * iio_device_release_direct_mode - releases claim on direct mode
+ * @indio_dev:	the iio_dev associated with the device
+ *
+ * Release the claim. Device is no longer guaranteed to stay
+ * in direct mode.
+ *
+ * Use with iio_device_claim_direct_mode()
+ */
+void iio_device_release_direct_mode(struct iio_dev *indio_dev)
+{
+	mutex_unlock(&indio_dev->mlock);
+}
+EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
+
 subsys_initcall(iio_init);
 module_exit(iio_exit);
 
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 19c94c9acc81..b6edc8dcbe61 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -527,6 +527,8 @@ void iio_device_unregister(struct iio_dev *indio_dev);
 int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev);
 void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev);
 int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
+int iio_device_claim_direct_mode(struct iio_dev *indio_dev);
+void iio_device_release_direct_mode(struct iio_dev *indio_dev);
 
 extern struct bus_type iio_bus_type;
 
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 3/8] iio: adc: Add support for TI ADC108S102 and ADC128S102
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 1/8] stmmac: Add support for SIMATIC IOT2000 platform Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 2/8] iio: core: implement iio_device_{claim|release}_direct_mode() Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 4/8] mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency Jan Kiszka
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Jan Kiszka <jan.kiszka@siemens.com>

commit 7e87d11c9bda75816ced8d0895e8d24e5c52833a upstream.

This is an upstream port of an IIO driver for the TI ADC108S102 and
ADC128S102. The former can be found on the Intel Galileo Gen2 and the
Siemens SIMATIC IOT2000. For those boards, ACPI-based enumeration is
included.

Due to the lack of regulators under ACPI, we hard-code the voltage
provided to the VA pin of the ADC to 5 V, the value used on Galileo and
IOT2000. For DT usage, the regulator "vref-supply" provides this
information. Note that DT usage has not been tested.

Original author: Bogdan Pricop <bogdan.pricop@emutex.com>
Ported from Intel Galileo Gen2 BSP to Intel Yocto kernel:
Todor Minchev <todor@minchev.co.uk>.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
[Jan: remove parameter from iio_get_time_ns for 4.4]
---
 .../devicetree/bindings/iio/adc/ti-adc108s102.txt  |  18 ++
 drivers/iio/adc/Kconfig                            |  12 +
 drivers/iio/adc/Makefile                           |   1 +
 drivers/iio/adc/ti-adc108s102.c                    | 348 +++++++++++++++++++++
 4 files changed, 379 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt
 create mode 100644 drivers/iio/adc/ti-adc108s102.c

diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt
new file mode 100644
index 000000000000..bbbbb4a9f58f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti-adc108s102.txt
@@ -0,0 +1,18 @@
+* Texas Instruments' ADC108S102 and ADC128S102 ADC chip
+
+Required properties:
+ - compatible: Should be "ti,adc108s102"
+ - reg: spi chip select number for the device
+ - vref-supply: The regulator supply for ADC reference voltage
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+		Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+adc at 0 {
+	compatible = "ti,adc108s102";
+	reg = <0>;
+	vref-supply = <&vdd_supply>;
+	spi-max-frequency = <1000000>;
+};
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index bda6bbe4479c..5c9d65101e9b 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -324,6 +324,18 @@ config TI_ADC081C
 	  This driver can also be built as a module. If so, the module will be
 	  called ti-adc081c.
 
+config TI_ADC108S102
+	tristate "Texas Instruments ADC108S102 and ADC128S102 driver"
+	depends on SPI
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  Say yes here to build support for Texas Instruments ADC108S102 and
+	  ADC128S102 ADC.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called ti-adc108s102.
+
 config TI_ADC128S052
 	tristate "Texas Instruments ADC128S052/ADC122S021"
 	depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 99b37a963a1e..4f942eae584a 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
 obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
 obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
+obj-$(CONFIG_TI_ADC108S102) += ti-adc108s102.o
 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
 obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c
new file mode 100644
index 000000000000..0b438bfdaea3
--- /dev/null
+++ b/drivers/iio/adc/ti-adc108s102.c
@@ -0,0 +1,348 @@
+/*
+ * TI ADC108S102 SPI ADC driver
+ *
+ * Copyright (c) 2013-2015 Intel Corporation.
+ * Copyright (c) 2017 Siemens AG
+ *
+ * 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.
+ *
+ * This IIO device driver is designed to work with the following
+ * analog to digital converters from Texas Instruments:
+ *  ADC108S102
+ *  ADC128S102
+ * The communication with ADC chip is via the SPI bus (mode 3).
+ */
+
+#include <linux/acpi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/types.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+/*
+ * In case of ACPI, we use the hard-wired 5000 mV of the Galileo and IOT2000
+ * boards as default for the reference pin VA. Device tree users encode that
+ * via the vref-supply regulator.
+ */
+#define ADC108S102_VA_MV_ACPI_DEFAULT	5000
+
+/*
+ * Defining the ADC resolution being 12 bits, we can use the same driver for
+ * both ADC108S102 (10 bits resolution) and ADC128S102 (12 bits resolution)
+ * chips. The ADC108S102 effectively returns a 12-bit result with the 2
+ * least-significant bits unset.
+ */
+#define ADC108S102_BITS		12
+#define ADC108S102_MAX_CHANNELS	8
+
+/*
+ * 16-bit SPI command format:
+ *   [15:14] Ignored
+ *   [13:11] 3-bit channel address
+ *   [10:0]  Ignored
+ */
+#define ADC108S102_CMD(ch)		((u16)(ch) << 11)
+
+/*
+ * 16-bit SPI response format:
+ *   [15:12] Zeros
+ *   [11:0]  12-bit ADC sample (for ADC108S102, [1:0] will always be 0).
+ */
+#define ADC108S102_RES_DATA(res)	((u16)res & GENMASK(11, 0))
+
+struct adc108s102_state {
+	struct spi_device		*spi;
+	struct regulator		*reg;
+	u32				va_millivolt;
+	/* SPI transfer used by triggered buffer handler*/
+	struct spi_transfer		ring_xfer;
+	/* SPI transfer used by direct scan */
+	struct spi_transfer		scan_single_xfer;
+	/* SPI message used by ring_xfer SPI transfer */
+	struct spi_message		ring_msg;
+	/* SPI message used by scan_single_xfer SPI transfer */
+	struct spi_message		scan_single_msg;
+
+	/*
+	 * SPI message buffers:
+	 *  tx_buf: |C0|C1|C2|C3|C4|C5|C6|C7|XX|
+	 *  rx_buf: |XX|R0|R1|R2|R3|R4|R5|R6|R7|tt|tt|tt|tt|
+	 *
+	 *  tx_buf: 8 channel read commands, plus 1 dummy command
+	 *  rx_buf: 1 dummy response, 8 channel responses, plus 64-bit timestamp
+	 */
+	__be16				rx_buf[13] ____cacheline_aligned;
+	__be16				tx_buf[9] ____cacheline_aligned;
+};
+
+#define ADC108S102_V_CHAN(index)					\
+	{								\
+		.type = IIO_VOLTAGE,					\
+		.indexed = 1,						\
+		.channel = index,					\
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+			BIT(IIO_CHAN_INFO_SCALE),			\
+		.address = index,					\
+		.scan_index = index,					\
+		.scan_type = {						\
+			.sign = 'u',					\
+			.realbits = ADC108S102_BITS,			\
+			.storagebits = 16,				\
+			.endianness = IIO_BE,				\
+		},							\
+	}
+
+static const struct iio_chan_spec adc108s102_channels[] = {
+	ADC108S102_V_CHAN(0),
+	ADC108S102_V_CHAN(1),
+	ADC108S102_V_CHAN(2),
+	ADC108S102_V_CHAN(3),
+	ADC108S102_V_CHAN(4),
+	ADC108S102_V_CHAN(5),
+	ADC108S102_V_CHAN(6),
+	ADC108S102_V_CHAN(7),
+	IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+static int adc108s102_update_scan_mode(struct iio_dev *indio_dev,
+		unsigned long const *active_scan_mask)
+{
+	struct adc108s102_state *st = iio_priv(indio_dev);
+	unsigned int bit, cmds;
+
+	/*
+	 * Fill in the first x shorts of tx_buf with the number of channels
+	 * enabled for sampling by the triggered buffer.
+	 */
+	cmds = 0;
+	for_each_set_bit(bit, active_scan_mask, ADC108S102_MAX_CHANNELS)
+		st->tx_buf[cmds++] = cpu_to_be16(ADC108S102_CMD(bit));
+
+	/* One dummy command added, to clock in the last response */
+	st->tx_buf[cmds++] = 0x00;
+
+	/* build SPI ring message */
+	st->ring_xfer.tx_buf = &st->tx_buf[0];
+	st->ring_xfer.rx_buf = &st->rx_buf[0];
+	st->ring_xfer.len = cmds * sizeof(st->tx_buf[0]);
+
+	spi_message_init_with_transfers(&st->ring_msg, &st->ring_xfer, 1);
+
+	return 0;
+}
+
+static irqreturn_t adc108s102_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct adc108s102_state *st = iio_priv(indio_dev);
+	int ret;
+
+	ret = spi_sync(st->spi, &st->ring_msg);
+	if (ret < 0)
+		goto out_notify;
+
+	/* Skip the dummy response in the first slot */
+	iio_push_to_buffers_with_timestamp(indio_dev,
+					   (u8 *)&st->rx_buf[1],
+					   iio_get_time_ns());
+
+out_notify:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int adc108s102_scan_direct(struct adc108s102_state *st, unsigned int ch)
+{
+	int ret;
+
+	st->tx_buf[0] = cpu_to_be16(ADC108S102_CMD(ch));
+	ret = spi_sync(st->spi, &st->scan_single_msg);
+	if (ret)
+		return ret;
+
+	/* Skip the dummy response in the first slot */
+	return be16_to_cpu(st->rx_buf[1]);
+}
+
+static int adc108s102_read_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long m)
+{
+	struct adc108s102_state *st = iio_priv(indio_dev);
+	int ret;
+
+	switch (m) {
+	case IIO_CHAN_INFO_RAW:
+		ret = iio_device_claim_direct_mode(indio_dev);
+		if (ret)
+			return ret;
+
+		ret = adc108s102_scan_direct(st, chan->address);
+
+		iio_device_release_direct_mode(indio_dev);
+
+		if (ret < 0)
+			return ret;
+
+		*val = ADC108S102_RES_DATA(ret);
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		if (chan->type != IIO_VOLTAGE)
+			break;
+
+		*val = st->va_millivolt;
+		*val2 = chan->scan_type.realbits;
+
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static const struct iio_info adc108s102_info = {
+	.read_raw		= &adc108s102_read_raw,
+	.update_scan_mode	= &adc108s102_update_scan_mode,
+	.driver_module		= THIS_MODULE,
+};
+
+static int adc108s102_probe(struct spi_device *spi)
+{
+	struct adc108s102_state *st;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+
+	if (ACPI_COMPANION(&spi->dev)) {
+		st->va_millivolt = ADC108S102_VA_MV_ACPI_DEFAULT;
+	} else {
+		st->reg = devm_regulator_get(&spi->dev, "vref");
+		if (IS_ERR(st->reg))
+			return PTR_ERR(st->reg);
+
+		ret = regulator_enable(st->reg);
+		if (ret < 0) {
+			dev_err(&spi->dev, "Cannot enable vref regulator\n");
+			return ret;
+		}
+
+		ret = regulator_get_voltage(st->reg);
+		if (ret < 0) {
+			dev_err(&spi->dev, "vref get voltage failed\n");
+			return ret;
+		}
+
+		st->va_millivolt = ret / 1000;
+	}
+
+	spi_set_drvdata(spi, indio_dev);
+	st->spi = spi;
+
+	indio_dev->name = spi->modalias;
+	indio_dev->dev.parent = &spi->dev;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = adc108s102_channels;
+	indio_dev->num_channels = ARRAY_SIZE(adc108s102_channels);
+	indio_dev->info = &adc108s102_info;
+
+	/* Setup default message */
+	st->scan_single_xfer.tx_buf = st->tx_buf;
+	st->scan_single_xfer.rx_buf = st->rx_buf;
+	st->scan_single_xfer.len = 2 * sizeof(st->tx_buf[0]);
+
+	spi_message_init_with_transfers(&st->scan_single_msg,
+					&st->scan_single_xfer, 1);
+
+	ret = iio_triggered_buffer_setup(indio_dev, NULL,
+					 &adc108s102_trigger_handler, NULL);
+	if (ret)
+		goto error_disable_reg;
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(&spi->dev, "Failed to register IIO device\n");
+		goto error_cleanup_triggered_buffer;
+	}
+	return 0;
+
+error_cleanup_triggered_buffer:
+	iio_triggered_buffer_cleanup(indio_dev);
+
+error_disable_reg:
+	regulator_disable(st->reg);
+
+	return ret;
+}
+
+static int adc108s102_remove(struct spi_device *spi)
+{
+	struct iio_dev *indio_dev = spi_get_drvdata(spi);
+	struct adc108s102_state *st = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	iio_triggered_buffer_cleanup(indio_dev);
+
+	regulator_disable(st->reg);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id adc108s102_of_match[] = {
+	{ .compatible = "ti,adc108s102" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, adc108s102_of_match);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id adc108s102_acpi_ids[] = {
+	{ "INT3495", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, adc108s102_acpi_ids);
+#endif
+
+static const struct spi_device_id adc108s102_id[] = {
+	{ "adc108s102", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, adc108s102_id);
+
+static struct spi_driver adc108s102_driver = {
+	.driver = {
+		.name   = "adc108s102",
+		.of_match_table = of_match_ptr(adc108s102_of_match),
+		.acpi_match_table = ACPI_PTR(adc108s102_acpi_ids),
+	},
+	.probe		= adc108s102_probe,
+	.remove		= adc108s102_remove,
+	.id_table	= adc108s102_id,
+};
+module_spi_driver(adc108s102_driver);
+
+MODULE_AUTHOR("Bogdan Pricop <bogdan.pricop@emutex.com>");
+MODULE_DESCRIPTION("Texas Instruments ADC108S102 and ADC128S102 driver");
+MODULE_LICENSE("GPL v2");
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 4/8] mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (2 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 3/8] iio: adc: Add support for TI ADC108S102 and ADC128S102 Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 5/8] mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform Jan Kiszka
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Jan Kiszka <jan.kiszka@siemens.com>

commit b518d4adb83e3e139d3de96d172d9b4dec6def09 upstream.

Avoids reimplementation of DMI matching in intel_quark_i2c_setup.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/intel_quark_i2c_gpio.c | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index 042137465300..57d4396dab5d 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -60,19 +60,18 @@ struct intel_quark_mfd {
 	struct clk_lookup	*i2c_clk_lookup;
 };
 
-struct i2c_mode_info {
-	const char *name;
-	unsigned int i2c_scl_freq;
-};
-
-static const struct i2c_mode_info platform_i2c_mode_info[] = {
+static const struct dmi_system_id dmi_platform_info[] = {
 	{
-		.name = "Galileo",
-		.i2c_scl_freq = 100000,
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
+		},
+		.driver_data = (void *)100000,
 	},
 	{
-		.name = "GalileoGen2",
-		.i2c_scl_freq = 400000,
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
+		},
+		.driver_data = (void *)400000,
 	},
 	{}
 };
@@ -167,8 +166,7 @@ static void intel_quark_unregister_i2c_clk(struct pci_dev *pdev)
 
 static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
 {
-	const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
-	const struct i2c_mode_info *info;
+	const struct dmi_system_id *dmi_id;
 	struct dw_i2c_platform_data *pdata;
 	struct resource *res = (struct resource *)cell->resources;
 	struct device *dev = &pdev->dev;
@@ -188,14 +186,9 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
 	/* Normal mode by default */
 	pdata->i2c_scl_freq = 100000;
 
-	if (board_name) {
-		for (info = platform_i2c_mode_info; info->name; info++) {
-			if (!strcmp(board_name, info->name)) {
-				pdata->i2c_scl_freq = info->i2c_scl_freq;
-				break;
-			}
-		}
-	}
+	dmi_id = dmi_first_match(dmi_platform_info);
+	if (dmi_id)
+		pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data;
 
 	cell->platform_data = pdata;
 	cell->pdata_size = sizeof(*pdata);
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 5/8] mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (3 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 4/8] mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO Jan Kiszka
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Jan Kiszka <jan.kiszka@siemens.com>

commit 842086d2b5a6cec23d598edffb5137c72b265c50 upstream.

The SIMATIC IOT2020 and IOT2040 are derived from the Galileo Gen2 board
and share its I2C frequency.

Signed-off-by: Sascha Weisenberger <sascha.weisenberger@siemens.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/intel_quark_i2c_gpio.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index 57d4396dab5d..1c09604978d3 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -73,6 +73,22 @@ static const struct dmi_system_id dmi_platform_info[] = {
 		},
 		.driver_data = (void *)400000,
 	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+					"6ES7647-0AA00-0YA2"),
+		},
+		.driver_data = (void *)400000,
+	},
+	{
+		.matches = {
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+			DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+					"6ES7647-0AA00-1YA2"),
+		},
+		.driver_data = (void *)400000,
+	},
 	{}
 };
 
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (4 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 5/8] mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-09-14 15:55   ` Ben Hutchings
  2017-08-30 18:52 ` [cip-dev] [PATCH 7/8] pwm: pca9685: Fix GPIO-only operation Jan Kiszka
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Mika Westerberg <mika.westerberg@linux.intel.com>

commit bccec89f0a35f65302734d1cdb01479df0f33ac9 upstream.

The PCA9685 controller has full on/off bit for each PWM channel. Setting
this bit bypasses the PWM control and the line works just as it would be a
GPIO. Furthermore in Intel Galileo it is actually used as GPIO output for
discreet muxes on the board.

This patch adds GPIO output only support for the driver so that we can
control the muxes on Galileo using standard GPIO interfaces available in
the kernel. GPIO and PWM functionality is exclusive so only one can be
active at a time on a single PWM channel.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
[Jan: adjusted gpio.parent to .dev for 4.4]
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 drivers/pwm/pwm-pca9685.c | 164 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 163 insertions(+), 1 deletion(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 01a6a83f625d..cad6cdf06d03 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -20,8 +20,10 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/gpio/driver.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
 #include <linux/pwm.h>
@@ -80,6 +82,10 @@ struct pca9685 {
 	int active_cnt;
 	int duty_ns;
 	int period_ns;
+#if IS_ENABLED(CONFIG_GPIOLIB)
+	struct mutex lock;
+	struct gpio_chip gpio;
+#endif
 };
 
 static inline struct pca9685 *to_pca(struct pwm_chip *chip)
@@ -87,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
 	return container_of(chip, struct pca9685, chip);
 }
 
+#if IS_ENABLED(CONFIG_GPIOLIB)
+static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
+	struct pwm_device *pwm;
+
+	mutex_lock(&pca->lock);
+
+	pwm = &pca->chip.pwms[offset];
+
+	if (pwm->flags & (PWMF_REQUESTED | PWMF_EXPORTED)) {
+		mutex_unlock(&pca->lock);
+		return -EBUSY;
+	}
+
+	pwm_set_chip_data(pwm, (void *)1);
+
+	mutex_unlock(&pca->lock);
+	return 0;
+}
+
+static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
+	struct pwm_device *pwm;
+
+	mutex_lock(&pca->lock);
+	pwm = &pca->chip.pwms[offset];
+	pwm_set_chip_data(pwm, NULL);
+	mutex_unlock(&pca->lock);
+}
+
+static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
+{
+	bool is_gpio = false;
+
+	mutex_lock(&pca->lock);
+
+	if (pwm->hwpwm >= PCA9685_MAXCHAN) {
+		unsigned int i;
+
+		/*
+		 * Check if any of the GPIOs are requested and in that case
+		 * prevent using the "all LEDs" channel.
+		 */
+		for (i = 0; i < pca->gpio.ngpio; i++)
+			if (gpiochip_is_requested(&pca->gpio, i)) {
+				is_gpio = true;
+				break;
+			}
+	} else if (pwm_get_chip_data(pwm)) {
+		is_gpio = true;
+	}
+
+	mutex_unlock(&pca->lock);
+	return is_gpio;
+}
+
+static int pca9685_pwm_gpio_get(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
+	struct pwm_device *pwm = &pca->chip.pwms[offset];
+	unsigned int value;
+
+	regmap_read(pca->regmap, LED_N_ON_H(pwm->hwpwm), &value);
+
+	return value & LED_FULL;
+}
+
+static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
+				 int value)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
+	struct pwm_device *pwm = &pca->chip.pwms[offset];
+	unsigned int on = value ? LED_FULL : 0;
+
+	/* Clear both OFF registers */
+	regmap_write(pca->regmap, LED_N_OFF_L(pwm->hwpwm), 0);
+	regmap_write(pca->regmap, LED_N_OFF_H(pwm->hwpwm), 0);
+
+	/* Set the full ON bit */
+	regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on);
+}
+
+static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
+					  unsigned int offset)
+{
+	/* Always out */
+	return 0;
+}
+
+static int pca9685_pwm_gpio_direction_input(struct gpio_chip *gpio,
+					    unsigned int offset)
+{
+	return -EINVAL;
+}
+
+static int pca9685_pwm_gpio_direction_output(struct gpio_chip *gpio,
+					     unsigned int offset, int value)
+{
+	pca9685_pwm_gpio_set(gpio, offset, value);
+
+	return 0;
+}
+
+/*
+ * The PCA9685 has a bit for turning the PWM output full off or on. Some
+ * boards like Intel Galileo actually uses these as normal GPIOs so we
+ * expose a GPIO chip here which can exclusively take over the underlying
+ * PWM channel.
+ */
+static int pca9685_pwm_gpio_probe(struct pca9685 *pca)
+{
+	struct device *dev = pca->chip.dev;
+
+	mutex_init(&pca->lock);
+
+	pca->gpio.label = dev_name(dev);
+	pca->gpio.dev = dev;
+	pca->gpio.request = pca9685_pwm_gpio_request;
+	pca->gpio.free = pca9685_pwm_gpio_free;
+	pca->gpio.get_direction = pca9685_pwm_gpio_get_direction;
+	pca->gpio.direction_input = pca9685_pwm_gpio_direction_input;
+	pca->gpio.direction_output = pca9685_pwm_gpio_direction_output;
+	pca->gpio.get = pca9685_pwm_gpio_get;
+	pca->gpio.set = pca9685_pwm_gpio_set;
+	pca->gpio.base = -1;
+	pca->gpio.ngpio = PCA9685_MAXCHAN;
+	pca->gpio.can_sleep = true;
+
+	return devm_gpiochip_add_data(dev, &pca->gpio, pca);
+}
+#else
+static inline bool pca9685_pwm_is_gpio(struct pca9685 *pca,
+				       struct pwm_device *pwm)
+{
+	return false;
+}
+
+static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
+{
+	return 0;
+}
+#endif
+
 static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			      int duty_ns, int period_ns)
 {
@@ -253,6 +404,9 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
 	struct pca9685 *pca = to_pca(chip);
 
+	if (pca9685_pwm_is_gpio(pca, pwm))
+		return -EBUSY;
+
 	if (pca->active_cnt++ == 0)
 		return regmap_update_bits(pca->regmap, PCA9685_MODE1,
 					  MODE1_SLEEP, 0x0);
@@ -334,7 +488,15 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 	pca->chip.base = -1;
 	pca->chip.can_sleep = true;
 
-	return pwmchip_add(&pca->chip);
+	ret = pwmchip_add(&pca->chip);
+	if (ret < 0)
+		return ret;
+
+	ret = pca9685_pwm_gpio_probe(pca);
+	if (ret < 0)
+		pwmchip_remove(&pca->chip);
+
+	return ret;
 }
 
 static int pca9685_pwm_remove(struct i2c_client *client)
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 7/8] pwm: pca9685: Fix GPIO-only operation
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (5 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-08-30 18:52 ` [cip-dev] [PATCH 8/8] gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2 Jan Kiszka
  2017-09-14 15:55 ` [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Ben Hutchings
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Sven Van Asbroeck <thesven73@gmail.com>

commit c40c461e1944b9cfb520e04184ec1e5c80fb210b upstream.

GPIO-only driver operation never clears the SLEEP bit, which can cause
the GPIOs to become unusable.

Example:
1. user requests first PWM  ->      driver clears SLEEP bit
2. user frees last PWM      ->      driver sets SLEEP bit
3. user requests GPIO
4. user switches GPIO on    ->      output does not turn on
                                    because SLEEP bit is set

Prevent this behaviour by letting the runtime PM framework control the
SLEEP bit. This will put the chip to SLEEP if no PWMs/GPIOs are exported
or in use.

Fixes: bccec89f0a35 ("Allow any of the 16 PWMs to be used as a GPIO")
Reported-by: Sven Van Asbroeck <TheSven73@googlemail.com>
Signed-off-by: Sven Van Asbroeck <TheSven73@googlemail.com>
Suggested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
---
 drivers/pwm/pwm-pca9685.c | 112 ++++++++++++++++++++++++++++++++--------------
 1 file changed, 79 insertions(+), 33 deletions(-)

diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index cad6cdf06d03..d2b92e940e38 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -30,6 +30,7 @@
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/pm_runtime.h>
 
 /*
  * Because the PCA9685 has only one prescaler per chip, changing the period of
@@ -79,7 +80,6 @@
 struct pca9685 {
 	struct pwm_chip chip;
 	struct regmap *regmap;
-	int active_cnt;
 	int duty_ns;
 	int period_ns;
 #if IS_ENABLED(CONFIG_GPIOLIB)
@@ -111,20 +111,10 @@ static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
 	pwm_set_chip_data(pwm, (void *)1);
 
 	mutex_unlock(&pca->lock);
+	pm_runtime_get_sync(pca->chip.dev);
 	return 0;
 }
 
-static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
-{
-	struct pca9685 *pca = gpiochip_get_data(gpio);
-	struct pwm_device *pwm;
-
-	mutex_lock(&pca->lock);
-	pwm = &pca->chip.pwms[offset];
-	pwm_set_chip_data(pwm, NULL);
-	mutex_unlock(&pca->lock);
-}
-
 static bool pca9685_pwm_is_gpio(struct pca9685 *pca, struct pwm_device *pwm)
 {
 	bool is_gpio = false;
@@ -177,6 +167,19 @@ static void pca9685_pwm_gpio_set(struct gpio_chip *gpio, unsigned int offset,
 	regmap_write(pca->regmap, LED_N_ON_H(pwm->hwpwm), on);
 }
 
+static void pca9685_pwm_gpio_free(struct gpio_chip *gpio, unsigned int offset)
+{
+	struct pca9685 *pca = gpiochip_get_data(gpio);
+	struct pwm_device *pwm;
+
+	pca9685_pwm_gpio_set(gpio, offset, 0);
+	pm_runtime_put(pca->chip.dev);
+	mutex_lock(&pca->lock);
+	pwm = &pca->chip.pwms[offset];
+	pwm_set_chip_data(pwm, NULL);
+	mutex_unlock(&pca->lock);
+}
+
 static int pca9685_pwm_gpio_get_direction(struct gpio_chip *chip,
 					  unsigned int offset)
 {
@@ -238,6 +241,16 @@ static inline int pca9685_pwm_gpio_probe(struct pca9685 *pca)
 }
 #endif
 
+static void pca9685_set_sleep_mode(struct pca9685 *pca, int sleep)
+{
+	regmap_update_bits(pca->regmap, PCA9685_MODE1,
+			   MODE1_SLEEP, sleep ? MODE1_SLEEP : 0);
+	if (!sleep) {
+		/* Wait 500us for the oscillator to be back up */
+		udelay(500);
+	}
+}
+
 static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 			      int duty_ns, int period_ns)
 {
@@ -252,19 +265,20 @@ static int pca9685_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
 
 		if (prescale >= PCA9685_PRESCALE_MIN &&
 			prescale <= PCA9685_PRESCALE_MAX) {
+			/*
+			 * putting the chip briefly into SLEEP mode
+			 *@this point won't interfere with the
+			 * pm_runtime framework, because the pm_runtime
+			 * state is guaranteed active here.
+			 */
 			/* Put chip into sleep mode */
-			regmap_update_bits(pca->regmap, PCA9685_MODE1,
-					   MODE1_SLEEP, MODE1_SLEEP);
+			pca9685_set_sleep_mode(pca, 1);
 
 			/* Change the chip-wide output frequency */
 			regmap_write(pca->regmap, PCA9685_PRESCALE, prescale);
 
 			/* Wake the chip up */
-			regmap_update_bits(pca->regmap, PCA9685_MODE1,
-					   MODE1_SLEEP, 0x0);
-
-			/* Wait 500us for the oscillator to be back up */
-			udelay(500);
+			pca9685_set_sleep_mode(pca, 0);
 
 			pca->period_ns = period_ns;
 		} else {
@@ -406,21 +420,15 @@ static int pca9685_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 	if (pca9685_pwm_is_gpio(pca, pwm))
 		return -EBUSY;
-
-	if (pca->active_cnt++ == 0)
-		return regmap_update_bits(pca->regmap, PCA9685_MODE1,
-					  MODE1_SLEEP, 0x0);
+	pm_runtime_get_sync(chip->dev);
 
 	return 0;
 }
 
 static void pca9685_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	struct pca9685 *pca = to_pca(chip);
-
-	if (--pca->active_cnt == 0)
-		regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP,
-				   MODE1_SLEEP);
+	pca9685_pwm_disable(chip, pwm);
+	pm_runtime_put(chip->dev);
 }
 
 static const struct pwm_ops pca9685_pwm_ops = {
@@ -493,22 +501,54 @@ static int pca9685_pwm_probe(struct i2c_client *client,
 		return ret;
 
 	ret = pca9685_pwm_gpio_probe(pca);
-	if (ret < 0)
+	if (ret < 0) {
 		pwmchip_remove(&pca->chip);
+		return ret;
+	}
+
+	/* the chip comes out of power-up in the active state */
+	pm_runtime_set_active(&client->dev);
+	/*
+	 * enable will put the chip into suspend, which is what we
+	 * want as all outputs are disabled at this point
+	 */
+	pm_runtime_enable(&client->dev);
 
-	return ret;
+	return 0;
 }
 
 static int pca9685_pwm_remove(struct i2c_client *client)
 {
 	struct pca9685 *pca = i2c_get_clientdata(client);
+	int ret;
 
-	regmap_update_bits(pca->regmap, PCA9685_MODE1, MODE1_SLEEP,
-			   MODE1_SLEEP);
+	ret = pwmchip_remove(&pca->chip);
+	if (ret)
+		return ret;
+	pm_runtime_disable(&client->dev);
+	return 0;
+}
 
-	return pwmchip_remove(&pca->chip);
+#ifdef CONFIG_PM
+static int pca9685_pwm_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pca9685 *pca = i2c_get_clientdata(client);
+
+	pca9685_set_sleep_mode(pca, 1);
+	return 0;
 }
 
+static int pca9685_pwm_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pca9685 *pca = i2c_get_clientdata(client);
+
+	pca9685_set_sleep_mode(pca, 0);
+	return 0;
+}
+#endif
+
 static const struct i2c_device_id pca9685_id[] = {
 	{ "pca9685", 0 },
 	{ /* sentinel */ },
@@ -531,11 +571,17 @@ static const struct of_device_id pca9685_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
 #endif
 
+static const struct dev_pm_ops pca9685_pwm_pm = {
+	SET_RUNTIME_PM_OPS(pca9685_pwm_runtime_suspend,
+			   pca9685_pwm_runtime_resume, NULL)
+};
+
 static struct i2c_driver pca9685_i2c_driver = {
 	.driver = {
 		.name = "pca9685-pwm",
 		.acpi_match_table = ACPI_PTR(pca9685_acpi_ids),
 		.of_match_table = of_match_ptr(pca9685_dt_ids),
+		.pm = &pca9685_pwm_pm,
 	},
 	.probe = pca9685_pwm_probe,
 	.remove = pca9685_pwm_remove,
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 8/8] gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (6 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 7/8] pwm: pca9685: Fix GPIO-only operation Jan Kiszka
@ 2017-08-30 18:52 ` Jan Kiszka
  2017-09-14 15:55 ` [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Ben Hutchings
  8 siblings, 0 replies; 11+ messages in thread
From: Jan Kiszka @ 2017-08-30 18:52 UTC (permalink / raw)
  To: cip-dev

From: Yong Li <yong.b.li@intel.com>

commit 44896beae605b93f2232301befccb7ef42953198 upstream.

Galileo Gen2 board uses the PCAL9535 as the GPIO expansion,
it is different from PCA9535 and includes interrupt mask/status registers,
The current driver does not support the interrupt registers configuration,
it causes some gpio pins cannot trigger interrupt events,
this patch fix this issue.

The original patch was submitted by
Josef Ahmad <josef.ahmad@linux.intel.com>
http://git.yoctoproject.org/cgit/cgit.cgi/meta-intel-quark/tree/recipes-kernel/linux/files/0015-Quark-GPIO-1-2-quark.patch

Signed-off-by: Yong Li <yong.b.li@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/gpio-pca953x.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index c844d7eccb6c..b45ba6be69ef 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -39,8 +39,13 @@
 #define PCA957X_MSK		6
 #define PCA957X_INTS		7
 
+#define PCAL953X_IN_LATCH	34
+#define PCAL953X_INT_MASK	37
+#define PCAL953X_INT_STAT	38
+
 #define PCA_GPIO_MASK		0x00FF
 #define PCA_INT			0x0100
+#define PCA_PCAL			0x0200
 #define PCA953X_TYPE		0x1000
 #define PCA957X_TYPE		0x2000
 #define PCA_TYPE_MASK		0xF000
@@ -78,7 +83,7 @@ static const struct i2c_device_id pca953x_id[] = {
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
 static const struct acpi_device_id pca953x_acpi_ids[] = {
-	{ "INT3491", 16 | PCA953X_TYPE | PCA_INT, },
+	{ "INT3491", 16 | PCA953X_TYPE | PCA_INT | PCA_PCAL, },
 	{ }
 };
 MODULE_DEVICE_TABLE(acpi, pca953x_acpi_ids);
@@ -403,6 +408,18 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 	struct pca953x_chip *chip = to_pca(gc);
 	u8 new_irqs;
 	int level, i;
+	u8 invert_irq_mask[MAX_BANK];
+
+	if (chip->driver_data & PCA_PCAL) {
+		/* Enable latch on interrupt-enabled inputs */
+		pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
+
+		for (i = 0; i < NBANK(chip); i++)
+			invert_irq_mask[i] = ~chip->irq_mask[i];
+
+		/* Unmask enabled interrupts */
+		pca953x_write_regs(chip, PCAL953X_INT_MASK, invert_irq_mask);
+	}
 
 	/* Look for any newly setup interrupt */
 	for (i = 0; i < NBANK(chip); i++) {
@@ -464,6 +481,29 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 	u8 trigger[MAX_BANK];
 	int ret, i, offset = 0;
 
+	if (chip->driver_data & PCA_PCAL) {
+		/* Read the current interrupt status from the device */
+		ret = pca953x_read_regs(chip, PCAL953X_INT_STAT, trigger);
+		if (ret)
+			return false;
+
+		/* Check latched inputs and clear interrupt status */
+		ret = pca953x_read_regs(chip, PCA953X_INPUT, cur_stat);
+		if (ret)
+			return false;
+
+		for (i = 0; i < NBANK(chip); i++) {
+			/* Apply filter for rising/falling edge selection */
+			pending[i] = (~cur_stat[i] & chip->irq_trig_fall[i]) |
+				(cur_stat[i] & chip->irq_trig_raise[i]);
+			pending[i] &= trigger[i];
+			if (pending[i])
+				pending_seen = true;
+		}
+
+		return pending_seen;
+	}
+
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
 		offset = PCA953X_INPUT;
-- 
2.12.3

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO
  2017-08-30 18:52 ` [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO Jan Kiszka
@ 2017-09-14 15:55   ` Ben Hutchings
  0 siblings, 0 replies; 11+ messages in thread
From: Ben Hutchings @ 2017-09-14 15:55 UTC (permalink / raw)
  To: cip-dev

On Wed, 2017-08-30 at 20:52 +0200, Jan Kiszka wrote:
> From: Mika Westerberg <mika.westerberg@linux.intel.com>
> 
> commit bccec89f0a35f65302734d1cdb01479df0f33ac9 upstream.
[...]
> @@ -87,6 +93,151 @@ static inline struct pca9685 *to_pca(struct pwm_chip *chip)
>  	return container_of(chip, struct pca9685, chip);
>  }
>  
> +#if IS_ENABLED(CONFIG_GPIOLIB)
> +static int pca9685_pwm_gpio_request(struct gpio_chip *gpio, unsigned int offset)
> +{
> +	struct pca9685 *pca = gpiochip_get_data(gpio);
[...]

gpiochip_get_data() doesn't exist in 4.4.

I've cherry-picked commits b08ea35a3296 "gpio: add a data pointer to
gpio_chip", 0cf3292cde22 "gpio: Add devm_ apis for gpiochip_add_data and
gpiochip_remove", and 3988d663c02f "gpiolib: Fix a WARN_ON that can
never trigger" before this.  But you should have included them in this
patch series.

Ben.

-- 
Ben Hutchings
Software Developer, Codethink Ltd.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices
  2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
                   ` (7 preceding siblings ...)
  2017-08-30 18:52 ` [cip-dev] [PATCH 8/8] gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2 Jan Kiszka
@ 2017-09-14 15:55 ` Ben Hutchings
  8 siblings, 0 replies; 11+ messages in thread
From: Ben Hutchings @ 2017-09-14 15:55 UTC (permalink / raw)
  To: cip-dev

On Wed, 2017-08-30 at 20:52 +0200, Jan Kiszka wrote:
> This is the first of 3 chunks to enable the CIP kernel for the IOT2000
> devices. It has the side effect of improving also the support of the
> by now discontinued Galileo Gen 2 board.
> 
> Features added:
>  - Ethernet MACs on IOT2000
>  - TI ADC108S102 on IOT2000 and Galileo
>  - I2C frequency tuning on IOT2000
>  - GPIO support for pca9685 PWMs on IOT2000 and Galileo
>  - interrupt support for PCAL9535 on IOT2000 and Galileo
[...]

Applied this series, along with the gpiolib additions already noted.

Ben.

-- 
Ben Hutchings
Software Developer, Codethink Ltd.

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2017-09-14 15:55 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-08-30 18:52 [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 1/8] stmmac: Add support for SIMATIC IOT2000 platform Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 2/8] iio: core: implement iio_device_{claim|release}_direct_mode() Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 3/8] iio: adc: Add support for TI ADC108S102 and ADC128S102 Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 4/8] mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 5/8] mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 6/8] pwm: pca9685: Allow any of the 16 PWMs to be used as a GPIO Jan Kiszka
2017-09-14 15:55   ` Ben Hutchings
2017-08-30 18:52 ` [cip-dev] [PATCH 7/8] pwm: pca9685: Fix GPIO-only operation Jan Kiszka
2017-08-30 18:52 ` [cip-dev] [PATCH 8/8] gpio: pca953x: add PCAL9535 interrupt support for Galileo Gen2 Jan Kiszka
2017-09-14 15:55 ` [cip-dev] [PATCH 0/8] Basic support for IOT2000 devices Ben Hutchings

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox