Commit 875064eca4f80aa5179f1dc434fe3495a358d41b
1 parent
3b1e04a5db
Exists in
smarc-imx_v2014.04_3.14.28_1.0.0_ga
Add U-Boot LVDS Backlight PWM Support
Showing 9 changed files with 255 additions and 7 deletions Side-by-side Diff
README
... | ... | @@ -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 |
drivers/Makefile
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