All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] cec: STM32 driver
@ 2017-05-16 12:56 ` Benjamin Gaignard
  0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 12:56 UTC (permalink / raw)
  To: yannick.fertre-qxv4g6HH51o, alexandre.torgue-qxv4g6HH51o,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
	hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w
  Cc: Benjamin Gaignard

version 2:
- fix typo in compagnie name
- add yannick sign-off
- use cec_message instead of custom struct in cec device
- add monitor mode

I don't change the split between irq handler and irq thread because
it would had mean to handle all errors cases irq handler to keep
a correct sequence. I don't think it is critical as it is since cec is a very
slow protocol.

This serie of patches add cec driver for STM32 platforms.

This code doesn't implement cec notifier because STM32 doesn't
provide HDMI yet but it will be added later.

Those patches have been developped on top of media_tree master branch
where STM32 DCMI code has not been merged so conflict in Kconfig and Makefile
could occur depending of merge ordering.

Compliance has been tested on STM32F769.

~ # cec-ctl -p 1.0.0.0 --playback 
Driver Info:
        Driver Name                : stm32-cec
        Adapter Name               : stm32-cec
        Capabilities               : 0x0000000f
                Physical Address
                Logical Addresses
                Transmit
                Passthrough
        Driver version             : 4.11.0
        Available Logical Addresses: 1
        Physical Address           : 1.0.0.0
        Logical Address Mask       : 0x0010
        CEC Version                : 2.0
        Vendor ID                  : 0x000c03 (HDMI)
        OSD Name                   : 'Playback'
        Logical Addresses          : 1 (Allow RC Passthrough)

          Logical Address          : 4 (Playback Device 1)
            Primary Device Type    : Playback
            Logical Address Type   : Playback
            All Device Types       : Playback
            RC TV Profile          : None
            Device Features        :
                None

~ # cec-compliance -A 
cec-compliance SHA                 : 6acac5cec698de39b9398b66c4f5f4db6b2730d8

Driver Info:
        Driver Name                : stm32-cec
        Adapter Name               : stm32-cec
        Capabilities               : 0x0000000f
                Physical Address
                Logical Addresses
                Transmit
                Passthrough
        Driver version             : 4.11.0
        Available Logical Addresses: 1
        Physical Address           : 1.0.0.0
        Logical Address Mask       : 0x0010
        CEC Version                : 2.0
        Vendor ID                  : 0x000c03
        Logical Addresses          : 1 (Allow RC Passthrough)

          Logical Address          : 4
            Primary Device Type    : Playback
            Logical Address Type   : Playback
            All Device Types       : Playback
            RC TV Profile          : None
            Device Features        :
                None

Compliance test for device /dev/cec0:

    The test results mean the following:
        OK                  Supported correctly by the device.
        OK (Not Supported)  Not supported and not mandatory for the device.
        OK (Presumed)       Presumably supported.  Manually check to confirm.
        OK (Unexpected)     Supported correctly but is not expected to be supported for this device.
        OK (Refused)        Supported by the device, but was refused.
        FAIL                Failed and was expected to be supported by this device.

Find remote devices:
        Polling: OK

CEC API:
        CEC_ADAP_G_CAPS: OK
        CEC_DQEVENT: OK
        CEC_ADAP_G/S_PHYS_ADDR: OK
        CEC_ADAP_G/S_LOG_ADDRS: OK
        CEC_TRANSMIT: OK
        CEC_RECEIVE: OK
        CEC_TRANSMIT/RECEIVE (non-blocking): OK (Presumed)
        CEC_G/S_MODE: OK
        CEC_EVENT_LOST_MSGS: OK

Network topology:
        System Information for device 0 (TV) from device 4 (Playback Device 1):
                CEC Version                : 1.4
                Physical Address           : 0.0.0.0
                Primary Device Type        : TV
                Vendor ID                  : 0x00903e
                OSD Name                   : 'TV'
                Menu Language              : fre
                Power Status               : On

Total: 10, Succeeded: 10, Failed: 0, Warnings: 0

Benjamin Gaignard (2):
  binding for stm32 cec driver
  cec: add STM32 cec driver

 .../devicetree/bindings/media/st,stm32-cec.txt     |  19 +
 drivers/media/platform/Kconfig                     |  11 +
 drivers/media/platform/Makefile                    |   2 +
 drivers/media/platform/stm32/Makefile              |   1 +
 drivers/media/platform/stm32/stm32-cec.c           | 384 +++++++++++++++++++++
 5 files changed, 417 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
 create mode 100644 drivers/media/platform/stm32/Makefile
 create mode 100644 drivers/media/platform/stm32/stm32-cec.c

-- 
1.9.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	[flat|nested] 12+ messages in thread

* [PATCH v2 0/2] cec: STM32 driver
@ 2017-05-16 12:56 ` Benjamin Gaignard
  0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 12:56 UTC (permalink / raw)
  To: yannick.fertre, alexandre.torgue, hverkuil, devicetree,
	linux-media, robh, hans.verkuil
  Cc: Benjamin Gaignard

version 2:
- fix typo in compagnie name
- add yannick sign-off
- use cec_message instead of custom struct in cec device
- add monitor mode

I don't change the split between irq handler and irq thread because
it would had mean to handle all errors cases irq handler to keep
a correct sequence. I don't think it is critical as it is since cec is a very
slow protocol.

This serie of patches add cec driver for STM32 platforms.

This code doesn't implement cec notifier because STM32 doesn't
provide HDMI yet but it will be added later.

Those patches have been developped on top of media_tree master branch
where STM32 DCMI code has not been merged so conflict in Kconfig and Makefile
could occur depending of merge ordering.

Compliance has been tested on STM32F769.

~ # cec-ctl -p 1.0.0.0 --playback 
Driver Info:
        Driver Name                : stm32-cec
        Adapter Name               : stm32-cec
        Capabilities               : 0x0000000f
                Physical Address
                Logical Addresses
                Transmit
                Passthrough
        Driver version             : 4.11.0
        Available Logical Addresses: 1
        Physical Address           : 1.0.0.0
        Logical Address Mask       : 0x0010
        CEC Version                : 2.0
        Vendor ID                  : 0x000c03 (HDMI)
        OSD Name                   : 'Playback'
        Logical Addresses          : 1 (Allow RC Passthrough)

          Logical Address          : 4 (Playback Device 1)
            Primary Device Type    : Playback
            Logical Address Type   : Playback
            All Device Types       : Playback
            RC TV Profile          : None
            Device Features        :
                None

