summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 9bd88bb)
raw | patch | inline | side by side (parent: 9bd88bb)
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | |
Tue, 26 May 2015 09:59:21 +0000 (12:59 +0300) | ||
committer | Jyri Sarha <jsarha@ti.com> | |
Wed, 27 May 2015 11:43:08 +0000 (14:43 +0300) |
The driver uses mcasp2 pin for a gpio, with direct register writes. On
system suspend the mcasp2 is left alive, preventing suspend.
Also, mcasp2 may be used for other purposes, so directly touching the
mcasp2 registers can cause problems. Luckily, the same pin can be muxed
to mcasp8 mode, and mcasp8 is not used by anyone.
We now have hacks made to mcasp driver which allows the dra7-tpd12s015
driver to manage the mcasp8 pin via the mcasp driver. While the solution
is a pure hack, it allows us to do proper power management, and remove
all the direct register write hackery.
dra7-tpd12s015's device tree data contains a phandle to the mcasp8 node,
and dra7-tpd12s015 driver uses this handle to enable and disable the
mcasp8 module, and to set the gpio output value.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Tested-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Jyri Sarha <jsarha@ti.com>
system suspend the mcasp2 is left alive, preventing suspend.
Also, mcasp2 may be used for other purposes, so directly touching the
mcasp2 registers can cause problems. Luckily, the same pin can be muxed
to mcasp8 mode, and mcasp8 is not used by anyone.
We now have hacks made to mcasp driver which allows the dra7-tpd12s015
driver to manage the mcasp8 pin via the mcasp driver. While the solution
is a pure hack, it allows us to do proper power management, and remove
all the direct register write hackery.
dra7-tpd12s015's device tree data contains a phandle to the mcasp8 node,
and dra7-tpd12s015 driver uses this handle to enable and disable the
mcasp8 module, and to set the gpio output value.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Tested-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Jyri Sarha <jsarha@ti.com>
arch/arm/boot/dts/dra7-evm.dts | patch | blob | history | |
drivers/video/fbdev/omap2/displays-new/dra7-evm-encoder-tpd12s015.c | patch | blob | history |
index 4af20a481bb739acbd0f82164d491a7746e366bd..56d0aba0335cdbc0aaebe9a2c88b2b9cd08768a9 100644 (file)
pinctrl-1 = <&hdmi_i2c_sel_pin &hdmi_i2c_pins_ddc>;
ddc-i2c-bus = <&i2c2>;
+ mcasp-gpio = <&mcasp8>;
gpios = <&pcf_hdmi 4 0>, /* P4, CT CP HPD */
<&pcf_hdmi 5 0>, /* P5, LS OE */
hdmi_i2c_sel_pin: pinmux_hdmi_i2c_sel_pin {
pinctrl-single,pins = <
/* this pin is used as a GPIO via mcasp */
- 0x2fc (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp2_aclkr */
+ 0x2fc (PIN_OUTPUT | MUX_MODE1) /* mcasp8_axr2 */
>;
};
diff --git a/drivers/video/fbdev/omap2/displays-new/dra7-evm-encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/dra7-evm-encoder-tpd12s015.c
index 78b6103b12e9af0d09cd8e7774bfe39a945580e8..6e4a7234a86a6eae064472da4d3422765cb89796 100644 (file)
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
+#include <linux/suspend.h>
+#include <linux/of_platform.h>
#include <video/omapdss.h>
-#define CLK_BASE 0x4a009000
-#define MCASP2_BASE 0x48464000
-
-#define CM_L4PER2_MCASP2_CLKCTRL 0x860
-#define CM_L4PER2_CLKSTCTRL 0x8fc
-#define MCASP_PFUNC 0x10
-#define MCASP_PDIR 0x14
-#define MCASP_PDOUT 0x18
-
#define SEL_I2C2 0
#define SEL_HDMI 1
+int dra7_mcasp_hdmi_gpio_get(struct platform_device *pdev);
+int dra7_mcasp_hdmi_gpio_put(struct platform_device *pdev);
+int dra7_mcasp_hdmi_gpio_set(struct platform_device *pdev, bool high);
+
/* HPD gpio debounce time in microseconds */
#define HPD_DEBOUNCE_TIME 1000
struct i2c_adapter *ddc_i2c_adapter;
};
-static void __iomem *mcasp2_base;
+static struct platform_device *mcasp;
-static int sel_hdmi_i2c2_init(struct device *dev)
+static int hdmi_i2c2_hack_init(struct device *dev)
{
- void __iomem *clk_base;
+ struct device_node *node;
- mcasp2_base = devm_ioremap(dev, MCASP2_BASE, 0x20);
- if (!mcasp2_base) {
- dev_err(dev, "couldn't ioremap MCASP2 regs\n");
- return -ENOMEM;
- }
+ node = of_parse_phandle(dev->of_node, "mcasp-gpio", 0);
- clk_base = devm_ioremap(dev, CLK_BASE, SZ_4K);
- if (!clk_base) {
- dev_err(dev, "couldn't ioremap clock domain regs\n");
- return -ENOMEM;
- }
+ if (!node)
+ return -ENODEV;
- /* set CM_L4PER2_CLKSTCTRL to sw supervised wkup */
- iowrite32(0x2, clk_base + CM_L4PER2_CLKSTCTRL);
+ mcasp = of_find_device_by_node(node);
- iowrite32(0x2, clk_base + CM_L4PER2_MCASP2_CLKCTRL);
+ return 0;
+}
- dev_dbg(dev, "CM_L4PER2_CLKSTCTRL %08x\n",
- ioread32(clk_base + CM_L4PER2_CLKSTCTRL));
+static int hdmi_i2c2_hack_resume_mcasp(void)
+{
+ return dra7_mcasp_hdmi_gpio_get(mcasp);
+}
- /* let it propogate */
+static void hdmi_i2c2_hack_suspend_mcasp(void)
+{
+ dra7_mcasp_hdmi_gpio_put(mcasp);
+}
- udelay(5);
+static int hdmi_i2c2_hack_pm_notif(struct notifier_block *b, unsigned long v, void *d)
+{
+ switch (v) {
+ case PM_SUSPEND_PREPARE:
+ hdmi_i2c2_hack_suspend_mcasp();
+ return 0;
- /*
- * make mcasp2_aclkr a gpio and set direction to high
- */
- iowrite32(1 << 29, mcasp2_base + MCASP_PFUNC);
- iowrite32(1 << 29, mcasp2_base + MCASP_PDIR);
+ case PM_POST_SUSPEND:
+ hdmi_i2c2_hack_resume_mcasp();
+ return 0;
- return 0;
+ default:
+ return 0;
+ }
}
+static struct notifier_block hdmi_i2c2_hack_pm_notif_block = {
+ .notifier_call = hdmi_i2c2_hack_pm_notif,
+};
+
/*
* use SEL_I2C2 to configure pcf8575@26 to set/unset LS_OE and CT_HPD, and use
* SEL_HDMI to read edid via the HDMI ddc lines
*/
-static void config_demux(struct device *dev, int sel)
+static void hdmi_i2c2_hack_demux(struct device *dev, int sel)
{
struct platform_device *pdev = to_platform_device(dev);
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
- u32 val;
/*
- * switch to I2C2 or HDMI DDC internal pinmux and drive MCASP2_ACLKR
+ * switch to I2C2 or HDMI DDC internal pinmux and drive MCASP8_AXR2
* to low or high to select I2C2 or HDMI path respectively
*/
if (sel == SEL_I2C2) {
pinctrl_select_state(ddata->pins, ddata->pin_state_i2c);
-
- val = ioread32(mcasp2_base + MCASP_PDOUT);
- iowrite32(val & ~(1 << 29), mcasp2_base + MCASP_PDOUT);
+ dra7_mcasp_hdmi_gpio_set(mcasp, false);
} else {
pinctrl_select_state(ddata->pins, ddata->pin_state_ddc);
-
- val = ioread32(mcasp2_base + MCASP_PDOUT);
- iowrite32(val | (1 << 29), mcasp2_base + MCASP_PDOUT);
+ dra7_mcasp_hdmi_gpio_set(mcasp, true);
}
/* let it propogate */
udelay(5);
-
- dev_dbg(dev, "select %d, PDOUT %08x\n", sel,
- ioread32(mcasp2_base + MCASP_PDOUT));
}
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
i2c_lock_adapter(ddata->ddc_i2c_adapter);
- config_demux(dssdev->dev, SEL_HDMI);
+ hdmi_i2c2_hack_demux(dssdev->dev, SEL_HDMI);
r = in->ops.hdmi->read_edid(in, edid, len);
- config_demux(dssdev->dev, SEL_I2C2);
+ hdmi_i2c2_hack_demux(dssdev->dev, SEL_I2C2);
i2c_unlock_adapter(ddata->ddc_i2c_adapter);
* initialize the SEL_HDMI_I2C2 line going to the demux. Configure the
* demux to select the I2C2 bus
*/
- r = sel_hdmi_i2c2_init(&pdev->dev);
+ r = hdmi_i2c2_hack_init(&pdev->dev);
if (r)
- return r;
+ goto err_hack;
- config_demux(&pdev->dev, SEL_I2C2);
+ r = hdmi_i2c2_hack_resume_mcasp();
+ if (r)
+ goto err_hack;
+
+ hdmi_i2c2_hack_demux(&pdev->dev, SEL_I2C2);
+
+ register_pm_notifier(&hdmi_i2c2_hack_pm_notif_block);
r = devm_gpio_request_one(&pdev->dev, ddata->ct_cp_hpd_gpio,
GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd");
err_reg:
err_debounce:
err_gpio:
+ hdmi_i2c2_hack_suspend_mcasp();
+err_hack:
tpd_uninit_pins(pdev);
err_pins:
omap_dss_put_device(ddata->in);
tpd_uninit_pins(pdev);
+ unregister_pm_notifier(&hdmi_i2c2_hack_pm_notif_block);
+
+ hdmi_i2c2_hack_suspend_mcasp();
+
omapdss_unregister_output(&ddata->dssdev);
WARN_ON(omapdss_device_is_enabled(dssdev));