* [PATCH v4 2/8] [media] stm32-dcmi: STM32 DCMI camera interface driver
From: Hugues Fruchet @ 2017-04-20 16:07 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre Torgue,
Mauro Carvalho Chehab, Hans Verkuil
Cc: devicetree, linux-kernel, Yannick Fertre, Benjamin Gaignard,
Hugues Fruchet, linux-arm-kernel, linux-media
In-Reply-To: <1492704445-22186-1-git-send-email-hugues.fruchet@st.com>
This V4L2 subdev driver enables Digital Camera Memory Interface (DCMI)
of STMicroelectronics STM32 SoC series.
Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
drivers/media/platform/Kconfig | 12 +
drivers/media/platform/Makefile | 2 +
drivers/media/platform/stm32/Makefile | 1 +
drivers/media/platform/stm32/stm32-dcmi.c | 1419 +++++++++++++++++++++++++++++
4 files changed, 1434 insertions(+)
create mode 100644 drivers/media/platform/stm32/Makefile
create mode 100644 drivers/media/platform/stm32/stm32-dcmi.c
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ac026ee..de6e18b 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -114,6 +114,18 @@ config VIDEO_S3C_CAMIF
To compile this driver as a module, choose M here: the module
will be called s3c-camif.
+config VIDEO_STM32_DCMI
+ tristate "Digital Camera Memory Interface (DCMI) support"
+ depends on VIDEO_V4L2 && OF && HAS_DMA
+ depends on ARCH_STM32 || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This module makes the STM32 Digital Camera Memory Interface (DCMI)
+ available as a v4l2 device.
+
+ To compile this driver as a module, choose M here: the module
+ will be called stm32-dcmi.
+
source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/am437x/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 63303d6..231f3c2 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -68,6 +68,8 @@ obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/
obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel/
+obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32/
+
ccflags-y += -I$(srctree)/drivers/media/i2c
obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/
diff --git a/drivers/media/platform/stm32/Makefile b/drivers/media/platform/stm32/Makefile
new file mode 100644
index 0000000..9b606a7
--- /dev/null
+++ b/drivers/media/platform/stm32/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32-dcmi.o
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
new file mode 100644
index 0000000..0ed3bd9
--- /dev/null
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -0,0 +1,1419 @@
+/*
+ * Driver for STM32 Digital Camera Memory Interface
+ *
+ * Copyright (C) STMicroelectronics SA 2017
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ * Hugues Fruchet <hugues.fruchet@st.com>
+ * for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * This driver is based on atmel_isi.c
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/init.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/reset.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define DRV_NAME "stm32-dcmi"
+
+/* Registers offset for DCMI */
+#define DCMI_CR 0x00 /* Control Register */
+#define DCMI_SR 0x04 /* Status Register */
+#define DCMI_RIS 0x08 /* Raw Interrupt Status register */
+#define DCMI_IER 0x0C /* Interrupt Enable Register */
+#define DCMI_MIS 0x10 /* Masked Interrupt Status register */
+#define DCMI_ICR 0x14 /* Interrupt Clear Register */
+#define DCMI_ESCR 0x18 /* Embedded Synchronization Code Register */
+#define DCMI_ESUR 0x1C /* Embedded Synchronization Unmask Register */
+#define DCMI_CWSTRT 0x20 /* Crop Window STaRT */
+#define DCMI_CWSIZE 0x24 /* Crop Window SIZE */
+#define DCMI_DR 0x28 /* Data Register */
+#define DCMI_IDR 0x2C /* IDentifier Register */
+
+/* Bits definition for control register (DCMI_CR) */
+#define CR_CAPTURE BIT(0)
+#define CR_CM BIT(1)
+#define CR_CROP BIT(2)
+#define CR_JPEG BIT(3)
+#define CR_ESS BIT(4)
+#define CR_PCKPOL BIT(5)
+#define CR_HSPOL BIT(6)
+#define CR_VSPOL BIT(7)
+#define CR_FCRC_0 BIT(8)
+#define CR_FCRC_1 BIT(9)
+#define CR_EDM_0 BIT(10)
+#define CR_EDM_1 BIT(11)
+#define CR_ENABLE BIT(14)
+
+/* Bits definition for status register (DCMI_SR) */
+#define SR_HSYNC BIT(0)
+#define SR_VSYNC BIT(1)
+#define SR_FNE BIT(2)
+
+/*
+ * Bits definition for interrupt registers
+ * (DCMI_RIS, DCMI_IER, DCMI_MIS, DCMI_ICR)
+ */
+#define IT_FRAME BIT(0)
+#define IT_OVR BIT(1)
+#define IT_ERR BIT(2)
+#define IT_VSYNC BIT(3)
+#define IT_LINE BIT(4)
+
+enum state {
+ STOPPED = 0,
+ RUNNING,
+ STOPPING,
+};
+
+#define MAX_BUS_WIDTH 14
+#define MAX_SUPPORT_WIDTH 2048
+#define MAX_SUPPORT_HEIGHT 2048
+#define MIN_SUPPORT_WIDTH 16
+#define MIN_SUPPORT_HEIGHT 16
+#define TIMEOUT_MS 1000
+
+struct dcmi_graph_entity {
+ struct device_node *node;
+
+ struct v4l2_async_subdev asd;
+ struct v4l2_subdev *subdev;
+};
+
+struct dcmi_format {
+ u32 fourcc;
+ u32 mbus_code;
+ u8 bpp;
+};
+
+struct dcmi_buf {
+ struct vb2_v4l2_buffer vb;
+ bool prepared;
+ dma_addr_t paddr;
+ size_t size;
+ struct list_head list;
+};
+
+struct stm32_dcmi {
+ /* Protects the access of variables shared within the interrupt */
+ spinlock_t irqlock;
+ struct device *dev;
+ void __iomem *regs;
+ struct resource *res;
+ struct reset_control *rstc;
+ int sequence;
+ struct list_head buffers;
+ struct dcmi_buf *active;
+
+ struct v4l2_device v4l2_dev;
+ struct video_device *vdev;
+ struct v4l2_async_notifier notifier;
+ struct dcmi_graph_entity entity;
+ struct v4l2_format fmt;
+
+ const struct dcmi_format **user_formats;
+ unsigned int num_user_formats;
+ const struct dcmi_format *current_fmt;
+
+ /* Protect this data structure */
+ struct mutex lock;
+ struct vb2_queue queue;
+
+ struct v4l2_of_bus_parallel bus;
+ struct completion complete;
+ struct clk *mclk;
+ enum state state;
+ struct dma_chan *dma_chan;
+ dma_cookie_t dma_cookie;
+ u32 misr;
+ int errors_count;
+ int buffers_count;
+};
+
+static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
+{
+ return container_of(n, struct stm32_dcmi, notifier);
+}
+
+static inline u32 reg_read(void __iomem *base, u32 reg)
+{
+ return readl_relaxed(base + reg);
+}
+
+static inline void reg_write(void __iomem *base, u32 reg, u32 val)
+{
+ writel_relaxed(val, base + reg);
+}
+
+static inline void reg_set(void __iomem *base, u32 reg, u32 mask)
+{
+ reg_write(base, reg, reg_read(base, reg) | mask);
+}
+
+static inline void reg_clear(void __iomem *base, u32 reg, u32 mask)
+{
+ reg_write(base, reg, reg_read(base, reg) & ~mask);
+}
+
+static int dcmi_start_capture(struct stm32_dcmi *dcmi);
+
+static void dcmi_dma_callback(void *param)
+{
+ struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param;
+ struct dma_chan *chan = dcmi->dma_chan;
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ spin_lock(&dcmi->irqlock);
+
+ /* Check DMA status */
+ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state);
+
+ switch (status) {
+ case DMA_IN_PROGRESS:
+ dev_dbg(dcmi->dev, "%s: Received DMA_IN_PROGRESS\n", __func__);
+ break;
+ case DMA_PAUSED:
+ dev_err(dcmi->dev, "%s: Received DMA_PAUSED\n", __func__);
+ break;
+ case DMA_ERROR:
+ dev_err(dcmi->dev, "%s: Received DMA_ERROR\n", __func__);
+ break;
+ case DMA_COMPLETE:
+ dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__);
+
+ if (dcmi->active) {
+ struct dcmi_buf *buf = dcmi->active;
+ struct vb2_v4l2_buffer *vbuf = &dcmi->active->vb;
+
+ vbuf->sequence = dcmi->sequence++;
+ vbuf->field = V4L2_FIELD_NONE;
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
+ vb2_set_plane_payload(&vbuf->vb2_buf, 0, buf->size);
+ vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
+ dev_dbg(dcmi->dev, "buffer[%d] done seq=%d\n",
+ vbuf->vb2_buf.index, vbuf->sequence);
+
+ dcmi->buffers_count++;
+ dcmi->active = NULL;
+ }
+
+ /* Restart a new DMA transfer with next buffer */
+ if (dcmi->state == RUNNING) {
+ int ret;
+
+ if (list_empty(&dcmi->buffers)) {
+ dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer",
+ __func__);
+ dcmi->errors_count++;
+ dcmi->active = NULL;
+
+ spin_unlock(&dcmi->irqlock);
+ return;
+ }
+
+ dcmi->active = list_entry(dcmi->buffers.next,
+ struct dcmi_buf, list);
+
+ list_del_init(&dcmi->active->list);
+
+ ret = dcmi_start_capture(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete",
+ __func__);
+
+ spin_unlock(&dcmi->irqlock);
+ return;
+ }
+
+ /* Enable capture */
+ reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE);
+ }
+
+ break;
+ default:
+ dev_err(dcmi->dev, "%s: Received unknown status\n", __func__);
+ break;
+ }
+
+ spin_unlock(&dcmi->irqlock);
+}
+
+static int dcmi_start_dma(struct stm32_dcmi *dcmi,
+ struct dcmi_buf *buf)
+{
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_slave_config config;
+ int ret;
+
+ memset(&config, 0, sizeof(config));
+
+ config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ config.dst_maxburst = 4;
+
+ /* Configure DMA channel */
+ ret = dmaengine_slave_config(dcmi->dma_chan, &config);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Prepare a DMA transaction */
+ desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr,
+ buf->size,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (!desc) {
+ dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer size %zu\n",
+ __func__, buf->size);
+ return -EINVAL;
+ }
+
+ /* Set completion callback routine for notification */
+ desc->callback = dcmi_dma_callback;
+ desc->callback_param = dcmi;
+
+ /* Push current DMA transaction in the pending queue */
+ dcmi->dma_cookie = dmaengine_submit(desc);
+
+ dma_async_issue_pending(dcmi->dma_chan);
+
+ return 0;
+}
+
+static int dcmi_start_capture(struct stm32_dcmi *dcmi)
+{
+ int ret;
+ struct dcmi_buf *buf = dcmi->active;
+
+ if (!buf)
+ return -EINVAL;
+
+ ret = dcmi_start_dma(dcmi, buf);
+ if (ret) {
+ dcmi->errors_count++;
+ return ret;
+ }
+
+ /* Enable capture */
+ reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE);
+
+ return 0;
+}
+
+static irqreturn_t dcmi_irq_thread(int irq, void *arg)
+{
+ struct stm32_dcmi *dcmi = arg;
+ int ret;
+
+ spin_lock(&dcmi->irqlock);
+
+ /* Stop capture is required */
+ if (dcmi->state == STOPPING) {
+ reg_clear(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+
+ dcmi->state = STOPPED;
+
+ complete(&dcmi->complete);
+
+ spin_unlock(&dcmi->irqlock);
+ return IRQ_HANDLED;
+ }
+
+ if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) {
+ /*
+ * An overflow or an error has been detected,
+ * stop current DMA transfert & restart it
+ */
+ dev_warn(dcmi->dev, "%s: Overflow or error detected\n",
+ __func__);
+
+ dcmi->errors_count++;
+ dmaengine_terminate_all(dcmi->dma_chan);
+
+ reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR);
+
+ dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n");
+
+ ret = dcmi_start_capture(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
+ __func__);
+
+ spin_unlock(&dcmi->irqlock);
+ return IRQ_HANDLED;
+ }
+ }
+
+ spin_unlock(&dcmi->irqlock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dcmi_irq_callback(int irq, void *arg)
+{
+ struct stm32_dcmi *dcmi = arg;
+
+ spin_lock(&dcmi->irqlock);
+
+ dcmi->misr = reg_read(dcmi->regs, DCMI_MIS);
+
+ /* Clear interrupt */
+ reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR);
+
+ spin_unlock(&dcmi->irqlock);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int dcmi_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers,
+ unsigned int *nplanes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
+ unsigned int size;
+
+ size = dcmi->fmt.fmt.pix.sizeimage;
+
+ /* Make sure the image size is large enough */
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ dcmi->active = NULL;
+
+ dev_dbg(dcmi->dev, "Setup queue, count=%d, size=%d\n",
+ *nbuffers, size);
+
+ return 0;
+}
+
+static int dcmi_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
+
+ INIT_LIST_HEAD(&buf->list);
+
+ return 0;
+}
+
+static int dcmi_buf_prepare(struct vb2_buffer *vb)
+{
+ struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
+ unsigned long size;
+
+ size = dcmi->fmt.fmt.pix.sizeimage;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_err(dcmi->dev, "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ if (!buf->prepared) {
+ /* Get memory addresses */
+ buf->paddr =
+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+ buf->prepared = true;
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
+
+ dev_dbg(dcmi->dev, "buffer[%d] phy=0x%pad size=%zu\n",
+ vb->index, &buf->paddr, buf->size);
+ }
+
+ return 0;
+}
+
+static void dcmi_buf_queue(struct vb2_buffer *vb)
+{
+ struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dcmi->irqlock, flags);
+
+ if ((dcmi->state == RUNNING) && (!dcmi->active)) {
+ int ret;
+
+ dcmi->active = buf;
+
+ dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n",
+ buf->vb.vb2_buf.index);
+
+ ret = dcmi_start_capture(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
+ __func__);
+
+ spin_unlock_irqrestore(&dcmi->irqlock, flags);
+ return;
+ }
+ } else {
+ /* Enqueue to video buffers list */
+ list_add_tail(&buf->list, &dcmi->buffers);
+ }
+
+ spin_unlock_irqrestore(&dcmi->irqlock, flags);
+}
+
+static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
+ struct dcmi_buf *buf, *node;
+ u32 val;
+ int ret;
+
+ /* Enable stream on the sub device */
+ ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD) {
+ dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error",
+ __func__);
+ goto err_release_buffers;
+ }
+
+ if (clk_enable(dcmi->mclk)) {
+ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock",
+ __func__);
+ goto err_subdev_streamoff;
+ }
+
+ spin_lock_irq(&dcmi->irqlock);
+
+ val = reg_read(dcmi->regs, DCMI_CR);
+
+ val &= ~(CR_PCKPOL | CR_HSPOL | CR_VSPOL |
+ CR_EDM_0 | CR_EDM_1 | CR_FCRC_0 |
+ CR_FCRC_1 | CR_JPEG | CR_ESS);
+
+ /* Set bus width */
+ switch (dcmi->bus.bus_width) {
+ case 14:
+ val &= CR_EDM_0 + CR_EDM_1;
+ break;
+ case 12:
+ val &= CR_EDM_1;
+ break;
+ case 10:
+ val &= CR_EDM_0;
+ break;
+ default:
+ /* Set bus width to 8 bits by default */
+ break;
+ }
+
+ /* Set vertical synchronization polarity */
+ if (dcmi->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ val |= CR_VSPOL;
+
+ /* Set horizontal synchronization polarity */
+ if (dcmi->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ val |= CR_HSPOL;
+
+ /* Set pixel clock polarity */
+ if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ val |= CR_PCKPOL;
+
+ reg_write(dcmi->regs, DCMI_CR, val);
+
+ /* Enable dcmi */
+ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
+
+ dcmi->state = RUNNING;
+
+ dcmi->sequence = 0;
+ dcmi->errors_count = 0;
+ dcmi->buffers_count = 0;
+ dcmi->active = NULL;
+
+ /*
+ * Start transfer if at least one buffer has been queued,
+ * otherwise transfer is defered at buffer queueing
+ */
+ if (list_empty(&dcmi->buffers)) {
+ dev_dbg(dcmi->dev, "Start streaming is defered to next buffer queueing\n");
+ spin_unlock_irq(&dcmi->irqlock);
+ return 0;
+ }
+
+ dcmi->active = list_entry(dcmi->buffers.next, struct dcmi_buf, list);
+ list_del_init(&dcmi->active->list);
+
+ dev_dbg(dcmi->dev, "Start streaming, starting capture\n");
+
+ ret = dcmi_start_capture(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture",
+ __func__);
+
+ spin_unlock_irq(&dcmi->irqlock);
+ goto err_subdev_streamoff;
+ }
+
+ /* Enable interruptions */
+ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+
+ spin_unlock_irq(&dcmi->irqlock);
+
+ return 0;
+
+err_subdev_streamoff:
+ v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
+
+err_release_buffers:
+ spin_lock_irq(&dcmi->irqlock);
+ /*
+ * Return all buffers to vb2 in QUEUED state.
+ * This will give ownership back to userspace
+ */
+ if (dcmi->active) {
+ buf = dcmi->active;
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ dcmi->active = NULL;
+ }
+ list_for_each_entry_safe(buf, node, &dcmi->buffers, list) {
+ list_del_init(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
+ spin_unlock_irq(&dcmi->irqlock);
+
+ return ret;
+}
+
+static void dcmi_stop_streaming(struct vb2_queue *vq)
+{
+ struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
+ struct dcmi_buf *buf, *node;
+ unsigned long time_ms = msecs_to_jiffies(TIMEOUT_MS);
+ long timeout;
+ int ret;
+
+ /* Disable stream on the sub device */
+ ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
+ if (ret && ret != -ENOIOCTLCMD)
+ dev_err(dcmi->dev, "stream off failed in subdev\n");
+
+ dcmi->state = STOPPING;
+
+ timeout = wait_for_completion_interruptible_timeout(&dcmi->complete,
+ time_ms);
+
+ spin_lock_irq(&dcmi->irqlock);
+
+ /* Disable interruptions */
+ reg_clear(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
+
+ /* Disable DCMI */
+ reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE);
+
+ if (!timeout) {
+ dev_err(dcmi->dev, "Timeout during stop streaming\n");
+ dcmi->state = STOPPED;
+ }
+
+ /* Return all queued buffers to vb2 in ERROR state */
+ if (dcmi->active) {
+ buf = dcmi->active;
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ dcmi->active = NULL;
+ }
+ list_for_each_entry_safe(buf, node, &dcmi->buffers, list) {
+ list_del_init(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ spin_unlock_irq(&dcmi->irqlock);
+
+ /* Stop all pending DMA operations */
+ dmaengine_terminate_all(dcmi->dma_chan);
+
+ clk_disable(dcmi->mclk);
+
+ dev_dbg(dcmi->dev, "Stop streaming, errors=%d buffers=%d\n",
+ dcmi->errors_count, dcmi->buffers_count);
+}
+
+static struct vb2_ops dcmi_video_qops = {
+ .queue_setup = dcmi_queue_setup,
+ .buf_init = dcmi_buf_init,
+ .buf_prepare = dcmi_buf_prepare,
+ .buf_queue = dcmi_buf_queue,
+ .start_streaming = dcmi_start_streaming,
+ .stop_streaming = dcmi_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int dcmi_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ *fmt = dcmi->fmt;
+
+ return 0;
+}
+
+static const struct dcmi_format *find_format_by_fourcc(struct stm32_dcmi *dcmi,
+ unsigned int fourcc)
+{
+ unsigned int num_formats = dcmi->num_user_formats;
+ const struct dcmi_format *fmt;
+ unsigned int i;
+
+ for (i = 0; i < num_formats; i++) {
+ fmt = dcmi->user_formats[i];
+ if (fmt->fourcc == fourcc)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
+ const struct dcmi_format **current_fmt)
+{
+ const struct dcmi_format *dcmi_fmt;
+ struct v4l2_pix_format *pixfmt = &f->fmt.pix;
+ struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ };
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ dcmi_fmt = find_format_by_fourcc(dcmi, pixfmt->pixelformat);
+ if (!dcmi_fmt) {
+ dcmi_fmt = dcmi->user_formats[dcmi->num_user_formats - 1];
+ pixfmt->pixelformat = dcmi_fmt->fourcc;
+ }
+
+ /* Limit to hardware capabilities */
+ if (pixfmt->width > MAX_SUPPORT_WIDTH)
+ pixfmt->width = MAX_SUPPORT_WIDTH;
+ if (pixfmt->height > MAX_SUPPORT_HEIGHT)
+ pixfmt->height = MAX_SUPPORT_HEIGHT;
+ if (pixfmt->width < MIN_SUPPORT_WIDTH)
+ pixfmt->width = MIN_SUPPORT_WIDTH;
+ if (pixfmt->height < MIN_SUPPORT_HEIGHT)
+ pixfmt->height = MIN_SUPPORT_HEIGHT;
+
+ v4l2_fill_mbus_format(&format.format, pixfmt, dcmi_fmt->mbus_code);
+ ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt,
+ &pad_cfg, &format);
+ if (ret < 0)
+ return ret;
+
+ v4l2_fill_pix_format(pixfmt, &format.format);
+
+ pixfmt->field = V4L2_FIELD_NONE;
+ pixfmt->bytesperline = pixfmt->width * dcmi_fmt->bpp;
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
+
+ if (current_fmt)
+ *current_fmt = dcmi_fmt;
+
+ return 0;
+}
+
+static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f)
+{
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ const struct dcmi_format *current_fmt;
+ int ret;
+
+ ret = dcmi_try_fmt(dcmi, f, ¤t_fmt);
+ if (ret)
+ return ret;
+
+ v4l2_fill_mbus_format(&format.format, &f->fmt.pix,
+ current_fmt->mbus_code);
+ ret = v4l2_subdev_call(dcmi->entity.subdev, pad,
+ set_fmt, NULL, &format);
+ if (ret < 0)
+ return ret;
+
+ dcmi->fmt = *f;
+ dcmi->current_fmt = current_fmt;
+
+ return 0;
+}
+
+static int dcmi_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ if (vb2_is_streaming(&dcmi->queue))
+ return -EBUSY;
+
+ return dcmi_set_fmt(dcmi, f);
+}
+
+static int dcmi_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ return dcmi_try_fmt(dcmi, f, NULL);
+}
+
+static int dcmi_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+
+ if (f->index >= dcmi->num_user_formats)
+ return -EINVAL;
+
+ f->pixelformat = dcmi->user_formats[f->index]->fourcc;
+ return 0;
+}
+
+static int dcmi_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, "STM32 Digital Camera Memory Interface",
+ sizeof(cap->card));
+ strlcpy(cap->bus_info, "platform:dcmi", sizeof(cap->bus_info));
+ return 0;
+}
+
+static int dcmi_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strlcpy(i->name, "Camera", sizeof(i->name));
+ return 0;
+}
+
+static int dcmi_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int dcmi_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int dcmi_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+ const struct dcmi_format *dcmi_fmt;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .index = fsize->index,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ dcmi_fmt = find_format_by_fourcc(dcmi, fsize->pixel_format);
+ if (!dcmi_fmt)
+ return -EINVAL;
+
+ fse.code = dcmi_fmt->mbus_code;
+
+ ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size,
+ NULL, &fse);
+ if (ret)
+ return ret;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fse.max_width;
+ fsize->discrete.height = fse.max_height;
+
+ return 0;
+}
+
+static int dcmi_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+ const struct dcmi_format *dcmi_fmt;
+ struct v4l2_subdev_frame_interval_enum fie = {
+ .index = fival->index,
+ .width = fival->width,
+ .height = fival->height,
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ int ret;
+
+ dcmi_fmt = find_format_by_fourcc(dcmi, fival->pixel_format);
+ if (!dcmi_fmt)
+ return -EINVAL;
+
+ fie.code = dcmi_fmt->mbus_code;
+
+ ret = v4l2_subdev_call(dcmi->entity.subdev, pad,
+ enum_frame_interval, NULL, &fie);
+ if (ret)
+ return ret;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = fie.interval;
+
+ return 0;
+}
+
+static const struct of_device_id stm32_dcmi_of_match[] = {
+ { .compatible = "st,stm32-dcmi"},
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_dcmi_of_match);
+
+static int dcmi_open(struct file *file)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+ struct v4l2_subdev *sd = dcmi->entity.subdev;
+ int ret;
+
+ if (mutex_lock_interruptible(&dcmi->lock))
+ return -ERESTARTSYS;
+
+ ret = v4l2_fh_open(file);
+ if (ret < 0)
+ goto unlock;
+
+ if (!v4l2_fh_is_singular_file(file))
+ goto fh_rel;
+
+ ret = v4l2_subdev_call(sd, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ goto fh_rel;
+
+ ret = dcmi_set_fmt(dcmi, &dcmi->fmt);
+ if (ret)
+ v4l2_subdev_call(sd, core, s_power, 0);
+fh_rel:
+ if (ret)
+ v4l2_fh_release(file);
+unlock:
+ mutex_unlock(&dcmi->lock);
+ return ret;
+}
+
+static int dcmi_release(struct file *file)
+{
+ struct stm32_dcmi *dcmi = video_drvdata(file);
+ struct v4l2_subdev *sd = dcmi->entity.subdev;
+ bool fh_singular;
+ int ret;
+
+ mutex_lock(&dcmi->lock);
+
+ fh_singular = v4l2_fh_is_singular_file(file);
+
+ ret = _vb2_fop_release(file, NULL);
+
+ if (fh_singular)
+ v4l2_subdev_call(sd, core, s_power, 0);
+
+ mutex_unlock(&dcmi->lock);
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops dcmi_ioctl_ops = {
+ .vidioc_querycap = dcmi_querycap,
+
+ .vidioc_try_fmt_vid_cap = dcmi_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = dcmi_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = dcmi_s_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = dcmi_enum_fmt_vid_cap,
+
+ .vidioc_enum_input = dcmi_enum_input,
+ .vidioc_g_input = dcmi_g_input,
+ .vidioc_s_input = dcmi_s_input,
+
+ .vidioc_enum_framesizes = dcmi_enum_framesizes,
+ .vidioc_enum_frameintervals = dcmi_enum_frameintervals,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_file_operations dcmi_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .open = dcmi_open,
+ .release = dcmi_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = vb2_fop_get_unmapped_area,
+#endif
+ .read = vb2_fop_read,
+};
+
+static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi)
+{
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = CIF_WIDTH,
+ .height = CIF_HEIGHT,
+ .field = V4L2_FIELD_NONE,
+ .pixelformat = dcmi->user_formats[0]->fourcc,
+ },
+ };
+ int ret;
+
+ ret = dcmi_try_fmt(dcmi, &f, NULL);
+ if (ret)
+ return ret;
+ dcmi->current_fmt = dcmi->user_formats[0];
+ dcmi->fmt = f;
+ return 0;
+}
+
+static const struct dcmi_format dcmi_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .bpp = 2,
+ },
+};
+
+static int dcmi_formats_init(struct stm32_dcmi *dcmi)
+{
+ const struct dcmi_format *dcmi_fmts[ARRAY_SIZE(dcmi_formats)];
+ unsigned int num_fmts = 0, i, j;
+ struct v4l2_subdev *subdev = dcmi->entity.subdev;
+ struct v4l2_subdev_mbus_code_enum mbus_code = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+
+ while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
+ NULL, &mbus_code)) {
+ for (i = 0; i < ARRAY_SIZE(dcmi_formats); i++) {
+ if (dcmi_formats[i].mbus_code != mbus_code.code)
+ continue;
+
+ /* Code supported, have we got this fourcc yet? */
+ for (j = 0; j < num_fmts; j++)
+ if (dcmi_fmts[j]->fourcc ==
+ dcmi_formats[i].fourcc)
+ /* Already available */
+ break;
+ if (j == num_fmts)
+ /* New */
+ dcmi_fmts[num_fmts++] = dcmi_formats + i;
+ }
+ mbus_code.index++;
+ }
+
+ if (!num_fmts)
+ return -ENXIO;
+
+ dcmi->num_user_formats = num_fmts;
+ dcmi->user_formats = devm_kcalloc(dcmi->dev,
+ num_fmts, sizeof(struct dcmi_format *),
+ GFP_KERNEL);
+ if (!dcmi->user_formats) {
+ dev_err(dcmi->dev, "could not allocate memory\n");
+ return -ENOMEM;
+ }
+
+ memcpy(dcmi->user_formats, dcmi_fmts,
+ num_fmts * sizeof(struct dcmi_format *));
+ dcmi->current_fmt = dcmi->user_formats[0];
+
+ return 0;
+}
+
+static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
+ int ret;
+
+ dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler;
+ ret = dcmi_formats_init(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "No supported mediabus format found\n");
+ return ret;
+ }
+
+ ret = dcmi_set_default_fmt(dcmi);
+ if (ret) {
+ dev_err(dcmi->dev, "Could not set default format\n");
+ return ret;
+ }
+
+ ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ dev_err(dcmi->dev, "Failed to register video device\n");
+ return ret;
+ }
+
+ dev_dbg(dcmi->dev, "Device registered as %s\n",
+ video_device_node_name(dcmi->vdev));
+ return 0;
+}
+
+static void dcmi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd,
+ struct v4l2_async_subdev *asd)
+{
+ struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
+
+ dev_dbg(dcmi->dev, "Removing %s\n", video_device_node_name(dcmi->vdev));
+
+ /* Checks internaly if vdev has been init or not */
+ video_unregister_device(dcmi->vdev);
+}
+
+static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
+
+ dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name);
+
+ dcmi->entity.subdev = subdev;
+
+ return 0;
+}
+
+static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
+{
+ struct device_node *ep = NULL;
+ struct device_node *remote;
+
+ while (1) {
+ ep = of_graph_get_next_endpoint(node, ep);
+ if (!ep)
+ return -EINVAL;
+
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote) {
+ of_node_put(ep);
+ return -EINVAL;
+ }
+
+ /* Remote node to connect */
+ dcmi->entity.node = remote;
+ dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_OF;
+ dcmi->entity.asd.match.of.node = remote;
+ return 0;
+ }
+}
+
+static int dcmi_graph_init(struct stm32_dcmi *dcmi)
+{
+ struct v4l2_async_subdev **subdevs = NULL;
+ int ret;
+
+ /* Parse the graph to extract a list of subdevice DT nodes. */
+ ret = dcmi_graph_parse(dcmi, dcmi->dev->of_node);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "Graph parsing failed\n");
+ return ret;
+ }
+
+ /* Register the subdevices notifier. */
+ subdevs = devm_kzalloc(dcmi->dev, sizeof(*subdevs), GFP_KERNEL);
+ if (!subdevs) {
+ of_node_put(dcmi->entity.node);
+ return -ENOMEM;
+ }
+
+ subdevs[0] = &dcmi->entity.asd;
+
+ dcmi->notifier.subdevs = subdevs;
+ dcmi->notifier.num_subdevs = 1;
+ dcmi->notifier.bound = dcmi_graph_notify_bound;
+ dcmi->notifier.unbind = dcmi_graph_notify_unbind;
+ dcmi->notifier.complete = dcmi_graph_notify_complete;
+
+ ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "Notifier registration failed\n");
+ of_node_put(dcmi->entity.node);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dcmi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match = NULL;
+ struct v4l2_of_endpoint ep;
+ struct stm32_dcmi *dcmi;
+ struct vb2_queue *q;
+ struct dma_chan *chan;
+ struct clk *mclk;
+ int irq;
+ int ret = 0;
+
+ match = of_match_device(of_match_ptr(stm32_dcmi_of_match), &pdev->dev);
+ if (!match) {
+ dev_err(&pdev->dev, "Could not find a match in devicetree\n");
+ return -ENODEV;
+ }
+
+ dcmi = devm_kzalloc(&pdev->dev, sizeof(struct stm32_dcmi), GFP_KERNEL);
+ if (!dcmi)
+ return -ENOMEM;
+
+ dcmi->rstc = of_reset_control_get(np, NULL);
+ if (IS_ERR(dcmi->rstc)) {
+ dev_err(&pdev->dev, "Could not get reset control\n");
+ return -ENODEV;
+ }
+
+ /* Get bus characteristics from devicetree */
+ np = of_graph_get_next_endpoint(np, NULL);
+ if (!np) {
+ dev_err(&pdev->dev, "Could not find the endpoint\n");
+ of_node_put(np);
+ goto err_reset_control_put;
+ }
+
+ ret = v4l2_of_parse_endpoint(np, &ep);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not parse the endpoint\n");
+ of_node_put(np);
+ goto err_reset_control_put;
+ }
+
+ if (ep.bus_type == V4L2_MBUS_CSI2) {
+ dev_err(&pdev->dev, "CSI bus not supported\n");
+ of_node_put(np);
+ goto err_reset_control_put;
+ }
+ dcmi->bus.flags = ep.bus.parallel.flags;
+ dcmi->bus.bus_width = ep.bus.parallel.bus_width;
+ dcmi->bus.data_shift = ep.bus.parallel.data_shift;
+
+ of_node_put(np);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "Could not get irq\n");
+ return -ENODEV;
+ }
+
+ dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!dcmi->res) {
+ dev_err(&pdev->dev, "Could not get resource\n");
+ return -ENODEV;
+ }
+
+ dcmi->regs = devm_ioremap_resource(&pdev->dev, dcmi->res);
+ if (IS_ERR(dcmi->regs)) {
+ dev_err(&pdev->dev, "Could not map registers\n");
+ return PTR_ERR(dcmi->regs);
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, dcmi_irq_callback,
+ dcmi_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), dcmi);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
+ return -ENODEV;
+ }
+
+ mclk = devm_clk_get(&pdev->dev, "mclk");
+ if (IS_ERR(mclk)) {
+ dev_err(&pdev->dev, "Unable to get mclk\n");
+ return PTR_ERR(mclk);
+ }
+
+ chan = dma_request_slave_channel(&pdev->dev, "tx");
+ if (!chan) {
+ dev_info(&pdev->dev, "Unable to request DMA channel, defer probing\n");
+ return -EPROBE_DEFER;
+ }
+
+ ret = clk_prepare(mclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to prepare mclk %p\n", mclk);
+ goto err_dma_release;
+ }
+
+ spin_lock_init(&dcmi->irqlock);
+ mutex_init(&dcmi->lock);
+ init_completion(&dcmi->complete);
+ INIT_LIST_HEAD(&dcmi->buffers);
+
+ dcmi->dev = &pdev->dev;
+ dcmi->mclk = mclk;
+ dcmi->state = STOPPED;
+ dcmi->dma_chan = chan;
+
+ q = &dcmi->queue;
+
+ /* Initialize the top-level structure */
+ ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
+ if (ret)
+ goto err_clk_unprepare;
+
+ dcmi->vdev = video_device_alloc();
+ if (!dcmi->vdev) {
+ ret = -ENOMEM;
+ goto err_device_unregister;
+ }
+
+ /* Video node */
+ dcmi->vdev->fops = &dcmi_fops;
+ dcmi->vdev->v4l2_dev = &dcmi->v4l2_dev;
+ dcmi->vdev->queue = &dcmi->queue;
+ strlcpy(dcmi->vdev->name, KBUILD_MODNAME, sizeof(dcmi->vdev->name));
+ dcmi->vdev->release = video_device_release;
+ dcmi->vdev->ioctl_ops = &dcmi_ioctl_ops;
+ dcmi->vdev->lock = &dcmi->lock;
+ dcmi->vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ video_set_drvdata(dcmi->vdev, dcmi);
+
+ /* Buffer queue */
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
+ q->lock = &dcmi->lock;
+ q->drv_priv = dcmi;
+ q->buf_struct_size = sizeof(struct dcmi_buf);
+ q->ops = &dcmi_video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 2;
+ q->dev = &pdev->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to initialize vb2 queue\n");
+ goto err_device_release;
+ }
+
+ ret = dcmi_graph_init(dcmi);
+ if (ret < 0)
+ goto err_device_release;
+
+ /* Reset device */
+ ret = reset_control_assert(dcmi->rstc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to assert the reset line\n");
+ goto err_device_release;
+ }
+
+ usleep_range(3000, 5000);
+
+ ret = reset_control_deassert(dcmi->rstc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to deassert the reset line\n");
+ goto err_device_release;
+ }
+
+ dev_info(&pdev->dev, "Probe done\n");
+
+ platform_set_drvdata(pdev, dcmi);
+ return 0;
+
+err_reset_control_put:
+ reset_control_put(dcmi->rstc);
+err_device_release:
+ video_device_release(dcmi->vdev);
+err_device_unregister:
+ v4l2_device_unregister(&dcmi->v4l2_dev);
+err_clk_unprepare:
+ clk_unprepare(dcmi->mclk);
+err_dma_release:
+ dma_release_channel(dcmi->dma_chan);
+
+ return ret;
+}
+
+static int dcmi_remove(struct platform_device *pdev)
+{
+ struct stm32_dcmi *dcmi = platform_get_drvdata(pdev);
+
+ v4l2_async_notifier_unregister(&dcmi->notifier);
+ v4l2_device_unregister(&dcmi->v4l2_dev);
+ clk_unprepare(dcmi->mclk);
+ dma_release_channel(dcmi->dma_chan);
+ reset_control_put(dcmi->rstc);
+
+ return 0;
+}
+
+static struct platform_driver stm32_dcmi_driver = {
+ .probe = dcmi_probe,
+ .remove = dcmi_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(stm32_dcmi_of_match),
+ },
+};
+
+module_platform_driver(stm32_dcmi_driver);
+
+MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
+MODULE_AUTHOR("Hugues Fruchet <hugues.fruchet@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Digital Camera Memory Interface driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("video");
--
1.9.1
^ permalink raw reply related
* [PATCH v4 1/8] dt-bindings: Document STM32 DCMI bindings
From: Hugues Fruchet @ 2017-04-20 16:07 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre Torgue,
Mauro Carvalho Chehab, Hans Verkuil
Cc: devicetree, linux-arm-kernel, linux-kernel, linux-media,
Benjamin Gaignard, Yannick Fertre, Hugues Fruchet
In-Reply-To: <1492704445-22186-1-git-send-email-hugues.fruchet@st.com>
This adds documentation of device tree bindings for the STM32 DCMI
(Digital Camera Memory Interface).
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
.../devicetree/bindings/media/st,stm32-dcmi.txt | 46 ++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.txt b/Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
new file mode 100644
index 0000000..f8baf65
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
@@ -0,0 +1,46 @@
+STMicroelectronics STM32 Digital Camera Memory Interface (DCMI)
+
+Required properties:
+- compatible: "st,stm32-dcmi"
+- reg: physical base address and length of the registers set for the device
+- interrupts: should contain IRQ line for the DCMI
+- resets: reference to a reset controller,
+ see Documentation/devicetree/bindings/reset/st,stm32-rcc.txt
+- clocks: list of clock specifiers, corresponding to entries in
+ the clock-names property
+- clock-names: must contain "mclk", which is the DCMI peripherial clock
+- pinctrl: the pincontrol settings to configure muxing properly
+ for pins that connect to DCMI device.
+ See Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt.
+- dmas: phandle to DMA controller node,
+ see Documentation/devicetree/bindings/dma/stm32-dma.txt
+- dma-names: must contain "tx", which is the transmit channel from DCMI to DMA
+
+DCMI supports a single port node with parallel bus. It should contain one
+'port' child node with child 'endpoint' node. Please refer to the bindings
+defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+ dcmi: dcmi@50050000 {
+ compatible = "st,stm32-dcmi";
+ reg = <0x50050000 0x400>;
+ interrupts = <78>;
+ resets = <&rcc STM32F4_AHB2_RESET(DCMI)>;
+ clocks = <&rcc 0 STM32F4_AHB2_CLOCK(DCMI)>;
+ clock-names = "mclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcmi_pins>;
+ dmas = <&dma2 1 1 0x414 0x3>;
+ dma-names = "tx";
+ port {
+ dcmi_0: endpoint {
+ remote-endpoint = <...>;
+ bus-width = <8>;
+ hsync-active = <0>;
+ vsync-active = <0>;
+ pclk-sample = <1>;
+ };
+ };
+ };
+
--
1.9.1
^ permalink raw reply related
* [PATCH v4 0/8] Add support for DCMI camera interface of STMicroelectronics STM32 SoC series
From: Hugues Fruchet @ 2017-04-20 16:07 UTC (permalink / raw)
To: Rob Herring, Mark Rutland, Maxime Coquelin, Alexandre Torgue,
Mauro Carvalho Chehab, Hans Verkuil
Cc: devicetree, linux-kernel, Yannick Fertre, Benjamin Gaignard,
Hugues Fruchet, linux-arm-kernel, linux-media
This patchset introduces a basic support for Digital Camera Memory Interface
(DCMI) of STMicroelectronics STM32 SoC series.
This first basic support implements RGB565 & YUV frame grabbing.
Cropping and JPEG support will be added later on.
This has been tested on STM324x9I-EVAL evaluation board embedding
an OV2640 camera sensor.
This driver depends on:
- [PATCHv6 00/14] atmel-isi/ov7670/ov2640: convert to standalone drivers http://www.spinics.net/lists/linux-media/msg113480.html
===========
= history =
===========
version 4:
- "v4l2-compliance -s -f" report
- fix behaviour in case of start_streaming failure (DMA memory shortage for ex.)
- dt-bindings: Fix remarks from Rob Herring:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg111340.html
Add "Acked-by: Rob Herring <robh@kernel.org>"
version 3:
- stm32-dcmi: Add "Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>"
- dt-bindings: Fix remarks from Rob Herring:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg110956.html
version 2:
- Fix a Kbuild warning in probe:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg110678.html
- Fix a warning in dcmi_queue_setup()
- dt-bindings: warn on sensor signals level inversion in board example
- Typos fixing
version 1:
- Initial submission
===================
= v4l2-compliance =
===================
Below is the v4l2-compliance report for this current version of the DCMI camera interface.
v4l2-compliance has been built from v4l-utils-1.12.3.
~ # v4l2-compliance -s -f -d /dev/video0
v4l2-compliance SHA : f5f45e17ee98a0ebad7836ade2b34ceec909d751
Driver Info:
Driver name : stm32-dcmi
Card type : STM32 Digital Camera Memory Int
Bus info : platform:dcmi
Driver version: 4.11.0
Capabilities : 0x85200001
Video Capture
Read/Write
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x05200001
Video Capture
Read/Write
Streaming
Extended Pix Format
Compliance test for device /dev/video0 (not using libv4l2):
Required ioctls:
test VIDIOC_QUERYCAP: OK
Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 1 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Test input 0:
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
test VIDIOC_QUERYCTRL: OK
test VIDIOC_G/S_CTRL: OK
test VIDIOC_G/S/TRY_EXT_CTRLS: OK
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 3 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK (Not Supported)
test Scaling: OK
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK
Test input 0:
Streaming ioctls:
test read/write: OK
test MMAP: OK
test USERPTR: OK (Not Supported)
test DMABUF: Cannot test, specify --expbuf-device
Stream using all formats:
test MMAP for Format YUYV, Frame Size 176x144:
Stride 352, Field None: OK
test MMAP for Format YUYV, Frame Size 320x240:
Stride 640, Field None: OK
test MMAP for Format UYVY, Frame Size 176x144:
Stride 352, Field None: OK
test MMAP for Format UYVY, Frame Size 320x240:
Stride 640, Field None: OK
test MMAP for Format RGBP, Frame Size 176x144:
Stride 352, Field None: OK
test MMAP for Format RGBP, Frame Size 320x240:
Stride 640, Field None: OK
Total: 52, Succeeded: 52, Failed: 0, Warnings: 0
Hugues Fruchet (8):
dt-bindings: Document STM32 DCMI bindings
[media] stm32-dcmi: STM32 DCMI camera interface driver
ARM: dts: stm32: Enable DCMI support on STM32F429 MCU
ARM: dts: stm32: Enable DCMI camera interface on STM32F429-EVAL board
ARM: dts: stm32: Enable STMPE1600 gpio expander of STM32F429-EVAL
board
ARM: dts: stm32: Enable OV2640 camera support of STM32F429-EVAL board
ARM: configs: stm32: STMPE1600 GPIO expander
ARM: configs: stm32: DCMI + OV2640 camera support
.../devicetree/bindings/media/st,stm32-dcmi.txt | 46 +
arch/arm/boot/dts/stm32429i-eval.dts | 56 +
arch/arm/boot/dts/stm32f429.dtsi | 37 +
arch/arm/configs/stm32_defconfig | 9 +
drivers/media/platform/Kconfig | 12 +
drivers/media/platform/Makefile | 2 +
drivers/media/platform/stm32/Makefile | 1 +
drivers/media/platform/stm32/stm32-dcmi.c | 1419 ++++++++++++++++++++
8 files changed, 1582 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/st,stm32-dcmi.txt
create mode 100644 drivers/media/platform/stm32/Makefile
create mode 100644 drivers/media/platform/stm32/stm32-dcmi.c
--
1.9.1
^ permalink raw reply
* Re: [PATCH 3/3] iio: tools: generic_buffer: increase trigger length
From: Daniel Baluta @ 2017-04-20 16:06 UTC (permalink / raw)
To: Eugen Hristev
Cc: nicolas.ferre, alexandre.belloni, linux-iio@vger.kernel.org,
Jonathan Cameron, Lars-Peter Clausen, linux-arm-kernel,
Devicetree List, Linux Kernel Mailing List, ludovic.desroches
In-Reply-To: <1492590045-17329-4-git-send-email-eugen.hristev@microchip.com>
On Wed, Apr 19, 2017 at 11:20 AM, Eugen Hristev
<eugen.hristev@microchip.com> wrote:
> Increased trigger length to 50 in order to cope with trigger names like
> fc030000.adc-dev0-external-rising
>
> Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
> ---
> tools/iio/iio_utils.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h
> index 780f201..9d59771 100644
> --- a/tools/iio/iio_utils.h
> +++ b/tools/iio/iio_utils.h
> @@ -13,7 +13,7 @@
> #include <stdint.h>
>
> /* Made up value to limit allocation sizes */
> -#define IIO_MAX_NAME_LENGTH 30
> +#define IIO_MAX_NAME_LENGTH 50
While at it, lets be brave and set it to 64. :)
Daniel.
^ permalink raw reply
* Re: [PATCH v6 4/4] net: dsa: LAN9303: add MDIO managed mode support
From: Rob Herring @ 2017-04-20 16:06 UTC (permalink / raw)
To: Juergen Borleis
Cc: netdev, linux-kernel, f.fainelli, kernel, andrew, vivien.didelot,
davem, devicetree, mark.rutland, sr
In-Reply-To: <20170418084827.19613-5-jbe@pengutronix.de>
On Tue, Apr 18, 2017 at 10:48:27AM +0200, Juergen Borleis wrote:
> When the LAN9303 device is in MDIO manged mode, all register accesses must
> be done via MDIO.
>
> Please note: this code is compile time tested only due to the absence of such
> configured hardware. It is based on a patch from Stefan Roese from 2014.
>
> Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
> CC: devicetree@vger.kernel.org
> CC: robh+dt@kernel.org
> CC: mark.rutland@arm.com
> CC: sr@denx.de
> ---
> .../devicetree/bindings/net/dsa/lan9303.txt | 45 ++++++-
I'd prefer to see the full binding in one separate patch.
Otherwise, looks fine to me.
Acked-by: Rob Herring <robh@kernel.org>
> drivers/net/dsa/Kconfig | 8 ++
> drivers/net/dsa/Makefile | 1 +
> drivers/net/dsa/lan9303_mdio.c | 148 +++++++++++++++++++++
> 4 files changed, 201 insertions(+), 1 deletion(-)
> create mode 100644 drivers/net/dsa/lan9303_mdio.c
^ permalink raw reply
* Re: [PATCH v6 3/4] net: dsa: LAN9303: add I2C managed mode support
From: Rob Herring @ 2017-04-20 16:04 UTC (permalink / raw)
To: Juergen Borleis
Cc: netdev, linux-kernel, f.fainelli, kernel, andrew, vivien.didelot,
davem, devicetree, mark.rutland
In-Reply-To: <20170418084827.19613-4-jbe@pengutronix.de>
On Tue, Apr 18, 2017 at 10:48:26AM +0200, Juergen Borleis wrote:
> In this mode the switch device and the internal phys will be managed via
> I2C interface. The MDIO interface is still supported, but for the
> (emulated) CPU port only.
>
> Signed-off-by: Juergen Borleis <jbe@pengutronix.de>
> CC: devicetree@vger.kernel.org
> CC: robh+dt@kernel.org
> CC: mark.rutland@arm.com
> ---
> .../devicetree/bindings/net/dsa/lan9303.txt | 62 +++++++++++
Acked-by: Rob Herring <robh@kernel.org>
> drivers/net/dsa/Kconfig | 16 +++
> drivers/net/dsa/Makefile | 2 +
> drivers/net/dsa/lan9303_i2c.c | 113 +++++++++++++++++++++
> 4 files changed, 193 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/net/dsa/lan9303.txt
> create mode 100644 drivers/net/dsa/lan9303_i2c.c
^ permalink raw reply
* Re: [PATCH v3 3/3] arm64: dts: exynos: Add support for s6e3hf2 panel device on TM2e board
From: Krzysztof Kozlowski @ 2017-04-20 16:01 UTC (permalink / raw)
To: Hoegeun Kwon
Cc: thierry.reding, airlied, robh+dt, mark.rutland, catalin.marinas,
will.deacon, kgene, dri-devel, devicetree, linux-arm-kernel,
linux-samsung-soc, linux-kernel, javier, a.hajda, inki.dae,
andi.shyti
In-Reply-To: <1492504836-19225-4-git-send-email-hoegeun.kwon@samsung.com>
On Tue, Apr 18, 2017 at 05:40:36PM +0900, Hoegeun Kwon wrote:
> This patch add the panel device tree node for s6e3hf2 display
> controller to TM2e dts.
>
> Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts | 11 +++++++++++
> 1 file changed, 11 insertions(+)
Thanks, applied.
Best regards,
Krzysztof
^ permalink raw reply
* Re: [PATCH v3 1/3] dt-bindings: Add support for samsung s6e3hf2 panel
From: Rob Herring @ 2017-04-20 15:59 UTC (permalink / raw)
To: Hoegeun Kwon
Cc: mark.rutland, devicetree, linux-samsung-soc, andi.shyti,
catalin.marinas, dri-devel, will.deacon, linux-kernel, krzk,
javier, kgene, linux-arm-kernel
In-Reply-To: <1492504836-19225-2-git-send-email-hoegeun.kwon@samsung.com>
On Tue, Apr 18, 2017 at 05:40:34PM +0900, Hoegeun Kwon wrote:
> The samsung s6e3hf2 panel is a 5.65" 1600x2560 AMOLED panel connected
> using MIPI-DSI interfaces.
>
> The s6e3hf2 is add to samsung,s6e3ha2.txt binding because it is a
> panel similar to the s6e3ha2. So add the compatible string and
> comments.
>
> Signed-off-by: Hoegeun Kwon <hoegeun.kwon@samsung.com>
> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> Documentation/devicetree/bindings/display/panel/samsung,s6e3ha2.txt | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
Acked-by: Rob Herring <robh@kernel.org>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* Re: [PATCH v6 1/6] dt-bindings: power: supply: add AXP20X/AXP22X battery DT binding
From: Rob Herring @ 2017-04-20 15:58 UTC (permalink / raw)
To: Quentin Schulz
Cc: sre-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
wens-jdAy2FN1RRM, linux-I+IVW8TIWO2tmTQ+vhA3Yw,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, icenowy-ymACFijhrKM,
liam-RYWXG+zxWwBdeoIcmNTgJF6hYfS7NtTn,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170418073421.31351-2-quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Tue, Apr 18, 2017 at 09:34:16AM +0200, Quentin Schulz wrote:
> The X-Powers AXP20X and AXP22X PMICs can have a battery as power supply.
>
> This patch adds the DT binding documentation for the battery power
> supply which gets various data from the PMIC, such as the battery status
> (charging, discharging, full, dead), current max limit, current current,
> battery capacity (in percentage), voltage max and min limits, current
> voltage and battery capacity (in Ah).
>
> Signed-off-by: Quentin Schulz <quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
> v6:
> - removed mention to monitored-battery, will be sent when the battery
> framework has been merged,
>
> v5:
> - removed DT property example from monitored-battery,
>
> v4:
> - added monitored-battery optional property,
> - added example with battery,
>
> v3:
> - removed constant charge current property, now should use the WIP
> battery framework,
>
> v2:
> - changed DT node name from ac_power_supply to ac-power-supply,
> - removed io-channels and io-channel-names from DT (the IIO mapping is
> done in the IIO ADC driver now),
> - added x-powers,constant-charge-current property to set the maximal
> default constant current charge of the battery,
>
> .../bindings/power/supply/axp20x_battery.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
^ permalink raw reply
* Re: [PATCH 1/2] clk: hi6220: add acpu clock
From: Rob Herring @ 2017-04-20 15:57 UTC (permalink / raw)
To: Zhangfei Gao
Cc: Stephen Boyd, guodong Xu, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Li Pengcheng
In-Reply-To: <1492478242-16146-1-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Tue, Apr 18, 2017 at 09:17:21AM +0800, Zhangfei Gao wrote:
> Add acpu clock, including sft clock controlling hi6220 coresight module
>
> Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Li Pengcheng <lipengcheng8-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
> ---
> .../devicetree/bindings/clock/hi6220-clock.txt | 1 +
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> drivers/clk/hisilicon/clk-hi6220.c | 23 ++++++++++++++++++++++
> include/dt-bindings/clock/hi6220-clock.h | 4 ++++
> 3 files changed, 28 insertions(+)
--
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] rtc: ds1374: Add trickle charger device tree binding
From: Rob Herring @ 2017-04-20 15:56 UTC (permalink / raw)
To: Moritz Fischer
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA, a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
mark.rutland-5wv7dgnIgG8
In-Reply-To: <1492468810-17224-1-git-send-email-mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
On Mon, Apr 17, 2017 at 03:40:10PM -0700, Moritz Fischer wrote:
> Introduce a device tree binding for specifying the trickle charger
> configuration for ds1374. This is based on the code for ds13390.
>
> Signed-off-by: Moritz Fischer <mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---
> .../devicetree/bindings/rtc/dallas,ds1374.txt | 18 ++++++++
> drivers/rtc/rtc-ds1374.c | 54 ++++++++++++++++++++++
> 2 files changed, 72 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/rtc/dallas,ds1374.txt
>
> diff --git a/Documentation/devicetree/bindings/rtc/dallas,ds1374.txt b/Documentation/devicetree/bindings/rtc/dallas,ds1374.txt
> new file mode 100644
> index 0000000..4cf5bd7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rtc/dallas,ds1374.txt
> @@ -0,0 +1,18 @@
> +* Dallas DS1374 I2C Real-Time Clock / WDT
Please remove from trivial-devices.txt, too. (which is moving in 4.12
BTW)
> +
> +Required properties:
> +- compatible: Should contain "dallas,ds1374".
> +- reg: I2C address for chip
> +
> +Optional properties:
> +- trickle-resistor-ohms : Selected resistor for trickle charger
> + Values usable for ds1374 are 250, 2000, 4000
> + Should be given if trickle charger should be enabled
> +- trickle-diode-disable : Do not use internal trickle charger diode
> + Should be given if internal trickle charger diode should be disabled
These should have vendor prefix unless you think they are common.
> +Example:
> + ds1374: rtc@0 {
> + compatible = "dallas,ds1374";
> + trickle-resistor-ohms = <250>;
> + reg = <0>;
> + };
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* Re: [PATCH 2/3] Documentation: dt: i2c: Add Altera I2C Controller
From: Rob Herring @ 2017-04-20 15:47 UTC (permalink / raw)
To: thor.thayer-VuQAYsv1563Yd54FQh9/CA
Cc: wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <7c803e53-5c1b-cd59-6c59-5a32b07edcb8-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
On Fri, Apr 14, 2017 at 8:46 AM, Thor Thayer
<thor.thayer-VuQAYsv1563Yd54FQh9/CA@public.gmane.org> wrote:
> Hi Rob,
>
> On 04/13/2017 04:22 PM, Rob Herring wrote:
>>
>> On Tue, Apr 11, 2017 at 11:02:26AM -0500, thor.thayer-VuQAYsv1563Yd54FQh9/CA@public.gmane.org
>> wrote:
>>>
>>> From: Thor Thayer <thor.thayer-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
[...]
>>> +Required properties :
>>> + - compatible : should be "altr,sip-i2c"
>>
>>
>> Seems kind of generic.
>>
> I'm using sip for soft IP - right now we only offer 1 flavor.
There is no versioning or release numbering associated with it?
Rob
--
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 2/3] ARM: dts: sk-rzg1m: add SCIF0 pins
From: Sergei Shtylyov @ 2017-04-20 15:45 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Simon Horman, Rob Herring, Mark Rutland, Linux-Renesas,
devicetree@vger.kernel.org, Magnus Damm, Russell King,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAMuHMdWCan+XRgbjdMXNqWuUoY_ZeWR1hiicgYg3s5gKQRchpQ@mail.gmail.com>
On 04/20/2017 05:19 PM, Geert Uytterhoeven wrote:
>> Add the (previously omitted) SCIF0 pin data to the SK-RZG1M board's
>> device tree.
>>
>> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>>
>> ---
>> arch/arm/boot/dts/r8a7743-sk-rzg1m.dts | 12 +++++++++++-
>> 1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> Index: renesas/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts
>> ===================================================================
>> --- renesas.orig/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts
>> +++ renesas/arch/arm/boot/dts/r8a7743-sk-rzg1m.dts
[...]
>> @@ -39,7 +39,17 @@
>> clock-frequency = <20000000>;
>> };
>>
>> +&pfc {
>> + scif0_pins: scif0 {
>> + groups = "scif0_data";
>
> I don't have schematics for this board, but you told me it's very similar to
> Porter. Hence I'd expect "scif0_data_d" instead.
And you are absolutely right! Sorry about my overlook...
> In my experience, when changing pinctrl to map the lines of a device to a new
> set of pins, but not mapping another device to the old set of pins, it may
> output the signals on both the old and the new set of pins.
>
> Does serial console input work with "scif0_data"?
Sure. :-)
MBR, Sergei
^ permalink raw reply
* Re: [PATCH 12/13] Documentation: DT: MIPS: lantiq: Add docs for the RCU bindings
From: Rob Herring @ 2017-04-20 15:42 UTC (permalink / raw)
To: Hauke Mehrtens
Cc: ralf-6z/3iImG2C8G8FEW9MqTrA, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg,
john-Pj+rj9U5foFAfugRpC6u6w, linux-spi-u79uwXL29TY76Z2rM5mHXA,
hauke.mehrtens-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <20170417192942.32219-13-hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
On Mon, Apr 17, 2017 at 09:29:41PM +0200, Hauke Mehrtens wrote:
> From: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>
> This adds the initial documentation for the RCU module (a MFD device
> which provides USB PHYs, reset controllers and more).
This should come before the other patches.
>
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
> .../devicetree/bindings/mips/lantiq/rcu.txt | 82 ++++++++++++++++++++++
> 1 file changed, 82 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mips/lantiq/rcu.txt
>
> diff --git a/Documentation/devicetree/bindings/mips/lantiq/rcu.txt b/Documentation/devicetree/bindings/mips/lantiq/rcu.txt
> new file mode 100644
> index 000000000000..9e5b1e7493e4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/lantiq/rcu.txt
> @@ -0,0 +1,82 @@
> +Lantiq XWAY SoC RCU binding
> +===========================
> +
> +This binding describes the RCU (reset controller unit) multifunction device,
> +where each sub-device has it's own set of registers.
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties:
> +- compatible : The first and second values must be: "simple-mfd", "syscon"
> +- reg : The address and length of the system control registers
> +
> +
> +-------------------------------------------------------------------------------
> +Example of the RCU bindings on a xRX200 SoC:
> + rcu0: rcu@203000 {
> + compatible = "simple-mfd", "syscon";
Needs an SoC specific compatible string here.
> + reg = <0x203000 0x100>;
> + big-endian;
> +
> + gphy0: rcu_gphy@0 {
> + compatible = "lantiq,xrx200a2x-rcu-gphy";
> + lantiq,rcu-syscon = <&rcu0 0x20>;
So these are already child nodes. You can get rid of this and use
reg/ranges instead.
> + resets = <&rcu_reset0 31>;
> + reset-names = "gphy";
> + lantiq,gphy-mode = <GPHY_MODE_GE>;
> + clocks = <&pmu0 XRX200_PMU_GATE_GPHY>;
> + clock-names = "gphy";
> + };
> +
> + gphy1: rcu_gphy@1 {
> + compatible = "lantiq,xrx200a2x-rcu-gphy";
> + lantiq,rcu-syscon = <&rcu0 0x68>;
> + resets = <&rcu_reset0 29>;
> + reset-names = "gphy";
> + lantiq,gphy-mode = <GPHY_MODE_FE>;
> + clocks = <&pmu0 XRX200_PMU_GATE_GPHY>;
> + clock-names = "gphy";
> + };
> +
> + rcu_reset0: rcu_reset@0 {
> + compatible = "lantiq,rcu-reset";
> + lantiq,rcu-syscon = <&rcu0 0x10 0x14>;
> + #reset-cells = <1>;
> + reset-request = <31>, <29>, <21>, <19>, <16>, <12>;
> + reset-status = <30>, <28>, <16>, <25>, <5>, <24>;
> + };
> +
> + rcu_reset1: rcu_reset@1 {
> + compatible = "lantiq,rcu-reset";
> + lantiq,rcu-syscon = <&rcu0 0x48 0x24>;
> + #reset-cells = <1>;
> + };
> +
> + usb_phys0: rcu-usb2-phy@0 {
> + compatible = "lantiq,xrx200-rcu-usb2-phy";
> +
> + lantiq,rcu-syscon = <&rcu0 0x18 0x38>;
> + resets = <&rcu_reset1 4>, <&rcu_reset0 4>;
> + reset-names = "phy", "ctrl";
> + #phy-cells = <0>;
> + };
> +
> + usb_phys1: rcu-usb2-phy@1 {
> + compatible = "lantiq,xrx200-rcu-usb2-phy";
> +
> + lantiq,rcu-syscon = <&rcu0 0x34 0x3C>;
> + resets = <&rcu_reset1 5>, <&rcu_reset0 4>;
> + reset-names = "phy", "ctrl";
> + #phy-cells = <0>;
> + };
> +
> + reboot {
> + compatible = "syscon-reboot";
> + regmap = <&rcu0>;
> + offset = <0x10>;
> + mask = <0x40000000>;
> + };
> +
> + /* more sub-device nodes (USB PHY, etc.) */
> + };
> +
> --
> 2.11.0
>
> --
> 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
--
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] iio: adc: Drop if clock from Renesas GyroADC bindings
From: Marek Vasut @ 2017-04-20 15:42 UTC (permalink / raw)
To: linux-renesas-soc
Cc: devicetree, Marek Vasut, Geert Uytterhoeven, Jonathan Cameron,
Rob Herring
The "if" interface clock speed is actually derived from the "fck"
block clock, as in the hardware they are the same clock. Drop the
incorrect second "if" clock and retain only the "fck" clock.
Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com>
Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: linux-renesas-soc@vger.kernel.org
To: devicetree@vger.kernel.org
---
Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
index f5b0adae6010..2a62908a774a 100644
--- a/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/renesas,gyroadc.txt
@@ -16,8 +16,7 @@ Required properties:
- clocks: References to all the clocks specified in the clock-names
property as specified in
Documentation/devicetree/bindings/clock/clock-bindings.txt.
-- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block
- clock, the "if" is the interface clock.
+- clock-names: Shall contain "fck". The "fck" is the GyroADC block clock.
- power-domains: Must contain a reference to the PM domain, if available.
- #address-cells: Should be <1> (setting for the subnodes) for all ADCs
except for "fujitsu,mb88101a". Should be <0> (setting for
@@ -75,8 +74,8 @@ Example:
adc@e6e54000 {
compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
reg = <0 0xe6e54000 0 64>;
- clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>;
- clock-names = "fck", "if";
+ clocks = <&mstp9_clks R8A7791_CLK_GYROADC>;
+ clock-names = "fck";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
pinctrl-0 = <&adc_pins>;
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 11/13] phy: Add an USB PHY driver for the Lantiq SoCs using the RCU module
From: Rob Herring @ 2017-04-20 15:36 UTC (permalink / raw)
To: Hauke Mehrtens
Cc: ralf-6z/3iImG2C8G8FEW9MqTrA, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg,
john-Pj+rj9U5foFAfugRpC6u6w, linux-spi-u79uwXL29TY76Z2rM5mHXA,
hauke.mehrtens-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <20170417192942.32219-12-hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
On Mon, Apr 17, 2017 at 09:29:40PM +0200, Hauke Mehrtens wrote:
> From: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>
> This driver starts the DWC2 core(s) built into the XWAY SoCs and provides
> the PHY interfaces for each core. The phy instances can be passed to the
> dwc2 driver, which already supports the generic phy interface.
>
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
> .../bindings/phy/phy-lantiq-rcu-usb2.txt | 59 ++++
> arch/mips/lantiq/xway/reset.c | 43 ---
> arch/mips/lantiq/xway/sysctrl.c | 24 +-
> drivers/phy/Kconfig | 8 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-lantiq-rcu-usb2.c | 325 +++++++++++++++++++++
> 6 files changed, 405 insertions(+), 55 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/phy/phy-lantiq-rcu-usb2.txt
> create mode 100644 drivers/phy/phy-lantiq-rcu-usb2.c
>
> diff --git a/Documentation/devicetree/bindings/phy/phy-lantiq-rcu-usb2.txt b/Documentation/devicetree/bindings/phy/phy-lantiq-rcu-usb2.txt
> new file mode 100644
> index 000000000000..0ec9f790b6e0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-lantiq-rcu-usb2.txt
> @@ -0,0 +1,59 @@
> +Lantiq XWAY SoC RCU USB 1.1/2.0 PHY binding
> +===========================================
> +
> +This binding describes the USB PHY hardware provided by the RCU module on the
> +Lantiq XWAY SoCs.
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties (controller (parent) node):
> +- compatible : Should be one of
> + "lantiq,ase-rcu-usb2-phy"
> + "lantiq,danube-rcu-usb2-phy"
> + "lantiq,xrx100-rcu-usb2-phy"
> + "lantiq,xrx200-rcu-usb2-phy"
> + "lantiq,xrx300-rcu-usb2-phy"
The first x in xrx seems to be a wildcard. Don't use wildcards in
compatible strings.
> +- lantiq,rcu-syscon : A phandle to the RCU module and the offsets to the
> + USB PHY configuration and USB MAC registers.
Same comment as gphy.
> +- address-cells : should be 1
> +- size-cells : should be 0
> +- phy-cells : from the generic PHY bindings, must be 1
Missing the '#'
> +
> +Optional properties (controller (parent) node):
> +- vbus-gpio : References a GPIO which enables VBUS all given USB
> + ports.
-gpios is preferred form.
> +
> +Required nodes : A sub-node is required for each USB PHY port.
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties (port (child) node):
Where's the sub nodes in the example?
> +- reg : The ID of the USB port, usually 0 or 1.
> +- clocks : References to the (PMU) "ctrl" and "phy" clk gates.
> +- clock-names : Must be one of the following:
> + "ctrl"
> + "phy"
> +- resets : References to the RCU USB configuration reset bits.
> +- reset-names : Must be one of the following:
> + "analog-config" (optional)
> + "statemachine-soft" (optional)
> +
> +Optional properties (port (child) node):
> +- vbus-gpio : References a GPIO which enables VBUS for the USB port.
> +
> +
> +-------------------------------------------------------------------------------
> +Example for the USB PHYs on an xRX200 SoC:
> + usb_phys0: rcu-usb2-phy@0 {
usb-phy@...
> + compatible = "lantiq,xrx200-rcu-usb2-phy";
Extra spaces.
> + reg = <0>;
> +
> + lantiq,rcu-syscon = <&rcu0 0x18 0x38>;
> + clocks = <&pmu PMU_GATE_USB0_CTRL>,
> + <&pmu PMU_GATE_USB0_PHY>;
> + clock-names = "ctrl", "phy";
> + vbus-gpios = <&gpio 32 GPIO_ACTIVE_HIGH>;
> + resets = <&rcu_reset1 4>, <&rcu_reset0 4>;
> + reset-names = "phy", "ctrl";
> + #phy-cells = <0>;
> + };
--
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 09/13] MIPS: lantiq: Add a GPHY driver which uses the RCU syscon-mfd
From: Rob Herring @ 2017-04-20 15:27 UTC (permalink / raw)
To: Hauke Mehrtens
Cc: ralf-6z/3iImG2C8G8FEW9MqTrA, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg,
john-Pj+rj9U5foFAfugRpC6u6w, linux-spi-u79uwXL29TY76Z2rM5mHXA,
hauke.mehrtens-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <20170417192942.32219-10-hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
On Mon, Apr 17, 2017 at 09:29:38PM +0200, Hauke Mehrtens wrote:
> From: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>
> Compared to the old xrx200_phy_fw driver the new version has multiple
> enhancements. The name of the firmware files does not have to be added
> to all .dts files anymore - one now configures the GPHY mode (FE or GE)
> instead. Each GPHY can now also boot separate firmware (thus mixing of
> GE and FE GPHYs is now possible).
> The new implementation is based on the RCU syscon-mfd and uses the
> reeset_controller framework instead of raw RCU register reads/writes.
>
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
> .../devicetree/bindings/mips/lantiq/rcu-gphy.txt | 54 +++++
> arch/mips/lantiq/xway/sysctrl.c | 4 +-
> drivers/soc/lantiq/Makefile | 1 +
> drivers/soc/lantiq/gphy.c | 242 +++++++++++++++++++++
> include/dt-bindings/mips/lantiq_rcu_gphy.h | 15 ++
> 5 files changed, 314 insertions(+), 2 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt
> create mode 100644 drivers/soc/lantiq/gphy.c
> create mode 100644 include/dt-bindings/mips/lantiq_rcu_gphy.h
>
> diff --git a/Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt b/Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt
> new file mode 100644
> index 000000000000..d525c7ce9f0b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/lantiq/rcu-gphy.txt
> @@ -0,0 +1,54 @@
> +Lantiq XWAY SoC GPHY binding
> +============================
> +
> +This binding describes a software-defined ethernet PHY, provided by the RCU
> +module on newer Lantiq XWAY SoCs (xRX200 and newer).
> +This depends on binary firmware blobs which must be provided by userspace.
Where the blobs come from is not relevant.
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties (controller (parent) node):
> +- compatible : Should be one of
> + "lantiq,xrx200a1x-rcu-gphy"
> + "lantiq,xrx200a2x-rcu-gphy"
> + "lantiq,xrx300-rcu-gphy"
> + "lantiq,xrx330-rcu-gphy"
> +- lantiq,rcu-syscon : A phandle and offset to the GPHY address registers in
> + the RCU
> +- resets : Must reference the RCU GPHY reset bit
> +- reset-names : One entry, value must be "gphy" or optional "gphy2"
> +
> +Optional properties (port (child) node):
> +- lantiq,gphy-mode : GPHY_MODE_GE (default) or GPHY_MODE_FE as defined in
> + <dt-bindings/mips/lantiq_xway_gphy.h>
> +- clocks : A reference to the (PMU) GPHY clock gate
> +- clock-names : If clocks is given then this must be "gphy"
Kind of pointless to have a name for a single clock.
> +
> +
> +-------------------------------------------------------------------------------
> +Example for the GPHys on the xRX200 SoCs:
> +
> +#include <dt-bindings/mips/lantiq_rcu_gphy.h>
> + gphy0: rcu_gphy@0 {
Use generic node names: phy@...
> + compatible = "lantiq,xrx200a2x-rcu-gphy";
> + reg = <0>;
> +
> + lantiq,rcu-syscon = <&rcu0 0x20>;
Could the phy just be a child of the rcu? Then you don't need a phandle
here and 0x20 becomes the reg address.
> + resets = <&rcu_reset0 31>, <&rcu_reset1 7>;
> + reset-names = "gphy", "gphy2";
> + lantiq,gphy-mode = <GPHY_MODE_GE>;
> + clocks = <&pmu0 XRX200_PMU_GATE_GPHY>;
> + clock-names = "gphy";
> + };
> +
> + gphy1: rcu_gphy@1 {
> + compatible = "lantiq,xrx200a2x-rcu-gphy";
> + reg = <0>;
> +
> + lantiq,rcu-syscon = <&rcu0 0x68>;
> + resets = <&rcu_reset0 29>, <&rcu_reset1 6>;
> + reset-names = "gphy", "gphy2";
> + lantiq,gphy-mode = <GPHY_MODE_FE>;
> + clocks = <&pmu0 XRX200_PMU_GATE_GPHY>;
> + clock-names = "gphy";
> + };
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" 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: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Peter Rosin @ 2017-04-20 15:01 UTC (permalink / raw)
To: Philipp Zabel
Cc: Rob Herring, Mark Rutland, Sakari Ailus, Steve Longerbeam,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <1492699816.2158.107.camel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
On 2017-04-20 16:50, Philipp Zabel wrote:
> mux: mux-controllers {
> compatible = "mmio-mux";
> #mux-control-cells = <1>;
>
> /* This list is not complete */
> mux-reg-masks = <0x04 0x00080000>, /* MIPI_IPU1_MUX */
> <0x04 0x00100000>, /* MIPI_IPU2_MUX */
> <0x0c 0x0000000c>, /* HDMI_MUX_CTL */
> <0x0c 0x000000c0>, /* LVDS0_MUX_CTL */
> <0x0c 0x0000030c>, /* LVDS1_MUX_CTL */
I hope you mean
<0x0c 0x00000300>, /* LVDS1_MUX_CTL */
:-)
> <0x28 0x00000003>, /* DCIC1_MUX_CTL */
> <0x28 0x0000000c>; /* DCIC2_MUX_CTL */
> };
(BTW, same bug in the other example)
Cheers,
peda
--
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 08/13] reset: Add a reset controller driver for the Lantiq XWAY based SoCs
From: Rob Herring @ 2017-04-20 14:54 UTC (permalink / raw)
To: Hauke Mehrtens
Cc: ralf-6z/3iImG2C8G8FEW9MqTrA, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg,
john-Pj+rj9U5foFAfugRpC6u6w, linux-spi-u79uwXL29TY76Z2rM5mHXA,
hauke.mehrtens-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <20170417192942.32219-9-hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
On Mon, Apr 17, 2017 at 09:29:37PM +0200, Hauke Mehrtens wrote:
> From: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>
> The reset controllers (on xRX200 and newer SoCs have two of them) are
> provided by the RCU module. This was initially implemented as a simple
> reset controller. However, the RCU module provides more functionality
> (ethernet GPHYs, USB PHY, etc.), which makes it a MFD device.
> The old reset controller driver implementation from
> arch/mips/lantiq/xway/reset.c did not honor this fact.
>
> For some devices the request and the status bits are different.
>
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
> .../devicetree/bindings/reset/lantiq,rcu-reset.txt | 43 ++++
> arch/mips/lantiq/xway/reset.c | 68 ------
> drivers/reset/Kconfig | 6 +
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-lantiq-rcu.c | 231 +++++++++++++++++++++
> 5 files changed, 281 insertions(+), 68 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/reset/lantiq,rcu-reset.txt
> create mode 100644 drivers/reset/reset-lantiq-rcu.c
>
> diff --git a/Documentation/devicetree/bindings/reset/lantiq,rcu-reset.txt b/Documentation/devicetree/bindings/reset/lantiq,rcu-reset.txt
> new file mode 100644
> index 000000000000..7f097d16bbb7
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/lantiq,rcu-reset.txt
> @@ -0,0 +1,43 @@
> +Lantiq XWAY SoC RCU reset controller binding
> +============================================
> +
> +This binding describes a reset-controller found on the RCU module on Lantiq
> +XWAY SoCs.
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties (controller (parent) node):
> +- compatible : Should be "lantiq,rcu-reset"
> +- lantiq,rcu-syscon : A phandle to the RCU syscon, the reset register
> + offset and the status register offset.
> +- #reset-cells : Specifies the number of cells needed to encode the
> + reset line, should be 1.
> +
> +Optional properties:
> +- reset-status : The request status bit. For some bits the request bit
> + and the status bit are different. This is depending
> + on the SoC. If the reset-status bit does not match
> + the reset-request bit, put the reset number into the
> + reset-request property and the status bit at the same
> + index into the reset-status property. If no
> + reset-request bit is given here, the driver assume
> + status and request bit are the same.
> +- reset-request : The reset request bit, to map it to the reset-status
> + bit.
These should either be implied by SoC specific compatible or be made
part of the reset cells. In the latter case, you still need the SoC
specific compatible.
> +-------------------------------------------------------------------------------
> +Example for the reset-controllers on the xRX200 SoCs:
> + rcu_reset0: rcu_reset {
> + compatible = "lantiq,rcu-reset";
> + lantiq,rcu-syscon = <&rcu0 0x10 0x14>;
> + #reset-cells = <1>;
> + reset-request = <31>, <29>, <21>, <19>, <16>, <12>;
> + reset-status = <30>, <28>, <16>, <25>, <5>, <24>;
> + };
> +
> + rcu_reset1: rcu_reset {
> + compatible = "lantiq,rcu-reset";
These 2 blocks are identical? Given different registers sizes, I'd say
not. So they should have different compatible strings.
> + lantiq,rcu-syscon = <&rcu0 0x48 0x24>;
> + #reset-cells = <1>;
> + };
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" 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: [RFC 1/2] dt-bindings: add mmio-based syscon mux controller DT bindings
From: Philipp Zabel @ 2017-04-20 14:50 UTC (permalink / raw)
To: Peter Rosin
Cc: Rob Herring, Mark Rutland, Sakari Ailus, Steve Longerbeam,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ
In-Reply-To: <b2e0c3bb-c74a-3ef3-6b58-1139d7a932a4-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On Thu, 2017-04-20 at 16:13 +0200, Peter Rosin wrote:
> On 2017-04-20 15:32, Peter Rosin wrote:
> > On 2017-04-20 00:09, Rob Herring wrote:
> >> On Thu, Apr 13, 2017 at 05:48:11PM +0200, Philipp Zabel wrote:
> >>> This adds device tree binding documentation for mmio-based syscon
> >>> multiplexers controlled by a single bitfield in a syscon register
> >>> range.
> >>>
> >>> Signed-off-by: Philipp Zabel <p.zabel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> >>> ---
> >>> Documentation/devicetree/bindings/mux/mmio-mux.txt | 56 ++++++++++++++++++++++
> >>> 1 file changed, 56 insertions(+)
> >>> create mode 100644 Documentation/devicetree/bindings/mux/mmio-mux.txt
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/mux/mmio-mux.txt b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> >>> new file mode 100644
> >>> index 0000000000000..11d96f5d98583
> >>> --- /dev/null
> >>> +++ b/Documentation/devicetree/bindings/mux/mmio-mux.txt
> >>> @@ -0,0 +1,56 @@
> >>> +MMIO bitfield-based multiplexer controller bindings
> >>> +
> >>> +Define a syscon bitfield to be used to control a multiplexer. The parent
> >>> +device tree node must be a syscon node to provide register access.
> >>> +
> >>> +Required properties:
> >>> +- compatible : "gpio-mux"
> >>
> >> ?
> >>
> >>> +- reg : register base of the register containing the control bitfield
> >>> +- bit-mask : bitmask of the control bitfield in the control register
> >>> +- bit-shift : bit offset of the control bitfield in the control register
> >>> +- #mux-control-cells : <0>
> >>> +* Standard mux-controller bindings as decribed in mux-controller.txt
> >>> +
> >>> +Optional properties:
> >>> +- idle-state : if present, the state the mux will have when idle. The
> >>> + special state MUX_IDLE_AS_IS is the default.
> >>> +
> >>> +The multiplexer state is defined as the value of the bitfield described
> >>> +by the reg, bit-mask, and bit-shift properties, accessed through the parent
> >>> +syscon.
> >>> +
> >>> +Example:
> >>> +
> >>> + syscon {
> >>> + compatible = "syscon";
> >>> +
> >>> + mux: mux-controller@3 {
> >>> + compatible = "mmio-mux";
> >>> + reg = <0x3>;
> >>> + bit-mask = <0x1>;
> >>> + bit-shift = <5>;
> >>
> >> This pattern doesn't scale once you have multiple fields @ addr 3. I
> >> also don't really think a node per register field in DT really scales.
> >>
> >> I think the parent should be declared as a mux controller instead. You
> >> could encode the mux addr and bit position in the mux cells.
> >
> > But then you need to create mux controllers on demand. I have not
> > succeeded in doing that while also following the rules of the driver
> > model. I had severe problems with life-time issues when I tried.
> > I would like to see code before embarking on this path, and I'm
> > apparently not the one writing it...
> >
> > So, either you meant that, or that the parent node should somehow
> > specify the possible mux controllers up front so that they can be
> > pre-created and ready when the consumers request them. But if you
> > do that, you can just refer to them by some enumeration from the
> > mux consumers instead of by some convoluted reg+field notation.
>
> Ok, thinking some more about this. Sorry for spamming and replying to
> self...
>
> How about:
>
> syscon {
> compatible = "syscon", "simple-mfd";
>
> mux: mux-controllers {
> compatible = "mmio-mux";
> #mux-control-cells = <1>;
>
> /* three mux controllers, one at reg 3 bits 0:2,
> * one at reg 3 bits 5:6 and one at reg 7 bit 3.
> */
> mux-reg-masks = <0x3 0x07>, <0x3 0x60>, <0x7 0x08>;
> idle-state = <7>, <MUX_IDLE_AS_IS>, <0>;
> };
>
>
> video-mux {
> compatible = "video-mux";
> mux-controls = <&mux 1>; /* i.e. reg 3 bits 5:6 */
>
> ports {
> /* ports 0..5 */
> };
> };
> };
>
> Optionally using some 64-bit safe 3-value encoding of the register fields
> in the mux-reg-masks binding...
I would prefer this to putting the registers and bit masks into the
phandle cells. The i.MX6Q/D GPR muxes could look like this:
gpr: iomuxc-gpr@020e0000 {
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
reg = <0x020e0000 0x38>;
mux: mux-controllers {
compatible = "mmio-mux";
#mux-control-cells = <1>;
/* This list is not complete */
mux-reg-masks = <0x04 0x00080000>, /* MIPI_IPU1_MUX */
<0x04 0x00100000>, /* MIPI_IPU2_MUX */
<0x0c 0x0000000c>, /* HDMI_MUX_CTL */
<0x0c 0x000000c0>, /* LVDS0_MUX_CTL */
<0x0c 0x0000030c>, /* LVDS1_MUX_CTL */
<0x28 0x00000003>, /* DCIC1_MUX_CTL */
<0x28 0x0000000c>; /* DCIC2_MUX_CTL */
};
ipu1_csi0_mux {
compatible = "video-mux";
mux-controls = <&mux 0>;
/* ... */
};
ipu2_csi1_mux {
compatible = "video-mux";
mux-controls = <&mux 1>;
/* ... */
};
};
and for i.MX6DL/S:
gpr: iomuxc-gpr@20e0000 {
compatible = "fsl,imx6q-iomuxc-gpr", "syscon";
reg = <0x020e0000 0x38>;
mux: mux-controllers {
compatible = "mmio-mux";
#mux-control-cells = <1>;
mux-reg-masks = <0x34 0x00000007>, /* IPU_CSI0_MUX */
<0x34 0x00000038>, /* IPU_CSI1_MUX */
<0x0c 0x0000000c>, /* HDMI_MUX_CTL */
<0x0c 0x000000c0>, /* LVDS0_MUX_CTL */
<0x0c 0x0000030c>, /* LVDS1_MUX_CTL */
<0x28 0x00000003>, /* DCIC1_MUX_CTL */
<0x28 0x0000000c>; /* DCIC2_MUX_CTL */
};
ipu1_csi0_mux {
compatible = "video-mux";
mux-controls = <&mux 0>;
/* ... */
};
ipu1_csi1_mux {
compatible = "video-mux";
mux-controls = <&mux 1>;
/* ... */
};
};
regards
Philipp
--
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 v4 3/8] arm: fix return value of parse_cpu_capacity
From: Vincent Guittot @ 2017-04-20 14:50 UTC (permalink / raw)
To: Juri Lelli
Cc: linux-kernel, linux-pm@vger.kernel.org, LAK,
devicetree@vger.kernel.org, Peter Zijlstra, Rob Herring,
Mark Rutland, Russell King - ARM Linux, Sudeep Holla,
Lorenzo Pieralisi, Catalin Marinas, Will Deacon, Morten Rasmussen,
Dietmar Eggemann, Mark Brown, gregkh@linuxfoundation.org
In-Reply-To: <20170420144316.15632-4-juri.lelli@arm.com>
On 20 April 2017 at 16:43, Juri Lelli <juri.lelli@arm.com> wrote:
> parse_cpu_capacity() has to return 0 on failure, but it currently returns
> 1 instead if raw_capacity kcalloc failed.
>
> Fix it (by directly returning 0).
>
> Cc: Russell King <linux@arm.linux.org.uk>
> Reported-by: Morten Rasmussen <morten.rasmussen@arm.com>
> Fixes: 06073ee26775 ('ARM: 8621/3: parse cpu capacity-dmips-mhz from DT')
> Signed-off-by: Juri Lelli <juri.lelli@arm.com>
> Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
> ---
>
> Changes from v3:
>
> - directly return 0 on failure (as pointed out by Vincent)
> ---
> arch/arm/kernel/topology.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> index f8a3ab82e77f..1b8ec3054642 100644
> --- a/arch/arm/kernel/topology.c
> +++ b/arch/arm/kernel/topology.c
> @@ -166,7 +166,7 @@ static int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
> if (!raw_capacity) {
> pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
> cap_parsing_failed = true;
> - return !ret;
> + return 0;
Acked-by: Vincent Guittot <vincent.guittot@linaor.org>
> }
> }
> capacity_scale = max(cpu_capacity, capacity_scale);
> --
> 2.10.0
>
^ permalink raw reply
* Re: [PATCH 06/13] MIPS: lantiq: Convert the xbar driver to a platform_driver
From: Rob Herring @ 2017-04-20 14:48 UTC (permalink / raw)
To: Hauke Mehrtens
Cc: ralf-6z/3iImG2C8G8FEW9MqTrA, linux-mips-6z/3iImG2C8G8FEW9MqTrA,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg,
john-Pj+rj9U5foFAfugRpC6u6w, linux-spi-u79uwXL29TY76Z2rM5mHXA,
hauke.mehrtens-ral2JQCrhuEAvxtiuMwx3w
In-Reply-To: <20170417192942.32219-7-hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
On Mon, Apr 17, 2017 at 09:29:35PM +0200, Hauke Mehrtens wrote:
> From: Martin Blumenstingl <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>
> This allows using the xbar driver on ARX300 based SoCs which require the
> same xbar setup as the xRX200 chipsets because the xbar driver
> initialization is not guarded by an xRX200 specific
> of_machine_is_compatible condition anymore. Additionally the new driver
> takes a syscon phandle to configure the XBAR endianness bits in RCU
> (before this was done in arch/mips/lantiq/xway/reset.c and also
> guarded by an xRX200 specific if-statement).
>
> Signed-off-by: Hauke Mehrtens <hauke-5/S+JYg5SzeELgA04lAiVw@public.gmane.org>
> ---
> .../devicetree/bindings/mips/lantiq/xbar.txt | 22 +++++
> MAINTAINERS | 1 +
> arch/mips/lantiq/xway/reset.c | 4 -
> arch/mips/lantiq/xway/sysctrl.c | 41 ---------
> drivers/soc/Makefile | 1 +
> drivers/soc/lantiq/Makefile | 1 +
> drivers/soc/lantiq/xbar.c | 100 +++++++++++++++++++++
> 7 files changed, 125 insertions(+), 45 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mips/lantiq/xbar.txt
> create mode 100644 drivers/soc/lantiq/Makefile
> create mode 100644 drivers/soc/lantiq/xbar.c
>
> diff --git a/Documentation/devicetree/bindings/mips/lantiq/xbar.txt b/Documentation/devicetree/bindings/mips/lantiq/xbar.txt
> new file mode 100644
> index 000000000000..86e53ff3b0d5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mips/lantiq/xbar.txt
> @@ -0,0 +1,22 @@
> +Lantiq XWAY SoC XBAR binding
> +============================
> +
> +
> +-------------------------------------------------------------------------------
> +Required properties:
> +- compatible : Should be "lantiq,xbar-xway"
This compatible is already in use so it is fine, but you should also
have per SoC compatible strings.
> +- reg : The address and length of the XBAR registers
> +
> +Optional properties:
> +- lantiq,rcu-syscon : A phandle and offset to the endianness configuration
> + registers in the RCU module
> +
> +
> +-------------------------------------------------------------------------------
> +Example for the XBAR on the xRX200 SoCs:
> + xbar0: xbar@400000 {
> + compatible = "lantiq,xbar-xway";
> + reg = <0x400000 0x1000>;
> + big-endian;
> + lantiq,rcu-syscon = <&rcu0 0x4c>;
> + };
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" 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 v4 8/8] arm,arm64,drivers: add a prefix to drivers arch_topology interfaces
From: Juri Lelli @ 2017-04-20 14:43 UTC (permalink / raw)
To: linux-kernel
Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
juri.lelli, broonie, gregkh
In-Reply-To: <20170420144316.15632-1-juri.lelli@arm.com>
Now that some functions that deal with arch topology information live
under drivers, there is a clash of naming that might create confusion.
Tidy things up by creating a drivers namespace for interfaces used by
arch code; achieve this by prepending a 'atd_' (arch topology driver)
prefix to driver interfaces.
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/kernel/topology.c | 8 ++++----
arch/arm64/kernel/topology.c | 4 ++--
drivers/base/arch_topology.c | 20 ++++++++++----------
include/linux/arch_topology.h | 8 ++++----
4 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 557be4f1d2d7..e53391026c1b 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -111,7 +111,7 @@ static void __init parse_dt_topology(void)
continue;
}
- if (parse_cpu_capacity(cn, cpu)) {
+ if (atd_parse_cpu_capacity(cn, cpu)) {
of_node_put(cn);
continue;
}
@@ -160,7 +160,7 @@ static void __init parse_dt_topology(void)
>> (SCHED_CAPACITY_SHIFT-1)) + 1;
if (cap_from_dt)
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
}
/*
@@ -173,10 +173,10 @@ static void update_cpu_capacity(unsigned int cpu)
if (!cpu_capacity(cpu) || cap_from_dt)
return;
- set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
+ atd_set_capacity_scale(cpu, cpu_capacity(cpu) / middle_capacity);
pr_info("CPU%u: update cpu_capacity %lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
+ cpu, atd_scale_cpu_capacity(NULL, cpu));
}
#else
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 255230c3e835..5f24faa09c05 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -39,7 +39,7 @@ static int __init get_cpu_for_node(struct device_node *node)
for_each_possible_cpu(cpu) {
if (of_get_cpu_node(cpu, NULL) == cpu_node) {
- parse_cpu_capacity(cpu_node, cpu);
+ atd_parse_cpu_capacity(cpu_node, cpu);
of_node_put(cpu_node);
return cpu;
}
@@ -191,7 +191,7 @@ static int __init parse_dt_topology(void)
if (ret != 0)
goto out_map;
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
/*
* Check that all cores are in the topology; the SMP code will
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 76c19aa0d82f..f04999e3ff75 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -25,12 +25,12 @@
static DEFINE_MUTEX(cpu_scale_mutex);
static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu)
+unsigned long atd_scale_cpu_capacity(struct sched_domain *sd, int cpu)
{
return per_cpu(cpu_scale, cpu);
}
-void set_capacity_scale(unsigned int cpu, unsigned long capacity)
+void atd_set_capacity_scale(unsigned int cpu, unsigned long capacity)
{
per_cpu(cpu_scale, cpu) = capacity;
}
@@ -42,7 +42,7 @@ static ssize_t cpu_capacity_show(struct device *dev,
struct cpu *cpu = container_of(dev, struct cpu, dev);
return sprintf(buf, "%lu\n",
- arch_scale_cpu_capacity(NULL, cpu->dev.id));
+ atd_scale_cpu_capacity(NULL, cpu->dev.id));
}
static ssize_t cpu_capacity_store(struct device *dev,
@@ -67,7 +67,7 @@ static ssize_t cpu_capacity_store(struct device *dev,
mutex_lock(&cpu_scale_mutex);
for_each_cpu(i, &cpu_topology[this_cpu].core_sibling)
- set_capacity_scale(i, new_capacity);
+ atd_set_capacity_scale(i, new_capacity);
mutex_unlock(&cpu_scale_mutex);
return count;
@@ -98,7 +98,7 @@ static u32 capacity_scale;
static u32 *raw_capacity;
static bool cap_parsing_failed;
-void normalize_cpu_capacity(void)
+void atd_normalize_cpu_capacity(void)
{
u64 capacity;
int cpu;
@@ -113,14 +113,14 @@ void normalize_cpu_capacity(void)
cpu, raw_capacity[cpu]);
capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
/ capacity_scale;
- set_capacity_scale(cpu, capacity);
+ atd_set_capacity_scale(cpu, capacity);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
- cpu, arch_scale_cpu_capacity(NULL, cpu));
+ cpu, atd_scale_cpu_capacity(NULL, cpu));
}
mutex_unlock(&cpu_scale_mutex);
}
-int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu)
+int __init atd_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
{
int ret = 1;
u32 cpu_capacity;
@@ -185,12 +185,12 @@ init_cpu_capacity_callback(struct notifier_block *nb,
cpus_to_visit,
policy->related_cpus);
for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = arch_scale_cpu_capacity(NULL, cpu) *
+ raw_capacity[cpu] = atd_scale_cpu_capacity(NULL, cpu) *
policy->cpuinfo.max_freq / 1000UL;
capacity_scale = max(raw_capacity[cpu], capacity_scale);
}
if (cpumask_empty(cpus_to_visit)) {
- normalize_cpu_capacity();
+ atd_normalize_cpu_capacity();
kfree(raw_capacity);
pr_debug("cpu_capacity: parsing done\n");
cap_parsing_done = true;
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
index 4edae9fe8cdd..e25458d7ee9a 100644
--- a/include/linux/arch_topology.h
+++ b/include/linux/arch_topology.h
@@ -4,14 +4,14 @@
#ifndef _LINUX_ARCH_TOPOLOGY_H_
#define _LINUX_ARCH_TOPOLOGY_H_
-void normalize_cpu_capacity(void);
+void atd_normalize_cpu_capacity(void);
struct device_node;
-int parse_cpu_capacity(struct device_node *cpu_node, int cpu);
+int atd_parse_cpu_capacity(struct device_node *cpu_node, int cpu);
struct sched_domain;
-unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
+unsigned long atd_scale_cpu_capacity(struct sched_domain *sd, int cpu);
-void set_capacity_scale(unsigned int cpu, unsigned long capacity);
+void atd_set_capacity_scale(unsigned int cpu, unsigned long capacity);
#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
--
2.10.0
^ permalink raw reply related
* [PATCH v4 7/8] arm,arm64,drivers: move externs in a new header file
From: Juri Lelli @ 2017-04-20 14:43 UTC (permalink / raw)
To: linux-kernel
Cc: linux-pm, linux-arm-kernel, devicetree, peterz, vincent.guittot,
robh+dt, mark.rutland, linux, sudeep.holla, lorenzo.pieralisi,
catalin.marinas, will.deacon, morten.rasmussen, dietmar.eggemann,
juri.lelli, broonie, gregkh
In-Reply-To: <20170420144316.15632-1-juri.lelli@arm.com>
Create a new header file (include/linux/arch_topology.h) and put there
declarations of interfaces used by arm, arm64 and drivers code.
Signed-off-by: Juri Lelli <juri.lelli@arm.com>
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/kernel/topology.c | 7 +------
arch/arm64/kernel/topology.c | 4 +---
drivers/base/arch_topology.c | 1 +
include/linux/arch_topology.h | 17 +++++++++++++++++
4 files changed, 20 insertions(+), 9 deletions(-)
create mode 100644 include/linux/arch_topology.h
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 1e35a3265ddf..557be4f1d2d7 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -11,6 +11,7 @@
* for more details.
*/
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/cpumask.h>
@@ -45,10 +46,6 @@
* updated during this sequence.
*/
-extern unsigned long
-arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
-extern void set_capacity_scale(unsigned int cpu, unsigned long capacity);
-
#ifdef CONFIG_OF
struct cpu_efficiency {
const char *compatible;
@@ -76,8 +73,6 @@ static unsigned long *__cpu_capacity;
static unsigned long middle_capacity = 1;
static bool cap_from_dt = true;
-extern void normalize_cpu_capacity(void);
-extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
/*
* Iterate all CPUs' descriptor in DT and compute the efficiency
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index 7e1f6f75185b..255230c3e835 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -11,6 +11,7 @@
* for more details.
*/
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -27,9 +28,6 @@
#include <asm/cputype.h>
#include <asm/topology.h>
-extern void normalize_cpu_capacity(void);
-extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
-
static int __init get_cpu_for_node(struct device_node *node)
{
struct device_node *cpu_node;
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index acf99372c5cf..76c19aa0d82f 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -13,6 +13,7 @@
*/
#include <linux/acpi.h>
+#include <linux/arch_topology.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h
new file mode 100644
index 000000000000..4edae9fe8cdd
--- /dev/null
+++ b/include/linux/arch_topology.h
@@ -0,0 +1,17 @@
+/*
+ * include/linux/arch_topology.h - arch specific cpu topology information
+ */
+#ifndef _LINUX_ARCH_TOPOLOGY_H_
+#define _LINUX_ARCH_TOPOLOGY_H_
+
+void normalize_cpu_capacity(void);
+
+struct device_node;
+int parse_cpu_capacity(struct device_node *cpu_node, int cpu);
+
+struct sched_domain;
+unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu);
+
+void set_capacity_scale(unsigned int cpu, unsigned long capacity);
+
+#endif /* _LINUX_ARCH_TOPOLOGY_H_ */
--
2.10.0
^ permalink raw reply related
* [PATCH v4 6/8] arm,arm64,drivers: reduce scope of cap_parsing_failed
From: Juri Lelli @ 2017-04-20 14:43 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: linux-pm-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
vincent.guittot-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
linux-lFZ/pmaqli7XmaaqVzeoHQ, sudeep.holla-5wv7dgnIgG8,
lorenzo.pieralisi-5wv7dgnIgG8, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, morten.rasmussen-5wv7dgnIgG8,
dietmar.eggemann-5wv7dgnIgG8, juri.lelli-5wv7dgnIgG8,
broonie-DgEjT+Ai2ygdnm+yROfE0A,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r
In-Reply-To: <20170420144316.15632-1-juri.lelli-5wv7dgnIgG8@public.gmane.org>
Reduce the scope of cap_parsing_failed (making it static in
drivers/base/arch_topology.c) by slightly changing {arm,arm64} DT
parsing code.
For arm checking for !cap_parsing_failed before calling normalize_
cpu_capacity() is superfluous, as returning an error from parse_
cpu_capacity() (above) means cap_from _dt is set to false.
For arm64 we can simply check if raw_capacity points to something,
which is not if capacity parsing has failed.
Suggested-by: Morten Rasmussen <morten.rasmussen-5wv7dgnIgG8@public.gmane.org>
Signed-off-by: Juri Lelli <juri.lelli-5wv7dgnIgG8@public.gmane.org>
Acked-by: Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org>
Acked-by: Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>
---
arch/arm/kernel/topology.c | 3 +--
arch/arm64/kernel/topology.c | 5 +----
drivers/base/arch_topology.c | 4 ++--
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 49ef025ffaa0..1e35a3265ddf 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -76,7 +76,6 @@ static unsigned long *__cpu_capacity;
static unsigned long middle_capacity = 1;
static bool cap_from_dt = true;
-extern bool cap_parsing_failed;
extern void normalize_cpu_capacity(void);
extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
@@ -165,7 +164,7 @@ static void __init parse_dt_topology(void)
middle_capacity = ((max_capacity / 3)
>> (SCHED_CAPACITY_SHIFT-1)) + 1;
- if (cap_from_dt && !cap_parsing_failed)
+ if (cap_from_dt)
normalize_cpu_capacity();
}
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index c5bc31eb97e8..7e1f6f75185b 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -27,7 +27,6 @@
#include <asm/cputype.h>
#include <asm/topology.h>
-extern bool cap_parsing_failed;
extern void normalize_cpu_capacity(void);
extern int __init parse_cpu_capacity(struct device_node *cpu_node, int cpu);
@@ -187,10 +186,8 @@ static int __init parse_dt_topology(void)
* cluster with restricted subnodes.
*/
map = of_get_child_by_name(cn, "cpu-map");
- if (!map) {
- cap_parsing_failed = true;
+ if (!map)
goto out;
- }
ret = parse_cluster(map, 0);
if (ret != 0)
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 097834f0fcd7..acf99372c5cf 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -95,7 +95,7 @@ subsys_initcall(register_cpu_capacity_sysctl);
static u32 capacity_scale;
static u32 *raw_capacity;
-bool cap_parsing_failed;
+static bool cap_parsing_failed;
void normalize_cpu_capacity(void)
{
@@ -210,7 +210,7 @@ static int __init register_cpufreq_notifier(void)
* until we have the necessary code to parse the cpu capacity, so
* skip registering cpufreq notifier.
*/
- if (!acpi_disabled || cap_parsing_failed)
+ if (!acpi_disabled || !raw_capacity)
return -EINVAL;
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
--
2.10.0
--
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
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