~ # cec-compliance -A 
cec-compliance SHA                 : 6acac5cec698de39b9398b66c4f5f4db6b2730d8

Driver Info:
        Driver Name                : stm32-cec
        Adapter Name               : stm32-cec
        Capabilities               : 0x0000000f
                Physical Address
                Logical Addresses
                Transmit
                Passthrough
        Driver version             : 4.11.0
        Available Logical Addresses: 1
        Physical Address           : 1.0.0.0
        Logical Address Mask       : 0x0010
        CEC Version                : 2.0
        Vendor ID                  : 0x000c03
        Logical Addresses          : 1 (Allow RC Passthrough)

          Logical Address          : 4
            Primary Device Type    : Playback
            Logical Address Type   : Playback
            All Device Types       : Playback
            RC TV Profile          : None
            Device Features        :
                None

Compliance test for device /dev/cec0:

    The test results mean the following:
        OK                  Supported correctly by the device.
        OK (Not Supported)  Not supported and not mandatory for the device.
        OK (Presumed)       Presumably supported.  Manually check to confirm.
        OK (Unexpected)     Supported correctly but is not expected to be supported for this device.
        OK (Refused)        Supported by the device, but was refused.
        FAIL                Failed and was expected to be supported by this device.

Find remote devices:
        Polling: OK

CEC API:
        CEC_ADAP_G_CAPS: OK
        CEC_DQEVENT: OK
        CEC_ADAP_G/S_PHYS_ADDR: OK
        CEC_ADAP_G/S_LOG_ADDRS: OK
        CEC_TRANSMIT: OK
        CEC_RECEIVE: OK
        CEC_TRANSMIT/RECEIVE (non-blocking): OK (Presumed)
        CEC_G/S_MODE: OK
        CEC_EVENT_LOST_MSGS: OK

Network topology:
        System Information for device 0 (TV) from device 4 (Playback Device 1):
                CEC Version                : 1.4
                Physical Address           : 0.0.0.0
                Primary Device Type        : TV
                Vendor ID                  : 0x00903e
                OSD Name                   : 'TV'
                Menu Language              : fre
                Power Status               : On

Total: 10, Succeeded: 10, Failed: 0, Warnings: 0

Benjamin Gaignard (2):
  binding for stm32 cec driver
  cec: add STM32 cec driver

 .../devicetree/bindings/media/st,stm32-cec.txt     |  19 +
 drivers/media/platform/Kconfig                     |  11 +
 drivers/media/platform/Makefile                    |   2 +
 drivers/media/platform/stm32/Makefile              |   1 +
 drivers/media/platform/stm32/stm32-cec.c           | 384 +++++++++++++++++++++
 5 files changed, 417 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
 create mode 100644 drivers/media/platform/stm32/Makefile
 create mode 100644 drivers/media/platform/stm32/stm32-cec.c

-- 
1.9.1

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

* [PATCH v2 1/2] binding for stm32 cec driver
  2017-05-16 12:56 ` Benjamin Gaignard
  (?)
@ 2017-05-16 12:56 ` Benjamin Gaignard
       [not found]   ` <1494939383-18937-2-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
  -1 siblings, 1 reply; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 12:56 UTC (permalink / raw)
  To: yannick.fertre, alexandre.torgue, hverkuil, devicetree,
	linux-media, robh, hans.verkuil
  Cc: Benjamin Gaignard

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
---
 .../devicetree/bindings/media/st,stm32-cec.txt        | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt

diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
new file mode 100644
index 0000000..6be2381
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
@@ -0,0 +1,19 @@
+STMicroelectronics STM32 CEC driver
+
+Required properties:
+ - compatible : value should be "st,stm32-cec"
+ - reg : Physical base address of the IP registers and length of memory
+	 mapped region.
+ - clocks : from common clock binding: handle to CEC clocks
+ - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
+ - interrupts : CEC interrupt number to the CPU.
+
+Example for stm32f746:
+
+cec: cec@40006c00 {
+	compatible = "st,stm32-cec";
+	reg = <0x40006C00 0x400>;
+	interrupts = <94>;
+	clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
+	clock-names = "cec", "hdmi-cec";
+};
-- 
1.9.1

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

* [PATCH v2 2/2] cec: add STM32 cec driver
  2017-05-16 12:56 ` Benjamin Gaignard
