* [PATCH v5 05/20] watchdog: orion: Remove unused macros
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
These are not used anywhere so it's safe to remove them.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index b92a991..6746033 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -33,8 +33,6 @@
#define WDT_VAL 0x0024
#define WDT_MAX_CYCLE_COUNT 0xffffffff
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
#define WDT_RESET_OUT_EN BIT(1)
#define WDT_INT_REQ BIT(3)
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 06/20] watchdog: orion: Make sure the watchdog is initially stopped
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Having the watchdog initially fully stopped is important to avoid
any spurious watchdog triggers, in case the registers are not in
its reset state.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 6746033..2dbeee9 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -142,6 +142,9 @@ static int orion_wdt_probe(struct platform_device *pdev)
orion_wdt.max_timeout = wdt_max_duration;
watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
+ /* Let's make sure the watchdog is fully stopped */
+ orion_wdt_stop(&orion_wdt);
+
watchdog_set_nowayout(&orion_wdt, nowayout);
ret = watchdog_register_device(&orion_wdt);
if (ret)
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 07/20] watchdog: orion: Handle the interrupt so it's properly acked
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
DT-enabled plaforms, where the irqchip driver for the brigde interrupt
controller is available, can handle the watchdog IRQ properly. Therefore,
request the interrupt and add a dummy handler that merely calls panic().
This is done in order to have an initial 'ack' of the interruption,
which clears the watchdog state.
Furthermore, since some platforms don't have such IRQ, this commit
makes the interrupt specification optional.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
Depends on the following irqchip-orion fix (not yet merged):
https://lkml.org/lkml/2014/1/23/594
.../devicetree/bindings/watchdog/marvel.txt | 2 ++
drivers/watchdog/orion_wdt.c | 24 +++++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 5dc8d30..0731fbd 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -7,6 +7,7 @@ Required Properties:
Optional properties:
+- interrupts : Contains the IRQ for watchdog expiration
- timeout-sec : Contains the watchdog timeout in seconds
Example:
@@ -14,6 +15,7 @@ Example:
wdt at 20300 {
compatible = "marvell,orion-wdt";
reg = <0x20300 0x28>;
+ interrupts = <3>;
timeout-sec = <10>;
status = "okay";
};
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 2dbeee9..7c5e94e 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
@@ -109,10 +110,16 @@ static struct watchdog_device orion_wdt = {
.min_timeout = 1,
};
+static irqreturn_t orion_wdt_irq(int irq, void *devid)
+{
+ panic("Watchdog Timeout");
+ return IRQ_HANDLED;
+}
+
static int orion_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
- int ret;
+ int ret, irq;
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
@@ -145,6 +152,21 @@ static int orion_wdt_probe(struct platform_device *pdev)
/* Let's make sure the watchdog is fully stopped */
orion_wdt_stop(&orion_wdt);
+ /* The IRQ request must be done only after the watchdog is disabled */
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ /*
+ * Not all supported platforms specify an interrupt for the
+ * watchdog, so let's make it optional.
+ */
+ ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0,
+ pdev->name, &orion_wdt);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ goto disable_clk;
+ }
+ }
+
watchdog_set_nowayout(&orion_wdt, nowayout);
ret = watchdog_register_device(&orion_wdt);
if (ret)
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 08/20] watchdog: orion: Make RSTOUT register a separate resource
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to support other SoC, it's required to distinguish
the 'control' timer register, from the 'rstout' register
that enables system reset on watchdog expiration.
To prevent a compatibility break, this commit adds a fallback
to a hardcoded RSTOUT address.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
.../devicetree/bindings/watchdog/marvel.txt | 6 ++-
arch/arm/mach-dove/include/mach/bridge-regs.h | 1 +
arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 +
arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 +
arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 +
arch/arm/plat-orion/common.c | 10 +++--
drivers/watchdog/orion_wdt.c | 45 +++++++++++++++++++++-
7 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 0731fbd..1544fe9 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -3,7 +3,9 @@
Required Properties:
- Compatibility : "marvell,orion-wdt"
-- reg : Address of the timer registers
+- reg : Should contain two entries: first one with the
+ timer control address, second one with the
+ rstout enable address.
Optional properties:
@@ -14,7 +16,7 @@ Example:
wdt at 20300 {
compatible = "marvell,orion-wdt";
- reg = <0x20300 0x28>;
+ reg = <0x20300 0x28>, <0x20108 0x4>;
interrupts = <3>;
timeout-sec = <10>;
status = "okay";
diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h
index 5362df3..f4a5b34 100644
--- a/arch/arm/mach-dove/include/mach/bridge-regs.h
+++ b/arch/arm/mach-dove/include/mach/bridge-regs.h
@@ -21,6 +21,7 @@
#define CPU_CTRL_PCIE1_LINK 0x00000008
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
index 8b9d1c9..60f6421 100644
--- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
+++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h
@@ -21,6 +21,7 @@
#define CPU_RESET 0x00000002
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
index 5f03484..e20d6da 100644
--- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
+++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h
@@ -15,6 +15,7 @@
#define L2_WRITETHROUGH 0x00020000
#define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108)
+#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108)
#define SOFT_RESET_OUT_EN 0x00000004
#define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c)
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
index f727d03..5766e3f 100644
--- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h
+++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h
@@ -18,6 +18,7 @@
#define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104)
#define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108)
+#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108)
#define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c)
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index c66d163..3375037 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -594,14 +594,16 @@ void __init orion_spi_1_init(unsigned long mapbase)
/*****************************************************************************
* Watchdog
****************************************************************************/
-static struct resource orion_wdt_resource =
- DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28);
+static struct resource orion_wdt_resource[] = {
+ DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04),
+ DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04),
+};
static struct platform_device orion_wdt_device = {
.name = "orion_wdt",
.id = -1,
- .num_resources = 1,
- .resource = &orion_wdt_resource,
+ .num_resources = ARRAY_SIZE(orion_wdt_resource),
+ .resource = orion_wdt_resource,
};
void __init orion_wdt_init(void)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 7c5e94e..fce0ec8 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -26,6 +26,12 @@
#include <linux/of.h>
#include <mach/bridge-regs.h>
+/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
+#define ORION_RSTOUT_MASK_OFFSET 0x20108
+
+/* Internal registers can be configured at any 1 MiB aligned address */
+#define INTERNAL_REGS_MASK ~(SZ_1M - 1)
+
/*
* Watchdog timer block registers.
*/
@@ -44,6 +50,7 @@ static unsigned int wdt_max_duration; /* (seconds) */
static struct clk *clk;
static unsigned int wdt_tclk;
static void __iomem *wdt_reg;
+static void __iomem *wdt_rstout;
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
@@ -64,14 +71,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
/* Enable reset on watchdog */
- atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
return 0;
}
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
/* Disable reset on watchdog */
- atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
/* Disable watchdog timer */
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
@@ -116,6 +123,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid)
return IRQ_HANDLED;
}
+/*
+ * The original devicetree binding for this driver specified only
+ * one memory resource, so in order to keep DT backwards compatibility
+ * we try to fallback to a hardcoded register address, if the resource
+ * is missing from the devicetree.
+ */
+static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
+ phys_addr_t internal_regs)
+{
+ struct resource *res;
+ phys_addr_t rstout;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res)
+ return devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+
+ /* This workaround works only for "orion-wdt", DT-enabled */
+ if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
+ return NULL;
+
+ rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
+
+ WARN(1, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n", rstout);
+ return devm_ioremap(&pdev->dev, rstout, 0x4);
+}
+
static int orion_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
@@ -143,6 +177,13 @@ static int orion_wdt_probe(struct platform_device *pdev)
goto disable_clk;
}
+ wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start &
+ INTERNAL_REGS_MASK);
+ if (!wdt_rstout) {
+ ret = -ENODEV;
+ goto disable_clk;
+ }
+
wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
orion_wdt.timeout = wdt_max_duration;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 09/20] watchdog: orion: Remove unneeded BRIDGE_CAUSE clear
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
After adding the IRQ request, the BRIDGE_CAUSE bit should be cleared by the
bridge interrupt controller. There's no longer a need to do it in the watchdog
driver, so we can simply remove it.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index fce0ec8..adacfd5 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -24,7 +24,6 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
-#include <mach/bridge-regs.h>
/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
#define ORION_RSTOUT_MASK_OFFSET 0x20108
@@ -42,7 +41,6 @@
#define WDT_MAX_CYCLE_COUNT 0xffffffff
#define WDT_RESET_OUT_EN BIT(1)
-#define WDT_INT_REQ BIT(3)
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
@@ -64,9 +62,6 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
/* Set watchdog duration */
writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
- /* Clear watchdog timer interrupt */
- writel(~WDT_INT_REQ, BRIDGE_CAUSE);
-
/* Enable watchdog timer */
atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 10/20] watchdog: orion: Introduce an orion_watchdog device structure
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to prepare to support multiple compatible-strings, this
commit adds a device structure to hold the driver's state.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 106 ++++++++++++++++++++++++++-----------------
1 file changed, 65 insertions(+), 41 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index adacfd5..1423fd8 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -44,45 +44,56 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
-static unsigned int wdt_max_duration; /* (seconds) */
-static struct clk *clk;
-static unsigned int wdt_tclk;
-static void __iomem *wdt_reg;
-static void __iomem *wdt_rstout;
+
+struct orion_watchdog {
+ struct watchdog_device wdt;
+ void __iomem *reg;
+ void __iomem *rstout;
+ unsigned long clk_rate;
+ struct clk *clk;
+};
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Reload watchdog duration */
- writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
return 0;
}
static int orion_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
/* Set watchdog duration */
- writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
/* Enable watchdog timer */
- atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN);
+ atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
/* Enable reset on watchdog */
- atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+
return 0;
}
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
/* Disable reset on watchdog */
- atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
/* Disable watchdog timer */
- atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0);
+ atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+
return 0;
}
static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
- return readl(wdt_reg + WDT_VAL) / wdt_tclk;
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+ return readl(dev->reg + WDT_VAL) / dev->clk_rate;
}
static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -106,12 +117,6 @@ static const struct watchdog_ops orion_wdt_ops = {
.get_timeleft = orion_wdt_get_timeleft,
};
-static struct watchdog_device orion_wdt = {
- .info = &orion_wdt_info,
- .ops = &orion_wdt_ops,
- .min_timeout = 1,
-};
-
static irqreturn_t orion_wdt_irq(int irq, void *devid)
{
panic("Watchdog Timeout");
@@ -147,18 +152,29 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
static int orion_wdt_probe(struct platform_device *pdev)
{
+ struct orion_watchdog *dev;
+ unsigned int wdt_max_duration; /* (seconds) */
struct resource *res;
int ret, irq;
- clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(clk)) {
+ dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
+ GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->wdt.info = &orion_wdt_info;
+ dev->wdt.ops = &orion_wdt_ops;
+ dev->wdt.min_timeout = 1;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
- return PTR_ERR(clk);
+ return PTR_ERR(dev->clk);
}
- ret = clk_prepare_enable(clk);
+ ret = clk_prepare_enable(dev->clk);
if (ret)
return ret;
- wdt_tclk = clk_get_rate(clk);
+ dev->clk_rate = clk_get_rate(dev->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -166,27 +182,31 @@ static int orion_wdt_probe(struct platform_device *pdev)
goto disable_clk;
}
- wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!wdt_reg) {
+ dev->reg = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!dev->reg) {
ret = -ENOMEM;
goto disable_clk;
}
- wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start &
- INTERNAL_REGS_MASK);
- if (!wdt_rstout) {
+ dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
+ INTERNAL_REGS_MASK);
+ if (!dev->rstout) {
ret = -ENODEV;
goto disable_clk;
}
- wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+ wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate;
+
+ dev->wdt.timeout = wdt_max_duration;
+ dev->wdt.max_timeout = wdt_max_duration;
+ watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev);
- orion_wdt.timeout = wdt_max_duration;
- orion_wdt.max_timeout = wdt_max_duration;
- watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
+ platform_set_drvdata(pdev, &dev->wdt);
+ watchdog_set_drvdata(&dev->wdt, dev);
/* Let's make sure the watchdog is fully stopped */
- orion_wdt_stop(&orion_wdt);
+ orion_wdt_stop(&dev->wdt);
/* It's important to request the IRQ only after the watchdog is disabled */
irq = platform_get_irq(pdev, 0);
@@ -196,37 +216,41 @@ static int orion_wdt_probe(struct platform_device *pdev)
* watchdog, so let's make it optional.
*/
ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0,
- pdev->name, &orion_wdt);
+ pdev->name, dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto disable_clk;
}
}
- watchdog_set_nowayout(&orion_wdt, nowayout);
- ret = watchdog_register_device(&orion_wdt);
+ watchdog_set_nowayout(&dev->wdt, nowayout);
+ ret = watchdog_register_device(&dev->wdt);
if (ret)
goto disable_clk;
pr_info("Initial timeout %d sec%s\n",
- orion_wdt.timeout, nowayout ? ", nowayout" : "");
+ dev->wdt.timeout, nowayout ? ", nowayout" : "");
return 0;
disable_clk:
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(dev->clk);
return ret;
}
static int orion_wdt_remove(struct platform_device *pdev)
{
- watchdog_unregister_device(&orion_wdt);
- clk_disable_unprepare(clk);
+ struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ watchdog_unregister_device(wdt_dev);
+ clk_disable_unprepare(dev->clk);
return 0;
}
static void orion_wdt_shutdown(struct platform_device *pdev)
{
- orion_wdt_stop(&orion_wdt);
+ struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
+ orion_wdt_stop(wdt_dev);
}
static const struct of_device_id orion_wdt_of_match_table[] = {
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 11/20] watchdog: orion: Introduce per-compatible of_device_id data
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
This commit adds an orion_watchdog_data structure to hold compatible-data
information. This allows to remove the driver-wide definition and to
be able to add support for multiple compatible-strings in the future.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 58 +++++++++++++++++++++++++++++++-------------
1 file changed, 41 insertions(+), 17 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 1423fd8..540b5c9 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -24,6 +24,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/of_device.h>
/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */
#define ORION_RSTOUT_MASK_OFFSET 0x20108
@@ -35,29 +36,33 @@
* Watchdog timer block registers.
*/
#define TIMER_CTRL 0x0000
-#define WDT_EN 0x0010
-#define WDT_VAL 0x0024
#define WDT_MAX_CYCLE_COUNT 0xffffffff
-#define WDT_RESET_OUT_EN BIT(1)
-
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
+struct orion_watchdog_data {
+ int wdt_counter_offset;
+ int wdt_enable_bit;
+ int rstout_enable_bit;
+};
+
struct orion_watchdog {
struct watchdog_device wdt;
void __iomem *reg;
void __iomem *rstout;
unsigned long clk_rate;
struct clk *clk;
+ const struct orion_watchdog_data *data;
};
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Reload watchdog duration */
- writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
return 0;
}
@@ -66,13 +71,16 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Set watchdog duration */
- writel(dev->clk_rate * wdt_dev->timeout, dev->reg + WDT_VAL);
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
/* Enable watchdog timer */
- atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, WDT_EN);
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+ dev->data->wdt_enable_bit);
/* Enable reset on watchdog */
- atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN);
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+ dev->data->rstout_enable_bit);
return 0;
}
@@ -82,10 +90,10 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
/* Disable reset on watchdog */
- atomic_io_modify(dev->rstout, WDT_RESET_OUT_EN, 0);
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 0);
/* Disable watchdog timer */
- atomic_io_modify(dev->reg + TIMER_CTRL, WDT_EN, 0);
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
return 0;
}
@@ -93,7 +101,7 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
- return readl(dev->reg + WDT_VAL) / dev->clk_rate;
+ return readl(dev->reg + dev->data->wdt_counter_offset) / dev->clk_rate;
}
static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
@@ -150,9 +158,25 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
return devm_ioremap(&pdev->dev, rstout, 0x4);
}
+static const struct orion_watchdog_data orion_data = {
+ .rstout_enable_bit = BIT(1),
+ .wdt_enable_bit = BIT(4),
+ .wdt_counter_offset = 0x24,
+};
+
+static const struct of_device_id orion_wdt_of_match_table[] = {
+ {
+ .compatible = "marvell,orion-wdt",
+ .data = &orion_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
+
static int orion_wdt_probe(struct platform_device *pdev)
{
struct orion_watchdog *dev;
+ const struct of_device_id *match;
unsigned int wdt_max_duration; /* (seconds) */
struct resource *res;
int ret, irq;
@@ -162,9 +186,15 @@ static int orion_wdt_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
+ match = of_match_device(orion_wdt_of_match_table, &pdev->dev);
+ if (!match)
+ /* Default legacy match */
+ match = &orion_wdt_of_match_table[0];
+
dev->wdt.info = &orion_wdt_info;
dev->wdt.ops = &orion_wdt_ops;
dev->wdt.min_timeout = 1;
+ dev->data = match->data;
dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
@@ -253,12 +283,6 @@ static void orion_wdt_shutdown(struct platform_device *pdev)
orion_wdt_stop(wdt_dev);
}
-static const struct of_device_id orion_wdt_of_match_table[] = {
- { .compatible = "marvell,orion-wdt", },
- {},
-};
-MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
-
static struct platform_driver orion_wdt_driver = {
.probe = orion_wdt_probe,
.remove = orion_wdt_remove,
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 12/20] watchdog: orion: Add per-compatible clock initialization
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Following the introduction of the compatible-data field,
it's now possible to further abstract the clock initialization.
This will allow to support SoC with a different clock setup.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 37 +++++++++++++++++++++++++++----------
1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 540b5c9..4100d5b 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -42,10 +42,14 @@
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
+struct orion_watchdog;
+
struct orion_watchdog_data {
int wdt_counter_offset;
int wdt_enable_bit;
int rstout_enable_bit;
+ int (*clock_init) (struct platform_device *,
+ struct orion_watchdog *);
};
struct orion_watchdog {
@@ -57,6 +61,22 @@ struct orion_watchdog {
const struct orion_watchdog_data *data;
};
+static int orion_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+ return 0;
+}
+
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -162,6 +182,7 @@ static const struct orion_watchdog_data orion_data = {
.rstout_enable_bit = BIT(1),
.wdt_enable_bit = BIT(4),
.wdt_counter_offset = 0x24,
+ .clock_init = orion_wdt_clock_init,
};
static const struct of_device_id orion_wdt_of_match_table[] = {
@@ -196,16 +217,6 @@ static int orion_wdt_probe(struct platform_device *pdev)
dev->wdt.min_timeout = 1;
dev->data = match->data;
- dev->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(dev->clk)) {
- dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
- return PTR_ERR(dev->clk);
- }
- ret = clk_prepare_enable(dev->clk);
- if (ret)
- return ret;
- dev->clk_rate = clk_get_rate(dev->clk);
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENODEV;
@@ -226,6 +237,12 @@ static int orion_wdt_probe(struct platform_device *pdev)
goto disable_clk;
}
+ ret = dev->data->clock_init(pdev, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot initialize clock\n");
+ return ret;
+ }
+
wdt_max_duration = WDT_MAX_CYCLE_COUNT / dev->clk_rate;
dev->wdt.timeout = wdt_max_duration;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 13/20] watchdog: orion: Add per-compatible watchdog start implementation
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
To handle differences between SoCs this commit adds per-compatible
string start() function for the watchdog kick-off. This is preparation
work and makes no functionality changes to the current driver.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 4100d5b..af855c9 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -50,6 +50,7 @@ struct orion_watchdog_data {
int rstout_enable_bit;
int (*clock_init) (struct platform_device *,
struct orion_watchdog *);
+ int (*start) (struct watchdog_device *);
};
struct orion_watchdog {
@@ -86,7 +87,7 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
return 0;
}
-static int orion_wdt_start(struct watchdog_device *wdt_dev)
+static int orion_start(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -105,6 +106,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
return 0;
}
+static int orion_wdt_start(struct watchdog_device *wdt_dev)
+{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ /* There are some per-SoC quirks to handle */
+ return dev->data->start(wdt_dev);
+}
+
static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -183,6 +192,7 @@ static const struct orion_watchdog_data orion_data = {
.wdt_enable_bit = BIT(4),
.wdt_counter_offset = 0x24,
.clock_init = orion_wdt_clock_init,
+ .start = orion_start,
};
static const struct of_device_id orion_wdt_of_match_table[] = {
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 14/20] watchdog: orion: Add support for Armada 370 and Armada XP SoC
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Using the added infrastructure for handling SoC differences,
this commit adds support for the watchdog controller available
in Armada 370 and Armada XP SoCs.
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/orion_wdt.c | 94 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+)
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index af855c9..1d99f5e 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -36,9 +36,17 @@
* Watchdog timer block registers.
*/
#define TIMER_CTRL 0x0000
+#define TIMER_A370_STATUS 0x04
#define WDT_MAX_CYCLE_COUNT 0xffffffff
+#define WDT_A370_RATIO_MASK(v) ((v) << 16)
+#define WDT_A370_RATIO_SHIFT 5
+#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT)
+
+#define WDT_AXP_FIXED_ENABLE_BIT BIT(10)
+#define WDT_A370_EXPIRED BIT(31)
+
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat = -1; /* module parameter (seconds) */
@@ -78,6 +86,48 @@ static int orion_wdt_clock_init(struct platform_device *pdev,
return 0;
}
+static int armada370_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ /* Setup watchdog input clock */
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
+
+ dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
+ return 0;
+}
+
+static int armadaxp_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+ ret = clk_prepare_enable(dev->clk);
+ if (ret)
+ return ret;
+
+ /* Enable the fixed watchdog clock input */
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_AXP_FIXED_ENABLE_BIT,
+ WDT_AXP_FIXED_ENABLE_BIT);
+
+ dev->clk_rate = clk_get_rate(dev->clk);
+ return 0;
+}
+
static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -87,6 +137,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
return 0;
}
+static int armada370_start(struct watchdog_device *wdt_dev)
+{
+ struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+ /* Set watchdog duration */
+ writel(dev->clk_rate * wdt_dev->timeout,
+ dev->reg + dev->data->wdt_counter_offset);
+
+ /* Clear the watchdog expiration bit */
+ atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
+
+ /* Enable watchdog timer */
+ atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+ dev->data->wdt_enable_bit);
+
+ atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
+ dev->data->rstout_enable_bit);
+ return 0;
+}
+
static int orion_start(struct watchdog_device *wdt_dev)
{
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -195,11 +265,35 @@ static const struct orion_watchdog_data orion_data = {
.start = orion_start,
};
+static const struct orion_watchdog_data armada370_data = {
+ .rstout_enable_bit = BIT(8),
+ .wdt_enable_bit = BIT(8),
+ .wdt_counter_offset = 0x34,
+ .clock_init = armada370_wdt_clock_init,
+ .start = armada370_start,
+};
+
+static const struct orion_watchdog_data armadaxp_data = {
+ .rstout_enable_bit = BIT(8),
+ .wdt_enable_bit = BIT(8),
+ .wdt_counter_offset = 0x34,
+ .clock_init = armadaxp_wdt_clock_init,
+ .start = armada370_start,
+};
+
static const struct of_device_id orion_wdt_of_match_table[] = {
{
.compatible = "marvell,orion-wdt",
.data = &orion_data,
},
+ {
+ .compatible = "marvell,armada-370-wdt",
+ .data = &armada370_data,
+ },
+ {
+ .compatible = "marvell,armada-xp-wdt",
+ .data = &armadaxp_data,
+ },
{},
};
MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 15/20] ARM: mvebu: Enable Armada 370/XP watchdog in the devicetree
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Add the DT nodes to enable watchdog support available in Armada 370
and Armada XP SoCs.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/armada-370-xp.dtsi | 4 ++++
arch/arm/boot/dts/armada-370.dtsi | 5 +++++
arch/arm/boot/dts/armada-xp.dtsi | 6 ++++++
3 files changed, 15 insertions(+)
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 7f10f62..96e0389 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -151,6 +151,10 @@
interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
};
+ watchdog at 20300 {
+ reg = <0x20300 0x34>, <0x20704 0x4>;
+ };
+
sata at a0000 {
compatible = "marvell,orion-sata";
reg = <0xa0000 0x5000>;
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 7a4b82e..aebed9e 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -168,6 +168,11 @@
clocks = <&coreclk 2>;
};
+ watchdog at 20300 {
+ compatible = "marvell,armada-370-wdt";
+ clocks = <&coreclk 2>;
+ };
+
coreclk: mvebu-sar at 18230 {
compatible = "marvell,armada-370-core-clock";
reg = <0x18230 0x08>;
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 281c644..8c6c06c 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -74,6 +74,12 @@
clock-names = "nbclk", "fixed";
};
+ watchdog at 20300 {
+ compatible = "marvell,armada-xp-wdt";
+ clocks = <&coreclk 2>, <&refclk>;
+ clock-names = "nbclk", "fixed";
+ };
+
coreclk: mvebu-sar at 18230 {
compatible = "marvell,armada-xp-core-clock";
reg = <0x18230 0x08>;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 16/20] ARM: kirkwood: Add RSTOUT 'reg' entry to devicetree
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
In order to support multiplatform builds the watchdog devicetree binding
was modified and now the 'reg' property is specified to need two
entries. This commit adds the second entry as-per the new specification.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/kirkwood.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 8b73c80..80a56b0 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -165,7 +165,7 @@
wdt: watchdog-timer at 20300 {
compatible = "marvell,orion-wdt";
- reg = <0x20300 0x28>;
+ reg = <0x20300 0x28>, <0x20108 0x4>;
interrupt-parent = <&bridge_intc>;
interrupts = <3>;
clocks = <&gate_clk 7>;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 17/20] ARM: dove: Enable Dove watchdog in the devicetree
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Add the devicetree node to enable watchdog support available in Dove SoCs.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/dove.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 113a8bc..14659a8 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -120,6 +120,14 @@
clocks = <&core_clk 0>;
};
+ watchdog at 20300 {
+ compatible = "marvell,orion-wdt";
+ reg = <0x20300 0x28>, <0x20108 0x4>;
+ interrupt-parent = <&bridge_intc>;
+ interrupts = <3>;
+ clocks = <&core_clk 0>;
+ };
+
intc: main-interrupt-ctrl at 20200 {
compatible = "marvell,orion-intc";
interrupt-controller;
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 18/20] watchdog: orion: Enable the build on ARCH_MVEBU
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
After adding support for Armada 370/XP SoC let's enable the build on
these platforms.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/watchdog/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 5be6e91..8b79012 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -282,7 +282,7 @@ config DAVINCI_WATCHDOG
config ORION_WATCHDOG
tristate "Orion watchdog"
- depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU
select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 19/20] ARM: mvebu: Enable watchdog support in defconfig
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Now that we have proper support for Armada 370/XP watchdog
let's enable it in the defconfig.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/configs/mvebu_defconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index 594d706..84ec924 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -60,6 +60,8 @@ CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_THERMAL=y
CONFIG_ARMADA_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_ORION_WATCHDOG=y
CONFIG_USB_SUPPORT=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
--
1.8.1.5
^ permalink raw reply related
* [PATCH v5 20/20] ARM: dove: Enable watchdog support in the defconfig
From: Ezequiel Garcia @ 2014-01-27 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1390836440-12744-1-git-send-email-ezequiel.garcia@free-electrons.com>
Now that we have watchdog support, let's add it to the defconfig.
Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/configs/dove_defconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig
index 1101054..a330690 100644
--- a/arch/arm/configs/dove_defconfig
+++ b/arch/arm/configs/dove_defconfig
@@ -80,6 +80,8 @@ CONFIG_SPI_ORION=y
# CONFIG_HWMON is not set
CONFIG_THERMAL=y
CONFIG_DOVE_THERMAL=y
+CONFIG_WATCHDOG=y
+CONFIG_ORION_WATCHDOG=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
--
1.8.1.5
^ permalink raw reply related
* [Q] block / zynq: DMA bouncing
From: Guennadi Liakhovetski @ 2014-01-27 15:35 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140127152457.GA1073@trinity.fluff.org>
Hi Ben,
On Mon, 27 Jan 2014, Ben Dooks wrote:
> On Mon, Jan 27, 2014 at 04:13:56PM +0100, Guennadi Liakhovetski wrote:
> > Hi all,
> >
> > I'm working on an MMC driver with a DMA capability. All has been working
> > well, until at some point I've got a bus error, when the mmc driver had
> > been handed in a buffer at 0x3000 physical RAM address. The reason is,
> > that on Zynq arch bus masters cannot access RAM below 0x80000. Therefore
> > my question: how shall I configure this in software?
> >
> > The way I found was to use ARM-specific struct dmabounce_device_info and
> > implement its .needs_bounce() method to return true for those addresses.
> > Is this the right way or is there a better / more straight-forward one?
> >
> > To do the above I have to enable CONFIG_DMABOUNCE, which then selects
> > CONFIG_ZONE_DMA. Having done just that I suddenly discover, that 0x3000
> > buffers aren't used any more, so, I cannot actually verify my
> > implementation :) Looking at ZONE_DMA it looks like it is still covering
> > the whole RAM range (/proc/zoneinfo shows start_pfn=0 in zone DMA), so, I
> > don't see why 0x3000 should be excluded now.
> >
> > So, is using the .needs_bounce() method the correct way to support DMA on
> > this arch or is there a better one?
>
> I have a similar issue with Renesas R8A7790 where there is a bus bridge
> that can only deal with transactions to one half of the available RAM.
Have you tried enabling CONFIG_DMABOUNCE?
Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/
^ permalink raw reply
* [PATCH RFC v3 0/8] Beaglebone-Black HDMI audio
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
Changes since RFC v2 version of the patches:
- Dropped out already applied:
ASoC: hdmi-codec: Add devicetree binding with documentation
- Addresses Mark's comments here:
http://mailman.alsa-project.org/pipermail/alsa-devel/2013-December/070605.html
- ASoC: davinci-evm: Add named clock reference to DT bindings
- Get rid of unnecessary castings
- Add mclk NULL checks
- Use devm_clk_get()
- Change clock name from "ti,codec-clock" to "mclk"
- Address Mark's comments here:
http://mailman.alsa-project.org/pipermail/alsa-devel/2013-December/070606.html - ASoC: davinci-evm: HDMI audio support for TDA998x trough McASP I2S bus
- Get rid of unnecessary castings
- Update commit message
- Add: ASoC: davinci-mcasp: Set BCLK divider if McASP is BCLK master
- Use snd_soc_params_to_bclk()
Changes since the first RFC version of the patches:
- Drop out already applied:
ASoC: hdmi-codec: Add SNDRV_PCM_FMTBIT_32_LE playback format
- Change sound node's compatible property
form: "ti,am33xx-beaglebone-black" to "ti,am33xx-beaglebone-black-audio"
- Some minor style issue fixes from TI internal review
Jyri Sarha (8):
clk: add gpio controlled clock
ASoC: davinci-evm: Add named clock reference to DT bindings
ASoC: davinci-mcasp: Set BCLK divider if McASP is BCLK master
ASoC: davinci-evm: HDMI audio support for TDA998x trough McASP I2S
bus
ASoC: davinci: HDMI audio build for AM33XX and TDA998x
drm/tilcdc: Add I2C HDMI audio config for tda998x
ARM: OMAP2+: omap2plus_defconfig: Enable tilcdc and TDA998X HDMI
support
ARM: OMAP2+: omap2plus_defconfig: Enable BeagleBone Black HDMI audio
support
.../devicetree/bindings/clock/gpio-clock.txt | 21 ++
.../bindings/sound/davinci-evm-audio.txt | 13 +-
arch/arm/configs/omap2plus_defconfig | 5 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-gpio.c | 210 +++++++++++++++++++
drivers/gpu/drm/tilcdc/tilcdc_slave.c | 24 ++-
include/linux/clk-provider.h | 25 +++
sound/soc/davinci/Kconfig | 12 ++
sound/soc/davinci/Makefile | 1 +
sound/soc/davinci/davinci-evm.c | 211 +++++++++++++++++++-
sound/soc/davinci/davinci-mcasp.c | 20 ++
11 files changed, 534 insertions(+), 9 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/gpio-clock.txt
create mode 100644 drivers/clk/clk-gpio.c
--
1.7.9.5
^ permalink raw reply
* [PATCH RFC v3 1/8] clk: add gpio controlled clock
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
The added clk-gpio is a basic clock that can be enabled and disabled
trough a gpio output. The DT binding document for the clock is also
added. For EPROBE_DEFER handling the registering of the clock has to
be delayed until of_clk_get() call time.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
cc: mturquette at linaro.org
cc: bcousson at baylibre.com
---
.../devicetree/bindings/clock/gpio-clock.txt | 21 ++
drivers/clk/Makefile | 1 +
drivers/clk/clk-gpio.c | 210 ++++++++++++++++++++
include/linux/clk-provider.h | 25 +++
4 files changed, 257 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/gpio-clock.txt
create mode 100644 drivers/clk/clk-gpio.c
diff --git a/Documentation/devicetree/bindings/clock/gpio-clock.txt b/Documentation/devicetree/bindings/clock/gpio-clock.txt
new file mode 100644
index 0000000..54fea39
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/gpio-clock.txt
@@ -0,0 +1,21 @@
+Binding for simple gpio controlled clock.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "gpio-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- enable-gpios : GPIO reference for enabling and disabling the clock.
+
+Optional properties:
+- clocks: Maximum of one parent clock is supported.
+
+Example:
+ clock {
+ compatible = "gpio-clock";
+ clocks = <&parentclk>;
+ #clock-cells = <0>;
+ enable-gpios = <&gpio 1 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 7a10bc9..9616e3a 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
+obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
# SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
new file mode 100644
index 0000000..e04b0e1
--- /dev/null
+++ b/drivers/clk/clk-gpio.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * 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.
+ *
+ * Gpio controlled clock implementation
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+/**
+ * DOC: basic gpio controlled clock which can be enabled and disabled
+ * with gpio output
+ * Traits of this clock:
+ * prepare - clk_(un)prepare only ensures parent is (un)prepared
+ * enable - clk_enable and clk_disable are functional & control gpio
+ * rate - inherits rate from parent. No clk_set_rate support
+ * parent - fixed parent. No clk_set_parent support
+ */
+
+#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
+
+static int clk_gpio_enable(struct clk_hw *hw)
+{
+ struct clk_gpio *gpio = to_clk_gpio(hw);
+ int value = gpio->active_low ? 0 : 1;
+
+ gpio_set_value(gpio->gpio, value);
+
+ return 0;
+}
+
+static void clk_gpio_disable(struct clk_hw *hw)
+{
+ struct clk_gpio *gpio = to_clk_gpio(hw);
+ int value = gpio->active_low ? 1 : 0;
+
+ gpio_set_value(gpio->gpio, value);
+}
+
+static int clk_gpio_is_enabled(struct clk_hw *hw)
+{
+ struct clk_gpio *gpio = to_clk_gpio(hw);
+ int value = gpio_get_value(gpio->gpio);
+
+ return gpio->active_low ? !value : value;
+}
+
+const struct clk_ops clk_gpio_ops = {
+ .enable = clk_gpio_enable,
+ .disable = clk_gpio_disable,
+ .is_enabled = clk_gpio_is_enabled,
+};
+EXPORT_SYMBOL_GPL(clk_gpio_ops);
+
+/**
+ * clk_register_gpio - register a gpip clock with the clock framework
+ * @dev: device that is registering this clock
+ * @name: name of this clock
+ * @parent_name: name of this clock's parent
+ * @flags: framework-specific flags for this clock
+ * @gpio: gpio to control this clock
+ * @active_low: gpio polarity
+ */
+struct clk *clk_register_gpio(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ unsigned int gpio, bool active_low)
+{
+ struct clk_gpio *clk_gpio;
+ struct clk *clk = ERR_PTR(-EINVAL);
+ struct clk_init_data init = { NULL };
+ unsigned long gpio_flags;
+ int err;
+
+ if (active_low)
+ gpio_flags = GPIOF_OUT_INIT_LOW;
+ else
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
+
+ err = gpio_request_one(gpio, gpio_flags, name);
+
+ if (err) {
+ pr_err("%s: %s: Error requesting clock control gpio %u\n",
+ __func__, name, gpio);
+ clk = ERR_PTR(err);
+ goto clk_register_gpio_err;
+ }
+
+ clk_gpio = kzalloc(sizeof(*clk_gpio), GFP_KERNEL);
+
+ if (!clk_gpio) {
+ pr_err("%s: %s: could not allocate gpio clk\n", __func__, name);
+ clk = ERR_PTR(-ENOMEM);
+ goto clk_register_gpio_err;
+ }
+
+ init.name = name;
+ init.ops = &clk_gpio_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ clk_gpio->gpio = gpio;
+ clk_gpio->active_low = active_low;
+ clk_gpio->hw.init = &init;
+
+ clk = clk_register(dev, &clk_gpio->hw);
+
+ if (!IS_ERR(clk))
+ return clk;
+
+ kfree(clk_gpio);
+
+clk_register_gpio_err:
+ gpio_free(gpio);
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register_gpio);
+
+#ifdef CONFIG_OF
+/**
+ * The clk_register_gpio has to be delayed, because the EPROBE_DEFER
+ * can not be handled properly at of_clk_init() call time.
+ */
+
+struct clk_gpio_delayed_register_data {
+ struct device_node *node;
+ struct mutex lock; /* Protect delayed clk registering */
+ struct clk *clk;
+};
+
+static
+struct clk *of_clk_gpio_delayed_register_get(struct of_phandle_args *clkspec,
+ void *_data)
+{
+ struct clk_gpio_delayed_register_data *data =
+ (struct clk_gpio_delayed_register_data *)_data;
+ struct clk *clk;
+ const char *clk_name = data->node->name;
+ const char *parent_name;
+ enum of_gpio_flags gpio_flags;
+ int gpio;
+ bool active_low;
+
+ mutex_lock(&data->lock);
+
+ if (data->clk) {
+ mutex_unlock(&data->lock);
+ return data->clk;
+ }
+
+ gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0,
+ &gpio_flags);
+
+ if (gpio < 0) {
+ mutex_unlock(&data->lock);
+ if (gpio != -EPROBE_DEFER)
+ pr_err("%s: %s: Can't get 'enable-gpios' DT property\n",
+ __func__, clk_name);
+ return ERR_PTR(gpio);
+ }
+
+ active_low = gpio_flags & OF_GPIO_ACTIVE_LOW;
+
+ parent_name = of_clk_get_parent_name(data->node, 0);
+
+ clk = clk_register_gpio(NULL, clk_name, parent_name, 0,
+ gpio, active_low);
+ if (IS_ERR(clk)) {
+ mutex_unlock(&data->lock);
+ return clk;
+ }
+
+ data->clk = clk;
+ mutex_unlock(&data->lock);
+
+ return clk;
+}
+
+/**
+ * of_gpio_clk_setup() - Setup function for gpio controlled clock
+ */
+void __init of_gpio_clk_setup(struct device_node *node)
+{
+ struct clk_gpio_delayed_register_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ pr_err("%s: could not allocate gpio clk\n", __func__);
+ return;
+ }
+
+ data->node = node;
+ mutex_init(&data->lock);
+
+ of_clk_add_provider(node, of_clk_gpio_delayed_register_get, data);
+}
+EXPORT_SYMBOL_GPL(of_gpio_clk_setup);
+CLK_OF_DECLARE(gpio_clk, "gpio-clock", of_gpio_clk_setup);
+#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7e59253..21082b2 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -407,6 +407,31 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
unsigned long flags);
+/***
+ * struct clk_gpio - gpio controlled clock
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @gpio: gpio
+ * @active_low: gpio polarity
+ *
+ * Clock with a gpio control for enabling and disabling the parent clock.
+ * Implements .enable, .disable and .is_enabled
+ */
+
+struct clk_gpio {
+ struct clk_hw hw;
+ unsigned int gpio;
+ bool active_low;
+};
+
+extern const struct clk_ops clk_gpio_ops;
+
+struct clk *clk_register_gpio(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ unsigned int gpio, bool active_low);
+
+void of_gpio_clk_setup(struct device_node *node);
+
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
* @dev: device that is registering this clock
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 2/8] ASoC: davinci-evm: Add named clock reference to DT bindings
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
The referenced clock is used to get codec clock rate and the clock is
disabled and enabled in startup and shutdown snd_soc_ops call
backs. The change is also documented in DT bindigs document.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
cc: bcousson at baylibre.com
---
.../bindings/sound/davinci-evm-audio.txt | 9 ++-
sound/soc/davinci/davinci-evm.c | 58 +++++++++++++++++++-
2 files changed, 64 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 865178d..963e100 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -5,12 +5,19 @@ Required properties:
- ti,model : The user-visible name of this sound complex.
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
- ti,mcasp-controller : The phandle of the McASP controller
-- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
- ti,audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the connection's sink,
the second being the connection's source. Valid names for sources and
sinks are the codec's pins, and the jacks on the board:
+Optional properties:
+- ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec.
+- clocks : Reference to the master clock
+- clock-names : The clock should be named "mclk"
+- Either codec-clock-rate or the codec-clock reference has to be defined. If
+ the both are defined the driver attempts to set referenced clock to the
+ defined rate and takes the rate from the clock reference.
+
Board connectors:
* Headphone Jack
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 70ff377..d3e4cb0 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -17,6 +17,7 @@
#include <linux/platform_data/edma.h>
#include <linux/i2c.h>
#include <linux/of_platform.h>
+#include <linux/clk.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -30,9 +31,34 @@
#include "davinci-i2s.h"
struct snd_soc_card_drvdata_davinci {
+ struct clk *mclk;
unsigned sysclk;
};
+static int evm_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+
+ if (drvdata->mclk)
+ return clk_prepare_enable(drvdata->mclk);
+
+ return 0;
+}
+
+static void evm_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+
+ if (drvdata->mclk)
+ clk_disable_unprepare(drvdata->mclk);
+}
+
static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
}
static struct snd_soc_ops evm_ops = {
+ .startup = evm_startup,
+ .shutdown = evm_shutdown,
.hw_params = evm_hw_params,
};
@@ -348,6 +376,7 @@ static int davinci_evm_probe(struct platform_device *pdev)
of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev);
struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data;
struct snd_soc_card_drvdata_davinci *drvdata = NULL;
+ struct clk *mclk;
int ret = 0;
evm_soc_card.dai_link = dai;
@@ -367,13 +396,38 @@ static int davinci_evm_probe(struct platform_device *pdev)
if (ret)
return ret;
+ mclk = devm_clk_get(&pdev->dev, "mclk");
+ if (PTR_ERR(mclk) == -EPROBE_DEFER) {
+ return -EPROBE_DEFER;
+ } else if (IS_ERR(mclk)) {
+ dev_dbg(&pdev->dev, "mclk not found.\n");
+ mclk = NULL;
+ }
+
drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
+ drvdata->mclk = mclk;
+
ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk);
- if (ret < 0)
- return -EINVAL;
+
+ if (ret < 0) {
+ if (!drvdata->mclk) {
+ dev_err(&pdev->dev,
+ "No clock or clock rate defined.\n");
+ return -EINVAL;
+ }
+ drvdata->sysclk = clk_get_rate(drvdata->mclk);
+ } else if (drvdata->mclk) {
+ unsigned int requestd_rate = drvdata->sysclk;
+ clk_set_rate(drvdata->mclk, drvdata->sysclk);
+ drvdata->sysclk = clk_get_rate(drvdata->mclk);
+ if (drvdata->sysclk != requestd_rate)
+ dev_warn(&pdev->dev,
+ "Could not get requested rate %u using %u.\n",
+ requestd_rate, drvdata->sysclk);
+ }
snd_soc_card_set_drvdata(&evm_soc_card, drvdata);
ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card);
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 3/8] ASoC: davinci-mcasp: Set BCLK divider if McASP is BCLK master
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
Make BCLK divider setting implicite in hw_params call if McASP device
is the bit clock master on the audio serial bus.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
sound/soc/davinci/davinci-mcasp.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index b7858bf..ae328be 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -53,6 +53,9 @@ struct davinci_mcasp {
u16 bclk_lrclk_ratio;
int streams;
+ int sysclk_freq;
+ bool bclk_master;
+
/* McASP FIFO related */
u8 txnumevt;
u8 rxnumevt;
@@ -292,6 +295,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 1;
break;
case SND_SOC_DAIFMT_CBM_CFS:
/* codec is clock master and frame slave */
@@ -303,6 +307,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR);
mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR);
+ mcasp->bclk_master = 0;
break;
case SND_SOC_DAIFMT_CBM_CFM:
/* codec is clock and frame master */
@@ -314,6 +319,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG,
ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR);
+ mcasp->bclk_master = 0;
break;
default:
@@ -405,6 +411,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id,
mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX);
}
+ mcasp->sysclk_freq = freq;
+
return 0;
}
@@ -607,6 +615,18 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
int channels;
struct snd_interval *pcm_channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* If mcasp is BCLK master we need to set BCLK divider */
+ if (mcasp->bclk_master) {
+ unsigned int bclk_freq = snd_soc_params_to_bclk(params);
+ if (mcasp->sysclk_freq % bclk_freq != 0) {
+ dev_err(mcasp->dev, "Can't produce requred BCLK\n");
+ return -EINVAL;
+ }
+ davinci_mcasp_set_clkdiv(
+ cpu_dai, 1, mcasp->sysclk_freq / bclk_freq);
+ }
+
channels = pcm_channels->min;
active_serializers = (channels + slots - 1) / slots;
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 4/8] ASoC: davinci-evm: HDMI audio support for TDA998x trough McASP I2S bus
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
Add machine driver support for BeagleBone-Black and other boards with
tilcdc support and NXP TDA998X HDMI transmitter connected to McASP
port in I2S mode. McASP produces the bit clock for the i2s bus from
the masted clock by a simple divider and the available sample rates
depend on the used master clock frequency. The only properly working
sample format appears to be SNDRV_PCM_FORMAT_S32_LE. The other formats
have been disabled. The 8 least significant bits of the 32 bit samples
are ignored.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
cc: bcousson at baylibre.com
---
.../bindings/sound/davinci-evm-audio.txt | 4 +-
sound/soc/davinci/davinci-evm.c | 153 +++++++++++++++++++-
2 files changed, 152 insertions(+), 5 deletions(-)
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 963e100..2a535d9 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -1,7 +1,9 @@
* Texas Instruments SoC audio setups with TLV320AIC3X Codec
Required properties:
-- compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
+- compatible :
+ "ti,da830-evm-audio" : for DM365/DA8xx/OMAPL1x/AM33xx
+ "ti,am33xx-beaglebone-black-audio" : for Beaglebone-black HDMI audio
- ti,model : The user-visible name of this sound complex.
- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
- ti,mcasp-controller : The phandle of the McASP controller
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index d3e4cb0..00f1e83 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -21,6 +21,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/pcm_params.h>
#include <asm/dma.h>
#include <asm/mach-types.h>
@@ -33,8 +34,13 @@
struct snd_soc_card_drvdata_davinci {
struct clk *mclk;
unsigned sysclk;
+ struct snd_pcm_hw_constraint_list *rate_constraint;
};
+/* If changing sample format the tda998x configuration (REG_CTS_N) needs
+ to be changed. */
+#define TDA998X_SAMPLE_FORMAT SNDRV_PCM_FORMAT_S32_LE
+
static int evm_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -67,9 +73,10 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_card *soc_card = codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+ unsigned sysclk = drvdata->sysclk;
int ret = 0;
- unsigned sysclk = ((struct snd_soc_card_drvdata_davinci *)
- snd_soc_card_get_drvdata(soc_card))->sysclk;
/* set the codec system clock */
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
@@ -84,12 +91,63 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int evm_tda998x_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+ struct snd_mask *fmt = constrs_mask(&runtime->hw_constraints,
+ SNDRV_PCM_HW_PARAM_FORMAT);
+ snd_mask_none(fmt);
+ snd_mask_set(fmt, TDA998X_SAMPLE_FORMAT);
+
+ runtime->hw.rate_min = drvdata->rate_constraint->list[0];
+ runtime->hw.rate_max = drvdata->rate_constraint->list[
+ drvdata->rate_constraint->count - 1];
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+
+ snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ drvdata->rate_constraint);
+ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
+ 2, 2);
+
+ return evm_startup(substream);
+}
+
+static int evm_tda998x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *soc_card = codec->card;
+ struct platform_device *pdev = to_platform_device(soc_card->dev);
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+ unsigned sysclk = drvdata->sysclk;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
static struct snd_soc_ops evm_ops = {
.startup = evm_startup,
.shutdown = evm_shutdown,
.hw_params = evm_hw_params,
};
+static struct snd_soc_ops evm_tda998x_ops = {
+ .startup = evm_tda998x_startup,
+ .shutdown = evm_shutdown,
+ .hw_params = evm_tda998x_hw_params,
+};
+
/* davinci-evm machine dapm widgets */
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -156,6 +214,79 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static unsigned int tda998x_hdmi_rates[] = {
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+};
+
+static struct snd_pcm_hw_constraint_list *evm_tda998x_rate_constraint(
+ struct snd_soc_card *soc_card)
+{
+ struct platform_device *pdev = to_platform_device(soc_card->dev);
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+ unsigned sysclk = drvdata->sysclk;
+ struct snd_pcm_hw_constraint_list *ret;
+ unsigned int *rates;
+ int i, j = 0;
+
+ ret = devm_kzalloc(soc_card->dev, sizeof(*ret), GFP_KERNEL);
+ rates = devm_kzalloc(soc_card->dev, sizeof(tda998x_hdmi_rates),
+ GFP_KERNEL);
+ if (!ret || !rates)
+ return NULL;
+
+ ret->list = rates;
+ ret->mask = 0;
+ for (i = 0; i < ARRAY_SIZE(tda998x_hdmi_rates); i++) {
+ unsigned int bclk_freq = tda998x_hdmi_rates[i] * 2 *
+ snd_pcm_format_width(TDA998X_SAMPLE_FORMAT);
+ if (sysclk % bclk_freq == 0) {
+ rates[j++] = tda998x_hdmi_rates[i];
+ dev_dbg(soc_card->dev, "Allowing rate %u\n",
+ tda998x_hdmi_rates[i]);
+ }
+ }
+ ret->count = j;
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget tda998x_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("HDMI Out"),
+};
+
+static int evm_tda998x_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dapm_context *dapm = &rtd->codec->dapm;
+ struct snd_soc_card *soc_card = rtd->codec->card;
+ struct snd_soc_card_drvdata_davinci *drvdata =
+ snd_soc_card_get_drvdata(soc_card);
+ int ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ drvdata->rate_constraint = evm_tda998x_rate_constraint(soc_card);
+
+ snd_soc_dapm_new_controls(dapm, tda998x_dapm_widgets,
+ ARRAY_SIZE(tda998x_dapm_widgets));
+
+ ret = snd_soc_of_parse_audio_routing(soc_card, "ti,audio-routing");
+
+ /* not connected */
+ snd_soc_dapm_disable_pin(dapm, "RX");
+
+ /* always connected */
+ snd_soc_dapm_enable_pin(dapm, "HDMI Out");
+
+ return 0;
+}
+
/* davinci-evm digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link dm6446_evm_dai = {
.name = "TLV320AIC3X",
@@ -341,7 +472,7 @@ static struct snd_soc_card da850_snd_soc_card = {
#if defined(CONFIG_OF)
/*
- * The struct is used as place holder. It will be completely
+ * The structs are used as place holders. They will be completely
* filled with data from dt node.
*/
static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
@@ -354,10 +485,24 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
SND_SOC_DAIFMT_IB_NF,
};
+static struct snd_soc_dai_link evm_dai_tda998x_hdmi = {
+ .name = "NXP TDA998x HDMI Chip",
+ .stream_name = "HDMI",
+ .codec_dai_name = "hdmi-hifi",
+ .ops = &evm_tda998x_ops,
+ .init = evm_tda998x_init,
+ .dai_fmt = (SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_IB_NF),
+};
+
static const struct of_device_id davinci_evm_dt_ids[] = {
{
.compatible = "ti,da830-evm-audio",
- .data = (void *) &evm_dai_tlv320aic3x,
+ .data = &evm_dai_tlv320aic3x,
+ },
+ {
+ .compatible = "ti,am33xx-beaglebone-black-audio",
+ .data = &evm_dai_tda998x_hdmi,
},
{ /* sentinel */ }
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 5/8] ASoC: davinci: HDMI audio build for AM33XX and TDA998x
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
Adds configuration option for HDMI audio support for AM33XX based
boards with NXP TDA998x HDMI transmitter. The audio is connected to
NXP TDA998x trough McASP running in i2s mode.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
sound/soc/davinci/Kconfig | 12 ++++++++++++
sound/soc/davinci/Makefile | 1 +
2 files changed, 13 insertions(+)
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index a8ec1fc..40dd5d1 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -26,6 +26,18 @@ config SND_AM33XX_SOC_EVM
AM335X-EVMSK, and BeagelBone with AudioCape boards have this
setup.
+config SND_AM335X_SOC_NXPTDA_EVM
+ tristate "HDMI Audio for the AM33XX chip based boards with TDA998x"
+ depends on SND_DAVINCI_SOC && SOC_AM33XX
+ depends on DRM_TILCDC && DRM_I2C_NXP_TDA998X
+ select SND_SOC_HDMI_CODEC
+ select SND_DAVINCI_SOC_MCASP
+ help
+ Say Y or M if you want to add support for HDMI SoC audio on
+ AM33XX boards with NXP TDA998x HDMI transmitter. For example
+ BeagleBoneBack. The audio is connected to NXP TDA998x trough
+ McASP running in i2s mode.
+
config SND_DAVINCI_SOC_EVM
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
depends on SND_DAVINCI_SOC
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index 744d4d9..7587a70 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
snd-soc-evm-objs := davinci-evm.o
obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_AM335X_SOC_NXPTDA_EVM) += snd-soc-evm.o
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 6/8] drm/tilcdc: Add I2C HDMI audio config for tda998x
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
The configuration is needed for HDMI audio. The "swap" and "mirr"
parameters have to be correctly set in the configuration in order to
have proper colors in the HDMI picture.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
cc: airlied at linux.ie
---
drivers/gpu/drm/tilcdc/tilcdc_slave.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
index 595068b..e43240a 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
@@ -19,6 +19,7 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <drm/drm_encoder_slave.h>
+#include <drm/i2c/tda998x.h>
#include "tilcdc_drv.h"
@@ -111,8 +112,29 @@ static const struct drm_encoder_helper_funcs slave_encoder_helper_funcs = {
.restore = drm_i2c_encoder_restore,
};
+static struct tda998x_encoder_params tda998x_pdata = {
+ .swap_b = 0x3,
+ .mirr_b = 0x0,
+ .swap_a = 0x2,
+ .mirr_a = 0x0,
+ .swap_d = 0x1,
+ .mirr_d = 0x0,
+ .swap_c = 0x0,
+ .mirr_c = 0x0,
+ .swap_f = 0x5,
+ .mirr_f = 0x0,
+ .swap_e = 0x4,
+ .mirr_e = 0x0,
+ .audio_cfg = 0x3, /* I2S mode */
+ .audio_clk_cfg = 1, /* select clock pin */
+ .audio_frame[1] = 1, /* channels - 1 */
+ .audio_format = AFMT_I2S,
+ .audio_sample_rate = 48000,
+};
+
static const struct i2c_board_info info = {
- I2C_BOARD_INFO("tda998x", 0x70)
+ I2C_BOARD_INFO("tda998x", 0x70),
+ .platform_data = &tda998x_pdata,
};
static struct drm_encoder *slave_encoder_create(struct drm_device *dev,
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v3 7/8] ARM: OMAP2+: omap2plus_defconfig: Enable tilcdc and TDA998X HDMI support
From: Jyri Sarha @ 2014-01-27 15:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1390836773.git.jsarha@ti.com>
This enables HDMI video support on Beaglebone-Black.
Signed-off-by: Jyri Sarha <jsarha@ti.com>
cc: tony at atomide.com
---
arch/arm/configs/omap2plus_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index bfa80a1..9288172 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -180,6 +180,9 @@ CONFIG_REGULATOR_TPS6507X=y
CONFIG_REGULATOR_TPS65217=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TWL4030=y
+CONFIG_DRM=m
+CONFIG_DRM_I2C_NXP_TDA998X=m
+CONFIG_DRM_TILCDC=m
CONFIG_FB=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_MODE_HELPERS=y
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox