Commit 875064eca4f80aa5179f1dc434fe3495a358d41b

Authored by Eric Lee
1 parent 3b1e04a5db

Add U-Boot LVDS Backlight PWM Support

Showing 9 changed files with 255 additions and 7 deletions Side-by-side Diff

... ... @@ -1314,6 +1314,10 @@
1314 1314 CONFIG_SH_ETHER_CACHE_WRITEBACK
1315 1315 If this option is set, the driver enables cache flush.
1316 1316  
  1317 +- PWM Support:
  1318 + CONFIG_PWM_IMX
  1319 + Support for PWM modul on the imx6.
  1320 +
1317 1321 - TPM Support:
1318 1322 CONFIG_TPM
1319 1323 Support TPM devices.
arch/arm/include/asm/arch-mx6/imx-regs.h
... ... @@ -679,6 +679,23 @@
679 679 u16 wmcr; /* Miscellaneous Control */
680 680 };
681 681  
  682 +#define PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4)
  683 +#define PWMCR_DOZEEN (1 << 24)
  684 +#define PWMCR_WAITEN (1 << 23)
  685 +#define PWMCR_DBGEN (1 << 22)
  686 +#define PWMCR_CLKSRC_IPG_HIGH (2 << 16)
  687 +#define PWMCR_CLKSRC_IPG (1 << 16)
  688 +#define PWMCR_EN (1 << 0)
  689 +
  690 +struct pwm_regs {
  691 + u32 cr;
  692 + u32 sr;
  693 + u32 ir;
  694 + u32 sar;
  695 + u32 pr;
  696 + u32 cnr;
  697 +};
  698 +
682 699 struct dbg_monitor_regs {
683 700 u32 ctrl[4]; /* Control */
684 701 u32 master_en[4]; /* Master enable */
board/embedian/smarcfimx6/smarcfimx6.c
... ... @@ -32,6 +32,7 @@
32 32 #include <ipu_pixfmt.h>
33 33 #include <asm/io.h>
34 34 #include <asm/arch/sys_proto.h>
  35 +#include <pwm.h>
35 36 #ifdef CONFIG_SYS_I2C_MXC
36 37 #include <i2c.h>
37 38 #include <asm/imx-common/mxc_i2c.h>
38 39  
... ... @@ -835,11 +836,9 @@
835 836 MX6_PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL),
836 837 #define BACKLIGHT_EN IMX_GPIO_NR(1, 00)
837 838 /* PWM Backlight Control: S141 */
838   - MX6_PAD_GPIO_1__GPIO1_IO01 | MUX_PAD_CTRL(NO_PAD_CTRL),
839   -#define BACKLIGHT_PWM IMX_GPIO_NR(1, 01)
  839 +
840 840 /* Backlight Enable for LVDS: S127 */
841   - /*MX6_PAD_GPIO_0__GPIO1_IO00 | MUX_PAD_CTRL(NO_PAD_CTRL),
842   -#define LVDS_BACKLIGHT_EN IMX_GPIO_NR(1, 00)*/
  841 + MX6_PAD_GPIO_1__PWM2_OUT | MUX_PAD_CTRL(NO_PAD_CTRL),
843 842 /* LCD VDD Enable(for parallel LCD): S133 */
844 843 MX6_PAD_GPIO_2__GPIO1_IO02 | MUX_PAD_CTRL(NO_PAD_CTRL),
845 844 #define LCD_VDD_EN IMX_GPIO_NR(1, 02)
846 845  
847 846  
848 847  
... ... @@ -1075,13 +1074,25 @@
1075 1074 writel(reg, &iomux->gpr[3]);
1076 1075 /* backlights off until needed */
1077 1076  
1078   - /*imx_iomux_v3_setup_multiple_pads(backlight_pads,
  1077 + imx_iomux_v3_setup_multiple_pads(backlight_pads,
1079 1078 ARRAY_SIZE(backlight_pads));
1080   - gpio_direction_input(BACKLIGHT_EN);*/
  1079 + /*gpio_direction_input(BACKLIGHT_EN);*/
1081 1080 /* turn on backlight */
1082 1081 gpio_direction_output(BACKLIGHT_EN, 1);
1083   - gpio_direction_output(BACKLIGHT_PWM, 1);
1084 1082 gpio_direction_output(LCD_VDD_EN, 1);
  1083 + /* enable backlight PWM 2 */
  1084 + if (pwm_init(1, 0, 0))
  1085 + goto error;
  1086 + /* duty cycle 500ns, period: 3000ns */
  1087 + if (pwm_config(1, 1000, 3000))
  1088 + goto error;
  1089 + if (pwm_enable(1))
  1090 + goto error;
  1091 + return;
  1092 +
  1093 +error:
  1094 + puts("error init pwm for backlight\n");
  1095 + return;