@ 2017-05-16 12:56     ` Benjamin Gaignard
  -1 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 12:56 UTC (permalink / raw)
  To: yannick.fertre-qxv4g6HH51o, alexandre.torgue-qxv4g6HH51o,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
	hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w
  Cc: Benjamin Gaignard

This patch add cec driver for STM32 platforms.
cec hardware block isn't not always used with hdmi so
cec notifier is not implemented. That will be done later
when STM32 DSI driver will be available.

Driver compliance has been tested with cec-ctl and cec-compliance
tools.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Yannick Fertre <yannick.fertre-qxv4g6HH51o@public.gmane.org>
---
 drivers/media/platform/Kconfig           |  11 +
 drivers/media/platform/Makefile          |   2 +
 drivers/media/platform/stm32/Makefile    |   1 +
 drivers/media/platform/stm32/stm32-cec.c | 384 +++++++++++++++++++++++++++++++
 4 files changed, 398 insertions(+)
 create mode 100644 drivers/media/platform/stm32/Makefile
 create mode 100644 drivers/media/platform/stm32/stm32-cec.c

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ac026ee..72efe34 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -519,4 +519,15 @@ config VIDEO_STI_HDMI_CEC
          CEC bus is present in the HDMI connector and enables communication
          between compatible devices.
 
+config VIDEO_STM32_HDMI_CEC
+       tristate "STMicroelectronics STM32 HDMI CEC driver"
+       depends on CEC_CORE && (ARCH_STM32 || COMPILE_TEST)
+       select REGMAP
+       select REGMAP_MMIO
+       ---help---
+         This is a driver for STM32 interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
 endif #CEC_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 63303d6..7cd9965 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -44,6 +44,8 @@ obj-$(CONFIG_VIDEO_STI_HDMI_CEC) 	+= sti/cec/
 
 obj-$(CONFIG_VIDEO_STI_DELTA)		+= sti/delta/
 
+obj-$(CONFIG_VIDEO_STM32_HDMI_CEC) 	+= stm32/
+
 obj-$(CONFIG_BLACKFIN)                  += blackfin/
 
 obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
diff --git a/drivers/media/platform/stm32/Makefile b/drivers/media/platform/stm32/Makefile
new file mode 100644
index 0000000..632b04c
--- /dev/null
+++ b/drivers/media/platform/stm32/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_STM32_HDMI_CEC) += stm32-cec.o
diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c
new file mode 100644
index 0000000..9de3f1d
--- /dev/null
+++ b/drivers/media/platform/stm32/stm32-cec.c
@@ -0,0 +1,384 @@
+/*
+ * STM32 CEC driver
+ * Copyright (C) STMicroelectronics SA 2017
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <media/cec.h>
+
+#define CEC_NAME	"stm32-cec"
+
+/* CEC registers  */
+#define CEC_CR		0x0000 /* Control Register */
+#define CEC_CFGR	0x0004 /* ConFiGuration Register */
+#define CEC_TXDR	0x0008 /* Rx data Register */
+#define CEC_RXDR	0x000C /* Rx data Register */
+#define CEC_ISR		0x0010 /* Interrupt and status Register */
+#define CEC_IER		0x0014 /* Interrupt enable Register */
+
+#define TXEOM		BIT(2)
+#define TXSOM		BIT(1)
+#define CECEN		BIT(0)
+
+#define LSTN		BIT(31)
+#define OAR		GENMASK(30, 16)
+#define SFTOP		BIT(8)
+#define BRDNOGEN	BIT(7)
+#define LBPEGEN		BIT(6)
+#define BREGEN		BIT(5)
+#define BRESTP		BIT(4)
+#define RXTOL		BIT(3)
+#define SFT		GENMASK(2, 0)
+#define FULL_CFG	(LSTN | SFTOP | BRDNOGEN | LBPEGEN | BREGEN | BRESTP \
+			 | RXTOL | SFT | BRDNOGEN)
+
+#define TXACKE		BIT(12)
+#define TXERR		BIT(11)
+#define TXUDR		BIT(10)
+#define TXEND		BIT(9)
+#define TXBR		BIT(8)
+#define ARBLST		BIT(7)
+#define RXACKE		BIT(6)
+#define RXOVR		BIT(2)
+#define RXEND		BIT(1)
+#define RXBR		BIT(0)
+
+#define ALL_TX_IT	(TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST)
+#define ALL_RX_IT	(RXEND | RXBR | RXACKE | RXOVR)
+
+struct stm32_cec {
+	struct cec_adapter	*adap;
+	struct device		*dev;
+	struct clk		*clk_cec;
+	struct clk		*clk_hdmi_cec;
+	struct reset_control	*rstc;
+	struct regmap		*regmap;
+	int			irq;
+	u32			irq_status;
+	struct cec_msg		rx_msg;
+	struct cec_msg		tx_msg;
+	int			tx_cnt;
+};
+
+static void cec_hw_init(struct stm32_cec *cec)
+{
+	regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0);
+
+	regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT,
+			   ALL_TX_IT | ALL_RX_IT);
+
+	regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG);
+}
+
+static void stm32_tx_done(struct stm32_cec *cec, u32 status)
+{
+	if (status & (TXERR | TXUDR)) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR,
+				  0, 0, 0, 1);
+		return;
+	}
+
+	if (status & ARBLST) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST,
+				  1, 0, 0, 0);
+		return;
+	}
+
+	if (status & TXACKE) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK,
+				  0, 1, 0, 0);
+		return;
+	}
+
+	if (cec->irq_status & TXBR) {
+		/* send next byte */
+		if (cec->tx_cnt < cec->tx_msg.len)
+			regmap_write(cec->regmap, CEC_TXDR,
+				     cec->tx_msg.msg[cec->tx_cnt++]);
+
+		/* TXEOM is set to command transmission of the last byte */
+		if (cec->tx_cnt == cec->tx_msg.len)
+			regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
+	}
+
+	if (cec->irq_status & TXEND)
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
+}
+
+static void stm32_rx_done(struct stm32_cec *cec, u32 status)
+{
+	if (cec->irq_status & (RXACKE | RXOVR)) {
+		cec->rx_msg.len = 0;
+		return;
+	}
+
+	if (cec->irq_status & RXBR) {
+		u32 val;
+
+		regmap_read(cec->regmap, CEC_RXDR, &val);
+		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
+	}
+
+	if (cec->irq_status & RXEND) {
+		cec_received_msg(cec->adap, &cec->rx_msg);
+		cec->rx_msg.len = 0;
+	}
+}
+
+static irqreturn_t stm32_cec_irq_thread(int irq, void *arg)
+{
+	struct stm32_cec *cec = arg;
+
+	if (cec->irq_status & ALL_TX_IT)
+		stm32_tx_done(cec, cec->irq_status);
+
+	if (cec->irq_status & ALL_RX_IT)
+		stm32_rx_done(cec, cec->irq_status);
+
+	cec->irq_status = 0;
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t stm32_cec_irq_handler(int irq, void *arg)
+{
+	struct stm32_cec *cec = arg;
+
+	regmap_read(cec->regmap, CEC_ISR, &cec->irq_status);
+
+	regmap_update_bits(cec->regmap, CEC_ISR,
+			   ALL_TX_IT | ALL_RX_IT,
+			   ALL_TX_IT | ALL_RX_IT);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+	struct stm32_cec *cec = adap->priv;
+	int ret = 0;
+
+	if (enable) {
+		ret = clk_enable(cec->clk_cec);
+		if (ret)
+			dev_err(cec->dev, "fail to enable cec clock\n");
+
+		clk_enable(cec->clk_hdmi_cec);
+		regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+	} else {
+		clk_disable(cec->clk_cec);
+		clk_disable(cec->clk_hdmi_cec);
+		regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+	}
+
+	return ret;
+}
+
+static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+
+	if (logical_addr == CEC_LOG_ADDR_INVALID)
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
+	else
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR,
+				   (1 << logical_addr) << 16);
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+
+	return 0;
+}
+
+static int stm32_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+				   u32 signal_free_time, struct cec_msg *msg)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	/* Copy message */
+	cec->tx_msg = *msg;
+	cec->tx_cnt = 0;
+
+	/*
+	 * If the CEC message consists of only one byte,
+	 * TXEOM must be set before of TXSOM.
+	 */
+	if (cec->tx_msg.len == 1)
+		regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
+
+	/* TXSOM is set to command transmission of the first byte */
+	regmap_update_bits(cec->regmap, CEC_CR, TXSOM, TXSOM);
+
+	/* Write the header (first byte of message) */
+	regmap_write(cec->regmap, CEC_TXDR, cec->tx_msg.msg[0]);
+	cec->tx_cnt++;
+
+	return 0;
+}
+
+static int stm32_cec_monitor_all(struct cec_adapter *adap, bool enable)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+
+	if (enable) {
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, OAR);
+		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, 0);
+	} else {
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
+		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, LSTN);
+	}
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+
+	return 0;
+}
+
+static const struct cec_adap_ops stm32_cec_adap_ops = {
+	.adap_enable = stm32_cec_adap_enable,
+	.adap_log_addr = stm32_cec_adap_log_addr,
+	.adap_transmit = stm32_cec_adap_transmit,
+	.adap_monitor_all_enable = stm32_cec_monitor_all,
+};
+
+static const struct regmap_config stm32_cec_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x14,
+	.fast_io = true,
+};
+
+static int stm32_cec_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_cec *cec;
+	void __iomem *mmio;
+	int ret;
+
+	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+	if (!cec)
+		return -ENOMEM;
+
+	cec->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mmio = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio,
+						&stm32_cec_regmap_cfg);
+
+	if (IS_ERR(cec->regmap))
+		return PTR_ERR(cec->regmap);
+
+	cec->irq = platform_get_irq(pdev, 0);
+	if (cec->irq < 0)
+		return cec->irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, cec->irq,
+					stm32_cec_irq_handler,
+					stm32_cec_irq_thread,
+					0,
+					pdev->name, cec);
+	if (ret)
+		return ret;
+
+	cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
+	if (IS_ERR(cec->clk_cec)) {
+		dev_err(&pdev->dev, "Cannot get cec clock\n");
+		return PTR_ERR(cec->clk_cec);
+	}
+
+	ret = clk_prepare(cec->clk_cec);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to prepare cec clock\n");
+		return ret;
+	}
+
+	cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
+	if (!IS_ERR(cec->clk_hdmi_cec)) {
+		ret = clk_prepare(cec->clk_hdmi_cec);
+		if (ret) {
+			dev_err(&pdev->dev, "Unable to prepare hdmi-cec clock\n");
+			return ret;
+		}
+	}
+
+	/*
+	 * CEC_CAP_PHYS_ADDR could be removed when a cec notifier is available
+	 */
+	cec->adap = cec_allocate_adapter(&stm32_cec_adap_ops, cec,
+			CEC_NAME,
+			CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH |
+			CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT |
+			CEC_CAP_RC | CEC_MODE_MONITOR_ALL,
+			CEC_MAX_LOG_ADDRS);
+	ret = PTR_ERR_OR_ZERO(cec->adap);
+	if (ret)
+		return ret;
+
+	ret = cec_register_adapter(cec->adap, &pdev->dev);
+	if (ret) {
+		cec_delete_adapter(cec->adap);
+		return ret;
+	}
+
+	cec_hw_init(cec);
+
+	platform_set_drvdata(pdev, cec);
+
+	return 0;
+}
+
+static int stm32_cec_remove(struct platform_device *pdev)
+{
+	struct stm32_cec *cec = platform_get_drvdata(pdev);
+
+	clk_unprepare(cec->clk_cec);
+	clk_unprepare(cec->clk_hdmi_cec);
+
+	cec_unregister_adapter(cec->adap);
+
+	cec_delete_adapter(cec->adap);
+
+	return 0;
+}
+
+static const struct of_device_id stm32_cec_of_match[] = {
+	{ .compatible = "st,stm32-cec" },
+	{ /* end node */ }
+};
+MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
+
+static struct platform_driver stm32_cec_driver = {
+	.probe  = stm32_cec_probe,
+	.remove = stm32_cec_remove,
+	.driver = {
+		.name		= CEC_NAME,
+		.of_match_table = stm32_cec_of_match,
+	},
+};
+
+module_platform_driver(stm32_cec_driver);
+
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>");
+MODULE_AUTHOR("Yannick Fertre <yannick.fertre-qxv4g6HH51o@public.gmane.org>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Consumer Electronics Control");
+MODULE_LICENSE("GPL v2");
-- 
1.9.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	[flat|nested] 12+ messages in thread

* [PATCH v2 2/2] cec: add STM32 cec driver
@ 2017-05-16 12:56     ` Benjamin Gaignard
  0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 12:56 UTC (permalink / raw)
  To: yannick.fertre, alexandre.torgue, hverkuil, devicetree,
	linux-media, robh, hans.verkuil
  Cc: Benjamin Gaignard

