[media] move s5p-cec to staging
authorMauro Carvalho Chehab <mchehab@s-opensource.com>
Tue, 28 Jun 2016 14:36:02 +0000 (11:36 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Tue, 28 Jun 2016 14:42:16 +0000 (11:42 -0300)
As the CEC core is currently at staging, it doesn't make any sense
to put a dependent driver outside staging. So, move it also to
staging.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
19 files changed:
MAINTAINERS
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/s5p-cec/Makefile [deleted file]
drivers/media/platform/s5p-cec/exynos_hdmi_cec.h [deleted file]
drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c [deleted file]
drivers/media/platform/s5p-cec/regs-cec.h [deleted file]
drivers/media/platform/s5p-cec/s5p_cec.c [deleted file]
drivers/media/platform/s5p-cec/s5p_cec.h [deleted file]
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/s5p-cec/Kconfig [new file with mode: 0644]
drivers/staging/media/s5p-cec/Makefile [new file with mode: 0644]
drivers/staging/media/s5p-cec/TODO [new file with mode: 0644]
drivers/staging/media/s5p-cec/exynos_hdmi_cec.h [new file with mode: 0644]
drivers/staging/media/s5p-cec/exynos_hdmi_cecctrl.c [new file with mode: 0644]
drivers/staging/media/s5p-cec/regs-cec.h [new file with mode: 0644]
drivers/staging/media/s5p-cec/s5p_cec.c [new file with mode: 0644]
drivers/staging/media/s5p-cec/s5p_cec.h [new file with mode: 0644]

index 7f76a3bf069fe9be01b9175671a202d400fc8558..962c5b0d2a3d345f5c994227968b497349563472 100644 (file)
@@ -1647,7 +1647,7 @@ M:        Kyungmin Park <kyungmin.park@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/platform/s5p-cec/
+F:     drivers/staging/media/platform/s5p-cec/
 
 ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
 M:     Andrzej Pietrasiewicz <andrzej.p@samsung.com>
index 567717583246f8cf2a33df80f680a16b32341135..382f3937379e40cedf5aa440dbb016be11155299 100644 (file)
@@ -108,16 +108,6 @@ config VIDEO_S3C_CAMIF
 source "drivers/media/platform/soc_camera/Kconfig"
 source "drivers/media/platform/exynos4-is/Kconfig"
 source "drivers/media/platform/s5p-tv/Kconfig"
-
-config VIDEO_SAMSUNG_S5P_CEC
-       tristate "Samsung S5P CEC driver"
-       depends on VIDEO_DEV && MEDIA_CEC && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
-       ---help---
-         This is a driver for Samsung S5P HDMI CEC interface. It uses the
-         generic CEC framework interface.
-         CEC bus is present in the HDMI connector and enables communication
-         between compatible devices.
-
 source "drivers/media/platform/am437x/Kconfig"
 source "drivers/media/platform/xilinx/Kconfig"
 source "drivers/media/platform/rcar-vin/Kconfig"
index 9a2fe95132828739ee3fb9af3dbbc65f8e482e94..99cf31542f5460f0913dc6381c421fdb57a6121a 100644 (file)
@@ -28,7 +28,6 @@ obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE)       += m2m-deinterlace.o
 
 obj-$(CONFIG_VIDEO_S3C_CAMIF)          += s3c-camif/
 obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS)         += exynos4-is/
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC)    += s5p-cec/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)   += s5p-jpeg/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)    += s5p-mfc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)     += s5p-tv/
diff --git a/drivers/media/platform/s5p-cec/Makefile b/drivers/media/platform/s5p-cec/Makefile
deleted file mode 100644 (file)
index 0e2cf45..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC)    += s5p-cec.o
-s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
deleted file mode 100644 (file)
index 3e4fc7b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
- *
- * Copyright (c) 2010, 2014 Samsung Electronics
- *             http://www.samsung.com/
- *
- * Header file for interface of Samsung Exynos hdmi cec hardware
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _EXYNOS_HDMI_CEC_H_
-#define _EXYNOS_HDMI_CEC_H_ __FILE__
-
-#include <linux/regmap.h>
-#include <linux/miscdevice.h>
-#include "s5p_cec.h"
-
-void s5p_cec_set_divider(struct s5p_cec_dev *cec);
-void s5p_cec_enable_rx(struct s5p_cec_dev *cec);
-void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec);
-void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec);
-void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec);
-void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec);
-void s5p_cec_reset(struct s5p_cec_dev *cec);
-void s5p_cec_tx_reset(struct s5p_cec_dev *cec);
-void s5p_cec_rx_reset(struct s5p_cec_dev *cec);
-void s5p_cec_threshold(struct s5p_cec_dev *cec);
-void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
-                        size_t count, u8 retries);
-void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr);
-u32 s5p_cec_get_status(struct s5p_cec_dev *cec);
-void s5p_clr_pending_tx(struct s5p_cec_dev *cec);
-void s5p_clr_pending_rx(struct s5p_cec_dev *cec);
-void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer);
-
-#endif /* _EXYNOS_HDMI_CEC_H_ */
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
deleted file mode 100644 (file)
index ce95e0f..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
- *
- * Copyright (c) 2009, 2014 Samsung Electronics
- *             http://www.samsung.com/
- *
- * cec ftn file for Samsung TVOUT driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/io.h>
-#include <linux/device.h>
-
-#include "exynos_hdmi_cec.h"
-#include "regs-cec.h"
-
-#define S5P_HDMI_FIN                   24000000
-#define CEC_DIV_RATIO                  320000
-
-#define CEC_MESSAGE_BROADCAST_MASK     0x0F
-#define CEC_MESSAGE_BROADCAST          0x0F
-#define CEC_FILTER_THRESHOLD           0x15
-
-void s5p_cec_set_divider(struct s5p_cec_dev *cec)
-{
-       u32 div_ratio, div_val;
-       unsigned int reg;
-
-       div_ratio  = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
-
-       if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, &reg)) {
-               dev_err(cec->dev, "failed to read phy control\n");
-               return;
-       }
-
-       reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
-
-       if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) {
-               dev_err(cec->dev, "failed to write phy control\n");
-               return;
-       }
-
-       div_val = CEC_DIV_RATIO * 0.00005 - 1;
-
-       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_3);
-       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_2);
-       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_1);
-       writeb(div_val, cec->reg + S5P_CEC_DIVISOR_0);
-}
-
-void s5p_cec_enable_rx(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       reg = readb(cec->reg + S5P_CEC_RX_CTRL);
-       reg |= S5P_CEC_RX_CTRL_ENABLE;
-       writeb(reg, cec->reg + S5P_CEC_RX_CTRL);
-}
-
-void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
-       reg |= S5P_CEC_IRQ_RX_DONE;
-       reg |= S5P_CEC_IRQ_RX_ERROR;
-       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
-}
-
-void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
-       reg &= ~S5P_CEC_IRQ_RX_DONE;
-       reg &= ~S5P_CEC_IRQ_RX_ERROR;
-       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
-}
-
-void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
-       reg |= S5P_CEC_IRQ_TX_DONE;
-       reg |= S5P_CEC_IRQ_TX_ERROR;
-       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
-
-}
-
-void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
-       reg &= ~S5P_CEC_IRQ_TX_DONE;
-       reg &= ~S5P_CEC_IRQ_TX_ERROR;
-       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
-}
-
-void s5p_cec_reset(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
-       writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
-
-       reg = readb(cec->reg + 0xc4);
-       reg &= ~0x1;
-       writeb(reg, cec->reg + 0xc4);
-}
-
-void s5p_cec_tx_reset(struct s5p_cec_dev *cec)
-{
-       writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
-}
-
-void s5p_cec_rx_reset(struct s5p_cec_dev *cec)
-{
-       u8 reg;
-
-       writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
-
-       reg = readb(cec->reg + 0xc4);
-       reg &= ~0x1;
-       writeb(reg, cec->reg + 0xc4);
-}
-
-void s5p_cec_threshold(struct s5p_cec_dev *cec)
-{
-       writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH);
-       writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL);
-}
-
-void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
-                        size_t count, u8 retries)
-{
-       int i = 0;
-       u8 reg;
-
-       while (i < count) {
-               writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4)));
-               i++;
-       }
-
-       writeb(count, cec->reg + S5P_CEC_TX_BYTES);
-       reg = readb(cec->reg + S5P_CEC_TX_CTRL);
-       reg |= S5P_CEC_TX_CTRL_START;
-       reg &= ~0x70;
-       reg |= retries << 4;
-
-       if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) {
-               dev_dbg(cec->dev, "Broadcast");
-               reg |= S5P_CEC_TX_CTRL_BCAST;
-       } else {
-               dev_dbg(cec->dev, "No Broadcast");
-               reg &= ~S5P_CEC_TX_CTRL_BCAST;
-       }
-
-       writeb(reg, cec->reg + S5P_CEC_TX_CTRL);
-       dev_dbg(cec->dev, "cec-tx: cec count (%zu): %*ph", count,
-               (int)count, data);
-}
-
-void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr)
-{
-       writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR);
-}
-
-u32 s5p_cec_get_status(struct s5p_cec_dev *cec)
-{
-       u32 status = 0;
-
-       status = readb(cec->reg + S5P_CEC_STATUS_0);
-       status |= readb(cec->reg + S5P_CEC_STATUS_1) << 8;
-       status |= readb(cec->reg + S5P_CEC_STATUS_2) << 16;
-       status |= readb(cec->reg + S5P_CEC_STATUS_3) << 24;
-
-       dev_dbg(cec->dev, "status = 0x%x!\n", status);
-
-       return status;
-}
-
-void s5p_clr_pending_tx(struct s5p_cec_dev *cec)
-{
-       writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
-                                       cec->reg + S5P_CEC_IRQ_CLEAR);
-}
-
-void s5p_clr_pending_rx(struct s5p_cec_dev *cec)
-{
-       writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
-                                       cec->reg + S5P_CEC_IRQ_CLEAR);
-}
-
-void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)
-{
-       u32 i = 0;
-       char debug[40];
-
-       while (i < size) {
-               buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4));
-               sprintf(debug + i * 2, "%02x ", buffer[i]);
-               i++;
-       }
-       dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug);
-}
diff --git a/drivers/media/platform/s5p-cec/regs-cec.h b/drivers/media/platform/s5p-cec/regs-cec.h
deleted file mode 100644 (file)
index b2e7e12..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/* drivers/media/platform/s5p-cec/regs-cec.h
- *
- * Copyright (c) 2010 Samsung Electronics
- *             http://www.samsung.com/
- *
- *  register header file for Samsung TVOUT driver
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __EXYNOS_REGS__H
-#define __EXYNOS_REGS__H
-
-/*
- * Register part
- */
-#define S5P_CEC_STATUS_0                       (0x0000)
-#define S5P_CEC_STATUS_1                       (0x0004)
-#define S5P_CEC_STATUS_2                       (0x0008)
-#define S5P_CEC_STATUS_3                       (0x000C)
-#define S5P_CEC_IRQ_MASK                       (0x0010)
-#define S5P_CEC_IRQ_CLEAR                      (0x0014)
-#define S5P_CEC_LOGIC_ADDR                     (0x0020)
-#define S5P_CEC_DIVISOR_0                      (0x0030)
-#define S5P_CEC_DIVISOR_1                      (0x0034)
-#define S5P_CEC_DIVISOR_2                      (0x0038)
-#define S5P_CEC_DIVISOR_3                      (0x003C)
-
-#define S5P_CEC_TX_CTRL                                (0x0040)
-#define S5P_CEC_TX_BYTES                       (0x0044)
-#define S5P_CEC_TX_STAT0                       (0x0060)
-#define S5P_CEC_TX_STAT1                       (0x0064)
-#define S5P_CEC_TX_BUFF0                       (0x0080)
-#define S5P_CEC_TX_BUFF1                       (0x0084)
-#define S5P_CEC_TX_BUFF2                       (0x0088)
-#define S5P_CEC_TX_BUFF3                       (0x008C)
-#define S5P_CEC_TX_BUFF4                       (0x0090)
-#define S5P_CEC_TX_BUFF5                       (0x0094)
-#define S5P_CEC_TX_BUFF6                       (0x0098)
-#define S5P_CEC_TX_BUFF7                       (0x009C)
-#define S5P_CEC_TX_BUFF8                       (0x00A0)
-#define S5P_CEC_TX_BUFF9                       (0x00A4)
-#define S5P_CEC_TX_BUFF10                      (0x00A8)
-#define S5P_CEC_TX_BUFF11                      (0x00AC)
-#define S5P_CEC_TX_BUFF12                      (0x00B0)
-#define S5P_CEC_TX_BUFF13                      (0x00B4)
-#define S5P_CEC_TX_BUFF14                      (0x00B8)
-#define S5P_CEC_TX_BUFF15                      (0x00BC)
-
-#define S5P_CEC_RX_CTRL                                (0x00C0)
-#define S5P_CEC_RX_STAT0                       (0x00E0)
-#define S5P_CEC_RX_STAT1                       (0x00E4)
-#define S5P_CEC_RX_BUFF0                       (0x0100)
-#define S5P_CEC_RX_BUFF1                       (0x0104)
-#define S5P_CEC_RX_BUFF2                       (0x0108)
-#define S5P_CEC_RX_BUFF3                       (0x010C)
-#define S5P_CEC_RX_BUFF4                       (0x0110)
-#define S5P_CEC_RX_BUFF5                       (0x0114)
-#define S5P_CEC_RX_BUFF6                       (0x0118)
-#define S5P_CEC_RX_BUFF7                       (0x011C)
-#define S5P_CEC_RX_BUFF8                       (0x0120)
-#define S5P_CEC_RX_BUFF9                       (0x0124)
-#define S5P_CEC_RX_BUFF10                      (0x0128)
-#define S5P_CEC_RX_BUFF11                      (0x012C)
-#define S5P_CEC_RX_BUFF12                      (0x0130)
-#define S5P_CEC_RX_BUFF13                      (0x0134)
-#define S5P_CEC_RX_BUFF14                      (0x0138)
-#define S5P_CEC_RX_BUFF15                      (0x013C)
-
-#define S5P_CEC_RX_FILTER_CTRL                 (0x0180)
-#define S5P_CEC_RX_FILTER_TH                   (0x0184)
-
-/*
- * Bit definition part
- */
-#define S5P_CEC_IRQ_TX_DONE                    (1<<0)
-#define S5P_CEC_IRQ_TX_ERROR                   (1<<1)
-#define S5P_CEC_IRQ_RX_DONE                    (1<<4)
-#define S5P_CEC_IRQ_RX_ERROR                   (1<<5)
-
-#define S5P_CEC_TX_CTRL_START                  (1<<0)
-#define S5P_CEC_TX_CTRL_BCAST                  (1<<1)
-#define S5P_CEC_TX_CTRL_RETRY                  (0x04<<4)
-#define S5P_CEC_TX_CTRL_RESET                  (1<<7)
-
-#define S5P_CEC_RX_CTRL_ENABLE                 (1<<0)
-#define S5P_CEC_RX_CTRL_RESET                  (1<<7)
-
-#define S5P_CEC_LOGIC_ADDR_MASK                        (0xF)
-
-/* PMU Registers for PHY */
-#define EXYNOS_HDMI_PHY_CONTROL                        0x700
-
-#endif /* __EXYNOS_REGS__H     */
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c
deleted file mode 100644 (file)
index 3844f39..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/* drivers/media/platform/s5p-cec/s5p_cec.c
- *
- * Samsung S5P CEC driver
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This driver is based on the "cec interface driver for exynos soc" by
- * SangPil Moon.
- */
-
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/timer.h>
-#include <linux/version.h>
-#include <linux/workqueue.h>
-#include <media/cec.h>
-
-#include "exynos_hdmi_cec.h"
-#include "regs-cec.h"
-#include "s5p_cec.h"
-
-#define CEC_NAME       "s5p-cec"
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "debug level (0-2)");
-
-static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
-{
-       struct s5p_cec_dev *cec = adap->priv;
-       int ret;
-
-       if (enable) {
-               ret = pm_runtime_get_sync(cec->dev);
-
-               s5p_cec_reset(cec);
-
-               s5p_cec_set_divider(cec);
-               s5p_cec_threshold(cec);
-
-               s5p_cec_unmask_tx_interrupts(cec);
-               s5p_cec_unmask_rx_interrupts(cec);
-               s5p_cec_enable_rx(cec);
-       } else {
-               s5p_cec_mask_tx_interrupts(cec);
-               s5p_cec_mask_rx_interrupts(cec);
-               pm_runtime_disable(cec->dev);
-       }
-
-       return 0;
-}
-
-static int s5p_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
-{
-       struct s5p_cec_dev *cec = adap->priv;
-
-       s5p_cec_set_addr(cec, addr);
-       return 0;
-}
-
-static int s5p_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
-                                u32 signal_free_time, struct cec_msg *msg)
-{
-       struct s5p_cec_dev *cec = adap->priv;
-
-       /*
-        * Unclear if 0 retries are allowed by the hardware, so have 1 as
-        * the minimum.
-        */
-       s5p_cec_copy_packet(cec, msg->msg, msg->len, max(1, attempts - 1));
-       return 0;
-}
-
-static irqreturn_t s5p_cec_irq_handler(int irq, void *priv)
-{
-       struct s5p_cec_dev *cec = priv;
-       u32 status = 0;
-
-       status = s5p_cec_get_status(cec);
-
-       dev_dbg(cec->dev, "irq received\n");
-
-       if (status & CEC_STATUS_TX_DONE) {
-               if (status & CEC_STATUS_TX_ERROR) {
-                       dev_dbg(cec->dev, "CEC_STATUS_TX_ERROR set\n");
-                       cec->tx = STATE_ERROR;
-               } else {
-                       dev_dbg(cec->dev, "CEC_STATUS_TX_DONE\n");
-                       cec->tx = STATE_DONE;
-               }
-               s5p_clr_pending_tx(cec);
-       }
-
-       if (status & CEC_STATUS_RX_DONE) {
-               if (status & CEC_STATUS_RX_ERROR) {
-                       dev_dbg(cec->dev, "CEC_STATUS_RX_ERROR set\n");
-                       s5p_cec_rx_reset(cec);
-                       s5p_cec_enable_rx(cec);
-               } else {
-                       dev_dbg(cec->dev, "CEC_STATUS_RX_DONE set\n");
-                       if (cec->rx != STATE_IDLE)
-                               dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n");
-                       cec->rx = STATE_BUSY;
-                       cec->msg.len = status >> 24;
-                       cec->msg.rx_status = CEC_RX_STATUS_OK;
-                       s5p_cec_get_rx_buf(cec, cec->msg.len,
-                                       cec->msg.msg);
-                       cec->rx = STATE_DONE;
-                       s5p_cec_enable_rx(cec);
-               }
-               /* Clear interrupt pending bit */
-               s5p_clr_pending_rx(cec);
-       }
-       return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t s5p_cec_irq_handler_thread(int irq, void *priv)
-{
-       struct s5p_cec_dev *cec = priv;
-
-       dev_dbg(cec->dev, "irq processing thread\n");
-       switch (cec->tx) {
-       case STATE_DONE:
-               cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
-               cec->tx = STATE_IDLE;
-               break;
-       case STATE_ERROR:
-               cec_transmit_done(cec->adap,
-                       CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_ERROR,
-                       0, 0, 0, 1);
-               cec->tx = STATE_IDLE;
-               break;
-       case STATE_BUSY:
-               dev_err(cec->dev, "state set to busy, this should not occur here\n");
-               break;
-       default:
-               break;
-       }
-
-       switch (cec->rx) {
-       case STATE_DONE:
-               cec_received_msg(cec->adap, &cec->msg);
-               cec->rx = STATE_IDLE;
-               break;
-       default:
-               break;
-       }
-
-       return IRQ_HANDLED;
-}
-
-static const struct cec_adap_ops s5p_cec_adap_ops = {
-       .adap_enable = s5p_cec_adap_enable,
-       .adap_log_addr = s5p_cec_adap_log_addr,
-       .adap_transmit = s5p_cec_adap_transmit,
-};
-
-static int s5p_cec_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       struct s5p_cec_dev *cec;
-       int ret;
-
-       cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       cec->dev = dev;
-
-       cec->irq = platform_get_irq(pdev, 0);
-       if (cec->irq < 0)
-               return cec->irq;
-
-       ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler,
-               s5p_cec_irq_handler_thread, 0, pdev->name, cec);
-       if (ret)
-               return ret;
-
-       cec->clk = devm_clk_get(dev, "hdmicec");
-       if (IS_ERR(cec->clk))
-               return PTR_ERR(cec->clk);
-
-       cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
-                                                "samsung,syscon-phandle");
-       if (IS_ERR(cec->pmu))
-               return -EPROBE_DEFER;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       cec->reg = devm_ioremap_resource(dev, res);
-       if (IS_ERR(cec->reg))
-               return PTR_ERR(cec->reg);
-
-       cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec,
-               CEC_NAME,
-               CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
-               CEC_CAP_PASSTHROUGH | CEC_CAP_RC,
-               1, &pdev->dev);
-       ret = PTR_ERR_OR_ZERO(cec->adap);
-       if (ret)
-               return ret;
-       ret = cec_register_adapter(cec->adap);
-       if (ret) {
-               cec_delete_adapter(cec->adap);
-               return ret;
-       }
-
-       platform_set_drvdata(pdev, cec);
-       pm_runtime_enable(dev);
-
-       dev_dbg(dev, "successfuly probed\n");
-       return 0;
-}
-
-static int s5p_cec_remove(struct platform_device *pdev)
-{
-       struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
-
-       cec_unregister_adapter(cec->adap);
-       pm_runtime_disable(&pdev->dev);
-       return 0;
-}
-
-static int s5p_cec_runtime_suspend(struct device *dev)
-{
-       struct s5p_cec_dev *cec = dev_get_drvdata(dev);
-
-       clk_disable_unprepare(cec->clk);
-       return 0;
-}
-
-static int s5p_cec_runtime_resume(struct device *dev)
-{
-       struct s5p_cec_dev *cec = dev_get_drvdata(dev);
-       int ret;
-
-       ret = clk_prepare_enable(cec->clk);
-       if (ret < 0)
-               return ret;
-       return 0;
-}
-
-static int s5p_cec_suspend(struct device *dev)
-{
-       if (pm_runtime_suspended(dev))
-               return 0;
-       return s5p_cec_runtime_suspend(dev);
-}
-
-static int s5p_cec_resume(struct device *dev)
-{
-       if (pm_runtime_suspended(dev))
-               return 0;
-       return s5p_cec_runtime_resume(dev);
-}
-
-static const struct dev_pm_ops s5p_cec_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(s5p_cec_suspend, s5p_cec_resume)
-       SET_RUNTIME_PM_OPS(s5p_cec_runtime_suspend, s5p_cec_runtime_resume,
-                          NULL)
-};
-
-static const struct of_device_id s5p_cec_match[] = {
-       {
-               .compatible     = "samsung,s5p-cec",
-       },
-       {},
-};
-
-static struct platform_driver s5p_cec_pdrv = {
-       .probe  = s5p_cec_probe,
-       .remove = s5p_cec_remove,
-       .driver = {
-               .name           = CEC_NAME,
-               .of_match_table = s5p_cec_match,
-               .pm             = &s5p_cec_pm_ops,
-       },
-};
-
-module_platform_driver(s5p_cec_pdrv);
-
-MODULE_AUTHOR("Kamil Debski <kamil@wypas.org>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Samsung S5P CEC driver");
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.h b/drivers/media/platform/s5p-cec/s5p_cec.h
deleted file mode 100644 (file)
index 03732c1..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* drivers/media/platform/s5p-cec/s5p_cec.h
- *
- * Samsung S5P HDMI CEC driver
- *
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _S5P_CEC_H_
-#define _S5P_CEC_H_ __FILE__
-
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/mfd/syscon.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/timer.h>
-#include <linux/version.h>
-#include <linux/workqueue.h>
-#include <media/cec.h>
-
-#include "exynos_hdmi_cec.h"
-#include "regs-cec.h"
-#include "s5p_cec.h"
-
-#define CEC_NAME       "s5p-cec"
-
-#define CEC_STATUS_TX_RUNNING          (1 << 0)
-#define CEC_STATUS_TX_TRANSFERRING     (1 << 1)
-#define CEC_STATUS_TX_DONE             (1 << 2)
-#define CEC_STATUS_TX_ERROR            (1 << 3)
-#define CEC_STATUS_TX_BYTES            (0xFF << 8)
-#define CEC_STATUS_RX_RUNNING          (1 << 16)
-#define CEC_STATUS_RX_RECEIVING                (1 << 17)
-#define CEC_STATUS_RX_DONE             (1 << 18)
-#define CEC_STATUS_RX_ERROR            (1 << 19)
-#define CEC_STATUS_RX_BCAST            (1 << 20)
-#define CEC_STATUS_RX_BYTES            (0xFF << 24)
-
-#define CEC_WORKER_TX_DONE             (1 << 0)
-#define CEC_WORKER_RX_MSG              (1 << 1)
-
-/* CEC Rx buffer size */
-#define CEC_RX_BUFF_SIZE               16
-/* CEC Tx buffer size */
-#define CEC_TX_BUFF_SIZE               16
-
-enum cec_state {
-       STATE_IDLE,
-       STATE_BUSY,
-       STATE_DONE,
-       STATE_ERROR
-};
-
-struct s5p_cec_dev {
-       struct cec_adapter      *adap;
-       struct clk              *clk;
-       struct device           *dev;
-       struct mutex            lock;
-       struct regmap           *pmu;
-       int                     irq;
-       void __iomem            *reg;
-
-       enum cec_state          rx;
-       enum cec_state          tx;
-       struct cec_msg          msg;
-};
-
-#endif /* _S5P_CEC_H_ */
index 7ce679eb87e1161f0523ec0ac047a3a7a37bc37e..567078986c94e2b2cb2ca0307465ee6b7dc8cb75 100644 (file)
@@ -31,6 +31,8 @@ source "drivers/staging/media/omap4iss/Kconfig"
 
 source "drivers/staging/media/tw686x-kh/Kconfig"
 
