summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorKe Qinghua <qinghua.ke@freescale.com>2013-12-19 10:29:12 +0800
committerKe Qinghua <qinghua.ke@freescale.com>2013-12-19 12:17:06 +0800
commit6702ef28b741ab2895f4220ac70f7949a55bb8ee (patch)
treead771be3c7581889bbda0ea48c68d83472cb5225 /arch
parent6aa195c6f430c25f671c00b88601cc7550f5a72c (diff)
ENGR00292372 Add consumer IR support in android 4.4
Add IR char driver,mx6_ir driver,epit driver and update configuration for support IR. Signed-off-by: Ke Qinghua <qinghua.ke@freescale.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/configs/imx6_android_defconfig6
-rw-r--r--arch/arm/mach-mx6/Kconfig8
-rw-r--r--arch/arm/mach-mx6/Makefile1
-rw-r--r--arch/arm/mach-mx6/board-mx6dl_sabresd.h2
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.c12
-rw-r--r--arch/arm/mach-mx6/board-mx6q_sabresd.h2
-rw-r--r--arch/arm/mach-mx6/devices-imx6q.h10
-rw-r--r--arch/arm/mach-mx6/mx6_ir.c331
-rw-r--r--arch/arm/plat-mxc/epit.c17
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_ir.h37
-rwxr-xr-xarch/arm/plat-mxc/pwm.c17
11 files changed, 438 insertions, 5 deletions
diff --git a/arch/arm/configs/imx6_android_defconfig b/arch/arm/configs/imx6_android_defconfig
index 8e57fa7956e9..e8af9feefe0c 100644
--- a/arch/arm/configs/imx6_android_defconfig
+++ b/arch/arm/configs/imx6_android_defconfig
@@ -288,6 +288,7 @@ CONFIG_IMX_HAVE_PLATFORM_IMX_ESAI=y
CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y
CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI=y
CONFIG_IMX_HAVE_PLATFORM_MXC_PWM=y
+CONFIG_IMX_HAVE_PLATFORM_MXC_EPIT=y
CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX=y
CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y
CONFIG_IMX_HAVE_PLATFORM_IMX_IPUV3=y
@@ -346,12 +347,16 @@ CONFIG_USB_EHCI_ARC_H1=y
CONFIG_USB_FSL_ARC_OTG=y
# CONFIG_MX6_INTER_LDO_BYPASS is not set
CONFIG_MX6_CLK_FOR_BOOTUI_TRANS=y
+CONFIG_MX6_IR=y
CONFIG_ISP1504_MXC=y
# CONFIG_MXC_IRQ_PRIOR is not set
CONFIG_MXC_PWM=y
+CONFIG_MXC_EPIT=y
# CONFIG_MXC_DEBUG_BOARD is not set
+CONFIG_HAVE_EPIT=y
CONFIG_MXC_REBOOT_MFGMODE=y
CONFIG_MXC_REBOOT_ANDROID_CMD=y
+# CONFIG_MXC_USE_EPIT is not set
CONFIG_ARCH_MXC_IOMUX_V3=y
CONFIG_ARCH_MXC_AUDMUX_V2=y
CONFIG_IRAM_ALLOC=y
@@ -1605,6 +1610,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_PCH_UART is not set
# CONFIG_SERIAL_XILINX_PS_UART is not set
# CONFIG_TTY_PRINTK is not set
+CONFIG_DEVIR=y
CONFIG_FSL_OTP=y
# CONFIG_HVC_DCC is not set
# CONFIG_IPMI_HANDLER is not set
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig
index 005b56551ffb..75d7b823e64d 100644
--- a/arch/arm/mach-mx6/Kconfig
+++ b/arch/arm/mach-mx6/Kconfig
@@ -14,6 +14,7 @@ config ARCH_MX6Q
select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL
select IMX_HAVE_PLATFORM_IMX_IPUV3
select IMX_HAVE_PLATFORM_MXC_PWM
+ select IMX_HAVE_PLATFORM_MXC_EPIT
select IMX_HAVE_PLATFORM_LDB
select IMX_HAVE_PLATFORM_IMX_SPDIF
select IMX_HAVE_PLATFORM_IMX_VDOA
@@ -326,6 +327,13 @@ config MX6_CLK_FOR_BOOTUI_TRANS
avoid setting IPU related clocks' parents when initializing clock tree
so that bootloader splashimage can transition to kernel smoothly.
+config MX6_IR
+ bool "MX6 IR Support"
+ depends on IMX_HAVE_PLATFORM_MXC_PWM
+ default y
+ help
+ This config is for MX6 IR support. Enable it if hardware supported.
+
config MACH_IMX_BLUETOOTH_RFKILL
tristate "i.MX Bluetooth rfkill interface support"
depends on RFKILL
diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile
index 5acdcb3a5435..1d24719c7f3a 100644
--- a/arch/arm/mach-mx6/Makefile
+++ b/arch/arm/mach-mx6/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_USB_FSL_ARC_OTG) += usb_dr.o
obj-$(CONFIG_USB_EHCI_ARC_H1) += usb_h1.o
obj-$(CONFIG_MACH_IMX_BLUETOOTH_RFKILL) += mx6_bt_rfkill.o
obj-$(CONFIG_PCI_MSI) += msi.o
+obj-$(CONFIG_MX6_IR) += mx6_ir.o
diff --git a/arch/arm/mach-mx6/board-mx6dl_sabresd.h b/arch/arm/mach-mx6/board-mx6dl_sabresd.h
index 7cb69246a824..b40e71dd8b58 100644
--- a/arch/arm/mach-mx6/board-mx6dl_sabresd.h
+++ b/arch/arm/mach-mx6/board-mx6dl_sabresd.h
@@ -82,7 +82,7 @@ static iomux_v3_cfg_t mx6dl_sabresd_pads[] = {
MX6DL_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6,
MX6DL_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7,
MX6DL_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8,
- MX6DL_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9,
+ MX6DL_PAD_DISP0_DAT9__PWM2_PWMO,
MX6DL_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10,
MX6DL_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11,
MX6DL_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12,
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c
index 193931e446f3..f182dfcb9f2a 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c
@@ -70,6 +70,7 @@
#include <mach/mxc_hdmi.h>
#include <mach/mxc_asrc.h>
#include <mach/mipi_dsi.h>
+#include <mach/mxc_ir.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -1699,6 +1700,12 @@ static struct platform_pwm_backlight_data mx6_sabresd_pwm_backlight_data = {
.pwm_period_ns = 50000,
};
+static struct platform_ir_data mx6_sabresd_ir_data = {
+ .pwm_id = 1,
+ .epit_id = 0,
+ .gpio_id = 0,
+};
+
static struct mxc_dvfs_platform_data sabresd_dvfscore_data = {
.reg_id = "VDDCORE",
.soc_id = "VDDSOC",
@@ -2058,11 +2065,16 @@ static void __init mx6_sabresd_board_init(void)
gpio_request(SABRESD_CABC_EN1, "cabc-en1");
gpio_direction_output(SABRESD_CABC_EN1, 0);
+ imx6q_add_mxc_epit(0);
+ imx6q_add_mxc_epit(1);
+
imx6q_add_mxc_pwm(0);
imx6q_add_mxc_pwm(1);
imx6q_add_mxc_pwm(2);
imx6q_add_mxc_pwm(3);
imx6q_add_mxc_pwm_backlight(0, &mx6_sabresd_pwm_backlight_data);
+ /* add MXC IR device */
+ imx6q_add_mxc_ir(0, &mx6_sabresd_ir_data);
imx6q_add_otp();
imx6q_add_viim();
diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.h b/arch/arm/mach-mx6/board-mx6q_sabresd.h
index 73ee909e50ef..0523b688f46d 100644
--- a/arch/arm/mach-mx6/board-mx6q_sabresd.h
+++ b/arch/arm/mach-mx6/board-mx6q_sabresd.h
@@ -151,7 +151,7 @@ static iomux_v3_cfg_t mx6q_sabresd_pads[] = {
MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6,
MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7,
MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8,
- MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9,
+ MX6Q_PAD_DISP0_DAT9__PWM2_PWMO,
MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10,
MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11,
MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12,
diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h
index 4525e29a472a..a84327be90e1 100644
--- a/arch/arm/mach-mx6/devices-imx6q.h
+++ b/arch/arm/mach-mx6/devices-imx6q.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011-2013 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
@@ -170,7 +170,11 @@ extern const struct imx_viv_gpu_data imx6_gc2000_data __initconst;
extern const struct imx_viv_gpu_data imx6_gc320_data __initconst;
extern const struct imx_viv_gpu_data imx6_gc355_data __initconst;
+extern const struct imx_mxc_epit_data imx6q_mxc_epit_data[] __initconst;
extern const struct imx_mxc_pwm_data imx6q_mxc_pwm_data[] __initconst;
+
+#define imx6q_add_mxc_epit(id) \
+ imx_add_mxc_epit(&imx6q_mxc_epit_data[id])
#define imx6q_add_mxc_pwm(id) \
imx_add_mxc_pwm(&imx6q_mxc_pwm_data[id])
@@ -178,6 +182,10 @@ extern const struct imx_mxc_pwm_data imx6q_mxc_pwm_data[] __initconst;
platform_device_register_resndata(NULL, "pwm-backlight",\
id, NULL, 0, pdata, sizeof(*pdata));
+#define imx6q_add_mxc_ir(id, pdata) \
+ platform_device_register_resndata(NULL, "mx6-ir", \
+ id, NULL, 0, pdata, sizeof(*pdata));
+
extern const struct imx_spdif_data imx6q_imx_spdif_data __initconst;
#define imx6q_add_spdif(pdata) imx_add_spdif(&imx6q_imx_spdif_data, pdata)
diff --git a/arch/arm/mach-mx6/mx6_ir.c b/arch/arm/mach-mx6/mx6_ir.c
new file mode 100644
index 000000000000..73d18ce266b0
--- /dev/null
+++ b/arch/arm/mach-mx6/mx6_ir.c
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2005-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/fsl_devices.h>
+#include <linux/ir.h>
+#include <mach/hardware.h>
+#include <mach/mxc_ir.h>
+
+#ifdef IR_HRTIMER_USED
+#include <linux/hrtimer.h>
+#include <linux/ktime.h>
+#else
+#include <mach/epit.h>
+#endif
+
+#define IR_MAX_CARRIER_FREQ (11000000)
+#define IR_MIN_CARRIER_FREQ (3000)
+
+struct mx6_ir_device {
+ struct pwm_device *pwm;
+#ifdef IR_HRTIMER_USED
+ struct hrtimer hr_timer;
+#else
+ struct epit_device *epit;
+#endif
+ int pattern_len;
+ int *pattern;
+ int transmit_idx;
+ int transmit_level;
+ int gpio_pin;
+ struct device *dev;
+ wait_queue_head_t queue;
+ bool cond;
+ unsigned int carry_freq;
+};
+
+struct carrier_freq {
+ int min;
+ int max;
+};
+
+static const struct carrier_freq mx6_ir_carrier_freq[] = {
+ {IR_MIN_CARRIER_FREQ, IR_MAX_CARRIER_FREQ},
+};
+
+int ir_config(void *dev, int carry_freq)
+{
+ unsigned int period_ns;
+ struct mx6_ir_device *ir_dev = (struct mx6_ir_device *)dev;
+
+ if ((!ir_dev) || (!carry_freq))
+ return -EINVAL;
+
+ if (!ir_dev->pwm)
+ return -EINVAL;
+
+ period_ns = 1000000000;
+ do_div(period_ns, carry_freq);
+ pwm_config(ir_dev->pwm, (period_ns >> 1), period_ns);
+ pwm_out_enable(ir_dev->pwm, 0);
+ return 0;
+}
+EXPORT_SYMBOL(ir_config);
+
+int ir_get_carrier_range(int id, int *min, int *max)
+{
+ if ((!min) || (!max)) {
+ return -1;
+ } else {
+ *min = mx6_ir_carrier_freq[id].min;
+ *max = mx6_ir_carrier_freq[id].max;
+ return 0;
+ }
+}
+EXPORT_SYMBOL(ir_get_carrier_range);
+
+int ir_get_num_carrier_freqs(void)
+{
+ return ARRAY_SIZE(mx6_ir_carrier_freq);
+}
+EXPORT_SYMBOL(ir_get_num_carrier_freqs);
+
+
+#ifdef IR_HRTIMER_USED
+static void *hrtimer_cb_para;
+
+static inline void ir_hrtimer_start(struct hrtimer *hr_timer, int width_ns,
+ void *cb, void *para)
+{
+ ktime_t ktime;
+
+ ktime = ktime_set(0, width_ns);
+ hrtimer_init(hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hr_timer->function = cb;
+ hrtimer_cb_para = para;
+ hrtimer_start(hr_timer, ktime, HRTIMER_MODE_REL);
+}
+
+static inline void ir_hrtimer_stop(struct hrtimer *hr_timer)
+{
+ hrtimer_cancel(hr_timer);
+}
+
+static int ir_transmit_cb(struct hrtimer *timer)
+{
+ struct mx6_ir_device *ir_dev = (struct mx6_ir_device *)hrtimer_cb_para;
+ ktime_t ktime;
+
+ ir_dev->transmit_idx++;
+ if (ir_dev->pattern_len == ir_dev->transmit_idx) {
+ /* all bit transmit is done */
+ /* stop pwm output */
+ pwm_out_enable(ir_dev->pwm, 0);
+ ir_dev->cond = true;
+ wake_up(&ir_dev->queue);
+ return HRTIMER_NORESTART;
+ } else {
+ /* start next bit transmit */;
+ ir_dev->transmit_level = !ir_dev->transmit_level;
+ ktime = ktime_set(0, ir_dev->pattern[ir_dev->transmit_idx] * 1000);
+ hrtimer_forward(&ir_dev->hr_timer,
+ ktime_get(),
+ ktime);
+ pwm_out_enable(ir_dev->pwm, ir_dev->transmit_level);
+ return HRTIMER_RESTART;
+ }
+}
+
+int ir_transmit(void *dev, int len, int *pattern, unsigned char start_level)
+{
+ struct mx6_ir_device *ir_dev = (struct mx6_ir_device *)dev;
+ char level = start_level;
+
+ if ((!ir_dev) || (!pattern))
+ return -EINVAL;
+
+ if (!ir_dev->pwm)
+ return -EINVAL;
+
+ ir_dev->transmit_level = start_level;
+ ir_dev->transmit_idx = 0;
+ ir_dev->pattern = pattern;
+ ir_dev->pattern_len = len;
+ ir_dev->cond = false;
+ /*
+ 1. Enable/disable pwm output per level, start timer with width
+ 2. time cb will start next bit transmit,wait all bit transmit done
+ 3. disable pwm output
+ */
+ pwm_enable(ir_dev->pwm);
+ ir_dev->cond = false;
+ ir_hrtimer_start(&ir_dev->hr_timer,
+ (ir_dev->pattern[0] * 1000),
+ (void *)ir_transmit_cb,
+ (void *)(ir_dev));
+ pwm_out_enable(ir_dev->pwm, ir_dev->transmit_level);
+ wait_event(ir_dev->queue, ir_dev->cond);
+ ir_hrtimer_stop(&ir_dev->hr_timer);
+ pwm_disable(ir_dev->pwm);
+ return 0;
+}
+#else
+static int ir_transmit_cb(void *dev)
+{
+ struct mx6_ir_device *ir_dev = (struct mx6_ir_device *)dev;
+ ir_dev->transmit_idx++;
+ if (ir_dev->pattern_len == ir_dev->transmit_idx) {
+ /* all bit transmit is done */
+ /* stop pwm output */
+ pwm_out_enable(ir_dev->pwm, 0);
+ ir_dev->cond = true;
+ wake_up(&ir_dev->queue);
+ } else {
+ /* start next bit transmit */;
+ ir_dev->transmit_level = !ir_dev->transmit_level;
+ pwm_out_enable(ir_dev->pwm, ir_dev->transmit_level);
+ epit_start(ir_dev->epit,
+ (ir_dev->pattern[ir_dev->transmit_idx] * 1000));
+
+ }
+ return 0;
+}
+
+int ir_transmit(void *dev, int len, int *pattern, unsigned char start_level)
+{
+ struct mx6_ir_device *ir_dev = (struct mx6_ir_device *)dev;
+
+ if ((!ir_dev) || (!pattern))
+ return -EINVAL;
+
+ if ((!ir_dev->pwm) || (!ir_dev->epit))
+ return -EINVAL;
+
+ ir_dev->transmit_level = start_level;
+ ir_dev->transmit_idx = 0;
+ ir_dev->pattern = pattern;
+ ir_dev->pattern_len = len;
+ ir_dev->cond = false;
+ /*
+ 1. Enable/disable pwm output per level, start timer with width
+ 2. time cb will start next bit transmit,wait all bit transmit done
+ 3. disable pwm output
+ */
+ pwm_enable(ir_dev->pwm);
+ epit_config(ir_dev->epit,
+ EPIT_FREE_RUN_MODE,
+ (void *)ir_transmit_cb,
+ (void *)(ir_dev));
+ epit_start(ir_dev->epit,
+ (ir_dev->pattern[0] * 1000));
+ pwm_out_enable(ir_dev->pwm, ir_dev->transmit_level);
+ wait_event(ir_dev->queue, ir_dev->cond);
+ epit_stop(ir_dev->epit);
+ pwm_disable(ir_dev->pwm);
+ return 0;
+}
+#endif
+EXPORT_SYMBOL(ir_transmit);
+
+static int __devinit mx6_ir_probe(struct platform_device *pdev)
+{
+ struct platform_ir_data *plat_data = pdev->dev.platform_data;
+ struct mx6_ir_device *pb;
+ int ret = 0;
+
+ if (!plat_data) {
+ dev_err(&pdev->dev, "failed to find platform data\n");
+ return -EINVAL;
+ }
+ pb = kzalloc(sizeof(*pb), GFP_KERNEL);
+ if (!pb) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+ pb->dev = &pdev->dev;
+
+ pb->pwm = pwm_request(plat_data->pwm_id, "IR Carrier");
+ if (IS_ERR(pb->pwm)) {
+ dev_err(&pdev->dev, "unable to request PWM for IR Carrier\n");
+ ret = PTR_ERR(pb->pwm);
+ goto err_pwm;
+ } else {
+ dev_dbg(&pdev->dev, "got pwm for IR Carrier\n");
+ }
+
+#ifndef IR_HRTIMER_USED
+ pb->epit = epit_request(plat_data->epit_id, "IR Signal");
+ if (IS_ERR(pb->epit)) {
+ dev_err(&pdev->dev, "unable to request EPIT for IR Signal\n");
+ ret = PTR_ERR(pb->epit);
+ goto err_epit;
+ } else {
+ dev_dbg(&pdev->dev, "got EPIT for IR Signal\n");
+ }
+#endif
+
+ pb->gpio_pin = plat_data->gpio_id;
+ /* Init queue */
+ init_waitqueue_head(&pb->queue);
+
+ ir_device_register(dev_name(&pdev->dev), &pdev->dev, pb);
+ platform_set_drvdata(pdev, pb);
+ return 0;
+
+#ifndef IR_HRTIMER_USED
+err_epit:
+#endif
+ pwm_free(pb->pwm);
+err_pwm:
+ kfree(pb);
+err_alloc:
+ return ret;
+}
+
+static int __devexit mx6_ir_remove(struct platform_device *pdev)
+{
+ struct mx6_ir_device *pb = platform_get_drvdata(pdev);
+ ir_device_unregister();
+ pwm_disable(pb->pwm);
+ pwm_free(pb->pwm);
+#ifndef IR_HRTIMER_USED
+ epit_stop(pb->epit);
+ epit_free(pb->epit);
+#endif
+ kfree(pb);
+ return 0;
+}
+
+static struct platform_driver mx6_ir_driver = {
+ .driver = {
+ .name = "mx6-ir",
+ },
+ .probe = mx6_ir_probe,
+ .remove = __devexit_p(mx6_ir_remove),
+};
+
+static int __init mx6_ir_init(void)
+{
+ return platform_driver_register(&mx6_ir_driver);
+}
+module_init(mx6_ir_init);
+
+static void __exit mx6_ir_exit(void)
+{
+ platform_driver_unregister(&mx6_ir_driver);
+}
+module_exit(mx6_ir_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MX6 IR driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c
index 96f6a6b0c5d6..2a8a41f97169 100644
--- a/arch/arm/plat-mxc/epit.c
+++ b/arch/arm/plat-mxc/epit.c
@@ -8,6 +8,23 @@
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
+ *
+ * linux/arch/arm/plat-mxc/epit.c
+ *
+ * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
*/
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/arch/arm/plat-mxc/include/mach/mxc_ir.h b/arch/arm/plat-mxc/include/mach/mxc_ir.h
new file mode 100644
index 000000000000..11a5b590a257
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/mxc_ir.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+
+/*!
+ * @file arch-mxc/mxc_ir.h
+ *
+ * @brief This file contains the IR configuration structure definition.
+ *
+ *
+ * @ingroup IR
+ */
+
+#ifndef __ASM_ARCH_MXC_IR_H__
+#define __ASM_ARCH_MXC_IR_H__
+
+#ifdef __KERNEL__
+
+struct platform_ir_data {
+ int pwm_id; /* generate carry frequence */
+ int epit_id; /* generate payload pluse */
+ int gpio_id; /* dedicate GPIO for IR */
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_ARCH_MXC_IR_H__ */
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index eb49057116f1..8177475c10e7 100755
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -20,7 +20,6 @@
#include <linux/fsl_devices.h>
#include <mach/hardware.h>
-
/* i.MX1 and i.MX21 share the same PWM function block: */
#define MX1_PWMC 0x00 /* PWM Control Register */
@@ -48,6 +47,7 @@
#define MX3_PWMCR_DBGEN (1 << 22)
#define MX3_PWMCR_CLKSRC_IPG (1 << 16)
#define MX3_PWMCR_CLKSRC_IPG_32k (3 << 16)
+#define MX3_PWMCR_OUTPIN_DISCONNECT (3 << 18)
struct pwm_device {
struct list_head node;
@@ -66,6 +66,20 @@ struct pwm_device {
void (*disable_pwm_pad)(void);
};
+void pwm_out_enable(struct pwm_device *pwm, int enable)
+{
+ u32 cr = 0;
+
+ cr = readl(pwm->mmio_base + MX3_PWMCR);
+ if (enable)
+ cr &= ~(MX3_PWMCR_OUTPIN_DISCONNECT);
+ else
+ cr |= (MX3_PWMCR_OUTPIN_DISCONNECT);
+
+ writel(cr, pwm->mmio_base + MX3_PWMCR);
+}
+EXPORT_SYMBOL(pwm_out_enable);
+
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
{
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
@@ -139,7 +153,6 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
} else {
BUG();
}
-
return 0;
}
EXPORT_SYMBOL(pwm_config);