This patch add cec driver for STM32 platforms.
cec hardware block isn't not always used with hdmi so
cec notifier is not implemented. That will be done later
when STM32 DSI driver will be available.

Driver compliance has been tested with cec-ctl and cec-compliance
tools.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
---
 drivers/media/platform/Kconfig           |  11 +
 drivers/media/platform/Makefile          |   2 +
 drivers/media/platform/stm32/Makefile    |   1 +
 drivers/media/platform/stm32/stm32-cec.c | 384 +++++++++++++++++++++++++++++++
 4 files changed, 398 insertions(+)
 create mode 100644 drivers/media/platform/stm32/Makefile
 create mode 100644 drivers/media/platform/stm32/stm32-cec.c

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ac026ee..72efe34 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -519,4 +519,15 @@ config VIDEO_STI_HDMI_CEC
          CEC bus is present in the HDMI connector and enables communication
          between compatible devices.
 
+config VIDEO_STM32_HDMI_CEC
+       tristate "STMicroelectronics STM32 HDMI CEC driver"
+       depends on CEC_CORE && (ARCH_STM32 || COMPILE_TEST)
+       select REGMAP
+       select REGMAP_MMIO
+       ---help---
+         This is a driver for STM32 interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
 endif #CEC_PLATFORM_DRIVERS
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 63303d6..7cd9965 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -44,6 +44,8 @@ obj-$(CONFIG_VIDEO_STI_HDMI_CEC) 	+= sti/cec/
 
 obj-$(CONFIG_VIDEO_STI_DELTA)		+= sti/delta/
 
+obj-$(CONFIG_VIDEO_STM32_HDMI_CEC) 	+= stm32/
+
 obj-$(CONFIG_BLACKFIN)                  += blackfin/
 
 obj-$(CONFIG_ARCH_DAVINCI)		+= davinci/
