From: Alan Tull Date: Thu, 1 Sep 2011 16:51:09 +0000 (-0500) Subject: ENGR00155845-1 mfd for hdmi X-Git-Tag: v3.0.35-fsl_4.1.0~2271 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=ec482955d207d2bbe9ad6c0486c015f592441435;p=karo-tx-linux.git ENGR00155845-1 mfd for hdmi This is a mfd for the internal HDMI Transmitter on i.Mx. It handles resources that are shared by the seperate video and audio drivers. Signed-off-by: Alan Tull --- diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9721a2dc893d..d4cf4bfc8abb 100755 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -776,6 +776,14 @@ config MFD_MAX17135 This is the MAX17135 PMIC support. It includes core support for communication with the MAX17135 chip. +config MFD_MXC_HDMI + tristate "MXC HDMI Core" + select MFD_CORE + default y + help + This is the core driver for the i.Mx on-chip HDMI. This MFD + driver connects with the video and audio drivers for HDMI. + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 74dd652ec68c..1f6b27fc104c 100755 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -89,6 +89,8 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o + +obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_MAX17135) += max17135-core.o diff --git a/drivers/mfd/mxc-hdmi-core.c b/drivers/mfd/mxc-hdmi-core.c new file mode 100644 index 000000000000..0e59dafd0a3b --- /dev/null +++ b/drivers/mfd/mxc-hdmi-core.c @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct mxc_hdmi_data { + struct clk *isfr_clk; + struct platform_device *pdev; + unsigned long __iomem *reg_base; + unsigned long reg_phys_base; + struct device *dev; +}; + +static unsigned long hdmi_base; + +int mxc_hdmi_pixel_clk; +int mxc_hdmi_ratio; + +u8 hdmi_readb(unsigned int reg) +{ + u8 value; + + value = __raw_readb(hdmi_base + reg); + + pr_debug("hdmi rd: 0x%04x = 0x%02x\n", reg, value); + + return value; +} + +void hdmi_writeb(u8 value, unsigned int reg) +{ + pr_debug("hdmi wr: 0x%04x = 0x%02x\n", reg, value); + __raw_writeb(value, hdmi_base + reg); +} + +void hdmi_mask_writeb(u8 data, unsigned int reg, u8 shift, u8 mask) +{ + u8 value = hdmi_readb(reg) & ~mask; + value |= (data << shift) & mask; + hdmi_writeb(value, reg); +} + +unsigned int hdmi_read4(unsigned int reg) +{ + /* read a four byte address from registers */ + return (hdmi_readb(reg + 3) << 24) | + (hdmi_readb(reg + 2) << 16) | + (hdmi_readb(reg + 1) << 8) | + hdmi_readb(reg); +} + +void hdmi_write4(unsigned int value, unsigned int reg) +{ + /* write a four byte address to hdmi regs */ + hdmi_writeb(value & 0xff, reg); + hdmi_writeb((value >> 8) & 0xff, reg + 1); + hdmi_writeb((value >> 16) & 0xff, reg + 2); + hdmi_writeb((value >> 24) & 0xff, reg + 3); +} + +static void initialize_hdmi_ih_mutes(void) +{ + u8 ih_mute; + + /* + * Boot up defaults are: + * HDMI_IH_MUTE = 0x03 (disabled) + * HDMI_IH_MUTE_* = 0x00 (enabled) + */ + + /* Disable top level interrupt bits in HDMI block */ + ih_mute = hdmi_readb(HDMI_IH_MUTE) | + HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; + + hdmi_writeb(ih_mute, HDMI_IH_MUTE); + + /* Disable interrupts in the IH_MUTE_* registers */ + hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT1); + hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT2); + hdmi_writeb(0xff, HDMI_IH_MUTE_AS_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_PHY_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_I2CM_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_CEC_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_VP_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_I2CMPHY_STAT0); + hdmi_writeb(0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + /* Enable top level interrupt bits in HDMI block */ + ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT); + hdmi_writeb(ih_mute, HDMI_IH_MUTE); +} + +static int mxc_hdmi_core_probe(struct platform_device *pdev) +{ + struct mxc_hdmi_data *hdmi_data; + struct resource *res; + int ret = 0; + + /* 100% for 8 bit pixels */ + mxc_hdmi_ratio = 100; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENOENT; + + hdmi_data = kzalloc(sizeof(struct mxc_hdmi_data), GFP_KERNEL); + if (!hdmi_data) { + dev_err(&pdev->dev, "Couldn't allocate mxc hdmi mfd device\n"); + return -ENOMEM; + } + hdmi_data->pdev = pdev; + + hdmi_data->isfr_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_isfr_clk"); + if (IS_ERR(hdmi_data->isfr_clk)) { + ret = PTR_ERR(hdmi_data->isfr_clk); + dev_err(&hdmi_data->pdev->dev, + "Unable to get HDMI isfr clk: %d\n", ret); + goto eclkg; + } + + ret = clk_enable(hdmi_data->isfr_clk); + if (ret < 0) { + dev_err(&pdev->dev, "Cannot enable HDMI clock: %d\n", ret); + goto eclke; + } + + pr_debug("%s isfr_clk:%d\n", __func__, + (int)clk_get_rate(hdmi_data->isfr_clk)); + + hdmi_data->reg_phys_base = res->start; + if (!request_mem_region(res->start, resource_size(res), + dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto emem; + } + + hdmi_data->reg_base = ioremap(res->start, resource_size(res)); + if (!hdmi_data->reg_base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto eirq; + } + hdmi_base = (unsigned long)hdmi_data->reg_base; + + pr_debug("\n%s hdmi hw base = 0x%08x\n\n", __func__, (int)res->start); + + initialize_hdmi_ih_mutes(); + + /* Replace platform data coming in with a local struct */ + platform_set_drvdata(pdev, hdmi_data); + + return ret; + +eirq: + release_mem_region(res->start, resource_size(res)); +emem: + clk_disable(hdmi_data->isfr_clk); +eclke: + clk_put(hdmi_data->isfr_clk); +eclkg: + kfree(hdmi_data); + return ret; +} + + +static int __exit mxc_hdmi_core_remove(struct platform_device *pdev) +{ + struct mxc_hdmi_data *hdmi_data = platform_get_drvdata(pdev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + iounmap(hdmi_data->reg_base); + release_mem_region(res->start, resource_size(res)); + + kfree(hdmi_data); + + return 0; +} + +static struct platform_driver mxc_hdmi_core_driver = { + .driver = { + .name = "mxc_hdmi_core", + .owner = THIS_MODULE, + }, + .remove = __exit_p(mxc_hdmi_core_remove), +}; + +static int __init mxc_hdmi_core_init(void) +{ + return platform_driver_probe(&mxc_hdmi_core_driver, + mxc_hdmi_core_probe); +} + +static void __exit mxc_hdmi_core_exit(void) +{ + platform_driver_unregister(&mxc_hdmi_core_driver); +} + +subsys_initcall(mxc_hdmi_core_init); +module_exit(mxc_hdmi_core_exit); + +MODULE_DESCRIPTION("Core driver for Freescale i.Mx on-chip HDMI"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 30c30bd6018f..3811e48c7746 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2396,6 +2396,7 @@ endif config FB_MXC_HDMI depends on FB_MXC_SYNC_PANEL tristate "MXC HDMI driver support" + select MFD_MXC_HDMI help Driver for the on-chip MXC HDMI controller. diff --git a/include/linux/mfd/mxc-hdmi-core.h b/include/linux/mfd/mxc-hdmi-core.h new file mode 100644 index 000000000000..f5021c7acb44 --- /dev/null +++ b/include/linux/mfd/mxc-hdmi-core.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __LINUX_MXC_HDMI_CORE_H_ +#define __LINUX_MXC_HDMI_CORE_H_ + +u8 hdmi_readb(unsigned int reg); +void hdmi_writeb(u8 value, unsigned int reg); +void hdmi_mask_writeb(u8 data, unsigned int addr, u8 shift, u8 mask); +unsigned int hdmi_read4(unsigned int reg); +void hdmi_write4(unsigned int value, unsigned int reg); + +extern int mxc_hdmi_pixel_clk; +extern int mxc_hdmi_ratio; + +#endif