1085 1096 }
1086 1097 #endif /* CONFIG_VIDEO_IPUV3 */
1087 1098  
... ... @@ -15,4 +15,5 @@
15 15 obj-y += watchdog/
16 16 obj-y += fastboot/
17 17 obj-$(CONFIG_QE) += qe/
  18 +obj-y += pwm/
drivers/pwm/Makefile
  1 +#
  2 +# (C) Copyright 2006
  3 +# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
  4 +#
  5 +# (C) Copyright 2001
  6 +# Erik Theisen, Wave 7 Optics, etheisen at mindspring.com.
  7 +#
  8 +# SPDX-License-Identifier: GPL-2.0+
  9 +#
  10 +
  11 +#ccflags-y += -DDEBUG
  12 +
  13 +obj-$(CONFIG_PWM_IMX) += pwm-imx.o
drivers/pwm/pwm-imx-util.c
  1 +/*
  2 + * (C) Copyright 2014
  3 + * Heiko Schocher, DENX Software Engineering, hs@denx.de.
  4 + *
  5 + * Basic support for the pwm modul on imx6.
  6 + *
  7 + * Based on linux:drivers/pwm/pwm-imx.c
  8 + * from
  9 + * Sascha Hauer <s.hauer@pengutronix.de>
  10 + *
  11 + * SPDX-License-Identifier: GPL-2.0
  12 + */
  13 +
  14 +#include <common.h>
  15 +#include <div64.h>
  16 +#include <asm/arch/imx-regs.h>
  17 +
  18 +/* pwm_id from 0..3 */
  19 +struct pwm_regs *pwm_id_to_reg(int pwm_id)
  20 +{
  21 + switch (pwm_id) {
  22 + case 0:
  23 + return (struct pwm_regs *)PWM1_BASE_ADDR;
  24 + break;
  25 + case 1:
  26 + return (struct pwm_regs *)PWM2_BASE_ADDR;
  27 + break;
  28 + case 2:
  29 + return (struct pwm_regs *)PWM3_BASE_ADDR;
  30 + break;
  31 + case 3:
  32 + return (struct pwm_regs *)PWM4_BASE_ADDR;
  33 + break;
  34 + default:
  35 + printf("unknown pwm_id: %d\n", pwm_id);
  36 + break;
  37 + }
  38 + return NULL;
  39 +}
  40 +
  41 +int pwm_imx_get_parms(int period_ns, int duty_ns, unsigned long *period_c,
  42 + unsigned long *duty_c, unsigned long *prescale)
  43 +{
  44 + unsigned long long c;
  45 +
  46 + /*
  47 + * we have not yet a clock framework for imx6, so add the clock
  48 + * value here as a define. Replace it when we have the clock
  49 + * framework.
  50 + */
  51 + c = CONFIG_IMX6_PWM_PER_CLK;
  52 + c = c * period_ns;
  53 + do_div(c, 1000000000);
  54 + *period_c = c;
  55 +
  56 + *prescale = *period_c / 0x10000 + 1;
  57 +
  58 + *period_c /= *prescale;
  59 + c = (unsigned long long)(*period_c * duty_ns);
  60 + do_div(c, period_ns);
  61 + *duty_c = c;
  62 +
  63 + /*
  64 + * according to imx pwm RM, the real period value should be
  65 + * PERIOD value in PWMPR plus 2.
  66 + */
  67 + if (*period_c > 2)
  68 + *period_c -= 2;
  69 + else
  70 + *period_c = 0;
  71 +
  72 + return 0;
  73 +}
drivers/pwm/pwm-imx-util.h
  1 +/*
  2 + * (C) Copyright 2014
  3 + * Heiko Schocher, DENX Software Engineering, hs@denx.de.
  4 + *
  5 + * Basic support for the pwm modul on imx6.
  6 + *
  7 + * SPDX-License-Identifier: GPL-2.0
  8 + */
  9 +
  10 +#ifndef _pwm_imx_util_h_
  11 +#define _pwm_imx_util_h_
  12 +
  13 +struct pwm_regs *pwm_id_to_reg(int pwm_id);
  14 +int pwm_imx_get_parms(int period_ns, int duty_ns, unsigned long *period_c,
  15 + unsigned long *duty_c, unsigned long *prescale);
  16 +#endif