diff --git a/drivers/media/platform/stm32/Makefile b/drivers/media/platform/stm32/Makefile
new file mode 100644
index 0000000..632b04c
--- /dev/null
+++ b/drivers/media/platform/stm32/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_STM32_HDMI_CEC) += stm32-cec.o
diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c
new file mode 100644
index 0000000..9de3f1d
--- /dev/null
+++ b/drivers/media/platform/stm32/stm32-cec.c
@@ -0,0 +1,384 @@
+/*
+ * STM32 CEC driver
+ * Copyright (C) STMicroelectronics SA 2017
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <media/cec.h>
+
+#define CEC_NAME	"stm32-cec"
+
+/* CEC registers  */
+#define CEC_CR		0x0000 /* Control Register */
+#define CEC_CFGR	0x0004 /* ConFiGuration Register */
+#define CEC_TXDR	0x0008 /* Rx data Register */
+#define CEC_RXDR	0x000C /* Rx data Register */
+#define CEC_ISR		0x0010 /* Interrupt and status Register */
+#define CEC_IER		0x0014 /* Interrupt enable Register */
+
+#define TXEOM		BIT(2)
+#define TXSOM		BIT(1)
+#define CECEN		BIT(0)
+
+#define LSTN		BIT(31)
+#define OAR		GENMASK(30, 16)
+#define SFTOP		BIT(8)
+#define BRDNOGEN	BIT(7)
+#define LBPEGEN		BIT(6)
+#define BREGEN		BIT(5)
+#define BRESTP		BIT(4)
+#define RXTOL		BIT(3)
+#define SFT		GENMASK(2, 0)
+#define FULL_CFG	(LSTN | SFTOP | BRDNOGEN | LBPEGEN | BREGEN | BRESTP \
+			 | RXTOL | SFT | BRDNOGEN)
+
+#define TXACKE		BIT(12)
+#define TXERR		BIT(11)
+#define TXUDR		BIT(10)
+#define TXEND		BIT(9)
+#define TXBR		BIT(8)
+#define ARBLST		BIT(7)
+#define RXACKE		BIT(6)
+#define RXOVR		BIT(2)
+#define RXEND		BIT(1)
+#define RXBR		BIT(0)
+
+#define ALL_TX_IT	(TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST)
+#define ALL_RX_IT	(RXEND | RXBR | RXACKE | RXOVR)
+
+struct stm32_cec {
+	struct cec_adapter	*adap;
+	struct device		*dev;
+	struct clk		*clk_cec;
+	struct clk		*clk_hdmi_cec;
+	struct reset_control	*rstc;
+	struct regmap		*regmap;
+	int			irq;
+	u32			irq_status;
+	struct cec_msg		rx_msg;
+	struct cec_msg		tx_msg;
+	int			tx_cnt;
+};
+
+static void cec_hw_init(struct stm32_cec *cec)
+{
+	regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0);
+
+	regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT,
+			   ALL_TX_IT | ALL_RX_IT);
+
+	regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG);
+}
+
+static void stm32_tx_done(struct stm32_cec *cec, u32 status)
+{
+	if (status & (TXERR | TXUDR)) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR,
+				  0, 0, 0, 1);
+		return;
+	}
+
+	if (status & ARBLST) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST,
+				  1, 0, 0, 0);
+		return;
+	}
+
+	if (status & TXACKE) {
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK,
+				  0, 1, 0, 0);
+		return;
+	}
+
+	if (cec->irq_status & TXBR) {
+		/* send next byte */
+		if (cec->tx_cnt < cec->tx_msg.len)
+			regmap_write(cec->regmap, CEC_TXDR,
+				     cec->tx_msg.msg[cec->tx_cnt++]);
+
+		/* TXEOM is set to command transmission of the last byte */
+		if (cec->tx_cnt == cec->tx_msg.len)
+			regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
+	}
+
+	if (cec->irq_status & TXEND)
+		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
+}
+
+static void stm32_rx_done(struct stm32_cec *cec, u32 status)
+{
+	if (cec->irq_status & (RXACKE | RXOVR)) {
+		cec->rx_msg.len = 0;
+		return;
+	}
+
+	if (cec->irq_status & RXBR) {
+		u32 val;
+
+		regmap_read(cec->regmap, CEC_RXDR, &val);
+		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
+	}
+
+	if (cec->irq_status & RXEND) {
+		cec_received_msg(cec->adap, &cec->rx_msg);
+		cec->rx_msg.len = 0;
+	}
+}
+
+static irqreturn_t stm32_cec_irq_thread(int irq, void *arg)
+{
+	struct stm32_cec *cec = arg;
+
+	if (cec->irq_status & ALL_TX_IT)
+		stm32_tx_done(cec, cec->irq_status);
+
+	if (cec->irq_status & ALL_RX_IT)
+		stm32_rx_done(cec, cec->irq_status);
+
+	cec->irq_status = 0;
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t stm32_cec_irq_handler(int irq, void *arg)
+{
+	struct stm32_cec *cec = arg;
+
+	regmap_read(cec->regmap, CEC_ISR, &cec->irq_status);
+
+	regmap_update_bits(cec->regmap, CEC_ISR,
+			   ALL_TX_IT | ALL_RX_IT,
+			   ALL_TX_IT | ALL_RX_IT);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+	struct stm32_cec *cec = adap->priv;
+	int ret = 0;
+
+	if (enable) {
+		ret = clk_enable(cec->clk_cec);
+		if (ret)
+			dev_err(cec->dev, "fail to enable cec clock\n");
+
+		clk_enable(cec->clk_hdmi_cec);
+		regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+	} else {
+		clk_disable(cec->clk_cec);
+		clk_disable(cec->clk_hdmi_cec);
+		regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+	}
+
+	return ret;
+}
+
+static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+
+	if (logical_addr == CEC_LOG_ADDR_INVALID)
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
+	else
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR,
+				   (1 << logical_addr) << 16);
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+
+	return 0;
+}
+
+static int stm32_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+				   u32 signal_free_time, struct cec_msg *msg)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	/* Copy message */
+	cec->tx_msg = *msg;
+	cec->tx_cnt = 0;
+
+	/*
+	 * If the CEC message consists of only one byte,
+	 * TXEOM must be set before of TXSOM.
+	 */
+	if (cec->tx_msg.len == 1)
+		regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
+
+	/* TXSOM is set to command transmission of the first byte */
+	regmap_update_bits(cec->regmap, CEC_CR, TXSOM, TXSOM);
+
+	/* Write the header (first byte of message) */
+	regmap_write(cec->regmap, CEC_TXDR, cec->tx_msg.msg[0]);
+	cec->tx_cnt++;
+
+	return 0;
+}
+
+static int stm32_cec_monitor_all(struct cec_adapter *adap, bool enable)
+{
+	struct stm32_cec *cec = adap->priv;
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
+
+	if (enable) {
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, OAR);
+		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, 0);
+	} else {
+		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
+		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, LSTN);
+	}
+
+	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
+
+	return 0;
+}
+
+static const struct cec_adap_ops stm32_cec_adap_ops = {
+	.adap_enable = stm32_cec_adap_enable,
+	.adap_log_addr = stm32_cec_adap_log_addr,
+	.adap_transmit = stm32_cec_adap_transmit,
+	.adap_monitor_all_enable = stm32_cec_monitor_all,
+};
+
+static const struct regmap_config stm32_cec_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x14,
+	.fast_io = true,
+};
+
+static int stm32_cec_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct stm32_cec *cec;
+	void __iomem *mmio;
+	int ret;
+
+	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+	if (!cec)
+		return -ENOMEM;
+
+	cec->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mmio = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio,
+						&stm32_cec_regmap_cfg);
+
+	if (IS_ERR(cec->regmap))
+		return PTR_ERR(cec->regmap);
+
+	cec->irq = platform_get_irq(pdev, 0);
+	if (cec->irq < 0)
+		return cec->irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, cec->irq,
+					stm32_cec_irq_handler,
+					stm32_cec_irq_thread,
+					0,
+					pdev->name, cec);
+	if (ret)
+		return ret;
+
+	cec->clk_cec = devm_clk_get(&pdev->dev, "cec");
+	if (IS_ERR(cec->clk_cec)) {
+		dev_err(&pdev->dev, "Cannot get cec clock\n");
+		return PTR_ERR(cec->clk_cec);
+	}
+
+	ret = clk_prepare(cec->clk_cec);
+	if (ret) {
+		dev_err(&pdev->dev, "Unable to prepare cec clock\n");
+		return ret;
+	}
+
+	cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec");
+	if (!IS_ERR(cec->clk_hdmi_cec)) {
+		ret = clk_prepare(cec->clk_hdmi_cec);
+		if (ret) {
+			dev_err(&pdev->dev, "Unable to prepare hdmi-cec clock\n");
+			return ret;
+		}
+	}
+
+	/*
+	 * CEC_CAP_PHYS_ADDR could be removed when a cec notifier is available
+	 */
+	cec->adap = cec_allocate_adapter(&stm32_cec_adap_ops, cec,
+			CEC_NAME,
+			CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH |
+			CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT |
+			CEC_CAP_RC | CEC_MODE_MONITOR_ALL,
+			CEC_MAX_LOG_ADDRS);
+	ret = PTR_ERR_OR_ZERO(cec->adap);
+	if (ret)
+		return ret;
+
+	ret = cec_register_adapter(cec->adap, &pdev->dev);
+	if (ret) {
+		cec_delete_adapter(cec->adap);
+		return ret;
+	}
+
+	cec_hw_init(cec);
+
+	platform_set_drvdata(pdev, cec);
+
+	return 0;
+}
+
+static int stm32_cec_remove(struct platform_device *pdev)
+{
+	struct stm32_cec *cec = platform_get_drvdata(pdev);
+
+	clk_unprepare(cec->clk_cec);
+	clk_unprepare(cec->clk_hdmi_cec);
+
+	cec_unregister_adapter(cec->adap);
+
+	cec_delete_adapter(cec->adap);
+
+	return 0;
+}
+
+static const struct of_device_id stm32_cec_of_match[] = {
+	{ .compatible = "st,stm32-cec" },
+	{ /* end node */ }
+};
+MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
+
+static struct platform_driver stm32_cec_driver = {
+	.probe  = stm32_cec_probe,
+	.remove = stm32_cec_remove,
+	.driver = {
+		.name		= CEC_NAME,
+		.of_match_table = stm32_cec_of_match,
+	},
+};
+
+module_platform_driver(stm32_cec_driver);
+
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
+MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Consumer Electronics Control");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

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

