* Re: [PATCH 1/3] dt-bindings: gpio: Add binding documentation for gpio-thunderx
From: David Daney @ 2017-01-06 23:26 UTC (permalink / raw)
To: Rob Herring
Cc: Linus Walleij, Alexandre Courbot, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, David Daney
In-Reply-To: <20170104143350.7clanzqrxg4pchr6@rob-hp-laptop>
On 01/04/2017 06:33 AM, Rob Herring wrote:
> On Tue, Jan 03, 2017 at 04:55:32PM -0800, David Daney wrote:
>> From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>>
>> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>> ---
>> .../devicetree/bindings/gpio/gpio-thunderx.txt | 33 ++++++++++++++++++++++
>> 1 file changed, 33 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
>>
>> diff --git a/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt b/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
>> new file mode 100644
>> index 0000000..ba3cdae
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
>> @@ -0,0 +1,33 @@
>> +Cavium ThunderX/OCTEON-TX GPIO controller bindings
>> +
>> +Required Properties:
>> +- reg: The controller bus address.
>> +- gpio-controller: Marks the device node as a GPIO controller.
>> +- #gpio-cells: Must be 2.
>> + - First cell is the GPIO pin number relative to the controller.
>> + - Second cell is standard of_gpio_flags:
>> + 1 - Active Low.
>> + 2 - Single Ended.
>
> Just reference where these are defined.
Thanks for the review. This and the two changes below have been
addressed in v2 of the patch set.
David.
>
>> +
>> +Optional Properties:
>> +- compatible: "cavium,thunder-8890-gpio", unused as PCI driver binding is used.
>> +- interrupt-controller: Marks the device node as an interrupt controller.
>> +- #interrupt-cells: Must be present and have value of 2 if
>> + "interrupt-controller" is present.
>> + - First cell is the GPIO pin number relative to the controller.
>> + - Second cell is triggering flags, one of:
>> + 1 - Edge Rising
>> + 2 - Edge Falling
>> + 4 - Level High
>> + 8 - Level Low
>
> Just reference interrupt-controller/interrupts.txt or the header
> defining these.
>
>> +
>> +Example:
>> +
>> +gpio_6_0: gpio0@6,0 {
>
> gpio@6,0
>
>> + compatible = "cavium,thunder-8890-gpio";
>> + reg = <0x3000 0 0 0 0>; /* DEVFN = 0x30 (6:0) */
>> + gpio-controller;
>> + #gpio-cells = <2>;
>> + interrupt-controller;
>> + #interrupt-cells = <2>;
>> +};
>> --
>> 1.8.3.1
>>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 0/3] GPIO: Add driver for ThunderX and OCTEON-TX SoCs
From: David Daney @ 2017-01-06 23:24 UTC (permalink / raw)
To: David Daney, Linus Walleij, Alexandre Courbot, Rob Herring,
Mark Rutland, linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: David Daney
In-Reply-To: <1483491334-167095-1-git-send-email-ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This version is obsolete. v2 has been sent.
Thanks,
David Daney
On 01/03/2017 04:55 PM, David Daney wrote:
> From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> The subject says it all. The Cavium ThunderX and OCTEON-TX family of
> SoCs have on-chip GPIO lines. This patch set adds a driver for these.
>
> David Daney (3):
> dt-bindings: gpio: Add binding documentation for gpio-thunderx
> gpio: Add gpio driver support for ThunderX and OCTEON-TX
> MAINTAINERS: Add entry for THUNDERX GPIO Driver.
>
> .../devicetree/bindings/gpio/gpio-thunderx.txt | 33 ++
> MAINTAINERS | 5 +
> drivers/gpio/Kconfig | 7 +
> drivers/gpio/Makefile | 1 +
> drivers/gpio/gpio-thunderx.c | 467 +++++++++++++++++++++
> 5 files changed, 513 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
> create mode 100644 drivers/gpio/gpio-thunderx.c
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 3/3] MAINTAINERS: Add entry for THUNDERX GPIO Driver.
From: David Daney @ 2017-01-06 23:23 UTC (permalink / raw)
To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
linux-gpio, devicetree, linux-kernel
Cc: David Daney
In-Reply-To: <1483744980-25898-1-git-send-email-ddaney.cavm@gmail.com>
From: David Daney <david.daney@cavium.com>
Signed-off-by: David Daney <david.daney@cavium.com>
---
MAINTAINERS | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 97d0b68..3d254e9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10886,6 +10886,11 @@ M: Andreas Noever <andreas.noever@gmail.com>
S: Maintained
F: drivers/thunderbolt/
+THUNDERX GPIO DRIVER
+M: David Daney <david.daney@cavium.com>
+S: Maintained
+F: drivers/gpio/gpio-thunderx.c
+
TI BQ27XXX POWER SUPPLY DRIVER
R: Andrew F. Davis <afd@ti.com>
F: include/linux/power/bq27xxx_battery.h
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 2/3] gpio: Add gpio driver support for ThunderX and OCTEON-TX
From: David Daney @ 2017-01-06 23:22 UTC (permalink / raw)
To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: David Daney
In-Reply-To: <1483744980-25898-1-git-send-email-ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Cavium ThunderX and OCTEON-TX are arm64 based SoCs. Add driver for
the on-chip GPIO pins.
Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
---
drivers/gpio/Kconfig | 8 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-thunderx.c | 487 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 496 insertions(+)
create mode 100644 drivers/gpio/gpio-thunderx.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d5d3654..e691a5e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -421,6 +421,14 @@ config GPIO_TS4800
help
This driver support TS-4800 FPGA GPIO controllers.
+config GPIO_THUNDERX
+ tristate "Cavium ThunderX/OCTEON-TX GPIO"
+ depends on ARCH_THUNDER || (64BIT && COMPILE_TEST)
+ select GPIOLIB_IRQCHIP
+ help
+ Say yes here to support the on-chip GPIO lines on the ThunderX
+ and OCTEON-TX families of SoCs.
+
config GPIO_TZ1090
bool "Toumaz Xenif TZ1090 GPIO support"
depends on SOC_TZ1090
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a7676b8..c62bc72 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -108,6 +108,7 @@ obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
obj-$(CONFIG_GPIO_TB10X) += gpio-tb10x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
obj-$(CONFIG_GPIO_TEGRA) += gpio-tegra.o
+obj-$(CONFIG_GPIO_THUNDERX) += gpio-thunderx.o
obj-$(CONFIG_GPIO_TIMBERDALE) += gpio-timberdale.o
obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o
obj-$(CONFIG_GPIO_TPIC2810) += gpio-tpic2810.o
diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c
new file mode 100644
index 0000000..089d8d4
--- /dev/null
+++ b/drivers/gpio/gpio-thunderx.c
@@ -0,0 +1,487 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2016, 2017 Cavium Inc.
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+
+#define GPIO_RX_DAT 0x0
+#define GPIO_TX_SET 0x8
+#define GPIO_TX_CLR 0x10
+#define GPIO_CONST 0x90
+#define GPIO_CONST_GPIOS_MASK 0xff
+#define GPIO_BIT_CFG 0x400
+#define GPIO_BIT_CFG_TX_OE BIT(0)
+#define GPIO_BIT_CFG_PIN_XOR BIT(1)
+#define GPIO_BIT_CFG_INT_EN BIT(2)
+#define GPIO_BIT_CFG_INT_TYPE BIT(3)
+#define GPIO_BIT_CFG_FIL_CNT_SHIFT 4
+#define GPIO_BIT_CFG_FIL_SEL_SHIFT 8
+#define GPIO_BIT_CFG_TX_OD BIT(12)
+#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK(25, 16)
+#define GPIO_INTR 0x800
+#define GPIO_INTR_INTR BIT(0)
+#define GPIO_INTR_INTR_W1S BIT(1)
+#define GPIO_INTR_ENA_W1C BIT(2)
+#define GPIO_INTR_ENA_W1S BIT(3)
+#define GPIO_2ND_BANK 0x1400
+
+#define GLITCH_FILTER_400NS ((4ull << GPIO_BIT_CFG_FIL_SEL_SHIFT) | \
+ (9ull << GPIO_BIT_CFG_FIL_CNT_SHIFT))
+
+static unsigned int bit_cfg_reg(unsigned int line)
+{
+ return 8 * line + GPIO_BIT_CFG;
+}
+
+static unsigned int intr_reg(unsigned int line)
+{
+ return 8 * line + GPIO_INTR;
+}
+
+struct thunderx_gpio;
+
+struct thunderx_irqdev {
+ struct thunderx_gpio *gpio;
+ char *name;
+ unsigned int line;
+};
+
+struct thunderx_gpio {
+ struct gpio_chip chip;
+ u8 __iomem *register_base;
+ struct msix_entry *msix_entries;
+ struct thunderx_irqdev *irqdev_entries;
+ raw_spinlock_t lock;
+ unsigned long invert_mask[2];
+ unsigned long od_mask[2];
+ int base_msi;
+};
+
+
+/*
+ * Check (and WARN) that the pin is available for GPIO. We will not
+ * allow modification of the state of non-GPIO pins from this driver.
+ */
+static bool thunderx_gpio_is_gpio(struct thunderx_gpio *gpio,
+ unsigned int line)
+{
+ u64 bit_cfg = readq(gpio->register_base + bit_cfg_reg(line));
+ bool rv = (bit_cfg & GPIO_BIT_CFG_PIN_SEL_MASK) == 0;
+
+ WARN_RATELIMIT(!rv, "Pin %d not available for GPIO\n", line);
+
+ return rv;
+}
+
+static int thunderx_gpio_dir_in(struct gpio_chip *chip, unsigned int line)
+{
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+
+ if (!thunderx_gpio_is_gpio(gpio, line))
+ return -EIO;
+
+ raw_spin_lock(&gpio->lock);
+ clear_bit(line, gpio->invert_mask);
+ clear_bit(line, gpio->od_mask);
+ writeq(GLITCH_FILTER_400NS, gpio->register_base + bit_cfg_reg(line));
+ raw_spin_unlock(&gpio->lock);
+ return 0;
+}
+
+static void thunderx_gpio_set(struct gpio_chip *chip, unsigned int line,
+ int value)
+{
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ int bank = line / 64;
+ int bank_bit = line % 64;
+
+ void __iomem *reg = gpio->register_base +
+ (bank * GPIO_2ND_BANK) + (value ? GPIO_TX_SET : GPIO_TX_CLR);
+
+ writeq(1ull << bank_bit, reg);
+}
+
+static int thunderx_gpio_dir_out(struct gpio_chip *chip, unsigned int line,
+ int value)
+{
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ u64 bit_cfg = GPIO_BIT_CFG_TX_OE;
+
+ if (!thunderx_gpio_is_gpio(gpio, line))
+ return -EIO;
+
+ raw_spin_lock(&gpio->lock);
+
+ thunderx_gpio_set(chip, line, value);
+
+ if (test_bit(line, gpio->invert_mask))
+ bit_cfg |= GPIO_BIT_CFG_PIN_XOR;
+
+ if (test_bit(line, gpio->od_mask))
+ bit_cfg |= GPIO_BIT_CFG_TX_OD;
+
+ writeq(bit_cfg, gpio->register_base + bit_cfg_reg(line));
+
+ raw_spin_unlock(&gpio->lock);
+ return 0;
+}
+
+/*
+ * Weird, setting open-drain mode causes signal inversion. Note this
+ * so we can compensate in the dir_out function.
+ */
+static int thunderx_gpio_set_single_ended(struct gpio_chip *chip,
+ unsigned int line,
+ enum single_ended_mode mode)
+{
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+
+ if (mode == LINE_MODE_OPEN_SOURCE)
+ return -ENOTSUPP;
+
+ if (!thunderx_gpio_is_gpio(gpio, line))
+ return -EIO;
+
+ raw_spin_lock(&gpio->lock);
+ if (mode == LINE_MODE_OPEN_DRAIN) {
+ set_bit(line, gpio->invert_mask);
+ set_bit(line, gpio->od_mask);
+ } else {
+ clear_bit(line, gpio->invert_mask);
+ clear_bit(line, gpio->od_mask);
+ }
+ raw_spin_unlock(&gpio->lock);
+
+ return 0;
+}
+
+static int thunderx_gpio_get(struct gpio_chip *chip, unsigned int line)
+{
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ int bank = line / 64;
+ int bank_bit = line % 64;
+ u64 read_bits = readq(gpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_RX_DAT);
+
+ read_bits >>= bank_bit;
+
+ if (test_bit(line, gpio->invert_mask))
+ return !(read_bits & 1);
+ else
+ return read_bits & 1;
+}
+
+static void thunderx_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask,
+ unsigned long *bits)
+{
+ int bank;
+ u64 set_bits, clear_bits;
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+
+ for (bank = 0; bank <= chip->ngpio / 64; bank++) {
+ set_bits = bits[bank] & mask[bank];
+ clear_bits = ~bits[bank] & mask[bank];
+ writeq(set_bits, gpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_SET);
+ writeq(clear_bits, gpio->register_base + (bank * GPIO_2ND_BANK) + GPIO_TX_CLR);
+ }
+}
+
+static irqreturn_t thunderx_gpio_chain_handler(int irq, void *dev)
+{
+ struct thunderx_irqdev *irqdev = dev;
+ int chained_irq;
+ int ret;
+
+ chained_irq = irq_find_mapping(irqdev->gpio->chip.irqdomain,
+ irqdev->line);
+ if (!chained_irq)
+ return IRQ_NONE;
+
+ ret = generic_handle_irq(chained_irq);
+
+ return ret ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int thunderx_gpio_irq_request_resources(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+ struct thunderx_irqdev *irqdev;
+ int err;
+
+ if (!thunderx_gpio_is_gpio(gpio, line))
+ return -EIO;
+
+ irqdev = gpio->irqdev_entries + line;
+
+ irqdev->gpio = gpio;
+ irqdev->line = line;
+ irqdev->name = devm_kasprintf(chip->parent, GFP_KERNEL,
+ "gpio-%d", line + chip->base);
+
+ writeq(GPIO_INTR_ENA_W1C, gpio->register_base + intr_reg(line));
+
+ err = devm_request_irq(chip->parent, gpio->msix_entries[line].vector,
+ thunderx_gpio_chain_handler, IRQF_NO_THREAD, irqdev->name, irqdev);
+ return err;
+}
+
+static void thunderx_gpio_irq_release_resources(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+ struct thunderx_irqdev *irqdev;
+
+ irqdev = gpio->irqdev_entries + line;
+
+ /*
+ * The request_resources/release_resources functions may be
+ * called multiple times in the lifitime of the driver, so we
+ * need to clean up the devm_* things to avoid a resource
+ * leak.
+ */
+ devm_free_irq(chip->parent, gpio->msix_entries[line].vector, irqdev);
+
+ writeq(GPIO_INTR_ENA_W1C, gpio->register_base + intr_reg(line));
+
+ devm_kfree(chip->parent, irqdev->name);
+}
+
+static void thunderx_gpio_irq_ack(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+
+ writeq(GPIO_INTR_INTR,
+ gpio->register_base + intr_reg(line));
+}
+
+static void thunderx_gpio_irq_mask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+
+ writeq(GPIO_INTR_ENA_W1C, gpio->register_base + intr_reg(line));
+}
+
+static void thunderx_gpio_irq_mask_ack(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+
+ writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR,
+ gpio->register_base + intr_reg(line));
+}
+
+static void thunderx_gpio_irq_unmask(struct irq_data *data)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+
+ writeq(GPIO_INTR_ENA_W1S, gpio->register_base + intr_reg(line));
+}
+
+static int thunderx_gpio_irq_set_type(struct irq_data *data,
+ unsigned int flow_type)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
+ struct thunderx_gpio *gpio = container_of(chip, struct thunderx_gpio, chip);
+ unsigned int line = data->hwirq;
+ u64 bit_cfg;
+
+ irqd_set_trigger_type(data, flow_type);
+
+ bit_cfg = GLITCH_FILTER_400NS | GPIO_BIT_CFG_INT_EN;
+
+ if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+ irq_set_handler_locked(data, handle_edge_irq);
+ bit_cfg |= GPIO_BIT_CFG_INT_TYPE;
+ } else {
+ irq_set_handler_locked(data, handle_level_irq);
+ }
+
+ raw_spin_lock(&gpio->lock);
+ if (flow_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)) {
+ bit_cfg |= GPIO_BIT_CFG_PIN_XOR;
+ set_bit(line, gpio->invert_mask);
+ } else {
+ clear_bit(line, gpio->invert_mask);
+ }
+ clear_bit(line, gpio->od_mask);
+ writeq(bit_cfg, gpio->register_base + bit_cfg_reg(line));
+ raw_spin_unlock(&gpio->lock);
+
+ return IRQ_SET_MASK_OK;
+}
+
+/*
+ * Interrupts are chained from underlying MSI-X vectors. We have
+ * these irq_chip functions to be able to handle level triggering
+ * semantics and other acknowledgment tasks associated with the GPIO
+ * mechanism.
+ */
+static struct irq_chip thunderx_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_enable = thunderx_gpio_irq_unmask,
+ .irq_disable = thunderx_gpio_irq_mask,
+ .irq_ack = thunderx_gpio_irq_ack,
+ .irq_mask = thunderx_gpio_irq_mask,
+ .irq_mask_ack = thunderx_gpio_irq_mask_ack,
+ .irq_unmask = thunderx_gpio_irq_unmask,
+ .irq_set_type = thunderx_gpio_irq_set_type,
+ .irq_request_resources = thunderx_gpio_irq_request_resources,
+ .irq_release_resources = thunderx_gpio_irq_release_resources,
+ .flags = IRQCHIP_SET_TYPE_MASKED
+};
+
+static int thunderx_gpio_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ void __iomem * const *tbl;
+ struct device *dev = &pdev->dev;
+ struct thunderx_gpio *gpio;
+ struct gpio_chip *chip;
+ int ngpio, i;
+ int err = 0;
+
+ gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio)
+ return -ENOMEM;
+
+ raw_spin_lock_init(&gpio->lock);
+ chip = &gpio->chip;
+
+ pci_set_drvdata(pdev, gpio);
+
+ err = pcim_enable_device(pdev);
+ if (err) {
+ dev_err(dev, "Failed to enable PCI device: err %d\n", err);
+ goto out;
+ }
+
+ err = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME);
+ if (err) {
+ dev_err(dev, "Failed to iomap PCI device: err %d\n", err);
+ goto out;
+ }
+
+ tbl = pcim_iomap_table(pdev);
+ gpio->register_base = tbl[0];
+ if (!gpio->register_base) {
+ dev_err(dev, "Cannot map PCI resource\n");
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (pdev->subsystem_device == 0xa10a) {
+ /* CN88XX has no GPIO_CONST register*/
+ ngpio = 50;
+ gpio->base_msi = 48;
+ } else {
+ u64 c = readq(gpio->register_base + GPIO_CONST);
+
+ ngpio = c & GPIO_CONST_GPIOS_MASK;
+ gpio->base_msi = (c >> 8) & 0xff;
+ }
+
+ gpio->msix_entries = devm_kzalloc(dev,
+ sizeof(struct msix_entry) * ngpio,
+ GFP_KERNEL);
+ if (!gpio->msix_entries) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ gpio->irqdev_entries = devm_kzalloc(dev,
+ sizeof(struct thunderx_irqdev) * ngpio,
+ GFP_KERNEL);
+ if (!gpio->irqdev_entries) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < ngpio; i++)
+ gpio->msix_entries[i].entry = gpio->base_msi + (2 * i);
+
+ err = pci_enable_msix(pdev, gpio->msix_entries, ngpio);
+ if (err < 0)
+ goto out;
+
+ chip->label = KBUILD_MODNAME;
+ chip->parent = dev;
+ chip->owner = THIS_MODULE;
+ chip->base = -1; /* System allocated */
+ chip->can_sleep = false;
+ chip->ngpio = ngpio;
+ chip->direction_input = thunderx_gpio_dir_in;
+ chip->get = thunderx_gpio_get;
+ chip->direction_output = thunderx_gpio_dir_out;
+ chip->set = thunderx_gpio_set;
+ chip->set_multiple = thunderx_gpio_set_multiple;
+ chip->set_single_ended = thunderx_gpio_set_single_ended;
+ err = gpiochip_add(chip);
+ if (err)
+ goto out;
+
+ err = gpiochip_irqchip_add(chip, &thunderx_gpio_irq_chip, 0,
+ handle_level_irq, IRQ_TYPE_NONE);
+ if (err) {
+ dev_err(dev, "gpiochip_irqchip_add failed: %d\n", err);
+ goto irqchip_out;
+ }
+
+ dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n",
+ ngpio, chip->base);
+ return 0;
+
+irqchip_out:
+ gpiochip_remove(chip);
+out:
+ pci_set_drvdata(pdev, NULL);
+ return err;
+}
+
+static void thunderx_gpio_remove(struct pci_dev *pdev)
+{
+ struct thunderx_gpio *gpio = pci_get_drvdata(pdev);
+
+ gpiochip_remove(&gpio->chip);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static const struct pci_device_id thunderx_gpio_id_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, 0xA00A) },
+ { 0, } /* end of table */
+};
+
+MODULE_DEVICE_TABLE(pci, thunderx_gpio_id_table);
+
+static struct pci_driver thunderx_gpio_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = thunderx_gpio_id_table,
+ .probe = thunderx_gpio_probe,
+ .remove = thunderx_gpio_remove,
+};
+
+module_pci_driver(thunderx_gpio_driver);
+
+MODULE_DESCRIPTION("Cavium Inc. ThunderX/OCTEON-TX GPIO Driver");
+MODULE_LICENSE("GPL");
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 1/3] dt-bindings: gpio: Add binding documentation for gpio-thunderx
From: David Daney @ 2017-01-06 23:22 UTC (permalink / raw)
To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: David Daney
In-Reply-To: <1483744980-25898-1-git-send-email-ddaney.cavm-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/gpio/gpio-thunderx.txt | 27 ++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
diff --git a/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt b/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
new file mode 100644
index 0000000..3f883ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
@@ -0,0 +1,27 @@
+Cavium ThunderX/OCTEON-TX GPIO controller bindings
+
+Required Properties:
+- reg: The controller bus address.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Must be 2.
+ - First cell is the GPIO pin number relative to the controller.
+ - Second cell is a standard generic flag bitfield as described in gpio.txt.
+
+Optional Properties:
+- compatible: "cavium,thunder-8890-gpio", unused as PCI driver binding is used.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Must be present and have value of 2 if
+ "interrupt-controller" is present.
+ - First cell is the GPIO pin number relative to the controller.
+ - Second cell is triggering flags as defined in interrupts.txt.
+
+Example:
+
+gpio_6_0: gpio@6,0 {
+ compatible = "cavium,thunder-8890-gpio";
+ reg = <0x3000 0 0 0 0>; /* DEVFN = 0x30 (6:0) */
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+};
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 0/3] GPIO: Add driver for ThunderX and OCTEON-TX SoCs
From: David Daney @ 2017-01-06 23:22 UTC (permalink / raw)
To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
linux-gpio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: David Daney
From: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
The Cavium ThunderX and OCTEON-TX family of SoCs have on-chip GPIO
lines. This patch set adds a driver for these.
Changes from v1:
- in 1/3: Addressed Rob Harring's comments.
- in 2/3: Trivial cleanups found in internal review + add some
comments.
David Daney (3):
dt-bindings: gpio: Add binding documentation for gpio-thunderx
gpio: Add gpio driver support for ThunderX and OCTEON-TX
MAINTAINERS: Add entry for THUNDERX GPIO Driver.
.../devicetree/bindings/gpio/gpio-thunderx.txt | 27 ++
MAINTAINERS | 5 +
drivers/gpio/Kconfig | 8 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-thunderx.c | 487 +++++++++++++++++++++
5 files changed, 528 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-thunderx.txt
create mode 100644 drivers/gpio/gpio-thunderx.c
--
1.8.3.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] i2c: core: helper function to detect slave mode
From: Andy Shevchenko @ 2017-01-06 22:45 UTC (permalink / raw)
To: Vladimir Zapolskiy
Cc: Luis Oliveira, Wolfram Sang, Rob Herring, Mark Rutland,
Jarkko Nikula, Andy Shevchenko, Mika Westerberg,
linux-i2c-u79uwXL29TY76Z2rM5mHXA, devicetree,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w, Joao Pinto,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <73246c4a-504c-52d7-dde4-970a45dca0bd-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org>
On Fri, Jan 6, 2017 at 11:46 PM, Vladimir Zapolskiy <vz-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org> wrote:
>> + if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
>
> IS_BUILTIN(CONFIG_OF) looks excessive, check for non-NULL dev->of_node
> should be sufficient.
Sorry, but you missed the point.
This will enable compile time optimization and basically be collapsed to no-op.
>> + }
>> + } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
>> + dev_dbg(dev, "ACPI slave is not supported yet\n");
>> + }
>
> If so, then it might be better to drop else-if stub for now.
Please, don't.
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH linux 2/6] hwmon: occ: Add sysfs interface
From: Edward James @ 2017-01-06 22:17 UTC (permalink / raw)
To: Guenter Roeck
Cc: andrew, corbet, devicetree, eajames.ibm, jdelvare, joel,
linux-doc, linux-hwmon, linux-i2c, linux-kernel, mark.rutland,
robh+dt, wsa
In-Reply-To: <20161230193404.GB8516@roeck-us.net>
[-- Attachment #1: Type: text/plain, Size: 24685 bytes --]
Hi,
Thanks for your comments Guenter. Sorry to switch email addresses, but
gmail is rejecting my messages to this thread.
Guenter Roeck <linux@roeck-us.net> wrote on 12/30/2016 01:34:04 PM:
> On Fri, Dec 30, 2016 at 11:56:04AM -0600, eajames.ibm@gmail.com wrote:
> > From: "Edward A. James" <eajames@us.ibm.com>
> >
> > Add a generic mechanism to expose the sensors provided by the OCC in
> > sysfs.
> >
> > Signed-off-by: Edward A. James <eajames@us.ibm.com>
> > Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
> > Reviewed-by: Andrew Jeffery <andrew@aj.id.au>
> > ---
> > Documentation/hwmon/occ | 48 +++++
> > drivers/hwmon/occ/Makefile | 2 +-
> > drivers/hwmon/occ/occ_sysfs.c | 492 +++++++++++++++++++++++++++++
> +++++++++++++
> > drivers/hwmon/occ/occ_sysfs.h | 52 +++++
> > 4 files changed, 593 insertions(+), 1 deletion(-)
> > create mode 100644 drivers/hwmon/occ/occ_sysfs.c
> > create mode 100644 drivers/hwmon/occ/occ_sysfs.h
> >
> > diff --git a/Documentation/hwmon/occ b/Documentation/hwmon/occ
> > index 79d1642..1ee8689 100644
> > --- a/Documentation/hwmon/occ
> > +++ b/Documentation/hwmon/occ
> > @@ -25,6 +25,54 @@ Currently, all versions of the OCC support four
> types of sensor data: power,
> > temperature, frequency, and "caps," which indicate limits and
> thresholds used
> > internally on the OCC.
> >
> > +sysfs Entries
> > +-------------
> > +
> > +The OCC driver uses the hwmon sysfs framework to provide data to
userspace.
> > +
> > +The driver exports two sysfs files for each frequency,
> temperature, and power
> > +sensor. These are "input" and "label". The input file contains
> the value of the
> > +sensor. The label file contains the sensor id. The sensor id is the
unique
> > +internal OCC identifier. Sensor ids may be provided by the OCC
> specification.
> > +The names of these files will be in the following format:
> > + <sensor type><sensor index>_input
> > + <sensor type><sensor index>_label
> > +Sensor types will be one of "temp", "freq", or "power". The sensor
index is
> > +an index to differentiate different sensor files. For example, a
single
> > +temperature sensor will have two sysfs files: temp1_input and
temp1_label.
> > +
> > +Caps sensors are exported differently. For each caps sensor, the
> driver will
> > +export 6 entries:
> > + curr_powercap - current power cap in watts
> > + curr_powerreading - current power output in watts
> > + norm_powercap - power cap without redundant power
> > + max_powercap - maximum power cap that can be set in watts
> > + min_powercap - minimum power cap that can be set in watts
> > + user_powerlimit - power limit specified by the user in watts
> > +In addition, the OCC driver for P9 will export a 7th entry:
> > + user_powerlimit_source - can be one of two values depending on who
set
> > + the user_powerlimit. 0x1 - out of band from BMC or host. 0x2 -
> > + in band from other source.
> > +The format for these files is caps<sensor index>_<entry type>. For
example,
> > +caps1_curr_powercap.
> > +
> > +The driver also provides a number of sysfs entries through hwmon to
better
> > +control the driver and monitor the OCC.
> > + powercap - read or write the OCC user power limit in watts.
> > + name - read the name of the driver
> > + update_interval - read or write the minimum interval for polling
the
> > + OCC.
> > +
> > +The driver also exports a single sysfs file through the
> communication protocol
> > +device (see BMC - Host Communications). The filename is "online"
> and represents
> > +the status of the OCC with respect to the driver. The OCC can be
> in one of two
> > +states: OCC polling enabled or OCC polling disabled. The purpose
> of this file
> > +is to control the behavior of the driver and it's hwmon sysfs
> entries, not to
> > +infer any information about the state of the physical OCC. Reading the
file
> > +returns either a 0 (polling disabled) or 1 (polling enabled).
> Writing 1 to the
> > +file enables OCC polling in the driver if communications can be
established
> > +with the OCC. Writing a 0 to the driver disables OCC polling.
> > +
> > BMC - Host Communications
> > -------------------------
> >
> > diff --git a/drivers/hwmon/occ/Makefile b/drivers/hwmon/occ/Makefile
> > index 93cb52f..a6881f9 100644
> > --- a/drivers/hwmon/occ/Makefile
> > +++ b/drivers/hwmon/occ/Makefile
> > @@ -1 +1 @@
> > -obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o
> > +obj-$(CONFIG_SENSORS_PPC_OCC) += occ.o occ_sysfs.o
> > diff --git a/drivers/hwmon/occ/occ_sysfs.c
b/drivers/hwmon/occ/occ_sysfs.c
> > new file mode 100644
> > index 0000000..b0e063da
> > --- /dev/null
> > +++ b/drivers/hwmon/occ/occ_sysfs.c
> > @@ -0,0 +1,492 @@
> > +/*
> > + * occ_sysfs.c - OCC sysfs interface
> > + *
> > + * This file contains the methods and data structures for
> implementing the OCC
> > + * hwmon sysfs entries.
> > + *
> > + * Copyright 2016 IBM Corp.
> > + *
> > + * This program is free software; you can redistribute it and/or
modify
> > + * it under the terms of the GNU General Public License as published
by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/slab.h>
> > +#include <linux/jiffies.h>
> > +#include <linux/hwmon.h>
> > +#include <linux/hwmon-sysfs.h>
> > +#include <linux/err.h>
> > +#include <linux/mutex.h>
> > +#include <linux/delay.h>
> > +#include <linux/kernel.h>
> > +#include <linux/device.h>
> > +
> > +#include "occ_sysfs.h"
> > +
> > +#define MAX_SENSOR_ATTR_LEN 32
> > +
> > +#define RESP_RETURN_CMD_INVAL 0x13
> > +
> > +struct sensor_attr_data {
> > + enum sensor_type type;
> > + u32 hwmon_index;
> > + u32 attr_id;
> > + char name[MAX_SENSOR_ATTR_LEN];
> > + struct device_attribute dev_attr;
> > +};
> > +
> > +static ssize_t show_input(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + int val;
> > + struct sensor_attr_data *sdata = container_of(attr,
> > + struct sensor_attr_data,
> > + dev_attr);
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + val = occ_get_sensor_value(driver->occ, sdata->type,
> > + sdata->hwmon_index - 1);
> > + if (sdata->type == TEMP)
> > + val *= 1000; /* in millidegree Celsius */
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
> > +}
> > +
> > +/* show_label provides the OCC sensor id. The sensor id will be either
a
> > + * 2-byte (for P8) or 4-byte (for P9) value. The sensor id is a way to
> > + * identify what each sensor represents, according to the OCC
> specification.
> > + */
> > +static ssize_t show_label(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + int val;
> > + struct sensor_attr_data *sdata = container_of(attr,
> > + struct sensor_attr_data,
> > + dev_attr);
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + val = occ_get_sensor_id(driver->occ, sdata->type,
> > + sdata->hwmon_index - 1);
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
> > +}
> > +
> > +static ssize_t show_caps(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + int val;
> > + struct caps_sensor *sensor;
> > + struct sensor_attr_data *sdata = container_of(attr,
> > + struct sensor_attr_data,
> > + dev_attr);
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + sensor = occ_get_sensor(driver->occ, CAPS);
> > + if (!sensor) {
> > + val = -1;
> > + return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
> > + }
> > +
> > + val = occ_get_caps_value(driver->occ, sensor, sdata->hwmon_index -
1,
> > + sdata->attr_id);
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%d\n", val);
> > +}
> > +
> > +static ssize_t show_update_interval(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%lu\n", driver->
update_interval);
> > +}
> > +
> > +static ssize_t store_update_interval(struct device *dev,
> > + struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > + unsigned long val;
> > + int rc;
> > +
> > + rc = kstrtoul(buf, 10, &val);
> > + if (rc)
> > + return rc;
> > +
> > + driver->update_interval = val;
> > + occ_set_update_interval(driver->occ, val);
> > +
> > + return count;
> > +}
> > +
> > +static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO,
> show_update_interval,
> > + store_update_interval);
> > +
> > +static ssize_t show_name(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + return snprintf(buf, PAGE_SIZE - 1, "occ\n");
> > +}
> > +
> > +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
> > +
> > +static ssize_t show_user_powercap(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%u\n", driver->user_powercap);
> > +}
> > +
> > +static ssize_t store_user_powercap(struct device *dev,
> > + struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > + u16 val;
> > + int rc;
> > +
> > + rc = kstrtou16(buf, 10, &val);
> > + if (rc)
> > + return rc;
> > +
> > + dev_dbg(dev, "set user powercap to: %d\n", val);
> > + rc = occ_set_user_powercap(driver->occ, val);
> > + if (rc) {
> > + dev_err(dev, "set user powercap failed: 0x%x\n", rc);
> > + if (rc == RESP_RETURN_CMD_INVAL) {
> > + dev_err(dev, "set invalid powercap value: %d\n", val);
> > + return -EINVAL;
> > + }
> > +
> > + return rc;
> > + }
> > +
> > + driver->user_powercap = val;
> > +
> > + return count;
> > +}
> > +
> > +static DEVICE_ATTR(user_powercap, S_IWUSR | S_IRUGO,
show_user_powercap,
> > + store_user_powercap);
> > +
> > +static void deinit_sensor_groups(struct device *dev,
> > + struct sensor_group *sensor_groups)
> > +{
> > + int i;
> > +
> > + for (i = 0; i < MAX_OCC_SENSOR_TYPE; i++) {
> > + if (sensor_groups[i].group.attrs)
> > + devm_kfree(dev, sensor_groups[i].group.attrs);
> > + if (sensor_groups[i].sattr)
> > + devm_kfree(dev, sensor_groups[i].sattr);
> > + sensor_groups[i].group.attrs = NULL;
> > + sensor_groups[i].sattr = NULL;
> > + }
> > +}
> > +
> > +static void sensor_attr_init(struct sensor_attr_data *sdata,
> > + char *sensor_group_name,
> > + char *attr_name,
> > + ssize_t (*show)(struct device *dev,
> > + struct device_attribute *attr,
> > + char *buf))
> > +{
> > + sysfs_attr_init(&sdata->dev_attr.attr);
> > +
> > + snprintf(sdata->name, MAX_SENSOR_ATTR_LEN, "%s%d_%s",
> > + sensor_group_name, sdata->hwmon_index, attr_name);
> > + sdata->dev_attr.attr.name = sdata->name;
> > + sdata->dev_attr.attr.mode = S_IRUGO;
> > + sdata->dev_attr.show = show;
> > +}
> > +
> > +static int create_sensor_group(struct occ_sysfs *driver,
> > + enum sensor_type type, int sensor_num)
> > +{
> > + struct device *dev = driver->dev;
> > + struct sensor_group *sensor_groups = driver->sensor_groups;
> > + struct sensor_attr_data *sdata;
> > + int rc, i;
> > +
> > + /* each sensor has 'label' and 'input' attributes */
> > + sensor_groups[type].group.attrs =
> > + devm_kzalloc(dev, sizeof(struct attribute *) *
> > + sensor_num * 2 + 1, GFP_KERNEL);
> > + if (!sensor_groups[type].group.attrs) {
> > + rc = -ENOMEM;
> > + goto err;
> > + }
> > +
> > + sensor_groups[type].sattr =
> > + devm_kzalloc(dev, sizeof(struct sensor_attr_data) *
> > + sensor_num * 2, GFP_KERNEL);
> > + if (!sensor_groups[type].sattr) {
> > + rc = -ENOMEM;
> > + goto err;
> > + }
> > +
> > + for (i = 0; i < sensor_num; i++) {
> > + sdata = &sensor_groups[type].sattr[i];
> > + /* hwmon attributes index starts from 1 */
> > + sdata->hwmon_index = i + 1;
> > + sdata->type = type;
> > + sensor_attr_init(sdata, sensor_groups[type].name, "input",
> > + show_input);
> > + sensor_groups[type].group.attrs[i] = &sdata->dev_attr.attr;
> > +
> > + sdata = &sensor_groups[type].sattr[i + sensor_num];
> > + sdata->hwmon_index = i + 1;
> > + sdata->type = type;
> > + sensor_attr_init(sdata, sensor_groups[type].name, "label",
> > + show_label);
> > + sensor_groups[type].group.attrs[i + sensor_num] =
> > + &sdata->dev_attr.attr;
> > + }
> > +
> > + rc = sysfs_create_group(&dev->kobj, &sensor_groups[type].group);
> > + if (rc)
> > + goto err;
> > +
> > + return 0;
> > +err:
> > + deinit_sensor_groups(dev, sensor_groups);
> > + return rc;
> > +}
> > +
> > +static void caps_sensor_attr_init(struct sensor_attr_data *sdata,
> > + char *attr_name, uint32_t hwmon_index,
> > + uint32_t attr_id)
> > +{
> > + sdata->type = CAPS;
> > + sdata->hwmon_index = hwmon_index;
> > + sdata->attr_id = attr_id;
> > +
> > + snprintf(sdata->name, MAX_SENSOR_ATTR_LEN, "%s%d_%s",
> > + "caps", sdata->hwmon_index, attr_name);
> > +
> > + sysfs_attr_init(&sdata->dev_attr.attr);
> > + sdata->dev_attr.attr.name = sdata->name;
> > + sdata->dev_attr.attr.mode = S_IRUGO;
> > + sdata->dev_attr.show = show_caps;
> > +}
> > +
> > +static int create_caps_sensor_group(struct occ_sysfs *driver, int
> sensor_num)
> > +{
> > + struct device *dev = driver->dev;
> > + struct sensor_group *sensor_groups = driver->sensor_groups;
> > + int field_num = driver->num_caps_fields;
> > + struct sensor_attr_data *sdata;
> > + int i, j, rc;
> > +
> > + sensor_groups[CAPS].group.attrs =
> > + devm_kzalloc(dev, sizeof(struct attribute *) * sensor_num *
> > + field_num + 1, GFP_KERNEL);
> > + if (!sensor_groups[CAPS].group.attrs) {
> > + rc = -ENOMEM;
> > + goto err;
> > + }
> > +
> > + sensor_groups[CAPS].sattr =
> > + devm_kzalloc(dev, sizeof(struct sensor_attr_data) *
> > + sensor_num * field_num, GFP_KERNEL);
> > + if (!sensor_groups[CAPS].sattr) {
> > + rc = -ENOMEM;
> > + goto err;
> > + }
> > +
> > + for (j = 0; j < sensor_num; ++j) {
> > + for (i = 0; i < field_num; ++i) {
> > + sdata = &sensor_groups[CAPS].sattr[j * field_num + i];
> > + caps_sensor_attr_init(sdata,
> > + driver->caps_names[i], j + 1, i);
> > + sensor_groups[CAPS].group.attrs[j * field_num + i] =
> > + &sdata->dev_attr.attr;
> > + }
> > + }
> > +
> > + rc = sysfs_create_group(&dev->kobj, &sensor_groups[CAPS].group);
> > + if (rc)
> > + goto err;
> > +
> > + return rc;
> > +err:
> > + deinit_sensor_groups(dev, sensor_groups);
> > + return rc;
> > +}
> > +
> > +static void occ_remove_hwmon_attrs(struct occ_sysfs *driver)
> > +{
> > + struct device *dev = driver->dev;
> > +
> > + device_remove_file(dev, &dev_attr_user_powercap);
> > + device_remove_file(dev, &dev_attr_update_interval);
> > + device_remove_file(dev, &dev_attr_name);
> > +}
> > +
> > +static int occ_create_hwmon_attrs(struct occ_sysfs *driver)
> > +{
> > + int i, rc, id, sensor_num;
> > + struct device *dev = driver->dev;
> > + struct sensor_group *sensor_groups = driver->sensor_groups;
> > + struct occ_blocks *resp = NULL;
> > +
> > + occ_get_response_blocks(driver->occ, &resp);
> > +
> > + for (i = 0; i < MAX_OCC_SENSOR_TYPE; ++i)
> > + resp->sensor_block_id[i] = -1;
> > +
> > + /* read sensor data from occ */
> > + rc = occ_update_device(driver->occ);
> > + if (rc) {
> > + dev_err(dev, "cannot get occ sensor data: %d\n", rc);
> > + return rc;
> > + }
> > + if (!resp->blocks)
> > + return -ENOMEM;
> > +
> > + rc = device_create_file(dev, &dev_attr_name);
> > + if (rc)
> > + goto error;
> > +
> > + rc = device_create_file(dev, &dev_attr_update_interval);
> > + if (rc)
> > + goto error;
> > +
> > + if (resp->sensor_block_id[CAPS] >= 0) {
> > + /* user powercap: only for master OCC */
> > + rc = device_create_file(dev, &dev_attr_user_powercap);
> > + if (rc)
> > + goto error;
> > + }
> > +
> > + sensor_groups[FREQ].name = "freq";
> > + sensor_groups[TEMP].name = "temp";
> > + sensor_groups[POWER].name = "power";
> > + sensor_groups[CAPS].name = "caps";
> > +
> > + for (i = 0; i < MAX_OCC_SENSOR_TYPE; i++) {
> > + id = resp->sensor_block_id[i];
> > + if (id < 0)
> > + continue;
> > +
> > + sensor_num = resp->blocks[id].header.sensor_num;
> > + if (i == CAPS)
> > + rc = create_caps_sensor_group(driver, sensor_num);
> > + else
> > + rc = create_sensor_group(driver, i, sensor_num);
> > + if (rc)
> > + goto error;
> > + }
> > +
> > + return 0;
> > +
> > +error:
> > + dev_err(dev, "cannot create hwmon attributes: %d\n", rc);
> > + occ_remove_hwmon_attrs(driver);
> > + return rc;
> > +}
> > +
> > +static ssize_t show_occ_online(struct device *dev,
> > + struct device_attribute *attr, char *buf)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > +
> > + return snprintf(buf, PAGE_SIZE - 1, "%u\n", driver->occ_online);
> > +}
> > +
> > +static ssize_t store_occ_online(struct device *dev,
> > + struct device_attribute *attr,
> > + const char *buf, size_t count)
> > +{
> > + struct occ_sysfs *driver = dev_get_drvdata(dev);
> > + unsigned long val;
> > + int rc;
> > +
> > + rc = kstrtoul(buf, 10, &val);
> > + if (rc)
> > + return rc;
> > +
> > + if (val == 1) {
> > + if (driver->occ_online)
> > + return count;
> > +
> > + driver->dev = hwmon_device_register(dev);
>
> hwmon_device_register() is deprecated. Please consider using
> devm_hwmon_device_register_with_info() or at least
> hwmon_device_register_with_info().
OK, I'll address this.
>
> Uuh ... and registering a hwmon device based on writing into a
sysfsattribute
> is completely out of the question.
>
> Thanks,
> Guenter
>
> > + if (IS_ERR(driver->dev))
> > + return PTR_ERR(driver->dev);
> > +
> > + dev_set_drvdata(driver->dev, driver);
> > +
> > + rc = occ_create_hwmon_attrs(driver);
> > + if (rc) {
> > + hwmon_device_unregister(driver->dev);
> > + driver->dev = NULL;
> > + return rc;
> > + }
> > + } else if (val == 0) {
> > + if (!driver->occ_online)
> > + return count;
> > +
> > + occ_remove_hwmon_attrs(driver);
> > + hwmon_device_unregister(driver->dev);
> > + driver->dev = NULL;
> > + } else
> > + return -EINVAL;
> > +
> > + driver->occ_online = val;
> > + return count;
> > +}
> > +
> > +static DEVICE_ATTR(online, S_IWUSR | S_IRUGO, show_occ_online,
> > + store_occ_online);
> > +
> > +struct occ_sysfs *occ_sysfs_start(struct device *dev, struct occ *occ,
> > + struct occ_sysfs_config *config)
> > +{
> > + struct occ_sysfs *hwmon = devm_kzalloc(dev, sizeof(struct
occ_sysfs),
> > + GFP_KERNEL);
> > + int rc;
> > +
> > + if (!hwmon)
> > + return ERR_PTR(-ENOMEM);
> > +
> > + hwmon->occ = occ;
> > + hwmon->num_caps_fields = config->num_caps_fields;
> > + hwmon->caps_names = config->caps_names;
> > +
> > + dev_set_drvdata(dev, hwmon);
> > +
> > + rc = device_create_file(dev, &dev_attr_online);
> > + if (rc)
> > + return ERR_PTR(rc);
> > +
> > + return hwmon;
> > +}
> > +EXPORT_SYMBOL(occ_sysfs_start);
> > +
> > +int occ_sysfs_stop(struct device *dev, struct occ_sysfs *driver)
> > +{
> > + if (driver->dev) {
> > + occ_remove_hwmon_attrs(driver);
> > + hwmon_device_unregister(driver->dev);
> > + }
> > +
> > + device_remove_file(driver->dev, &dev_attr_online);
> > +
> > + devm_kfree(dev, driver);
>
> Thw point of using devm_ functions is not to require remove/free
functions.
> Something is completely wrong here if you need that call.
>
> Overall, this is architectually completely wrong. One does not register
> or instantiate drivers based on writing into sysfs attributes. Please
> reconsider your approach.
We had some trouble designing this driver because the BMC only has
access to the OCC once the processor is powered on. This will happen
sometime after the BMC boots (this driver runs only on the BMC). With
no access to the OCC, we don't know what sensors are present on the
system without a large static enumeration. Also any sysfs files created
before we have OCC access won't be able to return any data.
Instead of the "online" attribute, what do you think about using the
"bind"/"unbind" API to probe the device from user space once the system
is powered on? All the hwmon registration would take place in the probe
function, it would just occur some time after boot.
Thanks again,
Eddie
>
> > +
> > + return 0;
> > +}
> > +EXPORT_SYMBOL(occ_sysfs_stop);
> > +
> > +MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>");
> > +MODULE_DESCRIPTION("OCC sysfs driver");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/hwmon/occ/occ_sysfs.h
b/drivers/hwmon/occ/occ_sysfs.h
> > new file mode 100644
> > index 0000000..2a8044f
> > --- /dev/null
> > +++ b/drivers/hwmon/occ/occ_sysfs.h
> > @@ -0,0 +1,52 @@
> > +/*
> > + * occ_sysfs.h - OCC sysfs interface
> > + *
> > + * This file contains the data structures and function prototypes
> for the OCC
> > + * hwmon sysfs entries.
> > + *
> > + * Copyright 2016 IBM Corp.
> > + *
> > + * This program is free software; you can redistribute it and/or
modify
> > + * it under the terms of the GNU General Public License as published
by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + */
> > +
> > +#ifndef __OCC_SYSFS_H__
> > +#define __OCC_SYSFS_H__
> > +
> > +#include "occ.h"
> > +
> > +struct sensor_group {
> > + char *name;
> > + struct sensor_attr_data *sattr;
> > + struct attribute_group group;
> > +};
> > +
> > +struct occ_sysfs_config {
> > + unsigned int num_caps_fields;
> > + char **caps_names;
> > +};
> > +
> > +struct occ_sysfs {
> > + struct device *dev;
> > + struct occ *occ;
> > +
> > + u16 user_powercap;
> > + bool occ_online;
> > + struct sensor_group sensor_groups[MAX_OCC_SENSOR_TYPE];
> > + unsigned long update_interval;
> > + unsigned int num_caps_fields;
> > + char **caps_names;
> > +};
> > +
> > +struct occ_sysfs *occ_sysfs_start(struct device *dev, struct occ *occ,
> > + struct occ_sysfs_config *config);
> > +int occ_sysfs_stop(struct device *dev, struct occ_sysfs *driver);
> > +
> > +#endif /* __OCC_SYSFS_H__ */
> > --
> > 1.9.1
> >
>
[-- Attachment #2: Type: text/html, Size: 35433 bytes --]
^ permalink raw reply
* Re: [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Chanwoo Choi @ 2017-01-06 22:15 UTC (permalink / raw)
To: Andi Shyti
Cc: Dmitry Torokhov, Rob Herring, Mark Rutland, Catalin Marinas,
Will Deacon, Kukjin Kim, Krzysztof Kozlowski,
Javier Martinez Canillas, Chanwoo Choi, Beomho Seo,
linux-arm-kernel, linux-input, devicetree, linux-kernel,
linux-samsung-soc, Jaechul Lee, Andi Shyti, Jaechul Lee
In-Reply-To: <CAGTfZH347ZRve20cdGLwtuf6arRAJ4Ry+HQrTubDj-RGR=K9cA@mail.gmail.com>
Hi,
2017-01-07 7:09 GMT+09:00 Chanwoo Choi <cwchoi00@gmail.com>:
> Hi,
>
> 2017-01-07 6:31 GMT+09:00 Chanwoo Choi <cwchoi00@gmail.com>:
>> Hi,
>>
>> 2017-01-06 22:43 GMT+09:00 Andi Shyti <andi.shyti@samsung.com>:
>>> From: Jaechul Lee <jcsing.lee@samsung.com>
>>>
>>> Add DT node support for TM2 touchkey device.
>>>
>>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>>> Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
>>> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
>>> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
>>> ---
>>> arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 13 +++++++++++++
>>> 1 file changed, 13 insertions(+)
>>>
>>> diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>>> index 2449266b268f..92fcc4ec8319 100644
>>> --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>>> +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>>> @@ -18,6 +18,19 @@
>>> compatible = "samsung,tm2", "samsung,exynos5433";
>>> };
>>>
>>> +&hsi2c_9 {
>>> + status = "okay";
>>> +
>>> + touchkey@20 {
>>> + compatible = "samsung,tm2-touchkey";
>>> + reg = <0x20>;
>>> + interrupt-parent = <&gpa3>;
>>> + interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
>>> + vcc-supply = <&ldo32_reg>;
>>> + vdd-supply = <&ldo33_reg>;
>>> + };
>>> +};
>>> +
>>> &ldo31_reg {
>>> regulator-name = "TSP_VDD_1.85V_AP";
>>> regulator-min-microvolt = <1850000>;
>>
>> Looks good to me.
>> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
I'm sorry to send the empty mail without any content.
I repiled the touchkey driver against compatible name.
Usually, when developing the device driver, we use the specific h/w name
but in this patch, the touckey dt node uses the h/w board name instead of
original touckhey name.
If this touckey device is used on other h/w board, I think the current
compatible name
is not proper.
So. please drop the my reviewed-by tag until completing the discussion.
I'm sorry to make the confusion.
--
Best Regards,
Chanwoo Choi
^ permalink raw reply
* Re: [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Chanwoo Choi @ 2017-01-06 22:09 UTC (permalink / raw)
To: Andi Shyti
Cc: Mark Rutland, devicetree, linux-samsung-soc, Chanwoo Choi,
Catalin Marinas, Jaechul Lee, Dmitry Torokhov, Will Deacon,
linux-kernel, Rob Herring, Javier Martinez Canillas, Kukjin Kim,
Krzysztof Kozlowski, Andi Shyti, linux-input, Jaechul Lee,
Beomho Seo, linux-arm-kernel
In-Reply-To: <CAGTfZH2QYQK190kYFbOMqJMFgH32548ra-VqzYwc5LVBJwqisA@mail.gmail.com>
Hi,
2017-01-07 6:31 GMT+09:00 Chanwoo Choi <cwchoi00@gmail.com>:
> Hi,
>
> 2017-01-06 22:43 GMT+09:00 Andi Shyti <andi.shyti@samsung.com>:
>> From: Jaechul Lee <jcsing.lee@samsung.com>
>>
>> Add DT node support for TM2 touchkey device.
>>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
>> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
>> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
>> ---
>> arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 13 +++++++++++++
>> 1 file changed, 13 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>> index 2449266b268f..92fcc4ec8319 100644
>> --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>> +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
>> @@ -18,6 +18,19 @@
>> compatible = "samsung,tm2", "samsung,exynos5433";
>> };
>>
>> +&hsi2c_9 {
>> + status = "okay";
>> +
>> + touchkey@20 {
>> + compatible = "samsung,tm2-touchkey";
>> + reg = <0x20>;
>> + interrupt-parent = <&gpa3>;
>> + interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
>> + vcc-supply = <&ldo32_reg>;
>> + vdd-supply = <&ldo33_reg>;
>> + };
>> +};
>> +
>> &ldo31_reg {
>> regulator-name = "TSP_VDD_1.85V_AP";
>> regulator-min-microvolt = <1850000>;
>
> Looks good to me.
> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
>
> --
> Best Regards,
> Chanwoo Choi
--
Best Regards,
Chanwoo Choi
^ permalink raw reply
* Re: [PATCH v5 4/5] input: tm2-touchkey: Add touchkey driver support for TM2
From: Chanwoo Choi @ 2017-01-06 22:04 UTC (permalink / raw)
To: Andi Shyti
Cc: Mark Rutland, devicetree, linux-samsung-soc, Chanwoo Choi,
Catalin Marinas, Jaechul Lee, Dmitry Torokhov, Will Deacon,
linux-kernel, Rob Herring, Javier Martinez Canillas, Kukjin Kim,
Krzysztof Kozlowski, Andi Shyti, linux-input, Jaechul Lee,
Beomho Seo, linux-arm-kernel
In-Reply-To: <20170106134350.32428-5-andi.shyti@samsung.com>
Hi,
I have a question. In this patch, the compatible name includes the
specific h/w board name(TM2). Usually, when developing the device
driver, we prefer to use the original h/w name of each device.
- "samsung,tm2-touchkey"
If this touchkey device is used on other h/w board, you should add new
compatible name.
Why don't you use the original device name?
And I have a minor comment.
2017-01-06 22:43 GMT+09:00 Andi Shyti <andi.shyti@samsung.com>:
> From: Jaechul Lee <jcsing.lee@samsung.com>
>
> This patch adds support for the TM2 touch key and led
> functionality.
>
> The driver interfaces with userspace through an input device and
> reports KEY_PHONE and KEY_BACK event types. LED brightness can be
> controlled by "/sys/class/leds/tm2-touchkey/brightness".
>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
> Reviewed-by: Andi Shyti <andi.shyti@samsung.com>
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
> ---
> drivers/input/keyboard/Kconfig | 11 ++
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/tm2-touchkey.c | 280 ++++++++++++++++++++++++++++++++++
> 3 files changed, 292 insertions(+)
> create mode 100644 drivers/input/keyboard/tm2-touchkey.c
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index cbd75cf44739..e6e98585b4b0 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -666,6 +666,17 @@ config KEYBOARD_TC3589X
> To compile this driver as a module, choose M here: the
> module will be called tc3589x-keypad.
>
> +config KEYBOARD_TM2_TOUCHKEY
> + tristate "tm2-touchkey support"
> + depends on I2C
> + depends on LEDS_CLASS
> + help
> + Say Y here to enable device driver for tm2-touchkey with
> + LED control for the Exynos5433 TM2 board.
> +
> + To compile this driver as a module, choose M here.
> + module will be called tm2-touchkey.
> +
> config KEYBOARD_TWL4030
> tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
> depends on TWL4030_CORE
> diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
> index d9f4cfcf3410..7d9acff819a7 100644
> --- a/drivers/input/keyboard/Makefile
> +++ b/drivers/input/keyboard/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
> obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
> obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
> obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
> +obj-$(CONFIG_KEYBOARD_TM2_TOUCHKEY) += tm2-touchkey.o
> obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
> obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
> obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
> diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c
> new file mode 100644
> index 000000000000..92eacb62f8e7
> --- /dev/null
> +++ b/drivers/input/keyboard/tm2-touchkey.c
> @@ -0,0 +1,280 @@
> +/*
> + * TM2 touchkey device driver
> + *
> + * Copyright 2005 Phil Blundell
> + * Copyright 2016 Samsung Electronics Co., Ltd.
> + *
> + * Author: Beomho Seo <beomho.seo@samsung.com>
> + * Author: Jaechul Lee <jcsing.lee@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/leds.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define TM2_TOUCHKEY_DEV_NAME "tm2-touchkey"
> +#define TM2_TOUCHKEY_KEYCODE_REG 0x03
> +#define TM2_TOUCHKEY_BASE_REG 0x00
> +#define TM2_TOUCHKEY_CMD_LED_ON 0x10
> +#define TM2_TOUCHKEY_CMD_LED_OFF 0x20
> +#define TM2_TOUCHKEY_BIT_PRESS_EV BIT(3)
> +#define TM2_TOUCHKEY_BIT_KEYCODE GENMASK(2, 0)
> +#define TM2_TOUCHKEY_LED_VOLTAGE_MIN 2500000
> +#define TM2_TOUCHKEY_LED_VOLTAGE_MAX 3300000
> +
> +enum {
> + TM2_TOUCHKEY_KEY_MENU = 0x1,
> + TM2_TOUCHKEY_KEY_BACK,
> +};
> +
> +struct tm2_touchkey_data {
> + struct i2c_client *client;
> + struct input_dev *input_dev;
> + struct led_classdev led_dev;
> + struct regulator_bulk_data regulators[2];
> +
> + u8 keycode_type;
> + u8 pressed;
> +};
> +
> +static void tm2_touchkey_led_brightness_set(struct led_classdev *led_dev,
> + enum led_brightness brightness)
> +{
> + struct tm2_touchkey_data *touchkey =
> + container_of(led_dev, struct tm2_touchkey_data, led_dev);
> + u32 volt;
> + u8 data;
> +
> + if (brightness == LED_OFF) {
> + volt = TM2_TOUCHKEY_LED_VOLTAGE_MIN;
> + data = TM2_TOUCHKEY_CMD_LED_OFF;
> + } else {
> + volt = TM2_TOUCHKEY_LED_VOLTAGE_MAX;
> + data = TM2_TOUCHKEY_CMD_LED_ON;
> + }
> +
> + regulator_set_voltage(touchkey->regulators[1].consumer, volt, volt);
I don't force the modification. It is minor comment.
In the case, when handling the regulator, you better to use the
definition because the integer index is difficult to understand what
does this mean.
> + i2c_smbus_write_byte_data(touchkey->client,
> + TM2_TOUCHKEY_BASE_REG, data);
> +}
> +
> +static int tm2_touchkey_power_enable(struct tm2_touchkey_data *touchkey)
> +{
> + int ret = 0;
> +
> + ret = regulator_bulk_enable(ARRAY_SIZE(touchkey->regulators),
> + touchkey->regulators);
> + if (ret)
> + return ret;
> +
> + /* waiting for device initialization, at least 150ms */
> + msleep(150);
> +
> + return 0;
> +}
> +
> +static void tm2_touchkey_power_disable(void *data)
> +{
> + struct tm2_touchkey_data *touchkey = data;
> +
> + regulator_bulk_disable(ARRAY_SIZE(touchkey->regulators),
> + touchkey->regulators);
> +}
> +
> +static irqreturn_t tm2_touchkey_irq_handler(int irq, void *devid)
> +{
> + struct tm2_touchkey_data *touchkey = devid;
> + u32 data;
> +
> + data = i2c_smbus_read_byte_data(touchkey->client,
> + TM2_TOUCHKEY_KEYCODE_REG);
> +
> + if (data < 0) {
> + dev_err(&touchkey->client->dev, "Failed to read i2c data\n");
> + return IRQ_HANDLED;
> + }
> +
> + touchkey->keycode_type = data & TM2_TOUCHKEY_BIT_KEYCODE;
> + touchkey->pressed = !(data & TM2_TOUCHKEY_BIT_PRESS_EV);
> +
> + if (touchkey->keycode_type != TM2_TOUCHKEY_KEY_MENU &&
> + touchkey->keycode_type != TM2_TOUCHKEY_KEY_BACK) {
> + dev_warn(&touchkey->client->dev, "Skip unhandled keycode(%d)\n",
> + touchkey->keycode_type);
> + return IRQ_HANDLED;
> + }
> +
> + if (!touchkey->pressed) {
> + input_report_key(touchkey->input_dev, KEY_PHONE, 0);
> + input_report_key(touchkey->input_dev, KEY_BACK, 0);
> + } else {
> + if (touchkey->keycode_type == TM2_TOUCHKEY_KEY_MENU)
> + input_report_key(touchkey->input_dev,
> + KEY_PHONE, 1);
> + else
> + input_report_key(touchkey->input_dev,
> + KEY_BACK, 1);
> + }
> + input_sync(touchkey->input_dev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int tm2_touchkey_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct tm2_touchkey_data *touchkey;
> + int ret;
> +
> + ret = i2c_check_functionality(client->adapter,
> + I2C_FUNC_SMBUS_BYTE |
> + I2C_FUNC_SMBUS_BYTE_DATA);
> + if (!ret) {
> + dev_err(&client->dev, "No I2C functionality found\n");
> + return -ENODEV;
> + }
> +
> + touchkey = devm_kzalloc(&client->dev, sizeof(*touchkey), GFP_KERNEL);
> + if (!touchkey)
> + return -ENOMEM;
> +
> + touchkey->client = client;
> + i2c_set_clientdata(client, touchkey);
> +
> + /* regulators */
> + touchkey->regulators[0].supply = "vcc";
> + touchkey->regulators[1].supply = "vdd";
> + ret = devm_regulator_bulk_get(&client->dev,
> + ARRAY_SIZE(touchkey->regulators),
> + touchkey->regulators);
> + if (ret) {
> + dev_err(&client->dev, "Failed to get regulators\n");
> + return ret;
> + }
> +
> + /* power */
> + ret = tm2_touchkey_power_enable(touchkey);
> + if (ret) {
> + dev_err(&client->dev, "Failed to enable power\n");
> + return ret;
> + }
> +
> + ret = devm_add_action_or_reset(&client->dev,
> + tm2_touchkey_power_disable, touchkey);
> + if (ret)
> + return ret;
> +
> + /* input device */
> + touchkey->input_dev = devm_input_allocate_device(&client->dev);
> + if (!touchkey->input_dev) {
> + dev_err(&client->dev, "Failed to alloc input device\n");
> + return -ENOMEM;
> + }
> + touchkey->input_dev->name = TM2_TOUCHKEY_DEV_NAME;
> + touchkey->input_dev->id.bustype = BUS_I2C;
> +
> + set_bit(EV_KEY, touchkey->input_dev->evbit);
> + input_set_capability(touchkey->input_dev, EV_KEY, KEY_PHONE);
> + input_set_capability(touchkey->input_dev, EV_KEY, KEY_BACK);
> +
> + input_set_drvdata(touchkey->input_dev, touchkey);
> +
> + ret = input_register_device(touchkey->input_dev);
> + if (ret) {
> + dev_err(&client->dev, "Failed to register input device\n");
> + return ret;
> + }
> +
> + /* irq */
> + ret = devm_request_threaded_irq(&client->dev,
> + client->irq, NULL,
> + tm2_touchkey_irq_handler,
> + IRQF_ONESHOT, TM2_TOUCHKEY_DEV_NAME,
> + touchkey);
> + if (ret) {
> + dev_err(&client->dev, "Failed to request threaded irq\n");
> + return ret;
> + }
> +
> + /* led device */
> + touchkey->led_dev.name = TM2_TOUCHKEY_DEV_NAME;
> + touchkey->led_dev.brightness = LED_FULL;
> + touchkey->led_dev.max_brightness = LED_FULL;
> + touchkey->led_dev.brightness_set = tm2_touchkey_led_brightness_set;
> +
> + ret = devm_led_classdev_register(&client->dev, &touchkey->led_dev);
> + if (ret < 0) {
> + dev_err(&client->dev, "Failed to register touchkey led\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int __maybe_unused tm2_touchkey_suspend(struct device *dev)
> +{
> + struct tm2_touchkey_data *touchkey = dev_get_drvdata(dev);
> +
> + disable_irq(touchkey->client->irq);
> + tm2_touchkey_power_disable(touchkey);
> +
> + return 0;
> +}
> +
> +static int __maybe_unused tm2_touchkey_resume(struct device *dev)
> +{
> + struct tm2_touchkey_data *touchkey = dev_get_drvdata(dev);
> + int ret;
> +
> + enable_irq(touchkey->client->irq);
> + ret = tm2_touchkey_power_enable(touchkey);
> + if (ret)
> + dev_err(dev, "Failed to enable power\n");
> +
> + return ret;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops, tm2_touchkey_suspend,
> + tm2_touchkey_resume);
> +
> +static const struct i2c_device_id tm2_touchkey_id_table[] = {
> + {TM2_TOUCHKEY_DEV_NAME, 0},
> + {},
> +};
> +MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
> +
> +static const struct of_device_id tm2_touchkey_of_match[] = {
> + {.compatible = "samsung,tm2-touchkey",},
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, tm2_touchkey_of_match);
> +
> +static struct i2c_driver tm2_touchkey_driver = {
> + .driver = {
> + .name = TM2_TOUCHKEY_DEV_NAME,
> + .pm = &tm2_touchkey_pm_ops,
> + .of_match_table = of_match_ptr(tm2_touchkey_of_match),
> + },
> + .probe = tm2_touchkey_probe,
> + .id_table = tm2_touchkey_id_table,
> +};
> +
> +module_i2c_driver(tm2_touchkey_driver);
> +
> +MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
> +MODULE_AUTHOR("Jaechul Lee <jcsing.lee@samsung.com>");
> +MODULE_DESCRIPTION("Samsung touchkey driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.11.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Best Regards,
Chanwoo Choi
^ permalink raw reply
* [PATCH v2 9/9] ARM: dts: keystone-k2g: Reserve MSM RAM for boot monitor
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
The Keystone 2 boot monitor uses 32 KB of the MSM RAM @ 0x0c0f7000
on 66AK2G SoCs, so add a reserved child node for the same.
This address is aligned to the values used within the latest boot
monitor firmware [1] as of commit cf8b431e8b3b ("soc: Move load
address to end of MSMC").
[1] git://git.ti.com/processor-firmware/ks2-boot-monitor.git
Signed-off-by: Suman Anna <s-anna@ti.com>
---
arch/arm/boot/dts/keystone-k2g.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi
index e63e57e03b7c..c36d168bc874 100644
--- a/arch/arm/boot/dts/keystone-k2g.dtsi
+++ b/arch/arm/boot/dts/keystone-k2g.dtsi
@@ -83,6 +83,10 @@
ranges = <0x0 0x0c000000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ sram-bm@f7000 {
+ reg = <0x000f7000 0x8000>;
+ };
};
k2g_pinctrl: pinmux@02621000 {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 8/9] ARM: dts: keystone-k2e: Reserve MSM RAM for boot monitor
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
The Keystone 2 boot monitor uses 32 KB of the MSM RAM @ 0x0c1f0000
on 66AK2E SoCs, so add a reserved child node for the same.
This address is aligned to the values used within the latest boot
monitor firmware [1] as of commit cf8b431e8b3b ("soc: Move load
address to end of MSMC").
[1] git://git.ti.com/processor-firmware/ks2-boot-monitor.git
Signed-off-by: Suman Anna <s-anna@ti.com>
---
arch/arm/boot/dts/keystone-k2e.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2e.dtsi b/arch/arm/boot/dts/keystone-k2e.dtsi
index 256dcc87f36a..9d1d8a64d10e 100644
--- a/arch/arm/boot/dts/keystone-k2e.dtsi
+++ b/arch/arm/boot/dts/keystone-k2e.dtsi
@@ -88,6 +88,10 @@
ranges = <0x0 0x0c000000 0x200000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ sram-bm@1f0000 {
+ reg = <0x001f0000 0x8000>;
+ };
};
dspgpio0: keystone_dsp_gpio@02620240 {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 7/9] ARM: dts: keystone-k2l: Reserve MSM RAM for boot monitor
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
The Keystone 2 boot monitor uses 32 KB of the MSM RAM @ 0x0c1f8000
on 66AK2L SoCs, so add a reserved child node for the same.
This address is aligned to the values used within the latest boot
monitor firmware [1] as of commit cf8b431e8b3b ("soc: Move load
address to end of MSMC").
[1] git://git.ti.com/processor-firmware/ks2-boot-monitor.git
Signed-off-by: Suman Anna <s-anna@ti.com>
---
arch/arm/boot/dts/keystone-k2l.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2l.dtsi b/arch/arm/boot/dts/keystone-k2l.dtsi
index edc08de4e196..b58015737a35 100644
--- a/arch/arm/boot/dts/keystone-k2l.dtsi
+++ b/arch/arm/boot/dts/keystone-k2l.dtsi
@@ -210,6 +210,10 @@
ranges = <0x0 0x0c000000 0x200000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ sram-bm@1f8000 {
+ reg = <0x001f8000 0x8000>;
+ };
};
dspgpio0: keystone_dsp_gpio@02620240 {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 6/9] ARM: dts: keystone-k2hk: Reserve MSM RAM for boot monitor
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
The Keystone 2 boot monitor uses 32 KB of the MSM RAM @ 0x0c5f0000
on 66AK2H SoCs, so add a reserved child node for the same.
This address is aligned to the values used within the latest boot
monitor firmware [1] as of commit cf8b431e8b3b ("soc: Move load
address to end of MSMC").
[1] git://git.ti.com/processor-firmware/ks2-boot-monitor.git
Signed-off-by: Suman Anna <s-anna@ti.com>
---
arch/arm/boot/dts/keystone-k2hk.dtsi | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2hk.dtsi b/arch/arm/boot/dts/keystone-k2hk.dtsi
index 39e88d815235..e0780f111537 100644
--- a/arch/arm/boot/dts/keystone-k2hk.dtsi
+++ b/arch/arm/boot/dts/keystone-k2hk.dtsi
@@ -52,6 +52,10 @@
ranges = <0x0 0x0c000000 0x600000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ sram-bm@5f0000 {
+ reg = <0x5f0000 0x8000>;
+ };
};
dspgpio0: keystone_dsp_gpio@02620240 {
--
2.10.2
^ permalink raw reply related
* [PATCH v2 5/9] ARM: configs: keystone: Enable Generic on-chip SRAM driver
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
All the Keystone 2 SoCs have an on-chip RAM called the MultiCore
Shared Memory (MSM) RAM managed by the Multicore Shared Memory
Controller (MSMC) that provides faster access compared to normal
DDR.
This patch enables the Generic on-chip SRAM driver that manages
this memory in software.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: No changes
arch/arm/configs/keystone_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 78cd2f197e01..1331f6dc456a 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -126,6 +126,7 @@ CONFIG_MTD_NAND_DAVINCI=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
+CONFIG_SRAM=y
CONFIG_EEPROM_AT24=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
--
2.10.2
^ permalink raw reply related
* [PATCH v2 4/9] ARM: dts: keystone-k2g: Add MSM RAM node
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
Add the RAM managed by the Multicore Shared Memory Controller (MSMC)
as a mmio-sram node. The 66AK2G SoCs have 1 MB of such memory. Any
specific MSM memory range needed by a software module ought to be
reserved using an appropriate child node.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: No code changes, SoC name in commit message corrected to use 66AK2G
arch/arm/boot/dts/keystone-k2g.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2g.dtsi b/arch/arm/boot/dts/keystone-k2g.dtsi
index 63c7cf0c6b6d..e63e57e03b7c 100644
--- a/arch/arm/boot/dts/keystone-k2g.dtsi
+++ b/arch/arm/boot/dts/keystone-k2g.dtsi
@@ -77,6 +77,14 @@
ranges = <0x0 0x0 0x0 0xc0000000>;
dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>;
+ msm_ram: msmram@0c000000 {
+ compatible = "mmio-sram";
+ reg = <0x0c000000 0x100000>;
+ ranges = <0x0 0x0c000000 0x100000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
k2g_pinctrl: pinmux@02621000 {
compatible = "pinctrl-single";
reg = <0x02621000 0x410>;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 3/9] ARM: dts: keystone-k2e: Add MSM RAM node
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
Add the RAM managed by the Multicire Shared Memory Controller (MSMC)
as a mmio-sram node. The 66AK2E SoCs have 2 MB of such memory. Any
specific MSM memory range needed by a software module ought to be
reserved using an appropriate child node.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: No code changes, SoC name in commit message corrected to use 66AK2E
arch/arm/boot/dts/keystone-k2e.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2e.dtsi b/arch/arm/boot/dts/keystone-k2e.dtsi
index 497c417db5b6..256dcc87f36a 100644
--- a/arch/arm/boot/dts/keystone-k2e.dtsi
+++ b/arch/arm/boot/dts/keystone-k2e.dtsi
@@ -82,6 +82,14 @@
};
};
+ msm_ram: msmram@0c000000 {
+ compatible = "mmio-sram";
+ reg = <0x0c000000 0x200000>;
+ ranges = <0x0 0x0c000000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
dspgpio0: keystone_dsp_gpio@02620240 {
compatible = "ti,keystone-dsp-gpio";
gpio-controller;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 2/9] ARM: dts: keystone-k2l: Add MSM RAM node
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
Add the RAM managed by the Multicore Shared Memory Controller (MSMC)
as a mmio-sram node. The 66AK2L SoCs have 2 MB of such memory. Any
specific MSM memory range needed by a software module ought to be
reserved using an appropriate child node.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: No code changes, SoC name in commit message corrected to use 66AK2L
arch/arm/boot/dts/keystone-k2l.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2l.dtsi b/arch/arm/boot/dts/keystone-k2l.dtsi
index 0c5e74e79ba2..edc08de4e196 100644
--- a/arch/arm/boot/dts/keystone-k2l.dtsi
+++ b/arch/arm/boot/dts/keystone-k2l.dtsi
@@ -204,6 +204,14 @@
};
};
+ msm_ram: msmram@0c000000 {
+ compatible = "mmio-sram";
+ reg = <0x0c000000 0x200000>;
+ ranges = <0x0 0x0c000000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
dspgpio0: keystone_dsp_gpio@02620240 {
compatible = "ti,keystone-dsp-gpio";
gpio-controller;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 1/9] ARM: dts: keystone-k2hk: Add MSM RAM node
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>
Add the RAM managed by the Multicore Shared Memory Controller (MSMC)
as a mmio-sram node. The 66AK2H SoCs have 6 MB of such memory. Any
specific MSM memory range needed by a software module ought to be
reserved using an appropriate child node.
Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2: No code changes, SoC name in commit message corrected to use 66AK2H
arch/arm/boot/dts/keystone-k2hk.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/keystone-k2hk.dtsi b/arch/arm/boot/dts/keystone-k2hk.dtsi
index 8f67fa8df936..39e88d815235 100644
--- a/arch/arm/boot/dts/keystone-k2hk.dtsi
+++ b/arch/arm/boot/dts/keystone-k2hk.dtsi
@@ -46,6 +46,14 @@
soc {
/include/ "keystone-k2hk-clocks.dtsi"
+ msm_ram: msmram@0c000000 {
+ compatible = "mmio-sram";
+ reg = <0x0c000000 0x600000>;
+ ranges = <0x0 0x0c000000 0x600000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
dspgpio0: keystone_dsp_gpio@02620240 {
compatible = "ti,keystone-dsp-gpio";
gpio-controller;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 0/9] Use mmio-sram driver for Keystone MSMC RAM
From: Suman Anna @ 2017-01-06 21:57 UTC (permalink / raw)
To: Santosh Shilimkar
Cc: devicetree, Russell King, Vitaly Andrianov, linux-kernel,
Tero Kristo, Rob Herring, Murali Karicheri, linux-arm-kernel
Hi,
The Keystone 2 family of SoCs have an on-chip RAM called the
Multicore Shared Memory (MSM) RAM. This RAM is accessible through
the Multicore Shared Memory Controller (MSMC). This series represents
these on-chip RAMs as sram nodes so that the memory allocations
can be managed by the in-kernel mmio-sram driver.
This is v2 of the previous series [1], and now includes 4 additional
patches that reserve the portions of the MSMC RAM used by the
Keystone Boot Monitor. The first 5 patches are essentially the same
as in v1, with minor commit description updates for using the proper
SoC names, but no code changes.
Patches baselined on 4.10-rc1.
regards
Suman
[1] http://marc.info/?l=linux-arm-kernel&m=147277092730387&w=2
Suman Anna (9):
ARM: dts: keystone-k2hk: Add MSM RAM node
ARM: dts: keystone-k2l: Add MSM RAM node
ARM: dts: keystone-k2e: Add MSM RAM node
ARM: dts: keystone-k2g: Add MSM RAM node
ARM: configs: keystone: Enable Generic on-chip SRAM driver
ARM: dts: keystone-k2hk: Reserve MSM RAM for boot monitor
ARM: dts: keystone-k2l: Reserve MSM RAM for boot monitor
ARM: dts: keystone-k2e: Reserve MSM RAM for boot monitor
ARM: dts: keystone-k2g: Reserve MSM RAM for boot monitor
arch/arm/boot/dts/keystone-k2e.dtsi | 12 ++++++++++++
arch/arm/boot/dts/keystone-k2g.dtsi | 12 ++++++++++++
arch/arm/boot/dts/keystone-k2hk.dtsi | 12 ++++++++++++
arch/arm/boot/dts/keystone-k2l.dtsi | 12 ++++++++++++
arch/arm/configs/keystone_defconfig | 1 +
5 files changed, 49 insertions(+)
--
2.10.2
^ permalink raw reply
* Re: [PATCH v2] i2c: core: helper function to detect slave mode
From: Vladimir Zapolskiy @ 2017-01-06 21:49 UTC (permalink / raw)
To: Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <9ada747bd53bb5005a82f913412262b34b6e96b8.1483725370.git.lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Hi Luis,
On 01/06/2017 08:14 PM, Luis Oliveira wrote:
> This function has the purpose of mode detection by checking the
> device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag.
> Currently only checks using OF functions (ACPI slave not supported yet).
>
I've accidentally reviewed v1, please take the same comments for v2.
--
With best wishes,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] i2c: core: helper function to detect slave mode
From: Vladimir Zapolskiy @ 2017-01-06 21:46 UTC (permalink / raw)
To: Luis Oliveira, wsa-z923LK4zBo2bacvFa/9K2g,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <f4ec62119145bc70c938800c91eb396d30457304.1483636071.git.lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
Hello Luis,
On 01/05/2017 07:24 PM, Luis Oliveira wrote:
> This function has the purpose of mode detection by checking the
> device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag.
> Currently only checks using OF functions (ACPI slave not supported yet).
>
> Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
> ---
> Due to the need of checking if the I2C slave address is our own (in
> other words: if we are the I2C slave) I created a helper function
> (proposed to me by @Andy) to enable that check.
> Currently (because I am not able to test it using ACPI) it only
> supports devicetree declarations.
>
> drivers/i2c/i2c-core.c | 19 +++++++++++++++++++
> include/linux/i2c.h | 1 +
> 2 files changed, 20 insertions(+)
>
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index 3de95a29024c..48e705b23c59 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -3691,6 +3691,25 @@ int i2c_slave_unregister(struct i2c_client *client)
> return ret;
> }
> EXPORT_SYMBOL_GPL(i2c_slave_unregister);
> +
> +int i2c_slave_mode_detect(struct device *dev)
> +{
> + struct device_node *child;
> + u32 reg;
> +
> + if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
IS_BUILTIN(CONFIG_OF) looks excessive, check for non-NULL dev->of_node
should be sufficient.
But then you may do for_each_child_of_node() loop totally unconditionally,
because of_get_next_child() correctly handle NULL as the first argument.
> + for_each_child_of_node(dev->of_node, child) {
> + of_property_read_u32(child, "reg", ®);
> + if (reg & I2C_OWN_SLAVE_ADDRESS)
> + return 1;
Leaked incremented reference to a child device node, please add
of_node_put(child) before return in the loop body.
Also reg variable may be uninitialized here, if child device node
does not have "reg" property.
> + }
> + } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
> + dev_dbg(dev, "ACPI slave is not supported yet\n");
> + }
If so, then it might be better to drop else-if stub for now.
> + return 0;
> +}
> +EXPORT_SYMBOL_GPL(i2c_slave_mode_detect);
> +
> #endif
>
> MODULE_AUTHOR("Simon G. Vogl <simon-nD9nYVNVf00W+b/DJNNodF6hYfS7NtTn@public.gmane.org>");
> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
> index b2109c522dec..53cf99569af5 100644
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -282,6 +282,7 @@ enum i2c_slave_event {
>
> extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
> extern int i2c_slave_unregister(struct i2c_client *client);
> +extern int i2c_slave_mode_detect(struct device *dev);
>
> static inline int i2c_slave_event(struct i2c_client *client,
> enum i2c_slave_event event, u8 *val)
>
--
With best wishes,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v5 3/5] input: Add support for the tm2 touchkey device driver
From: Chanwoo Choi @ 2017-01-06 21:34 UTC (permalink / raw)
To: Andi Shyti
Cc: Dmitry Torokhov, Rob Herring, Mark Rutland, Catalin Marinas,
Will Deacon, Kukjin Kim, Krzysztof Kozlowski,
Javier Martinez Canillas, Chanwoo Choi, Beomho Seo,
linux-arm-kernel, linux-input, devicetree, linux-kernel,
linux-samsung-soc, Jaechul Lee, Andi Shyti, Jaechul Lee
In-Reply-To: <20170106134350.32428-4-andi.shyti@samsung.com>
Hi,
2017-01-06 22:43 GMT+09:00 Andi Shyti <andi.shyti@samsung.com>:
> From: Jaechul Lee <jcsing.lee@samsung.com>
>
> This patch adds the binding description of the tm2 touchkey
> device driver.
>
> Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
> Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
> Reviewed-by: Andi Shyti <andi.shyti@samsung.com>
> Acked-by: Rob Herring <robh@kernel.org>
> Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
> Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
> ---
> .../bindings/input/samsung,tm2-touchkey.txt | 27 ++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/samsung,tm2-touchkey.txt
>
> diff --git a/Documentation/devicetree/bindings/input/samsung,tm2-touchkey.txt b/Documentation/devicetree/bindings/input/samsung,tm2-touchkey.txt
> new file mode 100644
> index 000000000000..4de1af0f0a37
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/samsung,tm2-touchkey.txt
> @@ -0,0 +1,27 @@
> +Samsung tm2-touchkey
> +
> +Required properties:
> +- compatible: must be "samsung,tm2-touchkey"
> +- reg: I2C address of the chip.
> +- interrupt-parent: a phandle for the interrupt controller (see interrupt
> + binding[0]).
> +- interrupts: interrupt to which the chip is connected (see interrupt
> + binding[0]).
> +- vcc-supply : internal regulator output. 1.8V
> +- vdd-supply : power supply for IC 3.3V
> +
> +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
> +
> +Example:
> + &i2c0 {
> + /* ... */
> +
> + touchkey@20 {
> + compatible = "samsung,tm2-touchkey";
> + reg = <0x20>;
> + interrupt-parent = <&gpa3>;
> + interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> + vcc-supply=<&ldo32_reg>;
> + vdd-supply=<&ldo33_reg>;
> + };
> + };
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
--
Best Regards,
Chanwoo Choi
^ permalink raw reply
* Re: [PATCH] i2c: core: helper function to detect slave mode
From: Andy Shevchenko @ 2017-01-06 21:32 UTC (permalink / raw)
To: Luis Oliveira
Cc: Wolfram Sang, Rob Herring, Mark Rutland, Jarkko Nikula,
Andy Shevchenko, Mika Westerberg,
linux-i2c-u79uwXL29TY76Z2rM5mHXA, devicetree,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w, Joao Pinto,
CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w
In-Reply-To: <c73ee9ab-64a1-0419-314d-21d4575ca7bf-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
On Fri, Jan 6, 2017 at 7:46 PM, Luis Oliveira
<Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w@public.gmane.org> wrote:
> On 06-Jan-17 17:17, Andy Shevchenko wrote:
>> On Fri, Jan 6, 2017 at 7:15 PM, Luis Oliveira
>> <Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w@public.gmane.org> wrote:
>>> On 06-Jan-17 16:29, Andy Shevchenko wrote:
>>>> On Thu, Jan 5, 2017 at 7:24 PM, Luis Oliveira
>>
>>>> Please, add kernel doc description here, important thing is to explain
>>>> return codes in Return: section of it.
>>>>
>>>>> +int i2c_slave_mode_detect(struct device *dev)
>>
>> Just to make sure you didn't miss this one.
>>
>>
> Yes, I saw it. You were talking of something like this, right?
>
> /**
> * i2c_slave_mode_detect - detect operation mode
> * @dev: The device owning the bus
> *
> * This checks the device nodes for a I2C slave by checking the address
a -> an
> * used.
> *
> * Returns true if a I2C slave is detected, otherwise returns false.
It has int type and I would reword this accordingly.
Something like
* Return:
* 1 when an I2C slave is detected, 0 for I2C master mode,
* and negative error otherwise.
> */
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox