2013-10-14 21:02:56

by Marek Belisko

[permalink] [raw]
Subject: [PATCH 0/3] omapdss: venc: Add support for bypass and acbias.

This patches is adding bypass and acbias functionality to omapdss venc driver.
In first patch we export updatin bypass and acbias in devconf1 register. Next patch
add handling for updating in venc driver and last patch add driver for opa362 which
is used on gta04 board and set bypass + acbias.

Marek Belisko (3):
arm: omap2: Export devconf1 bypass and acbias.
video: venc: Add new callback and handling for bypass and acbias
setup.
omapdss: Add OPA362 analog video amplifier driver.

arch/arm/mach-omap2/Makefile | 2 +
arch/arm/mach-omap2/control.h | 2 +
arch/arm/mach-omap2/omap3-tvout.c | 36 +++
drivers/video/omap2/displays-new/Kconfig | 6 +
drivers/video/omap2/displays-new/Makefile | 1 +
.../video/omap2/displays-new/amplifier-opa362.c | 294 +++++++++++++++++++++
drivers/video/omap2/dss/venc.c | 21 ++
include/linux/omap-tvout.h | 14 +
include/video/omap-panel-data.h | 17 ++
include/video/omapdss.h | 2 +
10 files changed, 395 insertions(+)
create mode 100644 arch/arm/mach-omap2/omap3-tvout.c
create mode 100644 drivers/video/omap2/displays-new/amplifier-opa362.c
create mode 100644 include/linux/omap-tvout.h

--
1.8.1.2


2013-10-14 21:03:00

by Marek Belisko

[permalink] [raw]
Subject: [PATCH 1/3] arm: omap2: Export devconf1 bypass and acbias.

devconf1 reg access is localized only in mach-omap2 and we need to export
updating of devconf1 from omapdss venc driver (bypass and acbias bits).
Add simple api call which update only necessary bits.

Signed-off-by: Marek Belisko <[email protected]>
---
arch/arm/mach-omap2/Makefile | 2 ++
arch/arm/mach-omap2/control.h | 2 ++
arch/arm/mach-omap2/omap3-tvout.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/omap-tvout.h | 14 ++++++++++++++
4 files changed, 54 insertions(+)
create mode 100644 arch/arm/mach-omap2/omap3-tvout.c
create mode 100644 include/linux/omap-tvout.h

diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index afb457c..15e0f28 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -306,3 +306,5 @@ emac-$(CONFIG_TI_DAVINCI_EMAC) := am35xx-emac.o
obj-y += $(emac-m) $(emac-y)

obj-y += common-board-devices.o twl-common.o dss-common.o
+
+obj-$(CONFIG_ARCH_OMAP3) += omap3-tvout.o
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index f7d7c2e..65277f1 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -279,6 +279,8 @@

/* CONTROL_DEVCONF1 bits */
#define OMAP243X_MMC1_ACTIVE_OVERWRITE (1 << 31)
+#define OMAP2_TVOUTBYPASS (1 << 18)
+#define OMAP2_TVACEN (1 << 11)
#define OMAP2_MMCSDIO2ADPCLKISEL (1 << 6) /* MMC2 loop back clock */
#define OMAP2_MCBSP5_CLKS_MASK (1 << 4) /* > 242x */
#define OMAP2_MCBSP4_CLKS_MASK (1 << 2) /* > 242x */
diff --git a/arch/arm/mach-omap2/omap3-tvout.c b/arch/arm/mach-omap2/omap3-tvout.c
new file mode 100644
index 0000000..eaed225
--- /dev/null
+++ b/arch/arm/mach-omap2/omap3-tvout.c
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/mach-omap2/omap3-tvout.c
+ *
+ * Copyright (C) 2013 Golden Delicious Computers
+ * Author: Marek Belisko <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/omap-tvout.h>
+
+#include "soc.h"
+#include "control.h"
+
+void update_bypass_acbias(bool bypass, bool acbias)
+{
+#ifdef CONFIG_ARCH_OMAP3
+ int val = omap_ctrl_readl(OMAP343X_CONTROL_DEVCONF1);
+
+ if (bypass)
+ val |= OMAP2_TVOUTBYPASS;
+ else
+ val &= ~OMAP2_TVOUTBYPASS;
+
+ if (acbias)
+ val |= OMAP2_TVACEN;
+ else
+ val &= ~OMAP2_TVACEN;
+
+ omap_ctrl_writel(val, OMAP343X_CONTROL_DEVCONF1);
+#endif
+}
+
diff --git a/include/linux/omap-tvout.h b/include/linux/omap-tvout.h
new file mode 100644
index 0000000..25f676d
--- /dev/null
+++ b/include/linux/omap-tvout.h
@@ -0,0 +1,14 @@
+/*
+ * OMAP TV-out support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_OMAP_TVOUT_H
+#define __LINUX_OMAP_TVOUT_H
+
+extern void update_bypass_acbias(bool bypass, bool acbias);
+
+#endif
+
--
1.8.1.2

2013-10-14 21:03:07

by Marek Belisko

[permalink] [raw]
Subject: [PATCH 3/3] omapdss: Add OPA362 analog video amplifier driver.

This driver add handlign for opa362 chip which is
video amplifier with internal gain and filter. Enable/disable is
controlled via single gpio. This driver was tested on gta04 board.

Signed-off-by: Marek Belisko <[email protected]>
Signed-off-by: H. Nikolaus Schaller <[email protected]>
---
drivers/video/omap2/displays-new/Kconfig | 6 +
drivers/video/omap2/displays-new/Makefile | 1 +
.../video/omap2/displays-new/amplifier-opa362.c | 294 +++++++++++++++++++++
include/video/omap-panel-data.h | 17 ++
4 files changed, 318 insertions(+)
create mode 100644 drivers/video/omap2/displays-new/amplifier-opa362.c

diff --git a/drivers/video/omap2/displays-new/Kconfig b/drivers/video/omap2/displays-new/Kconfig
index 6c90885..5097640 100644
--- a/drivers/video/omap2/displays-new/Kconfig
+++ b/drivers/video/omap2/displays-new/Kconfig
@@ -1,6 +1,12 @@
menu "OMAP Display Device Drivers (new device model)"
depends on OMAP2_DSS

+config DISPLAY_AMPLIFIER_OPA362
+ tristate "Analog amplifier with output disable/high-Z"
+ help
+ Driver to enable an external analog TV amplifier (e.g. OPA362)
+ through a GPIO.
+
config DISPLAY_ENCODER_TFP410
tristate "TFP410 DPI to DVI Encoder"
help
diff --git a/drivers/video/omap2/displays-new/Makefile b/drivers/video/omap2/displays-new/Makefile
index 5aeb11b..2e8af8f 100644
--- a/drivers/video/omap2/displays-new/Makefile
+++ b/drivers/video/omap2/displays-new/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_DISPLAY_AMPLIFIER_OPA362) += amplifier-opa362.o
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
diff --git a/drivers/video/omap2/displays-new/amplifier-opa362.c b/drivers/video/omap2/displays-new/amplifier-opa362.c
new file mode 100644
index 0000000..677499c
--- /dev/null
+++ b/drivers/video/omap2/displays-new/amplifier-opa362.c
@@ -0,0 +1,294 @@
+/*
+ * OPA362 analog video amplifier with output/power control
+ *
+ * Copyright (C) 2013 Golden Delicious Computers
+ * Author: H. Nikolaus Schaller <[email protected]>
+ *
+ * based on encoder-tfp410
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <video/omapdss.h>
+#include <video/omap-panel-data.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ int enable_gpio;
+ bool bypass;
+ bool acbias;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int opa362_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (omapdss_device_is_connected(dssdev))
+ return -EBUSY;
+
+ r = in->ops.atv->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ return 0;
+}
+
+static void opa362_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ WARN_ON(!omapdss_device_is_connected(dssdev));
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ WARN_ON(dst != dssdev->dst);
+ if (dst != dssdev->dst)
+ return;
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.atv->disconnect(in, &ddata->dssdev);
+}
+
+static int opa362_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.atv->set_timings(in, &ddata->timings);
+ in->ops.atv->invert_vid_out_polarity(in, true);
+ in->ops.atv->bypass_and_acbias(in, ddata->bypass, ddata->acbias);
+
+ r = in->ops.atv->enable(in);
+ if (r)
+ return r;
+
+ if (gpio_is_valid(ddata->enable_gpio))
+ gpio_set_value_cansleep(ddata->enable_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void opa362_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (gpio_is_valid(ddata->enable_gpio))
+ gpio_set_value_cansleep(ddata->enable_gpio, 0);
+
+ in->ops.atv->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void opa362_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.atv->set_timings(in, timings);
+}
+
+static void opa362_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ *timings = ddata->timings;
+}
+
+static int opa362_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ return in->ops.atv->check_timings(in, timings);
+}
+
+static void opa362_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ /* we can only drive a COMPOSITE output */
+ WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
+
+}
+
+static void opa362_invert_vid_out_polarity(struct omap_dss_device *dssdev,
+ bool invert_polarity)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ /* OPA362 inverts the polarity */
+ in->ops.atv->invert_vid_out_polarity(in, !invert_polarity);
+}
+
+static const struct omapdss_atv_ops opa362_atv_ops = {
+ .connect = opa362_connect,
+ .disconnect = opa362_disconnect,
+
+ .enable = opa362_enable,
+ .disable = opa362_disable,
+
+ .check_timings = opa362_check_timings,
+ .set_timings = opa362_set_timings,
+ .get_timings = opa362_get_timings,
+
+ .set_type = opa362_set_type,
+ .invert_vid_out_polarity = opa362_invert_vid_out_polarity,
+};
+
+static int opa362_probe_pdata(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct amplifier_opa362_platform_data *pdata;
+ struct omap_dss_device *dssdev, *in;
+
+ pdata = dev_get_platdata(&pdev->dev);
+
+ ddata->enable_gpio = pdata->enable_gpio;
+ ddata->bypass = pdata->bypass;
+ ddata->acbias = pdata->acbias;
+
+ in = omap_dss_find_output(pdata->source);
+ if (in == NULL) {
+ dev_err(&pdev->dev, "Failed to find video source\n");
+ return -ENODEV;
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->name = pdata->name;
+
+ return 0;
+}
+
+static int opa362_probe(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev;
+ int r;
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ if (dev_get_platdata(&pdev->dev)) {
+ r = opa362_probe_pdata(pdev);
+ if (r)
+ return r;
+ } else {
+ return -ENODEV;
+ }
+
+ if (gpio_is_valid(ddata->enable_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio,
+ GPIOF_OUT_INIT_LOW, "opa362 enable");
+ if (r) {
+ dev_err(&pdev->dev, "Failed to request enable GPIO %d\n",
+ ddata->enable_gpio);
+ goto err_gpio;
+ }
+ }
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.atv = &opa362_atv_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->owner = THIS_MODULE;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit opa362_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ opa362_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ opa362_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static struct platform_driver opa362_driver = {
+ .probe = opa362_probe,
+ .remove = __exit_p(opa362_remove),
+ .driver = {
+ .name = "amplifier-opa362",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(opa362_driver);
+
+MODULE_AUTHOR("H. Nikolaus Schaller <[email protected]>");
+MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
+MODULE_LICENSE("GPL");
diff --git a/include/video/omap-panel-data.h b/include/video/omap-panel-data.h
index f7ac8d9..e1b3c13 100644
--- a/include/video/omap-panel-data.h
+++ b/include/video/omap-panel-data.h
@@ -33,6 +33,23 @@
struct omap_dss_device;

/**
+ * amplifier_opa362_platform_data platform data
+ * @name: name for this display entity
+ * @source: name of the display entity used as a video source
+ * @enable_gpio: gpio number for enable pin (or -1 if not available - but
+ * then you don't need this driver)
+ * @bypass: enable TV bypass mode for external video driver
+ * @acbias: AC coupling to remove DC offset
+ */
+struct amplifier_opa362_platform_data {
+ const char *name;
+ const char *source;
+ int enable_gpio;
+ bool bypass;
+ bool acbias;
+};
+
+/**
* encoder_tfp410 platform data
* @name: name for this display entity
* @power_down_gpio: gpio number for PD pin (or -1 if not available)
--
1.8.1.2

2013-10-14 21:03:56

by Marek Belisko

[permalink] [raw]
Subject: [PATCH 2/3] video: venc: Add new callback and handling for bypass and acbias setup.

Add new callback to set bypass and acbias. During venc enble disable those
bit are updated in devconf1 register.

Signed-off-by: Marek Belisko <[email protected]>
---
drivers/video/omap2/dss/venc.c | 21 +++++++++++++++++++++
include/video/omapdss.h | 2 ++
2 files changed, 23 insertions(+)

diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index 5f88ac4..17bd45b 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -34,6 +34,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/omap-tvout.h>

#include <video/omapdss.h>

@@ -303,6 +304,8 @@ static struct {
struct omap_video_timings timings;
enum omap_dss_venc_type type;
bool invert_polarity;
+ bool bypass;
+ bool acbias;

struct omap_dss_device output;
} venc;
@@ -455,6 +458,9 @@ static int venc_power_on(struct omap_dss_device *dssdev)

venc_write_reg(VENC_OUTPUT_CONTROL, l);

+ /* apply bypass and acbias */
+ update_bypass_acbias(venc.bypass, venc.acbias);
+
dss_mgr_set_timings(mgr, &venc.timings);

r = regulator_enable(venc.vdda_dac_reg);
@@ -485,6 +491,9 @@ static void venc_power_off(struct omap_dss_device *dssdev)
venc_write_reg(VENC_OUTPUT_CONTROL, 0);
dss_set_dac_pwrdn_bgz(0);

+ /* clear bypass and acbias */
+ update_bypass_acbias(false, false);
+
dss_mgr_disable(mgr);

regulator_disable(venc.vdda_dac_reg);
@@ -629,6 +638,17 @@ static void venc_invert_vid_out_polarity(struct omap_dss_device *dssdev,
mutex_unlock(&venc.venc_lock);
}

+static void venc_bypass_and_acbias(struct omap_dss_device *dssdev,
+ bool bypass, bool acbias)
+{
+ mutex_lock(&venc.venc_lock);
+
+ venc.bypass = bypass;
+ venc.acbias = acbias;
+
+ mutex_unlock(&venc.venc_lock);
+}
+
static int venc_init_regulator(void)
{
struct regulator *vdda_dac;
@@ -777,6 +797,7 @@ static const struct omapdss_atv_ops venc_ops = {

.set_type = venc_set_type,
.invert_vid_out_polarity = venc_invert_vid_out_polarity,
+ .bypass_and_acbias = venc_bypass_and_acbias,

.set_wss = venc_set_wss,
.get_wss = venc_get_wss,
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 3d7c51a..54a185f 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -607,6 +607,8 @@ struct omapdss_atv_ops {
enum omap_dss_venc_type type);
void (*invert_vid_out_polarity)(struct omap_dss_device *dssdev,
bool invert_polarity);
+ void (*bypass_and_acbias)(struct omap_dss_device *dssdev,
+ bool bypass, bool acbias);

int (*set_wss)(struct omap_dss_device *dssdev, u32 wss);
u32 (*get_wss)(struct omap_dss_device *dssdev);
--
1.8.1.2