* Re: [PATCH v2 2/2] cec: add STM32 cec driver
  2017-05-16 12:56     ` Benjamin Gaignard
@ 2017-05-16 13:09         ` Hans Verkuil
  -1 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2017-05-16 13:09 UTC (permalink / raw)
  To: Benjamin Gaignard, yannick.fertre-qxv4g6HH51o,
	alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA, robh-DgEjT+Ai2ygdnm+yROfE0A,
	hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w

Looks good, except for the logical address handling that I think is wrong:

On 16/05/17 14:56, Benjamin Gaignard wrote:
> This patch add cec driver for STM32 platforms.
> cec hardware block isn't not always used with hdmi so
> cec notifier is not implemented. That will be done later
> when STM32 DSI driver will be available.
> 
> Driver compliance has been tested with cec-ctl and cec-compliance
> tools.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Yannick Fertre <yannick.fertre-qxv4g6HH51o@public.gmane.org>
> ---
>  drivers/media/platform/Kconfig           |  11 +
>  drivers/media/platform/Makefile          |   2 +
>  drivers/media/platform/stm32/Makefile    |   1 +
>  drivers/media/platform/stm32/stm32-cec.c | 384 +++++++++++++++++++++++++++++++
>  4 files changed, 398 insertions(+)
>  create mode 100644 drivers/media/platform/stm32/Makefile
>  create mode 100644 drivers/media/platform/stm32/stm32-cec.c
> 

<snip>

> +static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
> +{
> +	struct stm32_cec *cec = adap->priv;
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
> +
> +	if (logical_addr == CEC_LOG_ADDR_INVALID)
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
> +	else
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR,
> +				   (1 << logical_addr) << 16);
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
> +
> +	return 0;
> +}
> +

If you allocate more than one logical address, then stm32_cec_adap_log_addr()
is called once for each LA. But right now the second call would overwrite
the first LA. Right?

Try 'cec-ctl --audio --playback' to allocate two logical addresses.

<snip>

> +static int stm32_cec_monitor_all(struct cec_adapter *adap, bool enable)
> +{
> +	struct stm32_cec *cec = adap->priv;
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
> +
> +	if (enable) {
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, OAR)

You shouldn't have to change the OAR mask. This would have the adapter
Ack all logical addresses.

> +		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, 0);
> +	} else {
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);

And this would disable all logical addresses.

I would expect that only the LSTN bit was changed.

In monitoring mode it should still Ack any messages directed to us.

> +		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, LSTN);
> +	}
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
> +
> +	return 0;
> +}

<snip>

Regards,

	Hans