+source "drivers/staging/media/s5p-cec/Kconfig"
+
 # Keep LIRC at the end, as it has sub-menus
 source "drivers/staging/media/lirc/Kconfig"
 
index 2d213dd54bc37fcd43312f1d0425df856d8fe7ad..989c844f49961adbfb1e4796caa6b5ab16b44066 100644 (file)
@@ -1,5 +1,6 @@
 obj-$(CONFIG_I2C_BCM2048)      += bcm2048/
 obj-$(CONFIG_MEDIA_CEC)                += cec/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
diff --git a/drivers/staging/media/s5p-cec/Kconfig b/drivers/staging/media/s5p-cec/Kconfig
new file mode 100644 (file)
index 0000000..0315fd7
--- /dev/null
@@ -0,0 +1,9 @@
+config VIDEO_SAMSUNG_S5P_CEC
+       tristate "Samsung S5P CEC driver"
+       depends on VIDEO_DEV && MEDIA_CEC && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
+       ---help---
+         This is a driver for Samsung S5P HDMI CEC interface. It uses the
+         generic CEC framework interface.
+         CEC bus is present in the HDMI connector and enables communication
+         between compatible devices.
+
diff --git a/drivers/staging/media/s5p-cec/Makefile b/drivers/staging/media/s5p-cec/Makefile
new file mode 100644 (file)
index 0000000..0e2cf45
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC)    += s5p-cec.o
+s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o
diff --git a/drivers/staging/media/s5p-cec/TODO b/drivers/staging/media/s5p-cec/TODO
new file mode 100644 (file)
index 0000000..7162f9a
--- /dev/null
@@ -0,0 +1,3 @@
+There's nothing wrong on this driver, except that it depends on
+the media staging core, that it is currently at staging. So,
+this should be kept here while the core is not promoted.
diff --git a/drivers/staging/media/s5p-cec/exynos_hdmi_cec.h b/drivers/staging/media/s5p-cec/exynos_hdmi_cec.h
new file mode 100644 (file)
index 0000000..3e4fc7b
--- /dev/null
@@ -0,0 +1,38 @@
+/* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
+ *
+ * Copyright (c) 2010, 2014 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * Header file for interface of Samsung Exynos hdmi cec hardware
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _EXYNOS_HDMI_CEC_H_
+#define _EXYNOS_HDMI_CEC_H_ __FILE__
+
+#include <linux/regmap.h>
+#include <linux/miscdevice.h>
+#include "s5p_cec.h"
+
+void s5p_cec_set_divider(struct s5p_cec_dev *cec);
+void s5p_cec_enable_rx(struct s5p_cec_dev *cec);
+void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec);
+void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec);
+void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec);
+void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec);
+void s5p_cec_reset(struct s5p_cec_dev *cec);
+void s5p_cec_tx_reset(struct s5p_cec_dev *cec);
+void s5p_cec_rx_reset(struct s5p_cec_dev *cec);
+void s5p_cec_threshold(struct s5p_cec_dev *cec);
+void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
+                        size_t count, u8 retries);
+void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr);
+u32 s5p_cec_get_status(struct s5p_cec_dev *cec);
+void s5p_clr_pending_tx(struct s5p_cec_dev *cec);
+void s5p_clr_pending_rx(struct s5p_cec_dev *cec);
+void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer);
+
+#endif /* _EXYNOS_HDMI_CEC_H_ */
diff --git a/drivers/staging/media/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/staging/media/s5p-cec/exynos_hdmi_cecctrl.c
new file mode 100644 (file)
index 0000000..ce95e0f
--- /dev/null
@@ -0,0 +1,209 @@
+/* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
+ *
+ * Copyright (c) 2009, 2014 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ * cec ftn file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/device.h>
+
+#include "exynos_hdmi_cec.h"
+#include "regs-cec.h"
+
+#define S5P_HDMI_FIN                   24000000
+#define CEC_DIV_RATIO                  320000
+
+#define CEC_MESSAGE_BROADCAST_MASK     0x0F
+#define CEC_MESSAGE_BROADCAST          0x0F
+#define CEC_FILTER_THRESHOLD           0x15
+
+void s5p_cec_set_divider(struct s5p_cec_dev *cec)
+{
+       u32 div_ratio, div_val;
+       unsigned int reg;
+
+       div_ratio  = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
+
+       if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, &reg)) {
+               dev_err(cec->dev, "failed to read phy control\n");
+               return;
+       }
+
+       reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
+
+       if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) {
+               dev_err(cec->dev, "failed to write phy control\n");
+               return;
+       }
+
+       div_val = CEC_DIV_RATIO * 0.00005 - 1;
+
+       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_3);
+       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_2);
+       writeb(0x0, cec->reg + S5P_CEC_DIVISOR_1);
+       writeb(div_val, cec->reg + S5P_CEC_DIVISOR_0);
+}
+
+void s5p_cec_enable_rx(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       reg = readb(cec->reg + S5P_CEC_RX_CTRL);
+       reg |= S5P_CEC_RX_CTRL_ENABLE;
+       writeb(reg, cec->reg + S5P_CEC_RX_CTRL);
+}
+
+void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+       reg |= S5P_CEC_IRQ_RX_DONE;
+       reg |= S5P_CEC_IRQ_RX_ERROR;
+       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+       reg &= ~S5P_CEC_IRQ_RX_DONE;
+       reg &= ~S5P_CEC_IRQ_RX_ERROR;
+       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+       reg |= S5P_CEC_IRQ_TX_DONE;
+       reg |= S5P_CEC_IRQ_TX_ERROR;
+       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+
+}
+
+void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+       reg &= ~S5P_CEC_IRQ_TX_DONE;
+       reg &= ~S5P_CEC_IRQ_TX_ERROR;
+       writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_reset(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
+       writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
+
+       reg = readb(cec->reg + 0xc4);
+       reg &= ~0x1;
+       writeb(reg, cec->reg + 0xc4);
+}
+
+void s5p_cec_tx_reset(struct s5p_cec_dev *cec)
+{
+       writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
+}
+
+void s5p_cec_rx_reset(struct s5p_cec_dev *cec)
+{
+       u8 reg;
+
+       writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
+
+       reg = readb(cec->reg + 0xc4);
+       reg &= ~0x1;
+       writeb(reg, cec->reg + 0xc4);
+}
+
+void s5p_cec_threshold(struct s5p_cec_dev *cec)
+{
+       writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH);
+       writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL);
+}
+
+void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
+                        size_t count, u8 retries)
+{
+       int i = 0;
+       u8 reg;
+
+       while (i < count) {
+               writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4)));
+               i++;
+       }
+
+       writeb(count, cec->reg + S5P_CEC_TX_BYTES);
+       reg = readb(cec->reg + S5P_CEC_TX_CTRL);
+       reg |= S5P_CEC_TX_CTRL_START;
+       reg &= ~0x70;
+       reg |= retries << 4;
+
+       if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) {
+               dev_dbg(cec->dev, "Broadcast");
+               reg |= S5P_CEC_TX_CTRL_BCAST;
+       } else {
+               dev_dbg(cec->dev, "No Broadcast");
+               reg &= ~S5P_CEC_TX_CTRL_BCAST;
+       }
+
+       writeb(reg, cec->reg + S5P_CEC_TX_CTRL);
+       dev_dbg(cec->dev, "cec-tx: cec count (%zu): %*ph", count,
+               (int)count, data);
+}
+
+void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr)
+{
+       writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR);
+}
+
+u32 s5p_cec_get_status(struct s5p_cec_dev *cec)
+{
+       u32 status = 0;
+
+       status = readb(cec->reg + S5P_CEC_STATUS_0);
+       status |= readb(cec->reg + S5P_CEC_STATUS_1) << 8;
+       status |= readb(cec->reg + S5P_CEC_STATUS_2) << 16;
+       status |= readb(cec->reg + S5P_CEC_STATUS_3) << 24;
+
+       dev_dbg(cec->dev, "status = 0x%x!\n", status);
+
+       return status;
+}
+
+void s5p_clr_pending_tx(struct s5p_cec_dev *cec)
+{
+       writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
+                                       cec->reg + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_clr_pending_rx(struct s5p_cec_dev *cec)
+{
+       writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
+                                       cec->reg + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)
+{
+       u32 i = 0;
+       char debug[40];
+
+       while (i < size) {
+               buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4));
+               sprintf(debug + i * 2, "%02x ", buffer[i]);
+               i++;
+       }
+       dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug);
+}
diff --git a/drivers/staging/media/s5p-cec/regs-cec.h b/drivers/staging/media/s5p-cec/regs-cec.h
new file mode 100644 (file)
index 0000000..b2e7e12
--- /dev/null
@@ -0,0 +1,96 @@
+/* drivers/media/platform/s5p-cec/regs-cec.h
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *             http://www.samsung.com/
+ *
+ *  register header file for Samsung TVOUT driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __EXYNOS_REGS__H
+#define __EXYNOS_REGS__H
+
+/*
+ * Register part
+ */
+#define S5P_CEC_STATUS_0                       (0x0000)
+#define S5P_CEC_STATUS_1                       (0x0004)
+#define S5P_CEC_STATUS_2                       (0x0008)
+#define S5P_CEC_STATUS_3                       (0x000C)
+#define S5P_CEC_IRQ_MASK                       (0x0010)
+#define S5P_CEC_IRQ_CLEAR                      (0x0014)
+#define S5P_CEC_LOGIC_ADDR                     (0x0020)
+#define S5P_CEC_DIVISOR_0                      (0x0030)
+#define S5P_CEC_DIVISOR_1                      (0x0034)
+#define S5P_CEC_DIVISOR_2                      (0x0038)
+#define S5P_CEC_DIVISOR_3                      (0x003C)
+
+#define S5P_CEC_TX_CTRL                                (0x0040)
+#define S5P_CEC_TX_BYTES                       (0x0044)
+#define S5P_CEC_TX_STAT0                       (0x0060)
+#define S5P_CEC_TX_STAT1                       (0x0064)
+#define S5P_CEC_TX_BUFF0                       (0x0080)
+#define S5P_CEC_TX_BUFF1                       (0x0084)
+#define S5P_CEC_TX_BUFF2                       (0x0088)
+#define S5P_CEC_TX_BUFF3                       (0x008C)
+#define S5P_CEC_TX_BUFF4                       (0x0090)
+#define S5P_CEC_TX_BUFF5                       (0x0094)
+#define S5P_CEC_TX_BUFF6                       (0x0098)
+#define S5P_CEC_TX_BUFF7                       (0x009C)
+#define S5P_CEC_TX_BUFF8                       (0x00A0)
+#define S5P_CEC_TX_BUFF9                       (0x00A4)
+#define S5P_CEC_TX_BUFF10                      (0x00A8)
+#define S5P_CEC_TX_BUFF11                      (0x00AC)
+#define S5P_CEC_TX_BUFF12                      (0x00B0)
+#define S5P_CEC_TX_BUFF13                      (0x00B4)
+#define S5P_CEC_TX_BUFF14                      (0x00B8)
+#define S5P_CEC_TX_BUFF15                      (0x00BC)
+
+#define S5P_CEC_RX_CTRL                                (0x00C0)
+#define S5P_CEC_RX_STAT0                       (0x00E0)
+#define S5P_CEC_RX_STAT1                       (0x00E4)
+#define S5P_CEC_RX_BUFF0                       (0x0100)
+#define S5P_CEC_RX_BUFF1                       (0x0104)
+#define S5P_CEC_RX_BUFF2                       (0x0108)
+#define S5P_CEC_RX_BUFF3                       (0x010C)
+#define S5P_CEC_RX_BUFF4                       (0x0110)
+#define S5P_CEC_RX_BUFF5                       (0x0114)
+#define S5P_CEC_RX_BUFF6                       (0x0118)
+#define S5P_CEC_RX_BUFF7                       (0x011C)
+#define S5P_CEC_RX_BUFF8                       (0x0120)
+#define S5P_CEC_RX_BUFF9                       (0x0124)
+#define S5P_CEC_RX_BUFF10                      (0x0128)
+#define S5P_CEC_RX_BUFF11                      (0x012C)
+#define S5P_CEC_RX_BUFF12                      (0x0130)
+#define S5P_CEC_RX_BUFF13                      (0x0134)
+#define S5P_CEC_RX_BUFF14                      (0x0138)
+#define S5P_CEC_RX_BUFF15                      (0x013C)
+
+#define S5P_CEC_RX_FILTER_CTRL                 (0x0180)
+#define S5P_CEC_RX_FILTER_TH                   (0x0184)
+
+/*
+ * Bit definition part
+ */
+#define S5P_CEC_IRQ_TX_DONE                    (1<<0)
+#define S5P_CEC_IRQ_TX_ERROR                   (1<<1)
+#define S5P_CEC_IRQ_RX_DONE                    (1<<4)
+#define S5P_CEC_IRQ_RX_ERROR                   (1<<5)
+
+#define S5P_CEC_TX_CTRL_START                  (1<<0)
+#define S5P_CEC_TX_CTRL_BCAST                  (1<<1)
+#define S5P_CEC_TX_CTRL_RETRY                  (0x04<<4)
+#define S5P_CEC_TX_CTRL_RESET                  (1<<7)
+
+#define S5P_CEC_RX_CTRL_ENABLE                 (1<<0)
+#define S5P_CEC_RX_CTRL_RESET                  (1<<7)
+
+#define S5P_CEC_LOGIC_ADDR_MASK                        (0xF)
+
+/* PMU Registers for PHY */
+#define EXYNOS_HDMI_PHY_CONTROL                        0x700
+
+#endif /* __EXYNOS_REGS__H     */
diff --git a/drivers/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c
new file mode 100644 (file)
index 0000000..3844f39
--- /dev/null
@@ -0,0 +1,295 @@
+/* drivers/media/platform/s5p-cec/s5p_cec.c
+ *
+ * Samsung S5P CEC driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This driver is based on the "cec interface driver for exynos soc" by
+ * SangPil Moon.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <media/cec.h>
+
+#include "exynos_hdmi_cec.h"
+#include "regs-cec.h"
+#include "s5p_cec.h"
+
+#define CEC_NAME       "s5p-cec"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+static int s5p_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+       struct s5p_cec_dev *cec = adap->priv;
+       int ret;
+
+       if (enable) {
+               ret = pm_runtime_get_sync(cec->dev);
+
+               s5p_cec_reset(cec);
+
+               s5p_cec_set_divider(cec);
+               s5p_cec_threshold(cec);
+
+               s5p_cec_unmask_tx_interrupts(cec);
+               s5p_cec_unmask_rx_interrupts(cec);
+               s5p_cec_enable_rx(cec);
+       } else {
+               s5p_cec_mask_tx_interrupts(cec);
+               s5p_cec_mask_rx_interrupts(cec);
+               pm_runtime_disable(cec->dev);
+       }
+
+       return 0;
+}
+
+static int s5p_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
+{
+       struct s5p_cec_dev *cec = adap->priv;
+
+       s5p_cec_set_addr(cec, addr);
+       return 0;
+}
+
+static int s5p_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
+                                u32 signal_free_time, struct cec_msg *msg)
+{
+       struct s5p_cec_dev *cec = adap->priv;
+
+       /*
+        * Unclear if 0 retries are allowed by the hardware, so have 1 as
+        * the minimum.
+        */
+       s5p_cec_copy_packet(cec, msg->msg, msg->len, max(1, attempts - 1));
+       return 0;
+}
+
+static irqreturn_t s5p_cec_irq_handler(int irq, void *priv)
+{
+       struct s5p_cec_dev *cec = priv;
+       u32 status = 0;
+
+       status = s5p_cec_get_status(cec);
+
+       dev_dbg(cec->dev, "irq received\n");
+
+       if (status & CEC_STATUS_TX_DONE) {
+               if (status & CEC_STATUS_TX_ERROR) {
+                       dev_dbg(cec->dev, "CEC_STATUS_TX_ERROR set\n");
+                       cec->tx = STATE_ERROR;
+               } else {
+                       dev_dbg(cec->dev, "CEC_STATUS_TX_DONE\n");
+                       cec->tx = STATE_DONE;
+               }
+               s5p_clr_pending_tx(cec);
+       }
+
+       if (status & CEC_STATUS_RX_DONE) {
+               if (status & CEC_STATUS_RX_ERROR) {
+                       dev_dbg(cec->dev, "CEC_STATUS_RX_ERROR set\n");
+                       s5p_cec_rx_reset(cec);
+                       s5p_cec_enable_rx(cec);
+               } else {
+                       dev_dbg(cec->dev, "CEC_STATUS_RX_DONE set\n");
+                       if (cec->rx != STATE_IDLE)
+                               dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n");
+                       cec->rx = STATE_BUSY;
+                       cec->msg.len = status >> 24;
+                       cec->msg.rx_status = CEC_RX_STATUS_OK;
+                       s5p_cec_get_rx_buf(cec, cec->msg.len,
+                                       cec->msg.msg);
+                       cec->rx = STATE_DONE;
+                       s5p_cec_enable_rx(cec);
+               }
+               /* Clear interrupt pending bit */
+               s5p_clr_pending_rx(cec);
+       }
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t s5p_cec_irq_handler_thread(int irq, void *priv)
+{
+       struct s5p_cec_dev *cec = priv;
+
+       dev_dbg(cec->dev, "irq processing thread\n");
+       switch (cec->tx) {
+       case STATE_DONE:
+               cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
+               cec->tx = STATE_IDLE;
+               break;
+       case STATE_ERROR:
+               cec_transmit_done(cec->adap,
+                       CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_ERROR,
+                       0, 0, 0, 1);
+               cec->tx = STATE_IDLE;
+               break;
+       case STATE_BUSY:
+               dev_err(cec->dev, "state set to busy, this should not occur here\n");
+               break;
+       default:
+               break;
+       }
+
+       switch (cec->rx) {
+       case STATE_DONE:
+               cec_received_msg(cec->adap, &cec->msg);
+               cec->rx = STATE_IDLE;
+               break;
+       default:
+               break;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct cec_adap_ops s5p_cec_adap_ops = {
+       .adap_enable = s5p_cec_adap_enable,
+       .adap_log_addr = s5p_cec_adap_log_addr,
+       .adap_transmit = s5p_cec_adap_transmit,
+};
+
+static int s5p_cec_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct s5p_cec_dev *cec;
+       int ret;
+
+       cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       cec->dev = dev;
+
+       cec->irq = platform_get_irq(pdev, 0);
+       if (cec->irq < 0)
+               return cec->irq;
+
+       ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler,
+               s5p_cec_irq_handler_thread, 0, pdev->name, cec);
+       if (ret)
+               return ret;
+
+       cec->clk = devm_clk_get(dev, "hdmicec");
+       if (IS_ERR(cec->clk))
+               return PTR_ERR(cec->clk);
+
+       cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                                "samsung,syscon-phandle");
+       if (IS_ERR(cec->pmu))
+               return -EPROBE_DEFER;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       cec->reg = devm_ioremap_resource(dev, res);
+       if (IS_ERR(cec->reg))
+               return PTR_ERR(cec->reg);
+
+       cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec,
+               CEC_NAME,
+               CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
+               CEC_CAP_PASSTHROUGH | CEC_CAP_RC,
+               1, &pdev->dev);
+       ret = PTR_ERR_OR_ZERO(cec->adap);
+       if (ret)
+               return ret;
+       ret = cec_register_adapter(cec->adap);
+       if (ret) {
+               cec_delete_adapter(cec->adap);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, cec);
+       pm_runtime_enable(dev);
+
+       dev_dbg(dev, "successfuly probed\n");
+       return 0;
+}
+
+static int s5p_cec_remove(struct platform_device *pdev)
+{
+       struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
+
+       cec_unregister_adapter(cec->adap);
+       pm_runtime_disable(&pdev->dev);
+       return 0;
+}
+
+static int s5p_cec_runtime_suspend(struct device *dev)
+{
+       struct s5p_cec_dev *cec = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(cec->clk);
+       return 0;
+}
+
+static int s5p_cec_runtime_resume(struct device *dev)
+{
+       struct s5p_cec_dev *cec = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(cec->clk);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int s5p_cec_suspend(struct device *dev)
+{
+       if (pm_runtime_suspended(dev))
+               return 0;
+       return s5p_cec_runtime_suspend(dev);
+}
+
+static int s5p_cec_resume(struct device *dev)
+{
+       if (pm_runtime_suspended(dev))
+               return 0;
+       return s5p_cec_runtime_resume(dev);
+}
+
+static const struct dev_pm_ops s5p_cec_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(s5p_cec_suspend, s5p_cec_resume)
+       SET_RUNTIME_PM_OPS(s5p_cec_runtime_suspend, s5p_cec_runtime_resume,
+                          NULL)
+};
+
+static const struct of_device_id s5p_cec_match[] = {
+       {
+               .compatible     = "samsung,s5p-cec",
+       },
+       {},
+};
+
+static struct platform_driver s5p_cec_pdrv = {
+       .probe  = s5p_cec_probe,
+       .remove = s5p_cec_remove,
+       .driver = {
+               .name           = CEC_NAME,
+               .of_match_table = s5p_cec_match,
+               .pm             = &s5p_cec_pm_ops,
+       },
+};
+
+module_platform_driver(s5p_cec_pdrv);
+
+MODULE_AUTHOR("Kamil Debski <kamil@wypas.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Samsung S5P CEC driver");
diff --git a/drivers/staging/media/s5p-cec/s5p_cec.h b/drivers/staging/media/s5p-cec/s5p_cec.h
new file mode 100644 (file)
index 0000000..03732c1
--- /dev/null
@@ -0,0 +1,76 @@
+/* drivers/media/platform/s5p-cec/s5p_cec.h
+ *
+ * Samsung S5P HDMI CEC driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _S5P_CEC_H_
+#define _S5P_CEC_H_ __FILE__
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+#include <linux/workqueue.h>
+#include <media/cec.h>
+
+#include "exynos_hdmi_cec.h"
+#include "regs-cec.h"
+#include "s5p_cec.h"
+
+#define CEC_NAME       "s5p-cec"
+
+#define CEC_STATUS_TX_RUNNING          (1 << 0)
+#define CEC_STATUS_TX_TRANSFERRING     (1 << 1)
+#define CEC_STATUS_TX_DONE             (1 << 2)
+#define CEC_STATUS_TX_ERROR            (1 << 3)
+#define CEC_STATUS_TX_BYTES            (0xFF << 8)
+#define CEC_STATUS_RX_RUNNING          (1 << 16)
+#define CEC_STATUS_RX_RECEIVING                (1 << 17)
+#define CEC_STATUS_RX_DONE             (1 << 18)
+#define CEC_STATUS_RX_ERROR            (1 << 19)
+#define CEC_STATUS_RX_BCAST            (1 << 20)
+#define CEC_STATUS_RX_BYTES            (0xFF << 24)
+
+#define CEC_WORKER_TX_DONE             (1 << 0)
+#define CEC_WORKER_RX_MSG              (1 << 1)
+
+/* CEC Rx buffer size */
+#define CEC_RX_BUFF_SIZE               16
+/* CEC Tx buffer size */
+#define CEC_TX_BUFF_SIZE               16
+
+enum cec_state {
+       STATE_IDLE,
+       STATE_BUSY,
+       STATE_DONE,
+       STATE_ERROR
+};
+
+struct s5p_cec_dev {
+       struct cec_adapter      *adap;
+       struct clk              *clk;
+       struct device           *dev;
+       struct mutex            lock;
+       struct regmap           *pmu;
+       int                     irq;
+       void __iomem            *reg;
+
+       enum cec_state          rx;
+       enum cec_state          tx;
+       struct cec_msg          msg;
+};
+
+#endif /* _S5P_CEC_H_ */
This page took 0.047512 seconds and 5 git commands to generate.