diff options
author | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2020-04-15 11:03:40 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+huawei@kernel.org> | 2020-04-15 12:06:40 +0200 |
commit | 4be5e8648b0c287aefc6ac3f3a0b12c696054f43 (patch) | |
tree | 7b71f97912a07048092cb7827e9bb8f17f874482 /drivers/media/platform | |
parent | 46d2a3b964ddbe63605dab502c847180b1efbfb2 (diff) |
media: move CEC platform drivers to a separate directory
As CEC support doesn't depend on MEDIA_SUPPORT, let's
place the platform drivers outside the media menu.
As a side effect, instead of depends on PCI, seco driver
can select it (and DMI).
Acked-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Diffstat (limited to 'drivers/media/platform')
25 files changed, 0 insertions, 5370 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 3df0d789d452..b1ac9c6c9cdb 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -552,131 +552,6 @@ if DVB_PLATFORM_DRIVERS source "drivers/media/platform/sti/c8sectpfe/Kconfig" endif #DVB_PLATFORM_DRIVERS -menuconfig CEC_PLATFORM_DRIVERS - bool "CEC platform devices" - depends on MEDIA_CEC_SUPPORT - -if CEC_PLATFORM_DRIVERS - -config VIDEO_CROS_EC_CEC - tristate "ChromeOS EC CEC driver" - depends on CROS_EC - select CEC_CORE - select CEC_NOTIFIER - select CROS_EC_PROTO - help - If you say yes here you will get support for the - ChromeOS Embedded Controller's CEC. - The CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config VIDEO_MESON_AO_CEC - tristate "Amlogic Meson AO CEC driver" - depends on ARCH_MESON || COMPILE_TEST - select CEC_CORE - select CEC_NOTIFIER - help - This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the - generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - -config VIDEO_MESON_G12A_AO_CEC - tristate "Amlogic Meson G12A AO CEC driver" - depends on ARCH_MESON || COMPILE_TEST - depends on COMMON_CLK && OF - select REGMAP - select REGMAP_MMIO - select CEC_CORE - select CEC_NOTIFIER - ---help--- - This is a driver for Amlogic Meson G12A SoCs AO CEC interface. - This driver if for the new AO-CEC module found in G12A SoCs, - usually named AO_CEC_B in documentation. - It uses the generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config CEC_GPIO - tristate "Generic GPIO-based CEC driver" - depends on PREEMPTION || COMPILE_TEST - select CEC_CORE - select CEC_PIN - select CEC_NOTIFIER - select GPIOLIB - help - This is a generic GPIO-based CEC driver. - The CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config VIDEO_SAMSUNG_S5P_CEC - tristate "Samsung S5P CEC driver" - depends on ARCH_EXYNOS || COMPILE_TEST - select CEC_CORE - select 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 ARCH_STI || COMPILE_TEST - select CEC_CORE - select CEC_NOTIFIER - help - This is a driver for STIH4xx 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_STM32_HDMI_CEC - tristate "STMicroelectronics STM32 HDMI CEC driver" - depends on ARCH_STM32 || COMPILE_TEST - select REGMAP - select REGMAP_MMIO - select CEC_CORE - help - This is a driver for STM32 interface. It uses the - generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config VIDEO_TEGRA_HDMI_CEC - tristate "Tegra HDMI CEC driver" - depends on ARCH_TEGRA || COMPILE_TEST - select CEC_CORE - select CEC_NOTIFIER - help - This is a driver for the Tegra HDMI CEC interface. It uses the - generic CEC framework interface. - The CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config VIDEO_SECO_CEC - tristate "SECO Boards HDMI CEC driver" - depends on (X86 || IA64) || COMPILE_TEST - depends on PCI && DMI - select CEC_CORE - select CEC_NOTIFIER - help - This is a driver for SECO Boards integrated CEC interface. - Selecting it will enable support for this device. - CEC bus is present in the HDMI connector and enables communication - between compatible devices. - -config VIDEO_SECO_RC - bool "SECO Boards IR RC5 support" - depends on VIDEO_SECO_CEC - depends on RC_CORE=y || RC_CORE = VIDEO_SECO_CEC - help - If you say yes here you will get support for the - SECO Boards Consumer-IR in seco-cec driver. - The embedded controller supports RC5 protocol only, default mapping - is set to rc-hauppauge. - -endif #CEC_PLATFORM_DRIVERS - menuconfig SDR_PLATFORM_DRIVERS bool "SDR platform devices" depends on MEDIA_SDR_SUPPORT diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a0194ef1211f..ac31d4748869 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -23,8 +23,6 @@ obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o -obj-$(CONFIG_CEC_GPIO) += cec-gpio/ - obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o obj-$(CONFIG_VIDEO_MUX) += video-mux.o @@ -35,22 +33,16 @@ 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/ obj-$(CONFIG_VIDEO_STI_HVA) += sti/hva/ obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ -obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += sti/cec/ obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ -obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/ - obj-y += stm32/ -obj-$(CONFIG_VIDEO_SECO_CEC) += seco-cec/ - obj-y += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o @@ -89,8 +81,4 @@ obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom/camss/ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ -obj-y += meson/ - -obj-y += cros-ec-cec/ - obj-y += sunxi/ diff --git a/drivers/media/platform/cec-gpio/Makefile b/drivers/media/platform/cec-gpio/Makefile deleted file mode 100644 index a40c621dbd24..000000000000 --- a/drivers/media/platform/cec-gpio/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CEC_GPIO) += cec-gpio.o diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c deleted file mode 100644 index 42d2c2cd9a78..000000000000 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ /dev/null @@ -1,298 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <media/cec-notifier.h> -#include <media/cec-pin.h> - -struct cec_gpio { - struct cec_adapter *adap; - struct cec_notifier *notifier; - struct device *dev; - - struct gpio_desc *cec_gpio; - int cec_irq; - bool cec_is_low; - - struct gpio_desc *hpd_gpio; - int hpd_irq; - bool hpd_is_high; - ktime_t hpd_ts; - - struct gpio_desc *v5_gpio; - int v5_irq; - bool v5_is_high; - ktime_t v5_ts; -}; - -static bool cec_gpio_read(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - if (cec->cec_is_low) - return false; - return gpiod_get_value(cec->cec_gpio); -} - -static void cec_gpio_high(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - if (!cec->cec_is_low) - return; - cec->cec_is_low = false; - gpiod_set_value(cec->cec_gpio, 1); -} - -static void cec_gpio_low(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - if (cec->cec_is_low) - return; - cec->cec_is_low = true; - gpiod_set_value(cec->cec_gpio, 0); -} - -static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) -{ - struct cec_gpio *cec = priv; - - cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts); - return IRQ_HANDLED; -} - -static irqreturn_t cec_5v_gpio_irq_handler(int irq, void *priv) -{ - struct cec_gpio *cec = priv; - bool is_high = gpiod_get_value(cec->v5_gpio); - - if (is_high == cec->v5_is_high) - return IRQ_HANDLED; - cec->v5_ts = ktime_get(); - cec->v5_is_high = is_high; - return IRQ_WAKE_THREAD; -} - -static irqreturn_t cec_5v_gpio_irq_handler_thread(int irq, void *priv) -{ - struct cec_gpio *cec = priv; - - cec_queue_pin_5v_event(cec->adap, cec->v5_is_high, cec->v5_ts); - return IRQ_HANDLED; -} - -static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) -{ - struct cec_gpio *cec = priv; - bool is_high = gpiod_get_value(cec->hpd_gpio); - - if (is_high == cec->hpd_is_high) - return IRQ_HANDLED; - cec->hpd_ts = ktime_get(); - cec->hpd_is_high = is_high; - return IRQ_WAKE_THREAD; -} - -static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) -{ - struct cec_gpio *cec = priv; - - cec_pin_changed(cec->adap, gpiod_get_value(cec->cec_gpio)); - return IRQ_HANDLED; -} - -static bool cec_gpio_enable_irq(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - enable_irq(cec->cec_irq); - return true; -} - -static void cec_gpio_disable_irq(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - disable_irq(cec->cec_irq); -} - -static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read"); - seq_printf(file, "using irq: %d\n", cec->cec_irq); - if (cec->hpd_gpio) - seq_printf(file, "hpd: %s\n", - cec->hpd_is_high ? "high" : "low"); - if (cec->v5_gpio) - seq_printf(file, "5V: %s\n", - cec->v5_is_high ? "high" : "low"); -} - -static int cec_gpio_read_hpd(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - if (!cec->hpd_gpio) - return -ENOTTY; - return gpiod_get_value(cec->hpd_gpio); -} - -static int cec_gpio_read_5v(struct cec_adapter *adap) -{ - struct cec_gpio *cec = cec_get_drvdata(adap); - - if (!cec->v5_gpio) - return -ENOTTY; - return gpiod_get_value(cec->v5_gpio); -} - -static void cec_gpio_free(struct cec_adapter *adap) -{ - cec_gpio_disable_irq(adap); -} - -static const struct cec_pin_ops cec_gpio_pin_ops = { - .read = cec_gpio_read, - .low = cec_gpio_low, - .high = cec_gpio_high, - .enable_irq = cec_gpio_enable_irq, - .disable_irq = cec_gpio_disable_irq, - .status = cec_gpio_status, - .free = cec_gpio_free, - .read_hpd = cec_gpio_read_hpd, - .read_5v = cec_gpio_read_5v, -}; - -static int cec_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device *hdmi_dev; - struct cec_gpio *cec; - u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; - int ret; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); - if (PTR_ERR(hdmi_dev) == -EPROBE_DEFER) - return PTR_ERR(hdmi_dev); - if (IS_ERR(hdmi_dev)) - caps |= CEC_CAP_PHYS_ADDR; - - cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); - if (!cec) - return -ENOMEM; - - cec->dev = dev; - - cec->cec_gpio = devm_gpiod_get(dev, "cec", GPIOD_OUT_HIGH_OPEN_DRAIN); - if (IS_ERR(cec->cec_gpio)) - return PTR_ERR(cec->cec_gpio); - cec->cec_irq = gpiod_to_irq(cec->cec_gpio); - - cec->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); - if (IS_ERR(cec->hpd_gpio)) - return PTR_ERR(cec->hpd_gpio); - - cec->v5_gpio = devm_gpiod_get_optional(dev, "v5", GPIOD_IN); - if (IS_ERR(cec->v5_gpio)) - return PTR_ERR(cec->v5_gpio); - - cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops, - cec, pdev->name, caps); - if (IS_ERR(cec->adap)) - return PTR_ERR(cec->adap); - - ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - cec->adap->name, cec); - if (ret) - goto del_adap; - - cec_gpio_disable_irq(cec->adap); - - if (cec->hpd_gpio) { - cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); - ret = devm_request_threaded_irq(dev, cec->hpd_irq, - cec_hpd_gpio_irq_handler, - cec_hpd_gpio_irq_handler_thread, - IRQF_ONESHOT | - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "hpd-gpio", cec); - if (ret) - goto del_adap; - } - - if (cec->v5_gpio) { - cec->v5_irq = gpiod_to_irq(cec->v5_gpio); - ret = devm_request_threaded_irq(dev, cec->v5_irq, - cec_5v_gpio_irq_handler, - cec_5v_gpio_irq_handler_thread, - IRQF_ONESHOT | - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "v5-gpio", cec); - if (ret) - goto del_adap; - } - - if (!IS_ERR(hdmi_dev)) { - cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, - cec->adap); - if (!cec->notifier) { - ret = -ENOMEM; - goto del_adap; - } - } - - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) - goto unreg_notifier; - - platform_set_drvdata(pdev, cec); - return 0; - -unreg_notifier: - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); -del_adap: - cec_delete_adapter(cec->adap); - return ret; -} - -static int cec_gpio_remove(struct platform_device *pdev) -{ - struct cec_gpio *cec = platform_get_drvdata(pdev); - - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); - cec_unregister_adapter(cec->adap); - return 0; -} - -static const struct of_device_id cec_gpio_match[] = { - { - .compatible = "cec-gpio", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, cec_gpio_match); - -static struct platform_driver cec_gpio_pdrv = { - .probe = cec_gpio_probe, - .remove = cec_gpio_remove, - .driver = { - .name = "cec-gpio", - .of_match_table = cec_gpio_match, - }, -}; - -module_platform_driver(cec_gpio_pdrv); - -MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("CEC GPIO driver"); diff --git a/drivers/media/platform/cros-ec-cec/Makefile b/drivers/media/platform/cros-ec-cec/Makefile deleted file mode 100644 index 2615cdc6e227..000000000000 --- a/drivers/media/platform/cros-ec-cec/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_CROS_EC_CEC) += cros-ec-cec.o diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c deleted file mode 100644 index 0e7e2772f08f..000000000000 --- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * CEC driver for ChromeOS Embedded Controller - * - * Copyright (c) 2018 BayLibre, SAS - * Author: Neil Armstrong <narmstrong@baylibre.com> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/dmi.h> -#include <linux/pci.h> -#include <linux/cec.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/platform_data/cros_ec_commands.h> -#include <linux/platform_data/cros_ec_proto.h> -#include <media/cec.h> -#include <media/cec-notifier.h> - -#define DRV_NAME "cros-ec-cec" - -/** - * struct cros_ec_cec - Driver data for EC CEC - * - * @cros_ec: Pointer to EC device - * @notifier: Notifier info for responding to EC events - * @adap: CEC adapter - * @notify: CEC notifier pointer - * @rx_msg: storage for a received message - */ -struct cros_ec_cec { - struct cros_ec_device *cros_ec; - struct notifier_block notifier; - struct cec_adapter *adap; - struct cec_notifier *notify; - struct cec_msg rx_msg; -}; - -static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) -{ - struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - uint8_t *cec_message = cros_ec->event_data.data.cec_message; - unsigned int len = cros_ec->event_size; - - cros_ec_cec->rx_msg.len = len; - memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); - - cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg); -} - -static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) -{ - struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - uint32_t events = cros_ec->event_data.data.cec_events; - - if (events & EC_MKBP_CEC_SEND_OK) - cec_transmit_attempt_done(cros_ec_cec->adap, - CEC_TX_STATUS_OK); - - /* FW takes care of all retries, tell core to avoid more retries */ - if (events & EC_MKBP_CEC_SEND_FAILED) - cec_transmit_attempt_done(cros_ec_cec->adap, - CEC_TX_STATUS_MAX_RETRIES | - CEC_TX_STATUS_NACK); -} - -static int cros_ec_cec_event(struct notifier_block *nb, - unsigned long queued_during_suspend, - void *_notify) -{ - struct cros_ec_cec *cros_ec_cec; - struct cros_ec_device *cros_ec; - - cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); - cros_ec = cros_ec_cec->cros_ec; - - if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { - handle_cec_event(cros_ec_cec); - return NOTIFY_OK; - } - - if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { - handle_cec_message(cros_ec_cec); - return NOTIFY_OK; - } - - return NOTIFY_DONE; -} - -static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct cros_ec_cec *cros_ec_cec = adap->priv; - struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; - int ret; - - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS; - msg.data.val = logical_addr; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); - if (ret < 0) { - dev_err(cros_ec->dev, - "error setting CEC logical address on EC: %d\n", ret); - return ret; - } - - return 0; -} - -static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *cec_msg) -{ - struct cros_ec_cec *cros_ec_cec = adap->priv; - struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_write data; - } __packed msg = {}; - int ret; - - msg.msg.command = EC_CMD_CEC_WRITE_MSG; - msg.msg.outsize = cec_msg->len; - memcpy(msg.data.msg, cec_msg->msg, cec_msg->len); - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); - if (ret < 0) { - dev_err(cros_ec->dev, - "error writing CEC msg on EC: %d\n", ret); - return ret; - } - - return 0; -} - -static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct cros_ec_cec *cros_ec_cec = adap->priv; - struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; - struct { - struct cros_ec_command msg; - struct ec_params_cec_set data; - } __packed msg = {}; - int ret; - - msg.msg.command = EC_CMD_CEC_SET; - msg.msg.outsize = sizeof(msg.data); - msg.data.cmd = CEC_CMD_ENABLE; - msg.data.val = enable; - - ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); - if (ret < 0) { - dev_err(cros_ec->dev, - "error %sabling CEC on EC: %d\n", - (enable ? "en" : "dis"), ret); - return ret; - } - - return 0; -} - -static const struct cec_adap_ops cros_ec_cec_ops = { - .adap_enable = cros_ec_cec_adap_enable, - .adap_log_addr = cros_ec_cec_set_log_addr, - .adap_transmit = cros_ec_cec_transmit, -}; - -#ifdef CONFIG_PM_SLEEP -static int cros_ec_cec_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); - - if (device_may_wakeup(dev)) - enable_irq_wake(cros_ec_cec->cros_ec->irq); - - return 0; -} - -static int cros_ec_cec_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); - - if (device_may_wakeup(dev)) - disable_irq_wake(cros_ec_cec->cros_ec->irq); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, - cros_ec_cec_suspend, cros_ec_cec_resume); - -#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) - -/* - * The Firmware only handles a single CEC interface tied to a single HDMI - * connector we specify along with the DRM device name handling the HDMI output - */ - -struct cec_dmi_match { - const char *sys_vendor; - const char *product_name; - const char *devname; - const char *conn; -}; - -static const struct cec_dmi_match cec_dmi_match_table[] = { - /* Google Fizz */ - { "Google", "Fizz", "0000:00:02.0", "Port B" }, -}; - -static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) -{ - int i; - - for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { - const struct cec_dmi_match *m = &cec_dmi_match_table[i]; - - if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && - dmi_match(DMI_PRODUCT_NAME, m->product_name)) { - struct device *d; - - /* Find the device, bail out if not yet registered */ - d = bus_find_device_by_name(&pci_bus_type, NULL, - m->devname); - if (!d) - return ERR_PTR(-EPROBE_DEFER); - put_device(d); - *conn = m->conn; - return d; - } - } - - /* Hardware support must be added in the cec_dmi_match_table */ - dev_warn(dev, "CEC notifier not configured for this hardware\n"); - - return ERR_PTR(-ENODEV); -} - -#else - -static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, - const char **conn) -{ - return ERR_PTR(-ENODEV); -} - -#endif - -static int cros_ec_cec_probe(struct platform_device *pdev) -{ - struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); - struct cros_ec_device *cros_ec = ec_dev->ec_dev; - struct cros_ec_cec *cros_ec_cec; - struct device *hdmi_dev; - const char *conn = NULL; - int ret; - - hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), - GFP_KERNEL); - if (!cros_ec_cec) - return -ENOMEM; - - platform_set_drvdata(pdev, cros_ec_cec); - cros_ec_cec->cros_ec = cros_ec; - - ret = device_init_wakeup(&pdev->dev, 1); - if (ret) { - dev_err(&pdev->dev, "failed to initialize wakeup\n"); - return ret; - } - - cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, - DRV_NAME, - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, 1); - if (IS_ERR(cros_ec_cec->adap)) - return PTR_ERR(cros_ec_cec->adap); - - cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, - cros_ec_cec->adap); - if (!cros_ec_cec->notify) { - ret = -ENOMEM; - goto out_probe_adapter; - } - - /* Get CEC events from the EC. */ - cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; - ret = blocking_notifier_chain_register(&cros_ec->event_notifier, - &cros_ec_cec->notifier); - if (ret) { - dev_err(&pdev->dev, "failed to register notifier\n"); - goto out_probe_notify; - } - - ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); - if (ret < 0) - goto out_probe_notify; - - return 0; - -out_probe_notify: - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); -out_probe_adapter: - cec_delete_adapter(cros_ec_cec->adap); - return ret; -} - -static int cros_ec_cec_remove(struct platform_device *pdev) -{ - struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - int ret; - - ret = blocking_notifier_chain_unregister( - &cros_ec_cec->cros_ec->event_notifier, - &cros_ec_cec->notifier); - - if (ret) { - dev_err(dev, "failed to unregister notifier\n"); - return ret; - } - - cec_notifier_cec_adap_unregister(cros_ec_cec->notify, - cros_ec_cec->adap); - cec_unregister_adapter(cros_ec_cec->adap); - - return 0; -} - -static struct platform_driver cros_ec_cec_driver = { - .probe = cros_ec_cec_probe, - .remove = cros_ec_cec_remove, - .driver = { - .name = DRV_NAME, - .pm = &cros_ec_cec_pm_ops, - }, -}; - -module_platform_driver(cros_ec_cec_driver); - -MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); -MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile deleted file mode 100644 index 6bf728addbf8..000000000000 --- a/drivers/media/platform/meson/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o -obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c deleted file mode 100644 index 891533060d49..000000000000 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ /dev/null @@ -1,796 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for Amlogic Meson AO CEC G12A Controller - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved - * Copyright (C) 2019 BayLibre, SAS - * Author: Neil Armstrong <narmstrong@baylibre.com> - */ - -#include <linux/bitfield.h> -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/reset.h> -#include <linux/slab.h> -#include <linux/regmap.h> -#include <media/cec.h> -#include <media/cec-notifier.h> -#include <linux/clk-provider.h> - -/* CEC Registers */ - -#define CECB_CLK_CNTL_REG0 0x00 - -#define CECB_CLK_CNTL_N1 GENMASK(11, 0) -#define CECB_CLK_CNTL_N2 GENMASK(23, 12) -#define CECB_CLK_CNTL_DUAL_EN BIT(28) -#define CECB_CLK_CNTL_OUTPUT_EN BIT(30) -#define CECB_CLK_CNTL_INPUT_EN BIT(31) - -#define CECB_CLK_CNTL_REG1 0x04 - -#define CECB_CLK_CNTL_M1 GENMASK(11, 0) -#define CECB_CLK_CNTL_M2 GENMASK(23, 12) -#define CECB_CLK_CNTL_BYPASS_EN BIT(24) - -/* - * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal - * change pulse width < filter_del * T(filter_tick) * 3. - * [9:8] Filter_tick_sel: Select which periodical pulse for - * glitch-filtering CEC line signal. - * - 0=Use T(xtal)*3 = 125ns; - * - 1=Use once-per-1us pulse; - * - 2=Use once-per-10us pulse; - * - 3=Use once-per-100us pulse. - * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock. - * [2:1] cntl_clk - * - 0 = Disable clk (Power-off mode) - * - 1 = Enable gated clock (Normal mode) - * - 2 = Enable free-run clk (Debug mode) - * [0] SW_RESET 1=Apply reset; 0=No reset. - */ -#define CECB_GEN_CNTL_REG 0x08 - -#define CECB_GEN_CNTL_RESET BIT(0) -#define CECB_GEN_CNTL_CLK_DISABLE 0 -#define CECB_GEN_CNTL_CLK_ENABLE 1 -#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2 -#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) -#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3) -#define CECB_GEN_CNTL_FILTER_TICK_125NS 0 -#define CECB_GEN_CNTL_FILTER_TICK_1US 1 -#define CECB_GEN_CNTL_FILTER_TICK_10US 2 -#define CECB_GEN_CNTL_FILTER_TICK_100US 3 -#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8) -#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12) - -/* - * [7:0] cec_reg_addr - * [15:8] cec_reg_wrdata - * [16] cec_reg_wr - * - 0 = Read - * - 1 = Write - * [31:24] cec_reg_rddata - */ -#define CECB_RW_REG 0x0c - -#define CECB_RW_ADDR GENMASK(7, 0) -#define CECB_RW_WR_DATA GENMASK(15, 8) -#define CECB_RW_WRITE_EN BIT(16) -#define CECB_RW_BUS_BUSY BIT(23) -#define CECB_RW_RD_DATA GENMASK(31, 24) - -/* - * [0] DONE Interrupt - * [1] End Of Message Interrupt - * [2] Not Acknowlegde Interrupt - * [3] Arbitration Loss Interrupt - * [4] Initiator Error Interrupt - * [5] Follower Error Interrupt - * [6] Wake-Up Interrupt - */ -#define CECB_INTR_MASKN_REG 0x10 -#define CECB_INTR_CLR_REG 0x14 -#define CECB_INTR_STAT_REG 0x18 - -#define CECB_INTR_DONE BIT(0) -#define CECB_INTR_EOM BIT(1) -#define CECB_INTR_NACK BIT(2) -#define CECB_INTR_ARB_LOSS BIT(3) -#define CECB_INTR_INITIATOR_ERR BIT(4) -#define CECB_INTR_FOLLOWER_ERR BIT(5) -#define CECB_INTR_WAKE_UP BIT(6) - -/* CEC Commands */ - -#define CECB_CTRL 0x00 - -#define CECB_CTRL_SEND BIT(0) -#define CECB_CTRL_TYPE GENMASK(2, 1) -#define CECB_CTRL_TYPE_RETRY 0 -#define CECB_CTRL_TYPE_NEW 1 -#define CECB_CTRL_TYPE_NEXT 2 - -#define CECB_CTRL2 0x01 - -#define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0) - -#define CECB_INTR_MASK 0x02 -#define CECB_LADD_LOW 0x05 -#define CECB_LADD_HIGH 0x06 -#define CECB_TX_CNT 0x07 -#define CECB_RX_CNT 0x08 -#define CECB_STAT0 0x09 -#define CECB_TX_DATA00 0x10 -#define CECB_TX_DATA01 0x11 -#define CECB_TX_DATA02 0x12 -#define CECB_TX_DATA03 0x13 -#define CECB_TX_DATA04 0x14 -#define CECB_TX_DATA05 0x15 -#define CECB_TX_DATA06 0x16 -#define CECB_TX_DATA07 0x17 -#define CECB_TX_DATA08 0x18 -#define CECB_TX_DATA09 0x19 -#define CECB_TX_DATA10 0x1A -#define CECB_TX_DATA11 0x1B -#define CECB_TX_DATA12 0x1C -#define CECB_TX_DATA13 0x1D -#define CECB_TX_DATA14 0x1E -#define CECB_TX_DATA15 0x1F -#define CECB_RX_DATA00 0x20 -#define CECB_RX_DATA01 0x21 -#define CECB_RX_DATA02 0x22 -#define CECB_RX_DATA03 0x23 -#define CECB_RX_DATA04 0x24 -#define CECB_RX_DATA05 0x25 -#define CECB_RX_DATA06 0x26 -#define CECB_RX_DATA07 0x27 -#define CECB_RX_DATA08 0x28 -#define CECB_RX_DATA09 0x29 -#define CECB_RX_DATA10 0x2A -#define CECB_RX_DATA11 0x2B -#define CECB_RX_DATA12 0x2C -#define CECB_RX_DATA13 0x2D -#define CECB_RX_DATA14 0x2E -#define CECB_RX_DATA15 0x2F -#define CECB_LOCK_BUF 0x30 - -#define CECB_LOCK_BUF_EN BIT(0) - -#define CECB_WAKEUPCTRL 0x31 - -struct meson_ao_cec_g12a_data { - /* Setup the internal CECB_CTRL2 register */ - bool ctrl2_setup; -}; - -struct meson_ao_cec_g12a_device { - struct platform_device *pdev; - struct regmap *regmap; - struct regmap *regmap_cec; - spinlock_t cec_reg_lock; - struct cec_notifier *notify; - struct cec_adapter *adap; - struct cec_msg rx_msg; - struct clk *oscin; - struct clk *core; - const struct meson_ao_cec_g12a_data *data; -}; - -static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { - .reg_bits = 8, - .val_bits = 32, - .reg_stride = 4, - .max_register = CECB_INTR_STAT_REG, -}; - -/* - * The AO-CECB embeds a dual/divider to generate a more precise - * 32,768KHz clock for CEC core clock. - * ______ ______ - * | | | | - * ______ | Div1 |-| Cnt1 | ______ - * | | /|______| |______|\ | | - * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> - * |______| | \| | | |/ | |______| - * | | Div2 |-| Cnt2 | | - * | |______| |______| | - * |_______________________| - * - * The dividing can be switched to single or dual, with a counter - * for each divider to set when the switching is done. - * The entire dividing mechanism can be also bypassed. - */ - -struct meson_ao_cec_g12a_dualdiv_clk { - struct clk_hw hw; - struct regmap *regmap; -}; - -#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \ - container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \ - -static unsigned long -meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = - hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); - unsigned long n1; - u32 reg0, reg1; - - regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0); - regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1); - - if (reg1 & CECB_CLK_CNTL_BYPASS_EN) - return parent_rate; - - if (reg0 & CECB_CLK_CNTL_DUAL_EN) { - unsigned long n2, m1, m2, f1, f2, p1, p2; - - n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; - n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1; - - m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; - m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; - - f1 = DIV_ROUND_CLOSEST(parent_rate, n1); - f2 = DIV_ROUND_CLOSEST(parent_rate, n2); - - p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); - p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); - - return DIV_ROUND_UP(100000000, p1 + p2); - } - - n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; - - return DIV_ROUND_CLOSEST(parent_rate, n1); -} - -static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw) -{ - struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = - hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); - - - /* Disable Input & Output */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, - 0); - - /* Set N1 & N2 */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_N1, - FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); - - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_N2, - FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); - - /* Set M1 & M2 */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, - CECB_CLK_CNTL_M1, - FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); - - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, - CECB_CLK_CNTL_M2, - FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); - - /* Enable Dual divisor */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN); - - /* Disable divisor bypass */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, - CECB_CLK_CNTL_BYPASS_EN, 0); - - /* Enable Input & Output */ - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, - CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN); - - return 0; -} - -static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw) -{ - struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = - hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); - - regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, - CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, - 0); -} - -static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw) -{ - struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = - hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); - int val; - - regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); - - return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN)); -} - -static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = { - .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate, - .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled, - .enable = meson_ao_cec_g12a_dualdiv_clk_enable, - .disable = meson_ao_cec_g12a_dualdiv_clk_disable, -}; - -static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec) -{ - struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk; - struct device *dev = &ao_cec->pdev->dev; - struct clk_init_data init; - const char *parent_name; - struct clk *clk; - char *name; - - dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL); - if (!dualdiv_clk) - return -ENOMEM; - - name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev)); - if (!name) - return -ENOMEM; - - parent_name = __clk_get_name(ao_cec->oscin); - - init.name = name; - init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops; - init.flags = 0; - init.parent_names = &parent_name; - init.num_parents = 1; - dualdiv_clk->regmap = ao_cec->regmap; - dualdiv_clk->hw.init = &init; - - clk = devm_clk_register(dev, &dualdiv_clk->hw); - kfree(name); - if (IS_ERR(clk)) { - dev_err(dev, "failed to register clock\n"); - return PTR_ERR(clk); - } - - ao_cec->core = clk; - - return 0; -} - -static int meson_ao_cec_g12a_read(void *context, unsigned int addr, - unsigned int *data) -{ - struct meson_ao_cec_g12a_device *ao_cec = context; - u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); - int ret = 0; - - ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); - if (ret) - return ret; - - ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, - !(reg & CECB_RW_BUS_BUSY), - 5, 1000); - if (ret) - return ret; - - ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); - - *data = FIELD_GET(CECB_RW_RD_DATA, reg); - - return ret; -} - -static int meson_ao_cec_g12a_write(void *context, unsigned int addr, - unsigned int data) -{ - struct meson_ao_cec_g12a_device *ao_cec = context; - u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | - FIELD_PREP(CECB_RW_WR_DATA, data) | - CECB_RW_WRITE_EN; - - return regmap_write(ao_cec->regmap, CECB_RW_REG, reg); -} - -static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { - .reg_bits = 8, - .val_bits = 8, - .reg_read = meson_ao_cec_g12a_read, - .reg_write = meson_ao_cec_g12a_write, - .max_register = 0xffff, -}; - -static inline void -meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, - bool enable) -{ - u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | - CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | - CECB_INTR_FOLLOWER_ERR; - - regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, - enable ? cfg : 0); -} - -static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) -{ - int i, ret = 0; - u32 val; - - ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); - - ao_cec->rx_msg.len = val; - if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) - ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; - - for (i = 0; i < ao_cec->rx_msg.len; i++) { - ret |= regmap_read(ao_cec->regmap_cec, - CECB_RX_DATA00 + i, &val); - - ao_cec->rx_msg.msg[i] = val & 0xff; - } - - ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); - if (ret) - return; - - cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); -} - -static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) -{ - struct meson_ao_cec_g12a_device *ao_cec = data; - u32 stat; - - regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); - if (stat) - return IRQ_WAKE_THREAD; - - return IRQ_NONE; -} - -static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) -{ - struct meson_ao_cec_g12a_device *ao_cec = data; - u32 stat; - - regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); - regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); - - if (stat & CECB_INTR_DONE) - cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); - - if (stat & CECB_INTR_EOM) - meson_ao_cec_g12a_irq_rx(ao_cec); - - if (stat & CECB_INTR_NACK) - cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); - - if (stat & CECB_INTR_ARB_LOSS) { - regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); - regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, - CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); - cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); - } - - /* Initiator reports an error on the CEC bus */ - if (stat & CECB_INTR_INITIATOR_ERR) - cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); - - /* Follower reports a receive error, just reset RX buffer */ - if (stat & CECB_INTR_FOLLOWER_ERR) - regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); - - return IRQ_HANDLED; -} - -static int -meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct meson_ao_cec_g12a_device *ao_cec = adap->priv; - int ret = 0; - - if (logical_addr == CEC_LOG_ADDR_INVALID) { - /* Assume this will allways succeed */ - regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); - regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); - - return 0; - } else if (logical_addr < 8) { - ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, - BIT(logical_addr), - BIT(logical_addr)); - } else { - ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, - BIT(logical_addr - 8), - BIT(logical_addr - 8)); - } - - /* Always set Broadcast/Unregistered 15 address */ - ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, - BIT(CEC_LOG_ADDR_UNREGISTERED - 8), - BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); - - return ret ? -EIO : 0; -} - -static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct meson_ao_cec_g12a_device *ao_cec = adap->priv; - unsigned int type; - int ret = 0; - u32 val; - int i; - - /* Check if RX is in progress */ - ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); - if (ret) - return ret; - if (val & CECB_LOCK_BUF_EN) - return -EBUSY; - - /* Check if TX Busy */ - ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); - if (ret) - return ret; - if (val & CECB_CTRL_SEND) - return -EBUSY; - - switch (signal_free_time) { - case CEC_SIGNAL_FREE_TIME_RETRY: - type = CECB_CTRL_TYPE_RETRY; - break; - case CEC_SIGNAL_FREE_TIME_NEXT_XFER: - type = CECB_CTRL_TYPE_NEXT; - break; - case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: - default: - type = CECB_CTRL_TYPE_NEW; - break; - } - - for (i = 0; i < msg->len; i++) - ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, - msg->msg[i]); - - ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); - if (ret) - return -EIO; - - ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, - CECB_CTRL_SEND | - CECB_CTRL_TYPE, - CECB_CTRL_SEND | - FIELD_PREP(CECB_CTRL_TYPE, type)); - - return ret; -} - -static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct meson_ao_cec_g12a_device *ao_cec = adap->priv; - - meson_ao_cec_g12a_irq_setup(ao_cec, false); - - regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, - CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); - - if (!enable) - return 0; - - /* Setup Filter */ - regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, - CECB_GEN_CNTL_FILTER_TICK_SEL | - CECB_GEN_CNTL_FILTER_DEL, - FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, - CECB_GEN_CNTL_FILTER_TICK_1US) | - FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); - - /* Enable System Clock */ - regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, - CECB_GEN_CNTL_SYS_CLK_EN, - CECB_GEN_CNTL_SYS_CLK_EN); - - /* Enable gated clock (Normal mode). */ - regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, - CECB_GEN_CNTL_CLK_CTRL_MASK, - FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, - CECB_GEN_CNTL_CLK_ENABLE)); - - /* Release Reset */ - regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, - CECB_GEN_CNTL_RESET, 0); - - if (ao_cec->data->ctrl2_setup) - regmap_write(ao_cec->regmap_cec, CECB_CTRL2, - FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2)); - - meson_ao_cec_g12a_irq_setup(ao_cec, true); - - return 0; -} - -static const struct cec_adap_ops meson_ao_cec_g12a_ops = { - .adap_enable = meson_ao_cec_g12a_adap_enable, - .adap_log_addr = meson_ao_cec_g12a_set_log_addr, - .adap_transmit = meson_ao_cec_g12a_transmit, -}; - -static int meson_ao_cec_g12a_probe(struct platform_device *pdev) -{ - struct meson_ao_cec_g12a_device *ao_cec; - struct device *hdmi_dev; - struct resource *res; - void __iomem *base; - int ret, irq; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); - if (!ao_cec) - return -ENOMEM; - - ao_cec->data = of_device_get_match_data(&pdev->dev); - if (!ao_cec->data) { - dev_err(&pdev->dev, "failed to get match data\n"); - return -ENODEV; - } - - spin_lock_init(&ao_cec->cec_reg_lock); - ao_cec->pdev = pdev; - - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, - "meson_g12a_ao_cec", - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, - CEC_MAX_LOG_ADDRS); - if (IS_ERR(ao_cec->adap)) - return PTR_ERR(ao_cec->adap); - - ao_cec->adap->owner = THIS_MODULE; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto out_probe_adapter; - } - - ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &meson_ao_cec_g12a_regmap_conf); - if (IS_ERR(ao_cec->regmap)) { - ret = PTR_ERR(ao_cec->regmap); - goto out_probe_adapter; - } - - ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, - &meson_ao_cec_g12a_cec_regmap_conf); - if (IS_ERR(ao_cec->regmap_cec)) { - ret = PTR_ERR(ao_cec->regmap_cec); - goto out_probe_adapter; - } - - irq = platform_get_irq(pdev, 0); - ret = devm_request_threaded_irq(&pdev->dev, irq, - meson_ao_cec_g12a_irq, - meson_ao_cec_g12a_irq_thread, - 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; - } - - ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); - if (IS_ERR(ao_cec->oscin)) { - dev_err(&pdev->dev, "oscin clock request failed\n"); - ret = PTR_ERR(ao_cec->oscin); - goto out_probe_adapter; - } - - ret = meson_ao_cec_g12a_setup_clk(ao_cec); - if (ret) - goto out_probe_adapter; - - ret = clk_prepare_enable(ao_cec->core); - if (ret) { - dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; - } - - device_reset_optional(&pdev->dev); - - platform_set_drvdata(pdev, ao_cec); - - ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, - ao_cec->adap); - if (!ao_cec->notify) { - ret = -ENOMEM; - goto out_probe_core_clk; - } - - ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) - goto out_probe_notify; - - /* Setup Hardware */ - regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); - - return 0; - -out_probe_notify: - cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); - -out_probe_core_clk: - clk_disable_unprepare(ao_cec->core); - -out_probe_adapter: - cec_delete_adapter(ao_cec->adap); - - dev_err(&pdev->dev, "CEC controller registration failed\n"); - - return ret; -} - -static int meson_ao_cec_g12a_remove(struct platform_device *pdev) -{ - struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); - - clk_disable_unprepare(ao_cec->core); - - cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); - - cec_unregister_adapter(ao_cec->adap); - - return 0; -} - -static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = { - .ctrl2_setup = false, -}; - -static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = { - .ctrl2_setup = true, -}; - -static const struct of_device_id meson_ao_cec_g12a_of_match[] = { - { - .compatible = "amlogic,meson-g12a-ao-cec", - .data = &ao_cec_g12a_data, - }, - { - .compatible = "amlogic,meson-sm1-ao-cec", - .data = &ao_cec_sm1_data, - }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); - -static struct platform_driver meson_ao_cec_g12a_driver = { - .probe = meson_ao_cec_g12a_probe, - .remove = meson_ao_cec_g12a_remove, - .driver = { - .name = "meson-ao-cec-g12a", - .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), - }, -}; - -module_platform_driver(meson_ao_cec_g12a_driver); - -MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); -MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c deleted file mode 100644 index 09aff82c3773..000000000000 --- a/drivers/media/platform/meson/ao-cec.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Driver for Amlogic Meson AO CEC Controller - * - * Copyright (C) 2015 Amlogic, Inc. All rights reserved - * Copyright (C) 2017 BayLibre, SAS - * Author: Neil Armstrong <narmstrong@baylibre.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <linux/bitfield.h> -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/reset.h> -#include <media/cec.h> -#include <media/cec-notifier.h> - -/* CEC Registers */ - -/* - * [2:1] cntl_clk - * - 0 = Disable clk (Power-off mode) - * - 1 = Enable gated clock (Normal mode) - * - 2 = Enable free-run clk (Debug mode) - */ -#define CEC_GEN_CNTL_REG 0x00 - -#define CEC_GEN_CNTL_RESET BIT(0) -#define CEC_GEN_CNTL_CLK_DISABLE 0 -#define CEC_GEN_CNTL_CLK_ENABLE 1 -#define CEC_GEN_CNTL_CLK_ENABLE_DBG 2 -#define CEC_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) - -/* - * [7:0] cec_reg_addr - * [15:8] cec_reg_wrdata - * [16] cec_reg_wr - * - 0 = Read - * - 1 = Write - * [23] bus free - * [31:24] cec_reg_rddata - */ -#define CEC_RW_REG 0x04 - -#define CEC_RW_ADDR GENMASK(7, 0) -#define CEC_RW_WR_DATA GENMASK(15, 8) -#define CEC_RW_WRITE_EN BIT(16) -#define CEC_RW_BUS_BUSY BIT(23) -#define CEC_RW_RD_DATA GENMASK(31, 24) - -/* - * [1] tx intr - * [2] rx intr - */ -#define CEC_INTR_MASKN_REG 0x08 -#define CEC_INTR_CLR_REG 0x0c -#define CEC_INTR_STAT_REG 0x10 - -#define CEC_INTR_TX BIT(1) -#define CEC_INTR_RX BIT(2) - -/* CEC Commands */ - -#define CEC_TX_MSG_0_HEADER 0x00 -#define CEC_TX_MSG_1_OPCODE 0x01 -#define CEC_TX_MSG_2_OP1 0x02 -#define CEC_TX_MSG_3_OP2 0x03 -#define CEC_TX_MSG_4_OP3 0x04 -#define CEC_TX_MSG_5_OP4 0x05 -#define CEC_TX_MSG_6_OP5 0x06 -#define CEC_TX_MSG_7_OP6 0x07 -#define CEC_TX_MSG_8_OP7 0x08 -#define CEC_TX_MSG_9_OP8 0x09 -#define CEC_TX_MSG_A_OP9 0x0A -#define CEC_TX_MSG_B_OP10 0x0B -#define CEC_TX_MSG_C_OP11 0x0C -#define CEC_TX_MSG_D_OP12 0x0D -#define CEC_TX_MSG_E_OP13 0x0E -#define CEC_TX_MSG_F_OP14 0x0F -#define CEC_TX_MSG_LENGTH 0x10 -#define CEC_TX_MSG_CMD 0x11 -#define CEC_TX_WRITE_BUF 0x12 -#define CEC_TX_CLEAR_BUF 0x13 -#define CEC_RX_MSG_CMD 0x14 -#define CEC_RX_CLEAR_BUF 0x15 -#define CEC_LOGICAL_ADDR0 0x16 -#define CEC_LOGICAL_ADDR1 0x17 -#define CEC_LOGICAL_ADDR2 0x18 -#define CEC_LOGICAL_ADDR3 0x19 -#define CEC_LOGICAL_ADDR4 0x1A -#define CEC_CLOCK_DIV_H 0x1B -#define CEC_CLOCK_DIV_L 0x1C -#define CEC_QUIESCENT_25MS_BIT7_0 0x20 -#define CEC_QUIESCENT_25MS_BIT11_8 0x21 -#define CEC_STARTBITMINL2H_3MS5_BIT7_0 0x22 -#define CEC_STARTBITMINL2H_3MS5_BIT8 0x23 -#define CEC_STARTBITMAXL2H_3MS9_BIT7_0 0x24 -#define CEC_STARTBITMAXL2H_3MS9_BIT8 0x25 -#define CEC_STARTBITMINH_0MS6_BIT7_0 0x26 -#define CEC_STARTBITMINH_0MS6_BIT8 0x27 -#define CEC_STARTBITMAXH_1MS0_BIT7_0 0x28 -#define CEC_STARTBITMAXH_1MS0_BIT8 0x29 -#define CEC_STARTBITMINTOT_4MS3_BIT7_0 0x2A -#define CEC_STARTBITMINTOT_4MS3_BIT9_8 0x2B -#define CEC_STARTBITMAXTOT_4MS7_BIT7_0 0x2C -#define CEC_STARTBITMAXTOT_4MS7_BIT9_8 0x2D -#define CEC_LOGIC1MINL2H_0MS4_BIT7_0 0x2E -#define CEC_LOGIC1MINL2H_0MS4_BIT8 0x2F -#define CEC_LOGIC1MAXL2H_0MS8_BIT7_0 0x30 -#define CEC_LOGIC1MAXL2H_0MS8_BIT8 0x31 -#define CEC_LOGIC0MINL2H_1MS3_BIT7_0 0x32 -#define CEC_LOGIC0MINL2H_1MS3_BIT8 0x33 -#define CEC_LOGIC0MAXL2H_1MS7_BIT7_0 0x34 -#define CEC_LOGIC0MAXL2H_1MS7_BIT8 0x35 -#define CEC_LOGICMINTOTAL_2MS05_BIT7_0 0x36 -#define CEC_LOGICMINTOTAL_2MS05_BIT9_8 0x37 -#define CEC_LOGICMAXHIGH_2MS8_BIT7_0 0x38 -#define CEC_LOGICMAXHIGH_2MS8_BIT8 0x39 -#define CEC_LOGICERRLOW_3MS4_BIT7_0 0x3A -#define CEC_LOGICERRLOW_3MS4_BIT8 0x3B -#define CEC_NOMSMPPOINT_1MS05 0x3C -#define CEC_DELCNTR_LOGICERR 0x3E -#define CEC_TXTIME_17MS_BIT7_0 0x40 -#define CEC_TXTIME_17MS_BIT10_8 0x41 -#define CEC_TXTIME_2BIT_BIT7_0 0x42 -#define CEC_TXTIME_2BIT_BIT10_8 0x43 -#define CEC_TXTIME_4BIT_BIT7_0 0x44 -#define CEC_TXTIME_4BIT_BIT10_8 0x45 -#define CEC_STARTBITNOML2H_3MS7_BIT7_0 0x46 -#define CEC_STARTBITNOML2H_3MS7_BIT8 0x47 -#define CEC_STARTBITNOMH_0MS8_BIT7_0 0x48 -#define CEC_STARTBITNOMH_0MS8_BIT8 0x49 -#define CEC_LOGIC1NOML2H_0MS6_BIT7_0 0x4A -#define CEC_LOGIC1NOML2H_0MS6_BIT8 0x4B -#define CEC_LOGIC0NOML2H_1MS5_BIT7_0 0x4C -#define CEC_LOGIC0NOML2H_1MS5_BIT8 0x4D -#define CEC_LOGIC1NOMH_1MS8_BIT7_0 0x4E -#define CEC_LOGIC1NOMH_1MS8_BIT8 0x4F -#define CEC_LOGIC0NOMH_0MS9_BIT7_0 0x50 -#define CEC_LOGIC0NOMH_0MS9_BIT8 0x51 -#define CEC_LOGICERRLOW_3MS6_BIT7_0 0x52 -#define CEC_LOGICERRLOW_3MS6_BIT8 0x53 -#define CEC_CHKCONTENTION_0MS1 0x54 -#define CEC_PREPARENXTBIT_0MS05_BIT7_0 0x56 -#define CEC_PREPARENXTBIT_0MS05_BIT8 0x57 -#define CEC_NOMSMPACKPOINT_0MS45 0x58 -#define CEC_ACK0NOML2H_1MS5_BIT7_0 0x5A -#define CEC_ACK0NOML2H_1MS5_BIT8 0x5B -#define CEC_BUGFIX_DISABLE_0 0x60 -#define CEC_BUGFIX_DISABLE_1 0x61 -#define CEC_RX_MSG_0_HEADER 0x80 -#define CEC_RX_MSG_1_OPCODE 0x81 -#define CEC_RX_MSG_2_OP1 0x82 -#define CEC_RX_MSG_3_OP2 0x83 -#define CEC_RX_MSG_4_OP3 0x84 -#define CEC_RX_MSG_5_OP4 0x85 -#define CEC_RX_MSG_6_OP5 0x86 -#define CEC_RX_MSG_7_OP6 0x87 -#define CEC_RX_MSG_8_OP7 0x88 -#define CEC_RX_MSG_9_OP8 0x89 -#define CEC_RX_MSG_A_OP9 0x8A -#define CEC_RX_MSG_B_OP10 0x8B -#define CEC_RX_MSG_C_OP11 0x8C -#define CEC_RX_MSG_D_OP12 0x8D -#define CEC_RX_MSG_E_OP13 0x8E -#define CEC_RX_MSG_F_OP14 0x8F -#define CEC_RX_MSG_LENGTH 0x90 -#define CEC_RX_MSG_STATUS 0x91 -#define CEC_RX_NUM_MSG 0x92 -#define CEC_TX_MSG_STATUS 0x93 -#define CEC_TX_NUM_MSG 0x94 - - -/* CEC_TX_MSG_CMD definition */ -#define TX_NO_OP 0 /* No transaction */ -#define TX_REQ_CURRENT 1 /* Transmit earliest message in buffer */ -#define TX_ABORT 2 /* Abort transmitting earliest message */ -#define TX_REQ_NEXT 3 /* Overwrite earliest msg, transmit next */ - -/* tx_msg_status definition */ -#define TX_IDLE 0 /* No transaction */ -#define TX_BUSY 1 /* Transmitter is busy */ -#define TX_DONE 2 /* Message successfully transmitted */ -#define TX_ERROR 3 /* Message transmitted with error */ - -/* rx_msg_cmd */ -#define RX_NO_OP 0 /* No transaction */ -#define RX_ACK_CURRENT 1 /* Read earliest message in buffer */ -#define RX_DISABLE 2 /* Disable receiving latest message */ -#define RX_ACK_NEXT 3 /* Clear earliest msg, read next */ - -/* rx_msg_status */ -#define RX_IDLE 0 /* No transaction */ -#define RX_BUSY 1 /* Receiver is busy */ -#define RX_DONE 2 /* Message has been received successfully */ -#define RX_ERROR 3 /* Message has been received with error */ - -/* RX_CLEAR_BUF options */ -#define CLEAR_START 1 -#define CLEAR_STOP 0 - -/* CEC_LOGICAL_ADDRx options */ -#define LOGICAL_ADDR_MASK 0xf -#define LOGICAL_ADDR_VALID BIT(4) -#define LOGICAL_ADDR_DISABLE 0 - -#define CEC_CLK_RATE 32768 - -struct meson_ao_cec_device { - struct platform_device *pdev; - void __iomem *base; - struct clk *core; - spinlock_t cec_reg_lock; - struct cec_notifier *notify; - struct cec_adapter *adap; - struct cec_msg rx_msg; -}; - -#define writel_bits_relaxed(mask, val, addr) \ - writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr) - -static inline int meson_ao_cec_wait_busy(struct meson_ao_cec_device *ao_cec) -{ - ktime_t timeout = ktime_add_us(ktime_get(), 5000); - - while (readl_relaxed(ao_cec->base + CEC_RW_REG) & CEC_RW_BUS_BUSY) { - if (ktime_compare(ktime_get(), timeout) > 0) - return -ETIMEDOUT; - } - - return 0; -} - -static void meson_ao_cec_read(struct meson_ao_cec_device *ao_cec, - unsigned long address, u8 *data, - int *res) -{ - unsigned long flags; - u32 reg = FIELD_PREP(CEC_RW_ADDR, address); - int ret = 0; - - if (res && *res) - return; - - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - - ret = meson_ao_cec_wait_busy(ao_cec); - if (ret) - goto read_out; - - writel_relaxed(reg, ao_cec->base + CEC_RW_REG); - - ret = meson_ao_cec_wait_busy(ao_cec); - if (ret) - goto read_out; - - *data = FIELD_GET(CEC_RW_RD_DATA, - readl_relaxed(ao_cec->base + CEC_RW_REG)); - -read_out: - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - - if (res) - *res = ret; -} - -static void meson_ao_cec_write(struct meson_ao_cec_device *ao_cec, - unsigned long address, u8 data, - int *res) -{ - unsigned long flags; - u32 reg = FIELD_PREP(CEC_RW_ADDR, address) | - FIELD_PREP(CEC_RW_WR_DATA, data) | - CEC_RW_WRITE_EN; - int ret = 0; - - if (res && *res) - return; - - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - - ret = meson_ao_cec_wait_busy(ao_cec); - if (ret) - goto write_out; - - writel_relaxed(reg, ao_cec->base + CEC_RW_REG); - -write_out: - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - - if (res) - *res = ret; -} - -static inline void meson_ao_cec_irq_setup(struct meson_ao_cec_device *ao_cec, - bool enable) -{ - u32 cfg = CEC_INTR_TX | CEC_INTR_RX; - - writel_bits_relaxed(cfg, enable ? cfg : 0, - ao_cec->base + CEC_INTR_MASKN_REG); -} - -static inline int meson_ao_cec_clear(struct meson_ao_cec_device *ao_cec) -{ - int ret = 0; - - meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_DISABLE, &ret); - meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret); - meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 1, &ret); - meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 1, &ret); - if (ret) - return ret; - - udelay(100); - - meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 0, &ret); - meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 0, &ret); - if (ret) - return ret; - - udelay(100); - - meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP, &ret); - meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP, &ret); - - return ret; -} - -static int meson_ao_cec_arbit_bit_time_set(struct meson_ao_cec_device *ao_cec, - unsigned int bit_set, - unsigned int time_set) -{ - int ret = 0; - - switch (bit_set) { - case CEC_SIGNAL_FREE_TIME_RETRY: - meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT7_0, - time_set & 0xff, &ret); - meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT10_8, - (time_set >> 8) & 0x7, &ret); - break; - - case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: - meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT7_0, - time_set & 0xff, &ret); - meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT10_8, - (time_set >> 8) & 0x7, &ret); - break; - - case CEC_SIGNAL_FREE_TIME_NEXT_XFER: - meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT7_0, - time_set & 0xff, &ret); - meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT10_8, - (time_set >> 8) & 0x7, &ret); - break; - } - - return ret; -} - -static irqreturn_t meson_ao_cec_irq(int irq, void *data) -{ - struct meson_ao_cec_device *ao_cec = data; - u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG); - - if (stat) - return IRQ_WAKE_THREAD; - - return IRQ_NONE; -} - -static void meson_ao_cec_irq_tx(struct meson_ao_cec_device *ao_cec) -{ - unsigned long tx_status = 0; - u8 stat; - int ret = 0; - - meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS, &stat, &ret); - if (ret) - goto tx_reg_err; - - switch (stat) { - case TX_DONE: - tx_status = CEC_TX_STATUS_OK; - break; - - case TX_BUSY: - tx_status = CEC_TX_STATUS_ARB_LOST; - break; - - case TX_IDLE: - tx_status = CEC_TX_STATUS_LOW_DRIVE; - break; - - case TX_ERROR: - default: - tx_status = CEC_TX_STATUS_NACK; - break; - } - - /* Clear Interruption */ - writel_relaxed(CEC_INTR_TX, ao_cec->base + CEC_INTR_CLR_REG); - - /* Stop TX */ - meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP, &ret); - if (ret) - goto tx_reg_err; - - cec_transmit_attempt_done(ao_cec->adap, tx_status); - return; - -tx_reg_err: - cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); -} - -static void meson_ao_cec_irq_rx(struct meson_ao_cec_device *ao_cec) -{ - int i, ret = 0; - u8 reg; - - meson_ao_cec_read(ao_cec, CEC_RX_MSG_STATUS, ®, &ret); - if (reg != RX_DONE) - goto rx_out; - - meson_ao_cec_read(ao_cec, CEC_RX_NUM_MSG, ®, &ret); - if (reg != 1) - goto rx_out; - - meson_ao_cec_read(ao_cec, CEC_RX_MSG_LENGTH, ®, &ret); - - ao_cec->rx_msg.len = reg + 1; - if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) - ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; - - for (i = 0; i < ao_cec->rx_msg.len; i++) { - u8 byte; - - meson_ao_cec_read(ao_cec, CEC_RX_MSG_0_HEADER + i, &byte, &ret); - - ao_cec->rx_msg.msg[i] = byte; - } - - if (ret) - goto rx_out; - - cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); - -rx_out: - /* Clear Interruption */ - writel_relaxed(CEC_INTR_RX, ao_cec->base + CEC_INTR_CLR_REG); - - /* Ack RX message */ - meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_ACK_CURRENT, &ret); - meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP, &ret); - - /* Clear RX buffer */ - meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_START, &ret); - meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_STOP, &ret); -} - -static irqreturn_t meson_ao_cec_irq_thread(int irq, void *data) -{ - struct meson_ao_cec_device *ao_cec = data; - u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG); - - if (stat & CEC_INTR_TX) - meson_ao_cec_irq_tx(ao_cec); - - meson_ao_cec_irq_rx(ao_cec); - - return IRQ_HANDLED; -} - -static int meson_ao_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct meson_ao_cec_device *ao_cec = adap->priv; - int ret = 0; - - meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, - LOGICAL_ADDR_DISABLE, &ret); - if (ret) - return ret; - - ret = meson_ao_cec_clear(ao_cec); - if (ret) - return ret; - - if (logical_addr == CEC_LOG_ADDR_INVALID) - return 0; - - meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, - logical_addr & LOGICAL_ADDR_MASK, &ret); - if (ret) - return ret; - - udelay(100); - - meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, - (logical_addr & LOGICAL_ADDR_MASK) | - LOGICAL_ADDR_VALID, &ret); - - return ret; -} - -static int meson_ao_cec_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct meson_ao_cec_device *ao_cec = adap->priv; - int i, ret = 0; - u8 reg; - - meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS, ®, &ret); - if (ret) - return ret; - - if (reg == TX_BUSY) { - dev_dbg(&ao_cec->pdev->dev, "%s: busy TX: aborting\n", - __func__); - meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret); - } - - for (i = 0; i < msg->len; i++) { - meson_ao_cec_write(ao_cec, CEC_TX_MSG_0_HEADER + i, - msg->msg[i], &ret); - } - - meson_ao_cec_write(ao_cec, CEC_TX_MSG_LENGTH, msg->len - 1, &ret); - meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_REQ_CURRENT, &ret); - - return ret; -} - -static int meson_ao_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct meson_ao_cec_device *ao_cec = adap->priv; - int ret; - - meson_ao_cec_irq_setup(ao_cec, false); - - writel_bits_relaxed(CEC_GEN_CNTL_RESET, CEC_GEN_CNTL_RESET, - ao_cec->base + CEC_GEN_CNTL_REG); - - if (!enable) - return 0; - - /* Enable gated clock (Normal mode). */ - writel_bits_relaxed(CEC_GEN_CNTL_CLK_CTRL_MASK, - FIELD_PREP(CEC_GEN_CNTL_CLK_CTRL_MASK, - CEC_GEN_CNTL_CLK_ENABLE), - ao_cec->base + CEC_GEN_CNTL_REG); - - udelay(100); - - /* Release Reset */ - writel_bits_relaxed(CEC_GEN_CNTL_RESET, 0, - ao_cec->base + CEC_GEN_CNTL_REG); - - /* Clear buffers */ - ret = meson_ao_cec_clear(ao_cec); - if (ret) - return ret; - - /* CEC arbitration 3/5/7 bit time set. */ - ret = meson_ao_cec_arbit_bit_time_set(ao_cec, - CEC_SIGNAL_FREE_TIME_RETRY, - 0x118); - if (ret) - return ret; - ret = meson_ao_cec_arbit_bit_time_set(ao_cec, - CEC_SIGNAL_FREE_TIME_NEW_INITIATOR, - 0x000); - if (ret) - return ret; - ret = meson_ao_cec_arbit_bit_time_set(ao_cec, - CEC_SIGNAL_FREE_TIME_NEXT_XFER, - 0x2aa); - if (ret) - return ret; - - meson_ao_cec_irq_setup(ao_cec, true); - - return 0; -} - -static const struct cec_adap_ops meson_ao_cec_ops = { - .adap_enable = meson_ao_cec_adap_enable, - .adap_log_addr = meson_ao_cec_set_log_addr, - .adap_transmit = meson_ao_cec_transmit, -}; - -static int meson_ao_cec_probe(struct platform_device *pdev) -{ - struct meson_ao_cec_device *ao_cec; - struct device *hdmi_dev; - struct resource *res; - int ret, irq; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); - if (!ao_cec) - return -ENOMEM; - - spin_lock_init(&ao_cec->cec_reg_lock); - - ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec, - "meson_ao_cec", - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, - 1); /* Use 1 for now */ - if (IS_ERR(ao_cec->adap)) - return PTR_ERR(ao_cec->adap); - - ao_cec->adap->owner = THIS_MODULE; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ao_cec->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ao_cec->base)) { - ret = PTR_ERR(ao_cec->base); - goto out_probe_adapter; - } - - irq = platform_get_irq(pdev, 0); - ret = devm_request_threaded_irq(&pdev->dev, irq, - meson_ao_cec_irq, - meson_ao_cec_irq_thread, - 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); - goto out_probe_adapter; - } - - ao_cec->core = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(ao_cec->core)) { - dev_err(&pdev->dev, "core clock request failed\n"); - ret = PTR_ERR(ao_cec->core); - goto out_probe_adapter; - } - - ret = clk_prepare_enable(ao_cec->core); - if (ret) { - dev_err(&pdev->dev, "core clock enable failed\n"); - goto out_probe_adapter; - } - - ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE); - if (ret) { - dev_err(&pdev->dev, "core clock set rate failed\n"); - goto out_probe_clk; - } - - device_reset_optional(&pdev->dev); - - ao_cec->pdev = pdev; - platform_set_drvdata(pdev, ao_cec); - - ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL, - ao_cec->adap); - if (!ao_cec->notify) { - ret = -ENOMEM; - goto out_probe_clk; - } - - ret = cec_register_adapter(ao_cec->adap, &pdev->dev); - if (ret < 0) - goto out_probe_notify; - - /* Setup Hardware */ - writel_relaxed(CEC_GEN_CNTL_RESET, - ao_cec->base + CEC_GEN_CNTL_REG); - - return 0; - -out_probe_notify: - cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); - -out_probe_clk: - clk_disable_unprepare(ao_cec->core); - -out_probe_adapter: - cec_delete_adapter(ao_cec->adap); - - dev_err(&pdev->dev, "CEC controller registration failed\n"); - - return ret; -} - -static int meson_ao_cec_remove(struct platform_device *pdev) -{ - struct meson_ao_cec_device *ao_cec = platform_get_drvdata(pdev); - - clk_disable_unprepare(ao_cec->core); - - cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap); - cec_unregister_adapter(ao_cec->adap); - - return 0; -} - -static const struct of_device_id meson_ao_cec_of_match[] = { - { .compatible = "amlogic,meson-gx-ao-cec", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match); - -static struct platform_driver meson_ao_cec_driver = { - .probe = meson_ao_cec_probe, - .remove = meson_ao_cec_remove, - .driver = { - .name = "meson-ao-cec", - .of_match_table = of_match_ptr(meson_ao_cec_of_match), - }, -}; - -module_platform_driver(meson_ao_cec_driver); - -MODULE_DESCRIPTION("Meson AO CEC Controller driver"); -MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s5p-cec/Makefile b/drivers/media/platform/s5p-cec/Makefile deleted file mode 100644 index bd0103b91bee..000000000000 --- a/drivers/media/platform/s5p-cec/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -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 index 325db8c432bd..000000000000 --- a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* 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 - */ - -#ifndef _EXYNOS_HDMI_CEC_H_ -#define _EXYNOS_HDMI_CEC_H_ __FILE__ - -#include <linux/regmap.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 index eb981ebce362..000000000000 --- a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* 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 - */ - -#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, ®)) { - 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) & 0xf; - status |= (readb(cec->reg + S5P_CEC_TX_STAT1) & 0xf) << 4; - 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 index 447f717028a2..000000000000 --- a/drivers/media/platform/s5p-cec/regs-cec.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* drivers/media/platform/s5p-cec/regs-cec.h - * - * Copyright (c) 2010 Samsung Electronics - * http://www.samsung.com/ - * - * register header file for Samsung TVOUT driver - */ - -#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 index 2a3e7ffefe0a..000000000000 --- a/drivers/media/platform/s5p-cec/s5p_cec.c +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* drivers/media/platform/s5p-cec/s5p_cec.c - * - * Samsung S5P CEC driver - * - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * - * 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/of_platform.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> -#include <linux/timer.h> -#include <linux/workqueue.h> -#include <media/cec.h> -#include <media/cec-notifier.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 = 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_NACK) { - dev_dbg(cec->dev, "CEC_STATUS_TX_NACK set\n"); - cec->tx = STATE_NACK; - } else 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_NACK: - cec_transmit_done(cec->adap, - CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_NACK, - 0, 1, 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 *hdmi_dev; - struct resource *res; - struct s5p_cec_dev *cec; - bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd"); - int ret; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); - - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - 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_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0) | - CEC_CAP_CONNECTOR_INFO, 1); - ret = PTR_ERR_OR_ZERO(cec->adap); - if (ret) - return ret; - - cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, - cec->adap); - if (!cec->notifier) { - ret = -ENOMEM; - goto err_delete_adapter; - } - - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) - goto err_notifier; - - platform_set_drvdata(pdev, cec); - pm_runtime_enable(dev); - - dev_dbg(dev, "successfully probed\n"); - return 0; - -err_notifier: - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); - -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_notifier_cec_adap_unregister(cec->notifier, cec->adap); - 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 <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 index 34d033b20f96..000000000000 --- a/drivers/media/platform/s5p-cec/s5p_cec.h +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* drivers/media/platform/s5p-cec/s5p_cec.h - * - * Samsung S5P HDMI CEC driver - * - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - */ - -#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/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_NACK (1 << 4) -#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_NACK, - 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/media/platform/seco-cec/Makefile b/drivers/media/platform/seco-cec/Makefile deleted file mode 100644 index 79fde6947ff2..000000000000 --- a/drivers/media/platform/seco-cec/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_SECO_CEC) += seco-cec.o diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c deleted file mode 100644 index 2ff62a488b27..000000000000 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ /dev/null @@ -1,803 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * CEC driver for SECO X86 Boards - * - * Author: Ettore Chimenti <ek5.chimenti@gmail.com> - * Copyright (C) 2018, SECO SpA. - * Copyright (C) 2018, Aidilab Srl. - */ - -#include <linux/module.h> -#include <linux/acpi.h> -#include <linux/delay.h> -#include <linux/dmi.h> -#include <linux/gpio/consumer.h> -#include <linux/gpio.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/platform_device.h> - -/* CEC Framework */ -#include <media/cec-notifier.h> - -#include "seco-cec.h" - -struct secocec_data { - struct device *dev; - struct platform_device *pdev; - struct cec_adapter *cec_adap; - struct cec_notifier *notifier; - struct rc_dev *ir; - char ir_input_phys[32]; - int irq; -}; - -#define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \ - cmd, data, SMBUS_WRITE, NULL) -#define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \ - cmd, 0, SMBUS_READ, res) - -static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data, - u8 operation, u16 *result) -{ - unsigned int count; - short _data_format; - int status = 0; - - switch (data_format) { - case CMD_BYTE_DATA: - _data_format = BRA_SMB_CMD_BYTE_DATA; - break; - case CMD_WORD_DATA: - _data_format = BRA_SMB_CMD_WORD_DATA; - break; - default: - return -EINVAL; - } - - /* Active wait until ready */ - for (count = 0; count <= SMBTIMEOUT; ++count) { - if (!(inb(HSTS) & BRA_INUSE_STS)) - break; - udelay(SMB_POLL_UDELAY); - } - - if (count > SMBTIMEOUT) - /* Reset the lock instead of failing */ - outb(0xff, HSTS); - - outb(0x00, HCNT); - outb((u8)(slave_addr & 0xfe) | operation, XMIT_SLVA); - outb(cmd, HCMD); - inb(HCNT); - - if (operation == SMBUS_WRITE) { - outb((u8)data, HDAT0); - outb((u8)(data >> 8), HDAT1); - } - - outb(BRA_START + _data_format, HCNT); - - for (count = 0; count <= SMBTIMEOUT; count++) { - if (!(inb(HSTS) & BRA_HOST_BUSY)) - break; - udelay(SMB_POLL_UDELAY); - } - - if (count > SMBTIMEOUT) { - status = -EBUSY; - goto err; - } - - if (inb(HSTS) & BRA_HSTS_ERR_MASK) { - status = -EIO; - goto err; - } - - if (operation == SMBUS_READ) - *result = ((inb(HDAT0) & 0xff) + ((inb(HDAT1) & 0xff) << 8)); - -err: - outb(0xff, HSTS); - return status; -} - -static int secocec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct secocec_data *cec = cec_get_drvdata(adap); - struct device *dev = cec->dev; - u16 val = 0; - int status; - - if (enable) { - /* Clear the status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - if (status) - goto err; - - /* Enable the interrupts */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_ENABLE_REG_1, - val | SECOCEC_ENABLE_REG_1_CEC); - if (status) - goto err; - - dev_dbg(dev, "Device enabled"); - } else { - /* Clear the status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &val); - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - - /* Disable the interrupts */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); - status = smb_wr16(SECOCEC_ENABLE_REG_1, val & - ~SECOCEC_ENABLE_REG_1_CEC & - ~SECOCEC_ENABLE_REG_1_IR); - - dev_dbg(dev, "Device disabled"); - } - - return 0; -err: - return status; -} - -static int secocec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - u16 enable_val = 0; - int status; - - /* Disable device */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &enable_val); - if (status) - return status; - - status = smb_wr16(SECOCEC_ENABLE_REG_1, - enable_val & ~SECOCEC_ENABLE_REG_1_CEC); - if (status) - return status; - - /* Write logical address - * NOTE: CEC_LOG_ADDR_INVALID is mapped to the 'Unregistered' LA - */ - status = smb_wr16(SECOCEC_DEVICE_LA, logical_addr & 0xf); - if (status) - return status; - - /* Re-enable device */ - status = smb_wr16(SECOCEC_ENABLE_REG_1, - enable_val | SECOCEC_ENABLE_REG_1_CEC); - if (status) - return status; - - return 0; -} - -static int secocec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - u16 payload_len, payload_id_len, destination, val = 0; - u8 *payload_msg; - int status; - u8 i; - - /* Device msg len already accounts for header */ - payload_id_len = msg->len - 1; - - /* Send data length */ - status = smb_wr16(SECOCEC_WRITE_DATA_LENGTH, payload_id_len); - if (status) - goto err; - - /* Send Operation ID if present */ - if (payload_id_len > 0) { - status = smb_wr16(SECOCEC_WRITE_OPERATION_ID, msg->msg[1]); - if (status) - goto err; - } - /* Send data if present */ - if (payload_id_len > 1) { - /* Only data; */ - payload_len = msg->len - 2; - payload_msg = &msg->msg[2]; - - /* Copy message into registers */ - for (i = 0; i < payload_len; i += 2) { - /* hi byte */ - val = payload_msg[i + 1] << 8; - - /* lo byte */ - val |= payload_msg[i]; - - status = smb_wr16(SECOCEC_WRITE_DATA_00 + i / 2, val); - if (status) - goto err; - } - } - /* Send msg source/destination and fire msg */ - destination = msg->msg[0]; - status = smb_wr16(SECOCEC_WRITE_BYTE0, destination); - if (status) - goto err; - - return 0; - -err: - return status; -} - -static void secocec_tx_done(struct cec_adapter *adap, u16 status_val) -{ - if (status_val & SECOCEC_STATUS_TX_ERROR_MASK) { - if (status_val & SECOCEC_STATUS_TX_NACK_ERROR) - cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK); - else - cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR); - } else { - cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK); - } - - /* Reset status reg */ - status_val = SECOCEC_STATUS_TX_ERROR_MASK | - SECOCEC_STATUS_MSG_SENT_MASK | - SECOCEC_STATUS_TX_NACK_ERROR; - smb_wr16(SECOCEC_STATUS, status_val); -} - -static void secocec_rx_done(struct cec_adapter *adap, u16 status_val) -{ - struct secocec_data *cec = cec_get_drvdata(adap); - struct device *dev = cec->dev; - struct cec_msg msg = { }; - bool flag_overflow = false; - u8 payload_len, i = 0; - u8 *payload_msg; - u16 val = 0; - int status; - - if (status_val & SECOCEC_STATUS_RX_OVERFLOW_MASK) { - /* NOTE: Untested, it also might not be necessary */ - dev_warn(dev, "Received more than 16 bytes. Discarding"); - flag_overflow = true; - } - - if (status_val & SECOCEC_STATUS_RX_ERROR_MASK) { - dev_warn(dev, "Message received with errors. Discarding"); - status = -EIO; - goto rxerr; - } - - /* Read message length */ - status = smb_rd16(SECOCEC_READ_DATA_LENGTH, &val); - if (status) - return; - - /* Device msg len already accounts for the header */ - msg.len = min(val + 1, CEC_MAX_MSG_SIZE); - - /* Read logical address */ - status = smb_rd16(SECOCEC_READ_BYTE0, &val); - if (status) - return; - - /* device stores source LA and destination */ - msg.msg[0] = val; - - /* Read operation ID */ - status = smb_rd16(SECOCEC_READ_OPERATION_ID, &val); - if (status) - return; - - msg.msg[1] = val; - - /* Read data if present */ - if (msg.len > 1) { - payload_len = msg.len - 2; - payload_msg = &msg.msg[2]; - - /* device stores 2 bytes in every 16-bit val */ - for (i = 0; i < payload_len; i += 2) { - status = smb_rd16(SECOCEC_READ_DATA_00 + i / 2, &val); - if (status) - return; - - /* low byte, skipping header */ - payload_msg[i] = val & 0x00ff; - - /* hi byte */ - payload_msg[i + 1] = (val & 0xff00) >> 8; - } - } - - cec_received_msg(cec->cec_adap, &msg); - - /* Reset status reg */ - status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK; - if (flag_overflow) - status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK; - - status = smb_wr16(SECOCEC_STATUS, status_val); - - return; - -rxerr: - /* Reset error reg */ - status_val = SECOCEC_STATUS_MSG_RECEIVED_MASK | - SECOCEC_STATUS_RX_ERROR_MASK; - if (flag_overflow) - status_val |= SECOCEC_STATUS_RX_OVERFLOW_MASK; - smb_wr16(SECOCEC_STATUS, status_val); -} - -static const struct cec_adap_ops secocec_cec_adap_ops = { - /* Low-level callbacks */ - .adap_enable = secocec_adap_enable, - .adap_log_addr = secocec_adap_log_addr, - .adap_transmit = secocec_adap_transmit, -}; - -#ifdef CONFIG_VIDEO_SECO_RC -static int secocec_ir_probe(void *priv) -{ - struct secocec_data *cec = priv; - struct device *dev = cec->dev; - int status; - u16 val; - - /* Prepare the RC input device */ - cec->ir = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE); - if (!cec->ir) - return -ENOMEM; - - snprintf(cec->ir_input_phys, sizeof(cec->ir_input_phys), - "%s/input0", dev_name(dev)); - - cec->ir->device_name = dev_name(dev); - cec->ir->input_phys = cec->ir_input_phys; - cec->ir->input_id.bustype = BUS_HOST; - cec->ir->input_id.vendor = 0; - cec->ir->input_id.product = 0; - cec->ir->input_id.version = 1; - cec->ir->driver_name = SECOCEC_DEV_NAME; - cec->ir->allowed_protocols = RC_PROTO_BIT_RC5; - cec->ir->priv = cec; - cec->ir->map_name = RC_MAP_HAUPPAUGE; - cec->ir->timeout = MS_TO_NS(100); - - /* Clear the status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &val); - if (status != 0) - goto err; - - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - if (status != 0) - goto err; - - /* Enable the interrupts */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); - if (status != 0) - goto err; - - status = smb_wr16(SECOCEC_ENABLE_REG_1, - val | SECOCEC_ENABLE_REG_1_IR); - if (status != 0) - goto err; - - dev_dbg(dev, "IR enabled"); - - status = devm_rc_register_device(dev, cec->ir); - - if (status) { - dev_err(dev, "Failed to prepare input device"); - cec->ir = NULL; - goto err; - } - - return 0; - -err: - smb_rd16(SECOCEC_ENABLE_REG_1, &val); - - smb_wr16(SECOCEC_ENABLE_REG_1, - val & ~SECOCEC_ENABLE_REG_1_IR); - - dev_dbg(dev, "IR disabled"); - return status; -} - -static int secocec_ir_rx(struct secocec_data *priv) -{ - struct secocec_data *cec = priv; - struct device *dev = cec->dev; - u16 val, status, key, addr, toggle; - - if (!cec->ir) - return -ENODEV; - - status = smb_rd16(SECOCEC_IR_READ_DATA, &val); - if (status != 0) - goto err; - - key = val & SECOCEC_IR_COMMAND_MASK; - addr = (val & SECOCEC_IR_ADDRESS_MASK) >> SECOCEC_IR_ADDRESS_SHL; - toggle = (val & SECOCEC_IR_TOGGLE_MASK) >> SECOCEC_IR_TOGGLE_SHL; - - rc_keydown(cec->ir, RC_PROTO_RC5, RC_SCANCODE_RC5(addr, key), toggle); - - dev_dbg(dev, "IR key pressed: 0x%02x addr 0x%02x toggle 0x%02x", key, - addr, toggle); - - return 0; - -err: - dev_err(dev, "IR Receive message failed (%d)", status); - return -EIO; -} -#else -static void secocec_ir_rx(struct secocec_data *priv) -{ -} - -static int secocec_ir_probe(void *priv) -{ - return 0; -} -#endif - -static irqreturn_t secocec_irq_handler(int irq, void *priv) -{ - struct secocec_data *cec = priv; - struct device *dev = cec->dev; - u16 status_val, cec_val, val = 0; - int status; - - /* Read status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &status_val); - if (status) - goto err; - - if (status_val & SECOCEC_STATUS_REG_1_CEC) { - /* Read CEC status register */ - status = smb_rd16(SECOCEC_STATUS, &cec_val); - if (status) - goto err; - - if (cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK) - secocec_rx_done(cec->cec_adap, cec_val); - - if (cec_val & SECOCEC_STATUS_MSG_SENT_MASK) - secocec_tx_done(cec->cec_adap, cec_val); - - if ((~cec_val & SECOCEC_STATUS_MSG_SENT_MASK) && - (~cec_val & SECOCEC_STATUS_MSG_RECEIVED_MASK)) - dev_warn_once(dev, - "Message not received or sent, but interrupt fired"); - - val = SECOCEC_STATUS_REG_1_CEC; - } - - if (status_val & SECOCEC_STATUS_REG_1_IR) { - val |= SECOCEC_STATUS_REG_1_IR; - - secocec_ir_rx(cec); - } - - /* Reset status register */ - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - if (status) - goto err; - - return IRQ_HANDLED; - -err: - dev_err_once(dev, "IRQ: R/W SMBus operation failed (%d)", status); - - /* Reset status register */ - val = SECOCEC_STATUS_REG_1_CEC | SECOCEC_STATUS_REG_1_IR; - smb_wr16(SECOCEC_STATUS_REG_1, val); - - return IRQ_HANDLED; -} - -struct cec_dmi_match { - const char *sys_vendor; - const char *product_name; - const char *devname; - const char *conn; -}; - -static const struct cec_dmi_match secocec_dmi_match_table[] = { - /* UDOO X86 */ - { "SECO", "UDOO x86", "0000:00:02.0", "Port B" }, -}; - -static struct device *secocec_cec_find_hdmi_dev(struct device *dev, - const char **conn) -{ - int i; - - for (i = 0 ; i < ARRAY_SIZE(secocec_dmi_match_table) ; ++i) { - const struct cec_dmi_match *m = &secocec_dmi_match_table[i]; - - if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && - dmi_match(DMI_PRODUCT_NAME, m->product_name)) { - struct device *d; - - /* Find the device, bail out if not yet registered */ - d = bus_find_device_by_name(&pci_bus_type, NULL, - m->devname); - if (!d) - return ERR_PTR(-EPROBE_DEFER); - - put_device(d); - *conn = m->conn; - return d; - } - } - - return ERR_PTR(-EINVAL); -} - -static int secocec_acpi_probe(struct secocec_data *sdev) -{ - struct device *dev = sdev->dev; - struct gpio_desc *gpio; - int irq = 0; - - gpio = devm_gpiod_get(dev, NULL, GPIOF_IN); - if (IS_ERR(gpio)) { - dev_err(dev, "Cannot request interrupt gpio"); - return PTR_ERR(gpio); - } - - irq = gpiod_to_irq(gpio); - if (irq < 0) { - dev_err(dev, "Cannot find valid irq"); - return -ENODEV; - } - dev_dbg(dev, "irq-gpio is bound to IRQ %d", irq); - - sdev->irq = irq; - - return 0; -} - -static int secocec_probe(struct platform_device *pdev) -{ - struct secocec_data *secocec; - struct device *dev = &pdev->dev; - struct device *hdmi_dev; - const char *conn = NULL; - int ret; - u16 val; - - hdmi_dev = secocec_cec_find_hdmi_dev(&pdev->dev, &conn); - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL); - if (!secocec) - return -ENOMEM; - - dev_set_drvdata(dev, secocec); - - /* Request SMBus regions */ - if (!request_muxed_region(BRA_SMB_BASE_ADDR, 7, "CEC00001")) { - dev_err(dev, "Request memory region failed"); - return -ENXIO; - } - - secocec->pdev = pdev; - secocec->dev = dev; - - if (!has_acpi_companion(dev)) { - dev_dbg(dev, "Cannot find any ACPI companion"); - ret = -ENODEV; - goto err; - } - - ret = secocec_acpi_probe(secocec); - if (ret) { - dev_err(dev, "Cannot assign gpio to IRQ"); - ret = -ENODEV; - goto err; - } - - /* Firmware version check */ - ret = smb_rd16(SECOCEC_VERSION, &val); - if (ret) { - dev_err(dev, "Cannot check fw version"); - goto err; - } - if (val < SECOCEC_LATEST_FW) { - dev_err(dev, "CEC Firmware not supported (v.%04x). Use ver > v.%04x", - val, SECOCEC_LATEST_FW); - ret = -EINVAL; - goto err; - } - - ret = devm_request_threaded_irq(dev, - secocec->irq, - NULL, - secocec_irq_handler, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - dev_name(&pdev->dev), secocec); - - if (ret) { - dev_err(dev, "Cannot request IRQ %d", secocec->irq); - ret = -EIO; - goto err; - } - - /* Allocate CEC adapter */ - secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops, - secocec, - dev_name(dev), - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, - SECOCEC_MAX_ADDRS); - - if (IS_ERR(secocec->cec_adap)) { - ret = PTR_ERR(secocec->cec_adap); - goto err; - } - - secocec->notifier = cec_notifier_cec_adap_register(hdmi_dev, conn, - secocec->cec_adap); - if (!secocec->notifier) { - ret = -ENOMEM; - goto err_delete_adapter; - } - - ret = cec_register_adapter(secocec->cec_adap, dev); - if (ret) - goto err_notifier; - - ret = secocec_ir_probe(secocec); - if (ret) - goto err_notifier; - - platform_set_drvdata(pdev, secocec); - - dev_dbg(dev, "Device registered"); - - return ret; - -err_notifier: - cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap); -err_delete_adapter: - cec_delete_adapter(secocec->cec_adap); -err: - release_region(BRA_SMB_BASE_ADDR, 7); - dev_err(dev, "%s device probe failed\n", dev_name(dev)); - - return ret; -} - -static int secocec_remove(struct platform_device *pdev) -{ - struct secocec_data *secocec = platform_get_drvdata(pdev); - u16 val; - - if (secocec->ir) { - smb_rd16(SECOCEC_ENABLE_REG_1, &val); - - smb_wr16(SECOCEC_ENABLE_REG_1, val & ~SECOCEC_ENABLE_REG_1_IR); - - dev_dbg(&pdev->dev, "IR disabled"); - } - cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap); - cec_unregister_adapter(secocec->cec_adap); - - release_region(BRA_SMB_BASE_ADDR, 7); - - dev_dbg(&pdev->dev, "CEC device removed"); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int secocec_suspend(struct device *dev) -{ - int status; - u16 val; - - dev_dbg(dev, "Device going to suspend, disabling"); - - /* Clear the status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - if (status) - goto err; - - /* Disable the interrupts */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_ENABLE_REG_1, val & - ~SECOCEC_ENABLE_REG_1_CEC & ~SECOCEC_ENABLE_REG_1_IR); - if (status) - goto err; - - return 0; - -err: - dev_err(dev, "Suspend failed (err: %d)", status); - return status; -} - -static int secocec_resume(struct device *dev) -{ - int status; - u16 val; - - dev_dbg(dev, "Resuming device from suspend"); - - /* Clear the status register */ - status = smb_rd16(SECOCEC_STATUS_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_STATUS_REG_1, val); - if (status) - goto err; - - /* Enable the interrupts */ - status = smb_rd16(SECOCEC_ENABLE_REG_1, &val); - if (status) - goto err; - - status = smb_wr16(SECOCEC_ENABLE_REG_1, val | SECOCEC_ENABLE_REG_1_CEC); - if (status) - goto err; - - dev_dbg(dev, "Device resumed from suspend"); - - return 0; - -err: - dev_err(dev, "Resume failed (err: %d)", status); - return status; -} - -static SIMPLE_DEV_PM_OPS(secocec_pm_ops, secocec_suspend, secocec_resume); -#define SECOCEC_PM_OPS (&secocec_pm_ops) -#else -#define SECOCEC_PM_OPS NULL -#endif - -#ifdef CONFIG_ACPI -static const struct acpi_device_id secocec_acpi_match[] = { - {"CEC00001", 0}, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, secocec_acpi_match); -#endif - -static struct platform_driver secocec_driver = { - .driver = { - .name = SECOCEC_DEV_NAME, - .acpi_match_table = ACPI_PTR(secocec_acpi_match), - .pm = SECOCEC_PM_OPS, - }, - .probe = secocec_probe, - .remove = secocec_remove, -}; - -module_platform_driver(secocec_driver); - -MODULE_DESCRIPTION("SECO CEC X86 Driver"); -MODULE_AUTHOR("Ettore Chimenti <ek5.chimenti@gmail.com>"); -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/media/platform/seco-cec/seco-cec.h b/drivers/media/platform/seco-cec/seco-cec.h deleted file mode 100644 index 843de8c7dfd4..000000000000 --- a/drivers/media/platform/seco-cec/seco-cec.h +++ /dev/null @@ -1,141 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* - * SECO X86 Boards CEC register defines - * - * Author: Ettore Chimenti <ek5.chimenti@gmail.com> - * Copyright (C) 2018, SECO Spa. - * Copyright (C) 2018, Aidilab Srl. - */ - -#ifndef __SECO_CEC_H__ -#define __SECO_CEC_H__ - -#define SECOCEC_MAX_ADDRS 1 -#define SECOCEC_DEV_NAME "secocec" -#define SECOCEC_LATEST_FW 0x0f0b - -#define SMBTIMEOUT 0xfff -#define SMB_POLL_UDELAY 10 - -#define SMBUS_WRITE 0 -#define SMBUS_READ 1 - -#define CMD_BYTE_DATA 0 -#define CMD_WORD_DATA 1 - -/* - * SMBus definitons for Braswell - */ - -#define BRA_DONE_STATUS BIT(7) -#define BRA_INUSE_STS BIT(6) -#define BRA_FAILED_OP BIT(4) -#define BRA_BUS_ERR BIT(3) -#define BRA_DEV_ERR BIT(2) -#define BRA_INTR BIT(1) -#define BRA_HOST_BUSY BIT(0) -#define BRA_HSTS_ERR_MASK (BRA_FAILED_OP | BRA_BUS_ERR | BRA_DEV_ERR) - -#define BRA_PEC_EN BIT(7) -#define BRA_START BIT(6) -#define BRA_LAST__BYTE BIT(5) -#define BRA_INTREN BIT(0) -#define BRA_SMB_CMD (7 << 2) -#define BRA_SMB_CMD_QUICK (0 << 2) -#define BRA_SMB_CMD_BYTE (1 << 2) -#define BRA_SMB_CMD_BYTE_DATA (2 << 2) -#define BRA_SMB_CMD_WORD_DATA (3 << 2) -#define BRA_SMB_CMD_PROCESS_CALL (4 << 2) -#define BRA_SMB_CMD_BLOCK (5 << 2) -#define BRA_SMB_CMD_I2CREAD (6 << 2) -#define BRA_SMB_CMD_BLOCK_PROCESS (7 << 2) - -#define BRA_SMB_BASE_ADDR 0x2040 -#define HSTS (BRA_SMB_BASE_ADDR + 0) -#define HCNT (BRA_SMB_BASE_ADDR + 2) -#define HCMD (BRA_SMB_BASE_ADDR + 3) -#define XMIT_SLVA (BRA_SMB_BASE_ADDR + 4) -#define HDAT0 (BRA_SMB_BASE_ADDR + 5) -#define HDAT1 (BRA_SMB_BASE_ADDR + 6) - -/* - * Microcontroller Address - */ - -#define SECOCEC_MICRO_ADDRESS 0x40 - -/* - * STM32 SMBus Registers - */ - -#define SECOCEC_VERSION 0x00 -#define SECOCEC_ENABLE_REG_1 0x01 -#define SECOCEC_ENABLE_REG_2 0x02 -#define SECOCEC_STATUS_REG_1 0x03 -#define SECOCEC_STATUS_REG_2 0x04 - -#define SECOCEC_STATUS 0x28 -#define SECOCEC_DEVICE_LA 0x29 -#define SECOCEC_READ_OPERATION_ID 0x2a -#define SECOCEC_READ_DATA_LENGTH 0x2b -#define SECOCEC_READ_DATA_00 0x2c -#define SECOCEC_READ_DATA_02 0x2d -#define SECOCEC_READ_DATA_04 0x2e -#define SECOCEC_READ_DATA_06 0x2f -#define SECOCEC_READ_DATA_08 0x30 -#define SECOCEC_READ_DATA_10 0x31 -#define SECOCEC_READ_DATA_12 0x32 -#define SECOCEC_READ_BYTE0 0x33 -#define SECOCEC_WRITE_OPERATION_ID 0x34 -#define SECOCEC_WRITE_DATA_LENGTH 0x35 -#define SECOCEC_WRITE_DATA_00 0x36 -#define SECOCEC_WRITE_DATA_02 0x37 -#define SECOCEC_WRITE_DATA_04 0x38 -#define SECOCEC_WRITE_DATA_06 0x39 -#define SECOCEC_WRITE_DATA_08 0x3a -#define SECOCEC_WRITE_DATA_10 0x3b -#define SECOCEC_WRITE_DATA_12 0x3c -#define SECOCEC_WRITE_BYTE0 0x3d - -#define SECOCEC_IR_READ_DATA 0x3e - -/* - * IR - */ - -#define SECOCEC_IR_COMMAND_MASK 0x007F -#define SECOCEC_IR_COMMAND_SHL 0 -#define SECOCEC_IR_ADDRESS_MASK 0x1F00 -#define SECOCEC_IR_ADDRESS_SHL 8 -#define SECOCEC_IR_TOGGLE_MASK 0x8000 -#define SECOCEC_IR_TOGGLE_SHL 15 - -/* - * Enabling register - */ - -#define SECOCEC_ENABLE_REG_1_CEC 0x1000 -#define SECOCEC_ENABLE_REG_1_IR 0x2000 -#define SECOCEC_ENABLE_REG_1_IR_PASSTHROUGH 0x4000 - -/* - * Status register - */ - -#define SECOCEC_STATUS_REG_1_CEC SECOCEC_ENABLE_REG_1_CEC -#define SECOCEC_STATUS_REG_1_IR SECOCEC_ENABLE_REG_1_IR -#define SECOCEC_STATUS_REG_1_IR_PASSTHR SECOCEC_ENABLE_REG_1_IR_PASSTHR - -/* - * Status data - */ - -#define SECOCEC_STATUS_MSG_RECEIVED_MASK BIT(0) -#define SECOCEC_STATUS_RX_ERROR_MASK BIT(1) -#define SECOCEC_STATUS_MSG_SENT_MASK BIT(2) -#define SECOCEC_STATUS_TX_ERROR_MASK BIT(3) - -#define SECOCEC_STATUS_TX_NACK_ERROR BIT(4) -#define SECOCEC_STATUS_RX_OVERFLOW_MASK BIT(5) - -#endif /* __SECO_CEC_H__ */ diff --git a/drivers/media/platform/sti/cec/Makefile b/drivers/media/platform/sti/cec/Makefile deleted file mode 100644 index d0c6b4ae94d6..000000000000 --- a/drivers/media/platform/sti/cec/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += stih-cec.o diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c deleted file mode 100644 index f0c73e64b586..000000000000 --- a/drivers/media/platform/sti/cec/stih-cec.c +++ /dev/null @@ -1,400 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * STIH4xx CEC driver - * Copyright (C) STMicroelectronics SA 2016 - * - */ -#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/of_platform.h> -#include <linux/platform_device.h> - -#include <media/cec.h> -#include <media/cec-notifier.h> - -#define CEC_NAME "stih-cec" - -/* CEC registers */ -#define CEC_CLK_DIV 0x0 -#define CEC_CTRL 0x4 -#define CEC_IRQ_CTRL 0x8 -#define CEC_STATUS 0xC -#define CEC_EXT_STATUS 0x10 -#define CEC_TX_CTRL 0x14 -#define CEC_FREE_TIME_THRESH 0x18 -#define CEC_BIT_TOUT_THRESH 0x1C -#define CEC_BIT_PULSE_THRESH 0x20 -#define CEC_DATA 0x24 -#define CEC_TX_ARRAY_CTRL 0x28 -#define CEC_CTRL2 0x2C -#define CEC_TX_ERROR_STS 0x30 -#define CEC_ADDR_TABLE 0x34 -#define CEC_DATA_ARRAY_CTRL 0x38 -#define CEC_DATA_ARRAY_STATUS 0x3C -#define CEC_TX_DATA_BASE 0x40 -#define CEC_TX_DATA_TOP 0x50 -#define CEC_TX_DATA_SIZE 0x1 -#define CEC_RX_DATA_BASE 0x54 -#define CEC_RX_DATA_TOP 0x64 -#define CEC_RX_DATA_SIZE 0x1 - -/* CEC_CTRL2 */ -#define CEC_LINE_INACTIVE_EN BIT(0) -#define CEC_AUTO_BUS_ERR_EN BIT(1) -#define CEC_STOP_ON_ARB_ERR_EN BIT(2) -#define CEC_TX_REQ_WAIT_EN BIT(3) - -/* CEC_DATA_ARRAY_CTRL */ -#define CEC_TX_ARRAY_EN BIT(0) -#define CEC_RX_ARRAY_EN BIT(1) -#define CEC_TX_ARRAY_RESET BIT(2) -#define CEC_RX_ARRAY_RESET BIT(3) -#define CEC_TX_N_OF_BYTES_IRQ_EN BIT(4) -#define CEC_TX_STOP_ON_NACK BIT(7) - -/* CEC_TX_ARRAY_CTRL */ -#define CEC_TX_N_OF_BYTES 0x1F -#define CEC_TX_START BIT(5) -#define CEC_TX_AUTO_SOM_EN BIT(6) -#define CEC_TX_AUTO_EOM_EN BIT(7) - -/* CEC_IRQ_CTRL */ -#define CEC_TX_DONE_IRQ_EN BIT(0) -#define CEC_ERROR_IRQ_EN BIT(2) -#define CEC_RX_DONE_IRQ_EN BIT(3) -#define CEC_RX_SOM_IRQ_EN BIT(4) -#define CEC_RX_EOM_IRQ_EN BIT(5) -#define CEC_FREE_TIME_IRQ_EN BIT(6) -#define CEC_PIN_STS_IRQ_EN BIT(7) - -/* CEC_CTRL */ -#define CEC_IN_FILTER_EN BIT(0) -#define CEC_PWR_SAVE_EN BIT(1) -#define CEC_EN BIT(4) -#define CEC_ACK_CTRL BIT(5) -#define CEC_RX_RESET_EN BIT(6) -#define CEC_IGNORE_RX_ERROR BIT(7) - -/* CEC_STATUS */ -#define CEC_TX_DONE_STS BIT(0) -#define CEC_TX_ACK_GET_STS BIT(1) -#define CEC_ERROR_STS BIT(2) -#define CEC_RX_DONE_STS BIT(3) -#define CEC_RX_SOM_STS BIT(4) -#define CEC_RX_EOM_STS BIT(5) -#define CEC_FREE_TIME_IRQ_STS BIT(6) -#define CEC_PIN_STS BIT(7) -#define CEC_SBIT_TOUT_STS BIT(8) -#define CEC_DBIT_TOUT_STS BIT(9) -#define CEC_LPULSE_ERROR_STS BIT(10) -#define CEC_HPULSE_ERROR_STS BIT(11) -#define CEC_TX_ERROR BIT(12) -#define CEC_TX_ARB_ERROR BIT(13) -#define CEC_RX_ERROR_MIN BIT(14) -#define CEC_RX_ERROR_MAX BIT(15) - -/* Signal free time in bit periods (2.4ms) */ -#define CEC_PRESENT_INIT_SFT 7 -#define CEC_NEW_INIT_SFT 5 -#define CEC_RETRANSMIT_SFT 3 - -/* Constants for CEC_BIT_TOUT_THRESH register */ -#define CEC_SBIT_TOUT_47MS BIT(1) -#define CEC_SBIT_TOUT_48MS (BIT(0) | BIT(1)) -#define CEC_SBIT_TOUT_50MS BIT(2) -#define CEC_DBIT_TOUT_27MS BIT(0) -#define CEC_DBIT_TOUT_28MS BIT(1) -#define CEC_DBIT_TOUT_29MS (BIT(0) | BIT(1)) - -/* Constants for CEC_BIT_PULSE_THRESH register */ -#define CEC_BIT_LPULSE_03MS BIT(1) -#define CEC_BIT_HPULSE_03MS BIT(3) - -/* Constants for CEC_DATA_ARRAY_STATUS register */ -#define CEC_RX_N_OF_BYTES 0x1F -#define CEC_TX_N_OF_BYTES_SENT BIT(5) -#define CEC_RX_OVERRUN BIT(6) - -struct stih_cec { - struct cec_adapter *adap; - struct device *dev; - struct clk *clk; - void __iomem *regs; - int irq; - u32 irq_status; - struct cec_notifier *notifier; -}; - -static int stih_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct stih_cec *cec = cec_get_drvdata(adap); - - if (enable) { - /* The doc says (input TCLK_PERIOD * CEC_CLK_DIV) = 0.1ms */ - unsigned long clk_freq = clk_get_rate(cec->clk); - u32 cec_clk_div = clk_freq / 10000; - - writel(cec_clk_div, cec->regs + CEC_CLK_DIV); - - /* Configuration of the durations activating a timeout */ - writel(CEC_SBIT_TOUT_47MS | (CEC_DBIT_TOUT_28MS << 4), - cec->regs + CEC_BIT_TOUT_THRESH); - - /* Configuration of the smallest allowed duration for pulses */ - writel(CEC_BIT_LPULSE_03MS | CEC_BIT_HPULSE_03MS, - cec->regs + CEC_BIT_PULSE_THRESH); - - /* Minimum received bit period threshold */ - writel(BIT(5) | BIT(7), cec->regs + CEC_TX_CTRL); - - /* Configuration of transceiver data arrays */ - writel(CEC_TX_ARRAY_EN | CEC_RX_ARRAY_EN | CEC_TX_STOP_ON_NACK, - cec->regs + CEC_DATA_ARRAY_CTRL); - - /* Configuration of the control bits for CEC Transceiver */ - writel(CEC_IN_FILTER_EN | CEC_EN | CEC_RX_RESET_EN, - cec->regs + CEC_CTRL); - - /* Clear logical addresses */ - writel(0, cec->regs + CEC_ADDR_TABLE); - - /* Clear the status register */ - writel(0x0, cec->regs + CEC_STATUS); - - /* Enable the interrupts */ - writel(CEC_TX_DONE_IRQ_EN | CEC_RX_DONE_IRQ_EN | - CEC_RX_SOM_IRQ_EN | CEC_RX_EOM_IRQ_EN | - CEC_ERROR_IRQ_EN, - cec->regs + CEC_IRQ_CTRL); - - } else { - /* Clear logical addresses */ - writel(0, cec->regs + CEC_ADDR_TABLE); - - /* Clear the status register */ - writel(0x0, cec->regs + CEC_STATUS); - - /* Disable the interrupts */ - writel(0, cec->regs + CEC_IRQ_CTRL); - } - - return 0; -} - -static int stih_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct stih_cec *cec = cec_get_drvdata(adap); - u32 reg = readl(cec->regs + CEC_ADDR_TABLE); - - reg |= 1 << logical_addr; - - if (logical_addr == CEC_LOG_ADDR_INVALID) - reg = 0; - - writel(reg, cec->regs + CEC_ADDR_TABLE); - - return 0; -} - -static int stih_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct stih_cec *cec = cec_get_drvdata(adap); - int i; - - /* Copy message into registers */ - for (i = 0; i < msg->len; i++) - writeb(msg->msg[i], cec->regs + CEC_TX_DATA_BASE + i); - - /* - * Start transmission, configure hardware to add start and stop bits - * Signal free time is handled by the hardware - */ - writel(CEC_TX_AUTO_SOM_EN | CEC_TX_AUTO_EOM_EN | CEC_TX_START | - msg->len, cec->regs + CEC_TX_ARRAY_CTRL); - - return 0; -} - -static void stih_tx_done(struct stih_cec *cec, u32 status) -{ - if (status & CEC_TX_ERROR) { - cec_transmit_attempt_done(cec->adap, CEC_TX_STATUS_ERROR); - return; - } - - if (status & CEC_TX_ARB_ERROR) { - cec_transmit_attempt_done(cec->adap, CEC_TX_STATUS_ARB_LOST); - return; - } - - if (!(status & CEC_TX_ACK_GET_STS)) { - cec_transmit_attempt_done(cec->adap, CEC_TX_STATUS_NACK); - return; - } - - cec_transmit_attempt_done(cec->adap, CEC_TX_STATUS_OK); -} - -static void stih_rx_done(struct stih_cec *cec, u32 status) -{ - struct cec_msg msg = {}; - u8 i; - - if (status & CEC_RX_ERROR_MIN) - return; - - if (status & CEC_RX_ERROR_MAX) - return; - - msg.len = readl(cec->regs + CEC_DATA_ARRAY_STATUS) & 0x1f; - - if (!msg.len) - return; - - if (msg.len > 16) - msg.len = 16; - - for (i = 0; i < msg.len; i++) - msg.msg[i] = readl(cec->regs + CEC_RX_DATA_BASE + i); - - cec_received_msg(cec->adap, &msg); -} - -static irqreturn_t stih_cec_irq_handler_thread(int irq, void *priv) -{ - struct stih_cec *cec = priv; - - if (cec->irq_status & CEC_TX_DONE_STS) - stih_tx_done(cec, cec->irq_status); - - if (cec->irq_status & CEC_RX_DONE_STS) - stih_rx_done(cec, cec->irq_status); - - cec->irq_status = 0; - - return IRQ_HANDLED; -} - -static irqreturn_t stih_cec_irq_handler(int irq, void *priv) -{ - struct stih_cec *cec = priv; - - cec->irq_status = readl(cec->regs + CEC_STATUS); - writel(cec->irq_status, cec->regs + CEC_STATUS); - - return IRQ_WAKE_THREAD; -} - -static const struct cec_adap_ops sti_cec_adap_ops = { - .adap_enable = stih_cec_adap_enable, - .adap_log_addr = stih_cec_adap_log_addr, - .adap_transmit = stih_cec_adap_transmit, -}; - -static int stih_cec_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - struct stih_cec *cec; - struct device *hdmi_dev; - int ret; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); - - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); - if (!cec) - return -ENOMEM; - - cec->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cec->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(cec->regs)) - return PTR_ERR(cec->regs); - - cec->irq = platform_get_irq(pdev, 0); - if (cec->irq < 0) - return cec->irq; - - ret = devm_request_threaded_irq(dev, cec->irq, stih_cec_irq_handler, - stih_cec_irq_handler_thread, 0, - pdev->name, cec); - if (ret) - return ret; - - cec->clk = devm_clk_get(dev, "cec-clk"); - if (IS_ERR(cec->clk)) { - dev_err(dev, "Cannot get cec clock\n"); - return PTR_ERR(cec->clk); - } - - cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, CEC_NAME, - CEC_CAP_DEFAULTS | - CEC_CAP_CONNECTOR_INFO, - CEC_MAX_LOG_ADDRS); - ret = PTR_ERR_OR_ZERO(cec->adap); - if (ret) - return ret; - - cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, - cec->adap); - if (!cec->notifier) { - ret = -ENOMEM; - goto err_delete_adapter; - } - - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) - goto err_notifier; - - platform_set_drvdata(pdev, cec); - return 0; - -err_notifier: - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); - -err_delete_adapter: - cec_delete_adapter(cec->adap); - return ret; -} - -static int stih_cec_remove(struct platform_device *pdev) -{ - struct stih_cec *cec = platform_get_drvdata(pdev); - - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); - cec_unregister_adapter(cec->adap); - - return 0; -} - -static const struct of_device_id stih_cec_match[] = { - { - .compatible = "st,stih-cec", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, stih_cec_match); - -static struct platform_driver stih_cec_pdrv = { - .probe = stih_cec_probe, - .remove = stih_cec_remove, - .driver = { - .name = CEC_NAME, - .of_match_table = stih_cec_match, - }, -}; - -module_platform_driver(stih_cec_pdrv); - -MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@linaro.org>"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("STIH4xx CEC driver"); diff --git a/drivers/media/platform/stm32/Makefile b/drivers/media/platform/stm32/Makefile index 5ed73599ca44..48b36db2c2e2 100644 --- a/drivers/media/platform/stm32/Makefile +++ b/drivers/media/platform/stm32/Makefile @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32-dcmi.o -obj-$(CONFIG_VIDEO_STM32_HDMI_CEC) += stm32-cec.o diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c deleted file mode 100644 index ea4b1ebfca99..000000000000 --- a/drivers/media/platform/stm32/stm32-cec.c +++ /dev/null @@ -1,374 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * STM32 CEC driver - * Copyright (C) STMicroelectronics SA 2017 - * - */ - -#include <linux/clk.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/regmap.h> - -#include <media/cec.h> - -#define CEC_NAME "stm32-cec" - -/* CEC registers */ -#define CEC_CR 0x0000 /* Control Register */ -#define CEC_CFGR 0x0004 /* ConFiGuration Register */ -#define CEC_TXDR 0x0008 /* Rx data Register */ -#define CEC_RXDR 0x000C /* Rx data Register */ -#define CEC_ISR 0x0010 /* Interrupt and status Register */ -#define CEC_IER 0x0014 /* Interrupt enable Register */ - -#define TXEOM BIT(2) -#define TXSOM BIT(1) -#define CECEN BIT(0) - -#define LSTN BIT(31) -#define OAR GENMASK(30, 16) -#define SFTOP BIT(8) -#define BRDNOGEN BIT(7) -#define LBPEGEN BIT(6) -#define BREGEN BIT(5) -#define BRESTP BIT(4) -#define RXTOL BIT(3) -#define SFT GENMASK(2, 0) -#define FULL_CFG (LSTN | SFTOP | BRDNOGEN | LBPEGEN | BREGEN | BRESTP \ - | RXTOL) - -#define TXACKE BIT(12) -#define TXERR BIT(11) -#define TXUDR BIT(10) -#define TXEND BIT(9) -#define TXBR BIT(8) -#define ARBLST BIT(7) -#define RXACKE BIT(6) -#define RXOVR BIT(2) -#define RXEND BIT(1) -#define RXBR BIT(0) - -#define ALL_TX_IT (TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST) -#define ALL_RX_IT (RXEND | RXBR | RXACKE | RXOVR) - -/* - * 400 ms is the time it takes for one 16 byte message to be - * transferred and 5 is the maximum number of retries. Add - * another 100 ms as a margin. - */ -#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) - -struct stm32_cec { - struct cec_adapter *adap; - struct device *dev; - struct clk *clk_cec; - struct clk *clk_hdmi_cec; - struct reset_control *rstc; - struct regmap *regmap; - int irq; - u32 irq_status; - struct cec_msg rx_msg; - struct cec_msg tx_msg; - int tx_cnt; -}; - -static void cec_hw_init(struct stm32_cec *cec) -{ - regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0); - - regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT, - ALL_TX_IT | ALL_RX_IT); - - regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG); -} - -static void stm32_tx_done(struct stm32_cec *cec, u32 status) -{ - if (status & (TXERR | TXUDR)) { - cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR, - 0, 0, 0, 1); - return; - } - - if (status & ARBLST) { - cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST, - 1, 0, 0, 0); - return; - } - - if (status & TXACKE) { - cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK, - 0, 1, 0, 0); - return; - } - - if (cec->irq_status & TXBR) { - /* send next byte */ - if (cec->tx_cnt < cec->tx_msg.len) - regmap_write(cec->regmap, CEC_TXDR, - cec->tx_msg.msg[cec->tx_cnt++]); - - /* TXEOM is set to command transmission of the last byte */ - if (cec->tx_cnt == cec->tx_msg.len) - regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM); - } - - if (cec->irq_status & TXEND) - cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); -} - -static void stm32_rx_done(struct stm32_cec *cec, u32 status) -{ - if (cec->irq_status & (RXACKE | RXOVR)) { - cec->rx_msg.len = 0; - return; - } - - if (cec->irq_status & RXBR) { - u32 val; - - regmap_read(cec->regmap, CEC_RXDR, &val); - cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF; - } - - if (cec->irq_status & RXEND) { - cec_received_msg(cec->adap, &cec->rx_msg); - cec->rx_msg.len = 0; - } -} - -static irqreturn_t stm32_cec_irq_thread(int irq, void *arg) -{ - struct stm32_cec *cec = arg; - - if (cec->irq_status & ALL_TX_IT) - stm32_tx_done(cec, cec->irq_status); - - if (cec->irq_status & ALL_RX_IT) - stm32_rx_done(cec, cec->irq_status); - - cec->irq_status = 0; - - return IRQ_HANDLED; -} - -static irqreturn_t stm32_cec_irq_handler(int irq, void *arg) -{ - struct stm32_cec *cec = arg; - - regmap_read(cec->regmap, CEC_ISR, &cec->irq_status); - - regmap_update_bits(cec->regmap, CEC_ISR, - ALL_TX_IT | ALL_RX_IT, - ALL_TX_IT | ALL_RX_IT); - - return IRQ_WAKE_THREAD; -} - -static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct stm32_cec *cec = adap->priv; - int ret = 0; - - if (enable) { - ret = clk_enable(cec->clk_cec); - if (ret) - dev_err(cec->dev, "fail to enable cec clock\n"); - - clk_enable(cec->clk_hdmi_cec); - regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN); - } else { - clk_disable(cec->clk_cec); - clk_disable(cec->clk_hdmi_cec); - regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); - } - - return ret; -} - -static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct stm32_cec *cec = adap->priv; - u32 oar = (1 << logical_addr) << 16; - u32 val; - - /* Poll every 100µs the register CEC_CR to wait end of transmission */ - regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), - 100, CEC_XFER_TIMEOUT_MS * 1000); - regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); - - if (logical_addr == CEC_LOG_ADDR_INVALID) - regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0); - else - regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar); - - regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN); - - return 0; -} - -static int stm32_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct stm32_cec *cec = adap->priv; - - /* Copy message */ - cec->tx_msg = *msg; - cec->tx_cnt = 0; - - /* - * If the CEC message consists of only one byte, - * TXEOM must be set before of TXSOM. - */ - if (cec->tx_msg.len == 1) - regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM); - - /* TXSOM is set to command transmission of the first byte */ - regmap_update_bits(cec->regmap, CEC_CR, TXSOM, TXSOM); - - /* Write the header (first byte of message) */ - regmap_write(cec->regmap, CEC_TXDR, cec->tx_msg.msg[0]); - cec->tx_cnt++; - - return 0; -} - -static const struct cec_adap_ops stm32_cec_adap_ops = { - .adap_enable = stm32_cec_adap_enable, - .adap_log_addr = stm32_cec_adap_log_addr, - .adap_transmit = stm32_cec_adap_transmit, -}; - -static const struct regmap_config stm32_cec_regmap_cfg = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = sizeof(u32), - .max_register = 0x14, - .fast_io = true, -}; - -static int stm32_cec_probe(struct platform_device *pdev) -{ - u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_MODE_MONITOR_ALL; - struct resource *res; - struct stm32_cec *cec; - void __iomem *mmio; - int ret; - - cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); - if (!cec) - return -ENOMEM; - - cec->dev = &pdev->dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mmio)) - return PTR_ERR(mmio); - - cec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "cec", mmio, - &stm32_cec_regmap_cfg); - - if (IS_ERR(cec->regmap)) - return PTR_ERR(cec->regmap); - - cec->irq = platform_get_irq(pdev, 0); - if (cec->irq < 0) - return cec->irq; - - ret = devm_request_threaded_irq(&pdev->dev, cec->irq, - stm32_cec_irq_handler, - stm32_cec_irq_thread, - 0, - pdev->name, cec); - if (ret) - return ret; - - cec->clk_cec = devm_clk_get(&pdev->dev, "cec"); - if (IS_ERR(cec->clk_cec)) { - if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER) - dev_err(&pdev->dev, "Cannot get cec clock\n"); - - return PTR_ERR(cec->clk_cec); - } - - ret = clk_prepare(cec->clk_cec); - if (ret) { - dev_err(&pdev->dev, "Unable to prepare cec clock\n"); - return ret; - } - - cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec"); - if (IS_ERR(cec->clk_hdmi_cec) && - PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!IS_ERR(cec->clk_hdmi_cec)) { - ret = clk_prepare(cec->clk_hdmi_cec); - if (ret) { - dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n"); - return ret; - } - } - - /* - * CEC_CAP_PHYS_ADDR caps should be removed when a cec notifier is - * available for example when a drm driver can provide edid - */ - cec->adap = cec_allocate_adapter(&stm32_cec_adap_ops, cec, - CEC_NAME, caps, CEC_MAX_LOG_ADDRS); - ret = PTR_ERR_OR_ZERO(cec->adap); - if (ret) - return ret; - - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; - } - - cec_hw_init(cec); - - platform_set_drvdata(pdev, cec); - - return 0; -} - -static int stm32_cec_remove(struct platform_device *pdev) -{ - struct stm32_cec *cec = platform_get_drvdata(pdev); - - clk_unprepare(cec->clk_cec); - clk_unprepare(cec->clk_hdmi_cec); - - cec_unregister_adapter(cec->adap); - - return 0; -} - -static const struct of_device_id stm32_cec_of_match[] = { - { .compatible = "st,stm32-cec" }, - { /* end node */ } -}; -MODULE_DEVICE_TABLE(of, stm32_cec_of_match); - -static struct platform_driver stm32_cec_driver = { - .probe = stm32_cec_probe, - .remove = stm32_cec_remove, - .driver = { - .name = CEC_NAME, - .of_match_table = stm32_cec_of_match, - }, -}; - -module_platform_driver(stm32_cec_driver); - -MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); -MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); -MODULE_DESCRIPTION("STMicroelectronics STM32 Consumer Electronics Control"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/tegra-cec/Makefile b/drivers/media/platform/tegra-cec/Makefile deleted file mode 100644 index 97e57c7493c0..000000000000 --- a/drivers/media/platform/tegra-cec/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra_cec.o diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c deleted file mode 100644 index 1ac0c70a5981..000000000000 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ /dev/null @@ -1,481 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Tegra CEC implementation - * - * The original 3.10 CEC driver using a custom API: - * - * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. - * - * Conversion to the CEC framework and to the mainline kernel: - * - * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/of.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> -#include <linux/clk/tegra.h> - -#include <media/cec-notifier.h> - -#include "tegra_cec.h" - -#define TEGRA_CEC_NAME "tegra-cec" - -struct tegra_cec { - struct cec_adapter *adap; - struct device *dev; - struct clk *clk; - void __iomem *cec_base; - struct cec_notifier *notifier; - int tegra_cec_irq; - bool rx_done; - bool tx_done; - int tx_status; - u8 rx_buf[CEC_MAX_MSG_SIZE]; - u8 rx_buf_cnt; - u32 tx_buf[CEC_MAX_MSG_SIZE]; - u8 tx_buf_cur; - u8 tx_buf_cnt; -}; - -static inline u32 cec_read(struct tegra_cec *cec, u32 reg) -{ - return readl(cec->cec_base + reg); -} - -static inline void cec_write(struct tegra_cec *cec, u32 reg, u32 val) -{ - writel(val, cec->cec_base + reg); -} - -static void tegra_cec_error_recovery(struct tegra_cec *cec) -{ - u32 hw_ctrl; - - hw_ctrl = cec_read(cec, TEGRA_CEC_HW_CONTROL); - cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); - cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); - cec_write(cec, TEGRA_CEC_HW_CONTROL, hw_ctrl); -} - -static irqreturn_t tegra_cec_irq_thread_handler(int irq, void *data) -{ - struct device *dev = data; - struct tegra_cec *cec = dev_get_drvdata(dev); - - if (cec->tx_done) { - cec_transmit_attempt_done(cec->adap, cec->tx_status); - cec->tx_done = false; - } - if (cec->rx_done) { - struct cec_msg msg = {}; - - msg.len = cec->rx_buf_cnt; - memcpy(msg.msg, cec->rx_buf, msg.len); - cec_received_msg(cec->adap, &msg); - cec->rx_done = false; - cec->rx_buf_cnt = 0; - } - return IRQ_HANDLED; -} - -static irqreturn_t tegra_cec_irq_handler(int irq, void *data) -{ - struct device *dev = data; - struct tegra_cec *cec = dev_get_drvdata(dev); - u32 status, mask; - - status = cec_read(cec, TEGRA_CEC_INT_STAT); - mask = cec_read(cec, TEGRA_CEC_INT_MASK); - - status &= mask; - - if (!status) - return IRQ_HANDLED; - - if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) { - dev_err(dev, "TX underrun, interrupt timing issue!\n"); - - tegra_cec_error_recovery(cec); - cec_write(cec, TEGRA_CEC_INT_MASK, - mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); - - cec->tx_done = true; - cec->tx_status = CEC_TX_STATUS_ERROR; - return IRQ_WAKE_THREAD; - } - - if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) || - (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) { - tegra_cec_error_recovery(cec); - cec_write(cec, TEGRA_CEC_INT_MASK, - mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); - - cec->tx_done = true; - if (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED) - cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; - else - cec->tx_status = CEC_TX_STATUS_ARB_LOST; - return IRQ_WAKE_THREAD; - } - - if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) { - cec_write(cec, TEGRA_CEC_INT_STAT, - TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED); - - if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) { - tegra_cec_error_recovery(cec); - - cec->tx_done = true; - cec->tx_status = CEC_TX_STATUS_NACK; - } else { - cec->tx_done = true; - cec->tx_status = CEC_TX_STATUS_OK; - } - return IRQ_WAKE_THREAD; - } - - if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) - dev_warn(dev, "TX NAKed on the fly!\n"); - - if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) { - if (cec->tx_buf_cur == cec->tx_buf_cnt) { - cec_write(cec, TEGRA_CEC_INT_MASK, - mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); - } else { - cec_write(cec, TEGRA_CEC_TX_REGISTER, - cec->tx_buf[cec->tx_buf_cur++]); - cec_write(cec, TEGRA_CEC_INT_STAT, - TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY); - } - } - - if (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) { - cec_write(cec, TEGRA_CEC_INT_STAT, - TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED); - cec->rx_done = false; - cec->rx_buf_cnt = 0; - } - if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { - u32 v; - - cec_write(cec, TEGRA_CEC_INT_STAT, - TEGRA_CEC_INT_STAT_RX_REGISTER_FULL); - v = cec_read(cec, TEGRA_CEC_RX_REGISTER); - if (cec->rx_buf_cnt < CEC_MAX_MSG_SIZE) - cec->rx_buf[cec->rx_buf_cnt++] = v & 0xff; - if (v & TEGRA_CEC_RX_REGISTER_EOM) { - cec->rx_done = true; - return IRQ_WAKE_THREAD; - } - } - - return IRQ_HANDLED; -} - -static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct tegra_cec *cec = adap->priv; - - cec->rx_buf_cnt = 0; - cec->tx_buf_cnt = 0; - cec->tx_buf_cur = 0; - - cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); - cec_write(cec, TEGRA_CEC_INT_MASK, 0); - cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); - cec_write(cec, TEGRA_CEC_SW_CONTROL, 0); - - if (!enable) - return 0; - - cec_write(cec, TEGRA_CEC_INPUT_FILTER, (1U << 31) | 0x20); - - cec_write(cec, TEGRA_CEC_RX_TIMING_0, - (0x7a << TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT) | - (0x6d << TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT) | - (0x93 << TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT) | - (0x86 << TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT)); - - cec_write(cec, TEGRA_CEC_RX_TIMING_1, - (0x35 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT) | - (0x21 << TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT) | - (0x56 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT) | - (0x40 << TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT)); - - cec_write(cec, TEGRA_CEC_RX_TIMING_2, - (0x50 << TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT)); - - cec_write(cec, TEGRA_CEC_TX_TIMING_0, - (0x74 << TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT) | - (0x8d << TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT) | - (0x08 << TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT) | - (0x71 << TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT)); - - cec_write(cec, TEGRA_CEC_TX_TIMING_1, - (0x2f << TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT) | - (0x13 << TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT) | - (0x4b << TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT) | - (0x21 << TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT)); - - cec_write(cec, TEGRA_CEC_TX_TIMING_2, - (0x07 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT) | - (0x05 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT) | - (0x03 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT)); - - cec_write(cec, TEGRA_CEC_INT_MASK, - TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN | - TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD | - TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED | - TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | - TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | - TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | - TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); - - cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); - return 0; -} - -static int tegra_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) -{ - struct tegra_cec *cec = adap->priv; - u32 state = cec_read(cec, TEGRA_CEC_HW_CONTROL); - - if (logical_addr == CEC_LOG_ADDR_INVALID) - state &= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK; - else - state |= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr)); - - cec_write(cec, TEGRA_CEC_HW_CONTROL, state); - return 0; -} - -static int tegra_cec_adap_monitor_all_enable(struct cec_adapter *adap, - bool enable) -{ - struct tegra_cec *cec = adap->priv; - u32 reg = cec_read(cec, TEGRA_CEC_HW_CONTROL); - - if (enable) - reg |= TEGRA_CEC_HWCTRL_RX_SNOOP; - else - reg &= ~TEGRA_CEC_HWCTRL_RX_SNOOP; - cec_write(cec, TEGRA_CEC_HW_CONTROL, reg); - return 0; -} - -static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time_ms, struct cec_msg *msg) -{ - bool retry_xfer = signal_free_time_ms == CEC_SIGNAL_FREE_TIME_RETRY; - struct tegra_cec *cec = adap->priv; - unsigned int i; - u32 mode = 0; - u32 mask; - - if (cec_msg_is_broadcast(msg)) - mode = TEGRA_CEC_TX_REG_BCAST; - - cec->tx_buf_cur = 0; - cec->tx_buf_cnt = msg->len; - - for (i = 0; i < msg->len; i++) { - cec->tx_buf[i] = mode | msg->msg[i]; - if (i == 0) - cec->tx_buf[i] |= TEGRA_CEC_TX_REG_START_BIT; - if (i == msg->len - 1) - cec->tx_buf[i] |= TEGRA_CEC_TX_REG_EOM; - if (i == 0 && retry_xfer) - cec->tx_buf[i] |= TEGRA_CEC_TX_REG_RETRY; - } - - mask = cec_read(cec, TEGRA_CEC_INT_MASK); - cec_write(cec, TEGRA_CEC_INT_MASK, - mask | TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); - - return 0; -} - -static const struct cec_adap_ops tegra_cec_ops = { - .adap_enable = tegra_cec_adap_enable, - .adap_log_addr = tegra_cec_adap_log_addr, - .adap_transmit = tegra_cec_adap_transmit, - .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, -}; - -static int tegra_cec_probe(struct platform_device *pdev) -{ - struct device *hdmi_dev; - struct tegra_cec *cec; - struct resource *res; - int ret = 0; - - hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - - if (IS_ERR(hdmi_dev)) - return PTR_ERR(hdmi_dev); - - cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); - - if (!cec) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - if (!res) { - dev_err(&pdev->dev, - "Unable to allocate resources for device\n"); - return -EBUSY; - } - - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, - "Unable to request mem region for device\n"); - return -EBUSY; - } - - cec->tegra_cec_irq = platform_get_irq(pdev, 0); - - if (cec->tegra_cec_irq <= 0) - return -EBUSY; - - cec->cec_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - - if (!cec->cec_base) { - dev_err(&pdev->dev, "Unable to grab IOs for device\n"); - return -EBUSY; - } - - cec->clk = devm_clk_get(&pdev->dev, "cec"); - - if (IS_ERR_OR_NULL(cec->clk)) { - dev_err(&pdev->dev, "Can't get clock for CEC\n"); - return -ENOENT; - } - - clk_prepare_enable(cec->clk); - - /* set context info. */ - cec->dev = &pdev->dev; - - platform_set_drvdata(pdev, cec); - - ret = devm_request_threaded_irq(&pdev->dev, cec->tegra_cec_irq, - tegra_cec_irq_handler, tegra_cec_irq_thread_handler, - 0, "cec_irq", &pdev->dev); - - if (ret) { - dev_err(&pdev->dev, - "Unable to request interrupt for device\n"); - goto err_clk; - } - - cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, - CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | - CEC_CAP_CONNECTOR_INFO, - CEC_MAX_LOG_ADDRS); - if (IS_ERR(cec->adap)) { - ret = -ENOMEM; - dev_err(&pdev->dev, "Couldn't create cec adapter\n"); - goto err_clk; - } - - cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, - cec->adap); - if (!cec->notifier) { - ret = -ENOMEM; - goto err_adapter; - } - - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Couldn't register device\n"); - goto err_notifier; - } - - return 0; - -err_notifier: - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); -err_adapter: - cec_delete_adapter(cec->adap); -err_clk: - clk_disable_unprepare(cec->clk); - return ret; -} - -static int tegra_cec_remove(struct platform_device *pdev) -{ - struct tegra_cec *cec = platform_get_drvdata(pdev); - - clk_disable_unprepare(cec->clk); - - cec_notifier_cec_adap_unregister(cec->notifier, cec->adap); - cec_unregister_adapter(cec->adap); - - return 0; -} - -#ifdef CONFIG_PM -static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct tegra_cec *cec = platform_get_drvdata(pdev); - - clk_disable_unprepare(cec->clk); - - dev_notice(&pdev->dev, "suspended\n"); - return 0; -} - -static int tegra_cec_resume(struct platform_device *pdev) -{ - struct tegra_cec *cec = platform_get_drvdata(pdev); - - dev_notice(&pdev->dev, "Resuming\n"); - - clk_prepare_enable(cec->clk); - - return 0; -} -#endif - -static const struct of_device_id tegra_cec_of_match[] = { - { .compatible = "nvidia,tegra114-cec", }, - { .compatible = "nvidia,tegra124-cec", }, - { .compatible = "nvidia,tegra210-cec", }, - {}, -}; - -static struct platform_driver tegra_cec_driver = { - .driver = { - .name = TEGRA_CEC_NAME, - .of_match_table = of_match_ptr(tegra_cec_of_match), - }, - .probe = tegra_cec_probe, - .remove = tegra_cec_remove, - -#ifdef CONFIG_PM - .suspend = tegra_cec_suspend, - .resume = tegra_cec_resume, -#endif -}; - -module_platform_driver(tegra_cec_driver); - -MODULE_DESCRIPTION("Tegra HDMI CEC driver"); -MODULE_AUTHOR("NVIDIA CORPORATION"); -MODULE_AUTHOR("Cisco Systems, Inc. and/or its affiliates"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/tegra-cec/tegra_cec.h b/drivers/media/platform/tegra-cec/tegra_cec.h deleted file mode 100644 index 8c370be38e1e..000000000000 --- a/drivers/media/platform/tegra-cec/tegra_cec.h +++ /dev/null @@ -1,116 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Tegra CEC register definitions - * - * The original 3.10 CEC driver using a custom API: - * - * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. - * - * Conversion to the CEC framework and to the mainline kernel: - * - * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef TEGRA_CEC_H -#define TEGRA_CEC_H - -/* CEC registers */ -#define TEGRA_CEC_SW_CONTROL 0x000 -#define TEGRA_CEC_HW_CONTROL 0x004 -#define TEGRA_CEC_INPUT_FILTER 0x008 -#define TEGRA_CEC_TX_REGISTER 0x010 -#define TEGRA_CEC_RX_REGISTER 0x014 -#define TEGRA_CEC_RX_TIMING_0 0x018 -#define TEGRA_CEC_RX_TIMING_1 0x01c -#define TEGRA_CEC_RX_TIMING_2 0x020 -#define TEGRA_CEC_TX_TIMING_0 0x024 -#define TEGRA_CEC_TX_TIMING_1 0x028 -#define TEGRA_CEC_TX_TIMING_2 0x02c -#define TEGRA_CEC_INT_STAT 0x030 -#define TEGRA_CEC_INT_MASK 0x034 -#define TEGRA_CEC_HW_DEBUG_RX 0x038 -#define TEGRA_CEC_HW_DEBUG_TX 0x03c - -#define TEGRA_CEC_HWCTRL_RX_LADDR_MASK 0x7fff -#define TEGRA_CEC_HWCTRL_RX_LADDR(x) \ - ((x) & TEGRA_CEC_HWCTRL_RX_LADDR_MASK) -#define TEGRA_CEC_HWCTRL_RX_SNOOP BIT(15) -#define TEGRA_CEC_HWCTRL_RX_NAK_MODE BIT(16) -#define TEGRA_CEC_HWCTRL_TX_NAK_MODE BIT(24) -#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE BIT(30) -#define TEGRA_CEC_HWCTRL_TX_RX_MODE BIT(31) - -#define TEGRA_CEC_INPUT_FILTER_MODE BIT(31) -#define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_SHIFT 0 - -#define TEGRA_CEC_TX_REG_DATA_SHIFT 0 -#define TEGRA_CEC_TX_REG_EOM BIT(8) -#define TEGRA_CEC_TX_REG_BCAST BIT(12) -#define TEGRA_CEC_TX_REG_START_BIT BIT(16) -#define TEGRA_CEC_TX_REG_RETRY BIT(17) - -#define TEGRA_CEC_RX_REGISTER_SHIFT 0 -#define TEGRA_CEC_RX_REGISTER_EOM BIT(8) -#define TEGRA_CEC_RX_REGISTER_ACK BIT(9) - -#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT 0 -#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT 8 -#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT 16 -#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT 24 - -#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT 0 -#define TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT 8 -#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT 16 -#define TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT 24 - -#define TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT 0 - -#define TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT 0 -#define TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT 8 -#define TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT 16 -#define TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT 24 - -#define TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT 0 -#define TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT 8 -#define TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT 16 -#define TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT 24 - -#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT 0 -#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT 4 -#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT 8 - -#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY BIT(0) -#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN BIT(1) -#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD BIT(2) -#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED BIT(3) -#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED BIT(4) -#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED BIT(5) -#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL BIT(8) -#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN BIT(9) -#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED BIT(10) -#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED BIT(11) -#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED BIT(12) -#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13) -#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14) - -#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY BIT(0) -#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN BIT(1) -#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD BIT(2) -#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED BIT(3) -#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED BIT(4) -#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED BIT(5) -#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL BIT(8) -#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN BIT(9) -#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED BIT(10) -#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED BIT(11) -#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED BIT(12) -#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13) -#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14) - -#define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_SHIFT 0 -#define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_SHIFT 17 -#define TEGRA_CEC_HW_DEBUG_TX_STATE_SHIFT 21 -#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT BIT(25) -#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER BIT(26) - -#endif /* TEGRA_CEC_H */ |