--
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	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 2/2] cec: add STM32 cec driver
@ 2017-05-16 13:09         ` Hans Verkuil
  0 siblings, 0 replies; 12+ messages in thread
From: Hans Verkuil @ 2017-05-16 13:09 UTC (permalink / raw)
  To: Benjamin Gaignard, yannick.fertre, alexandre.torgue, devicetree,
	linux-media, robh, hans.verkuil

Looks good, except for the logical address handling that I think is wrong:

On 16/05/17 14:56, Benjamin Gaignard wrote:
> This patch add cec driver for STM32 platforms.
> cec hardware block isn't not always used with hdmi so
> cec notifier is not implemented. That will be done later
> when STM32 DSI driver will be available.
> 
> Driver compliance has been tested with cec-ctl and cec-compliance
> tools.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
> ---
>  drivers/media/platform/Kconfig           |  11 +
>  drivers/media/platform/Makefile          |   2 +
>  drivers/media/platform/stm32/Makefile    |   1 +
>  drivers/media/platform/stm32/stm32-cec.c | 384 +++++++++++++++++++++++++++++++
>  4 files changed, 398 insertions(+)
>  create mode 100644 drivers/media/platform/stm32/Makefile
>  create mode 100644 drivers/media/platform/stm32/stm32-cec.c
> 

<snip>

> +static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
> +{
> +	struct stm32_cec *cec = adap->priv;
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
> +
> +	if (logical_addr == CEC_LOG_ADDR_INVALID)
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
> +	else
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR,
> +				   (1 << logical_addr) << 16);
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
> +
> +	return 0;
> +}
> +

If you allocate more than one logical address, then stm32_cec_adap_log_addr()
is called once for each LA. But right now the second call would overwrite
the first LA. Right?

Try 'cec-ctl --audio --playback' to allocate two logical addresses.

<snip>

> +static int stm32_cec_monitor_all(struct cec_adapter *adap, bool enable)
> +{
> +	struct stm32_cec *cec = adap->priv;
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
> +
> +	if (enable) {
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, OAR)

You shouldn't have to change the OAR mask. This would have the adapter
Ack all logical addresses.

> +		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, 0);
> +	} else {
> +		regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);

And this would disable all logical addresses.

I would expect that only the LSTN bit was changed.

In monitoring mode it should still Ack any messages directed to us.

> +		regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, LSTN);
> +	}
> +
> +	regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
> +
> +	return 0;
> +}

<snip>

Regards,

	Hans

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

* Re: [PATCH v2 2/2] cec: add STM32 cec driver
  2017-05-16 13:09         ` Hans Verkuil
  (?)
@ 2017-05-16 13:54         ` Benjamin Gaignard
  -1 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-16 13:54 UTC (permalink / raw)
  To: Hans Verkuil
  Cc: Yannick Fertre, Alexandre Torgue, devicetree, linux-media,
	Rob Herring, Hans Verkuil

2017-05-16 15:09 GMT+02:00 Hans Verkuil <hverkuil@xs4all.nl>:
> Looks good, except for the logical address handling that I think is wrong:
>
> On 16/05/17 14:56, Benjamin Gaignard wrote:
>> This patch add cec driver for STM32 platforms.
>> cec hardware block isn't not always used with hdmi so
>> cec notifier is not implemented. That will be done later
>> when STM32 DSI driver will be available.
>>
>> Driver compliance has been tested with cec-ctl and cec-compliance
>> tools.
>>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>> Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
>> ---
>>  drivers/media/platform/Kconfig           |  11 +
>>  drivers/media/platform/Makefile          |   2 +
>>  drivers/media/platform/stm32/Makefile    |   1 +
>>  drivers/media/platform/stm32/stm32-cec.c | 384 +++++++++++++++++++++++++++++++
>>  4 files changed, 398 insertions(+)
>>  create mode 100644 drivers/media/platform/stm32/Makefile
>>  create mode 100644 drivers/media/platform/stm32/stm32-cec.c
>>
>
> <snip>
>
>> +static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
>> +{
>> +     struct stm32_cec *cec = adap->priv;
>> +
>> +     regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
>> +
>> +     if (logical_addr == CEC_LOG_ADDR_INVALID)
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
>> +     else
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, OAR,
>> +                                (1 << logical_addr) << 16);
>> +
>> +     regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
>> +
>> +     return 0;
>> +}
>> +
>
> If you allocate more than one logical address, then stm32_cec_adap_log_addr()
> is called once for each LA. But right now the second call would overwrite
> the first LA. Right?
>
> Try 'cec-ctl --audio --playback' to allocate two logical addresses.

I will fix that in v3

>
> <snip>
>
>> +static int stm32_cec_monitor_all(struct cec_adapter *adap, bool enable)
>> +{
>> +     struct stm32_cec *cec = adap->priv;
>> +
>> +     regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
>> +
>> +     if (enable) {
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, OAR, OAR)
>
> You shouldn't have to change the OAR mask. This would have the adapter
> Ack all logical addresses.
>
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, 0);
>> +     } else {
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0);
>
> And this would disable all logical addresses.
>
> I would expect that only the LSTN bit was changed.
>
> In monitoring mode it should still Ack any messages directed to us.

This is an impossible mix in my hardware: messages are received if
corresponding OAR
bit is set and acked if LSTN is set to 1.
It can't receive all messages and only ack some of them....

>
>> +             regmap_update_bits(cec->regmap, CEC_CFGR, LSTN, LSTN);
>> +     }
>> +
>> +     regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN);
>> +
>> +     return 0;
>> +}
>
> <snip>
>
> Regards,
>
>         Hans



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org │ Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

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

* Re: [PATCH v2 1/2] binding for stm32 cec driver
  2017-05-16 12:56 ` [PATCH v2 1/2] binding for stm32 cec driver Benjamin Gaignard
@ 2017-05-23  0:14       ` Rob Herring
  0 siblings, 0 replies; 12+ messages in thread
From: Rob Herring @ 2017-05-23  0:14 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: yannick.fertre-qxv4g6HH51o, alexandre.torgue-qxv4g6HH51o,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA,
	hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w

On Tue, May 16, 2017 at 02:56:22PM +0200, Benjamin Gaignard wrote:

Commit message?

Preferred subject prefix is "dt-bindings: media: ..."

> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
>  .../devicetree/bindings/media/st,stm32-cec.txt        | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
> new file mode 100644
> index 0000000..6be2381
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
> @@ -0,0 +1,19 @@
> +STMicroelectronics STM32 CEC driver
> +
> +Required properties:
> + - compatible : value should be "st,stm32-cec"

All stm32 chips have same CEC block?

> + - reg : Physical base address of the IP registers and length of memory
> +	 mapped region.
> + - clocks : from common clock binding: handle to CEC clocks
> + - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
> + - interrupts : CEC interrupt number to the CPU.
> +
> +Example for stm32f746:
> +
> +cec: cec@40006c00 {
> +	compatible = "st,stm32-cec";
> +	reg = <0x40006C00 0x400>;
> +	interrupts = <94>;
> +	clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
> +	clock-names = "cec", "hdmi-cec";
> +};
> -- 
> 1.9.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	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/2] binding for stm32 cec driver
@ 2017-05-23  0:14       ` Rob Herring
  0 siblings, 0 replies; 12+ messages in thread