drivers/pwm/pwm-imx.c
  1 +/*
  2 + * (C) Copyright 2014
  3 + * Heiko Schocher, DENX Software Engineering, hs at denx.de.
  4 + *
  5 + * Basic support for the pwm modul on imx6.
  6 + *
  7 + * Based on linux:drivers/pwm/pwm-imx.c
  8 + * from
  9 + * Sascha Hauer <s.hauer at pengutronix.de>
  10 + *
  11 + * SPDX-License-Identifier: GPL-2.0+
  12 + */
  13 +
  14 +#include <common.h>
  15 +#include <div64.h>
  16 +#include <pwm.h>
  17 +#include <asm/arch/imx-regs.h>
  18 +#include <asm/io.h>
  19 +
  20 +/* pwm_id from 0..3 */
  21 +static struct pwm_regs *pwm_id_to_reg(int pwm_id)
  22 +{
  23 + switch (pwm_id) {
  24 + case 0:
  25 + return (struct pwm_regs *)PWM1_BASE_ADDR;
  26 + break;
  27 + case 1:
  28 + return (struct pwm_regs *)PWM2_BASE_ADDR;
  29 + break;
  30 + case 2:
  31 + return (struct pwm_regs *)PWM3_BASE_ADDR;
  32 + break;
  33 + case 3:
  34 + return (struct pwm_regs *)PWM4_BASE_ADDR;
  35 + break;
  36 + default:
  37 + printf("unknown pwm_id: %d\n", pwm_id);
  38 + break;
  39 + }
  40 + return NULL;
  41 +}
  42 +
  43 +int pwm_init(int pwm_id, int div, int invert)
  44 +{
  45 + struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
  46 +
  47 + writel(0, &pwm->ir);
  48 + return 0;
  49 +}
  50 +
  51 +int pwm_config(int pwm_id, int duty_ns, int period_ns)
  52 +{
  53 + struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
  54 + unsigned long long c;
  55 + unsigned long period_cycles, duty_cycles, prescale;
  56 + u32 cr;
  57 +
  58 + /*
  59 + * we have not yet a clock framework for imx6, so add the clock
  60 + * value here as a define. Replace it when we have the clock
  61 + * framework.
  62 + */
  63 + c = CONFIG_IMX6_PWM_PER_CLK;
  64 + c = c * period_ns;
  65 + do_div(c, 1000000000);
  66 + period_cycles = c;
  67 +
  68 + prescale = period_cycles / 0x10000 + 1;
  69 +
  70 + period_cycles /= prescale;
  71 + c = (unsigned long long)period_cycles * duty_ns;
  72 + do_div(c, period_ns);
  73 + duty_cycles = c;
  74 +
  75 + /*
  76 + * according to imx pwm RM, the real period value should be
  77 + * PERIOD value in PWMPR plus 2.
  78 + */
  79 + if (period_cycles > 2)
  80 + period_cycles -= 2;
  81 + else
  82 + period_cycles = 0;
  83 +
  84 + cr = PWMCR_PRESCALER(prescale) |
  85 + PWMCR_DOZEEN | PWMCR_WAITEN |
  86 + PWMCR_DBGEN | PWMCR_CLKSRC_IPG_HIGH;
  87 +
  88 + writel(cr, &pwm->cr);
  89 + /* set duty cycles */
  90 + writel(duty_cycles, &pwm->sar);
  91 + /* set period cycles */
  92 + writel(period_cycles, &pwm->pr);
  93 + return 0;
  94 +}
  95 +
  96 +int pwm_enable(int pwm_id)
  97 +{
  98 + struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
  99 +
  100 + setbits_le32(&pwm->cr, PWMCR_EN);
  101 + return 0;
  102 +}
  103 +
  104 +void pwm_disable(int pwm_id)
  105 +{
  106 + struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id);
  107 +
  108 + clrbits_le32(&pwm->cr, PWMCR_EN);
  109 +}
include/configs/smarcfimx6.h
... ... @@ -40,6 +40,10 @@
40 40  
41 41 #include "smarcfimx6_common.h"
42 42  
  43 +/* PWM Configs */
  44 +#define CONFIG_PWM_IMX
  45 +#define CONFIG_IMX6_PWM_PER_CLK 66000000
  46 +
43 47 /* USB Configs */
44 48 #define CONFIG_CMD_USB
45 49 #define CONFIG_USB_EHCI