From patchwork Mon Apr 10 16:14:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 9673271 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 83D9C60244 for ; Mon, 10 Apr 2017 16:35:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 86FAF27165 for ; Mon, 10 Apr 2017 16:35:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7AFC62839B; Mon, 10 Apr 2017 16:35:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 02DB527165 for ; Mon, 10 Apr 2017 16:35:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752002AbdDJQfe (ORCPT ); Mon, 10 Apr 2017 12:35:34 -0400 Received: from www.linuxtv.org ([130.149.80.248]:42832 "EHLO www.linuxtv.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751064AbdDJQfd (ORCPT ); Mon, 10 Apr 2017 12:35:33 -0400 Received: from mchehab by www.linuxtv.org with local (Exim 4.84_2) (envelope-from ) id 1cxc0o-0003Qc-Ll; Mon, 10 Apr 2017 16:17:54 +0000 From: Mauro Carvalho Chehab Date: Mon, 10 Apr 2017 16:14:03 +0000 Subject: [git:media_tree/master] [media] s5p-cec: add cec-notifier support, move out of staging To: linuxtv-commits@linuxtv.org Cc: Hans Verkuil , Krzysztof Kozlowski , Marek Szyprowski , linux-samsung-soc@vger.kernel.org Mail-followup-to: linux-media@vger.kernel.org Forward-to: linux-media@vger.kernel.org Reply-to: linux-media@vger.kernel.org Message-Id: Sender: linux-samsung-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-samsung-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This is an automatic generated email to let you know that the following patch were queued: Subject: [media] s5p-cec: add cec-notifier support, move out of staging Author: Hans Verkuil Date: Tue Dec 13 12:37:16 2016 -0200 By using the CEC notifier framework there is no longer any reason to manually set the physical address. This was the one blocking issue that prevented this driver from going out of staging, so do this move as well. Update the bindings documenting the new hdmi phandle and update exynos4.dtsi accordingly. Tested with my Odroid U3. Signed-off-by: Hans Verkuil Tested-by: Marek Szyprowski Acked-by: Krzysztof Kozlowski CC: linux-samsung-soc@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab drivers/media/platform/Kconfig | 10 + drivers/media/platform/Makefile | 1 + drivers/media/platform/s5p-cec/Makefile | 2 + drivers/media/platform/s5p-cec/exynos_hdmi_cec.h | 37 +++ .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c | 208 ++++++++++++++ drivers/media/platform/s5p-cec/regs-cec.h | 96 +++++++ drivers/media/platform/s5p-cec/s5p_cec.c | 305 +++++++++++++++++++++ drivers/media/platform/s5p-cec/s5p_cec.h | 79 ++++++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/s5p-cec/Kconfig | 9 - drivers/staging/media/s5p-cec/Makefile | 2 - drivers/staging/media/s5p-cec/TODO | 7 - drivers/staging/media/s5p-cec/exynos_hdmi_cec.h | 37 --- .../staging/media/s5p-cec/exynos_hdmi_cecctrl.c | 208 -------------- drivers/staging/media/s5p-cec/regs-cec.h | 96 ------- drivers/staging/media/s5p-cec/s5p_cec.c | 280 ------------------- drivers/staging/media/s5p-cec/s5p_cec.h | 76 ----- 18 files changed, 738 insertions(+), 718 deletions(-) --- -- To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index e252b2774291..7321f6123659 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -466,6 +466,16 @@ menuconfig V4L_CEC_DRIVERS if V4L_CEC_DRIVERS +config VIDEO_SAMSUNG_S5P_CEC + tristate "Samsung S5P CEC driver" + depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) + select MEDIA_CEC_NOTIFIER + ---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. + config VIDEO_STI_HDMI_CEC tristate "STMicroelectronics STiH4xx HDMI CEC driver" depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (ARCH_STI || COMPILE_TEST) diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 057422cd803e..ce59af58c925 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/ obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ diff --git a/drivers/media/platform/s5p-cec/Makefile b/drivers/media/platform/s5p-cec/Makefile new file mode 100644 index 000000000000..0e2cf457825a --- /dev/null +++ b/drivers/media/platform/s5p-cec/Makefile @@ -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/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h new file mode 100644 index 000000000000..7d9453505dce --- /dev/null +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h @@ -0,0 +1,37 @@ +/* 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 +#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 new file mode 100644 index 000000000000..1edf667d562a --- /dev/null +++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c @@ -0,0 +1,208 @@ +/* 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 +#include + +#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, ®)) { + 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 new file mode 100644 index 000000000000..b2e7e129920e --- /dev/null +++ b/drivers/media/platform/s5p-cec/regs-cec.h @@ -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/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c new file mode 100644 index 000000000000..4688f0879f55 --- /dev/null +++ b/drivers/media/platform/s5p-cec/s5p_cec.c @@ -0,0 +1,305 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 = cec_get_drvdata(adap); + + if (enable) { + 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 = cec_get_drvdata(adap); + + 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 = cec_get_drvdata(adap); + + /* + * 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 device_node *np; + struct platform_device *hdmi_dev; + struct resource *res; + struct s5p_cec_dev *cec; + int ret; + + np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + + if (!np) { + dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); + return -ENODEV; + } + hdmi_dev = of_find_device_by_node(np); + if (hdmi_dev == NULL) + return -EPROBE_DEFER; + + cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + 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->notifier = cec_notifier_get(&hdmi_dev->dev); + if (cec->notifier == NULL) + return -ENOMEM; + + cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, + CEC_NAME, + CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, 1); + ret = PTR_ERR_OR_ZERO(cec->adap); + if (ret) + return ret; + + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) + goto err_delete_adapter; + + cec_register_cec_notifier(cec->adap, cec->notifier); + + platform_set_drvdata(pdev, cec); + pm_runtime_enable(dev); + + dev_dbg(dev, "successfuly probed\n"); + return 0; + +err_delete_adapter: + cec_delete_adapter(cec->adap); + return ret; +} + +static int s5p_cec_remove(struct platform_device *pdev) +{ + struct s5p_cec_dev *cec = platform_get_drvdata(pdev); + + cec_unregister_adapter(cec->adap); + cec_notifier_put(cec->notifier); + pm_runtime_disable(&pdev->dev); + return 0; +} + +static int __maybe_unused 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 __maybe_unused 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 const struct dev_pm_ops s5p_cec_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_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", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, s5p_cec_match); + +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 "); +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 new file mode 100644 index 000000000000..7015845c1caa --- /dev/null +++ b/drivers/media/platform/s5p-cec/s5p_cec.h @@ -0,0 +1,79 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 cec_notifier; + +struct s5p_cec_dev { + struct cec_adapter *adap; + struct clk *clk; + struct device *dev; + struct mutex lock; + struct regmap *pmu; + struct cec_notifier *notifier; + int irq; + void __iomem *reg; + + enum cec_state rx; + enum cec_state tx; + struct cec_msg msg; +}; + +#endif /* _S5P_CEC_H_ */ diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 28088de6ddd0..8ed8202da57a 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -29,8 +29,6 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/platform/bcm2835/Kconfig" -source "drivers/staging/media/s5p-cec/Kconfig" - # Keep LIRC at the end, as it has sub-menus source "drivers/staging/media/lirc/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 75e47dcdddd6..3a6adeabede1 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_VIDEO_BCM2835) += platform/bcm2835/ diff --git a/drivers/staging/media/s5p-cec/Kconfig b/drivers/staging/media/s5p-cec/Kconfig deleted file mode 100644 index 7a3489df3e70..000000000000 --- a/drivers/staging/media/s5p-cec/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_SAMSUNG_S5P_CEC - tristate "Samsung S5P CEC driver" - depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (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 deleted file mode 100644 index 0e2cf457825a..000000000000 --- a/drivers/staging/media/s5p-cec/Makefile +++ /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/staging/media/s5p-cec/TODO b/drivers/staging/media/s5p-cec/TODO deleted file mode 100644 index 64f21bab38f5..000000000000 --- a/drivers/staging/media/s5p-cec/TODO +++ /dev/null @@ -1,7 +0,0 @@ -This driver requires that userspace sets the physical address. -However, this should be passed on from the corresponding -Samsung HDMI driver. - -We have to wait until the HDMI notifier framework has been merged -in order to handle this gracefully, until that time this driver -has to remain in staging. diff --git a/drivers/staging/media/s5p-cec/exynos_hdmi_cec.h b/drivers/staging/media/s5p-cec/exynos_hdmi_cec.h deleted file mode 100644 index 7d9453505dce..000000000000 --- a/drivers/staging/media/s5p-cec/exynos_hdmi_cec.h +++ /dev/null @@ -1,37 +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 -#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 deleted file mode 100644 index 1edf667d562a..000000000000 --- a/drivers/staging/media/s5p-cec/exynos_hdmi_cecctrl.c +++ /dev/null @@ -1,208 +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 -#include - -#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, ®)) { - 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 deleted file mode 100644 index b2e7e129920e..000000000000 --- a/drivers/staging/media/s5p-cec/regs-cec.h +++ /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/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c deleted file mode 100644 index a30b80a123dd..000000000000 --- a/drivers/staging/media/s5p-cec/s5p_cec.c +++ /dev/null @@ -1,280 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 = cec_get_drvdata(adap); - - if (enable) { - 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 = cec_get_drvdata(adap); - - 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 = cec_get_drvdata(adap); - - /* - * 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 (!cec) - 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); - ret = PTR_ERR_OR_ZERO(cec->adap); - if (ret) - return ret; - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; - } - - 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 __maybe_unused 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 __maybe_unused 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 const struct dev_pm_ops s5p_cec_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_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", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, s5p_cec_match); - -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 "); -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 deleted file mode 100644 index 03732c13d19f..000000000000 --- a/drivers/staging/media/s5p-cec/s5p_cec.h +++ /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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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_ */