From: Rob Herring @ 2017-05-23  0:14 UTC (permalink / raw)
  To: Benjamin Gaignard
  Cc: yannick.fertre, alexandre.torgue, hverkuil, devicetree,
	linux-media, hans.verkuil

On Tue, May 16, 2017 at 02:56:22PM +0200, Benjamin Gaignard wrote:

Commit message?

Preferred subject prefix is "dt-bindings: media: ..."

> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
> ---
>  .../devicetree/bindings/media/st,stm32-cec.txt        | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
> new file mode 100644
> index 0000000..6be2381
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
> @@ -0,0 +1,19 @@
> +STMicroelectronics STM32 CEC driver
> +
> +Required properties:
> + - compatible : value should be "st,stm32-cec"

All stm32 chips have same CEC block?

> + - reg : Physical base address of the IP registers and length of memory
> +	 mapped region.
> + - clocks : from common clock binding: handle to CEC clocks
> + - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
> + - interrupts : CEC interrupt number to the CPU.
> +
> +Example for stm32f746:
> +
> +cec: cec@40006c00 {
> +	compatible = "st,stm32-cec";
> +	reg = <0x40006C00 0x400>;
> +	interrupts = <94>;
> +	clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
> +	clock-names = "cec", "hdmi-cec";
> +};
> -- 
> 1.9.1
> 

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

* Re: [PATCH v2 1/2] binding for stm32 cec driver
  2017-05-23  0:14       ` Rob Herring
@ 2017-05-23  7:15         ` Benjamin Gaignard
  -1 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-23  7:15 UTC (permalink / raw)
  To: Rob Herring
  Cc: Yannick Fertre, Alexandre Torgue, Hans Verkuil,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-media-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil

2017-05-23 2:14 GMT+02:00 Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>:
> On Tue, May 16, 2017 at 02:56:22PM +0200, Benjamin Gaignard wrote:
>
> Commit message?

is missing, sorry..

>
> Preferred subject prefix is "dt-bindings: media: ..."

ok

>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>>  .../devicetree/bindings/media/st,stm32-cec.txt        | 19 +++++++++++++++++++
>>  1 file changed, 19 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
>> new file mode 100644
>> index 0000000..6be2381
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
>> @@ -0,0 +1,19 @@
>> +STMicroelectronics STM32 CEC driver
>> +
>> +Required properties:
>> + - compatible : value should be "st,stm32-cec"
>
> All stm32 chips have same CEC block?

yes the block is the same for all stm32 f4/f7/h7 chips

>
>> + - reg : Physical base address of the IP registers and length of memory
>> +      mapped region.
>> + - clocks : from common clock binding: handle to CEC clocks
>> + - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
>> + - interrupts : CEC interrupt number to the CPU.
>> +
>> +Example for stm32f746:
>> +
>> +cec: cec@40006c00 {
>> +     compatible = "st,stm32-cec";
>> +     reg = <0x40006C00 0x400>;
>> +     interrupts = <94>;
>> +     clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
>> +     clock-names = "cec", "hdmi-cec";
>> +};
>> --
>> 1.9.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	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 1/2] binding for stm32 cec driver
@ 2017-05-23  7:15         ` Benjamin Gaignard
  0 siblings, 0 replies; 12+ messages in thread
From: Benjamin Gaignard @ 2017-05-23  7:15 UTC (permalink / raw)
  To: Rob Herring
  Cc: Yannick Fertre, Alexandre Torgue, Hans Verkuil, devicetree,
	linux-media, Hans Verkuil

2017-05-23 2:14 GMT+02:00 Rob Herring <robh@kernel.org>:
> On Tue, May 16, 2017 at 02:56:22PM +0200, Benjamin Gaignard wrote:
>
> Commit message?

is missing, sorry..

>
> Preferred subject prefix is "dt-bindings: media: ..."

ok

>
>> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
>> ---
>>  .../devicetree/bindings/media/st,stm32-cec.txt        | 19 +++++++++++++++++++
>>  1 file changed, 19 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/media/st,stm32-cec.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.txt b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
>> new file mode 100644
>> index 0000000..6be2381
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/st,stm32-cec.txt
>> @@ -0,0 +1,19 @@
>> +STMicroelectronics STM32 CEC driver
>> +
>> +Required properties:
>> + - compatible : value should be "st,stm32-cec"
>
> All stm32 chips have same CEC block?

yes the block is the same for all stm32 f4/f7/h7 chips

>
>> + - reg : Physical base address of the IP registers and length of memory
>> +      mapped region.
>> + - clocks : from common clock binding: handle to CEC clocks
>> + - clock-names : from common clock binding: must be "cec" and "hdmi-cec".
>> + - interrupts : CEC interrupt number to the CPU.
>> +
>> +Example for stm32f746:
>> +
>> +cec: cec@40006c00 {
>> +     compatible = "st,stm32-cec";
>> +     reg = <0x40006C00 0x400>;
>> +     interrupts = <94>;
>> +     clocks = <&rcc 0 STM32F7_APB1_CLOCK(CEC)>, <&rcc 1 CLK_HDMI_CEC>;
>> +     clock-names = "cec", "hdmi-cec";
>> +};
>> --
>> 1.9.1
>>

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

end of thread, other threads:[~2017-05-23  7:15 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-16 12:56 [PATCH v2 0/2] cec: STM32 driver Benjamin Gaignard
2017-05-16 12:56 ` Benjamin Gaignard
2017-05-16 12:56 ` [PATCH v2 1/2] binding for stm32 cec driver Benjamin Gaignard
     [not found]   ` <1494939383-18937-2-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-05-23  0:14     ` Rob Herring
2017-05-23  0:14       ` Rob Herring
2017-05-23  7:15       ` Benjamin Gaignard
2017-05-23  7:15         ` Benjamin Gaignard
     [not found] ` <1494939383-18937-1-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-05-16 12:56   ` [PATCH v2 2/2] cec: add STM32 " Benjamin Gaignard
2017-05-16 12:56     ` Benjamin Gaignard
     [not found]     ` <1494939383-18937-3-git-send-email-benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-05-16 13:09       ` Hans Verkuil
2017-05-16 13:09         ` Hans Verkuil
2017-05-16 13:54         ` Benjamin Gaignard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.