summaryrefslogtreecommitdiff
authorBichao Zheng <bichao.zheng@amlogic.com>2019-03-10 13:26:05 (GMT)
committer Luan Yuan <luan.yuan@amlogic.com>2019-05-13 07:23:11 (GMT)
commit43e1b61dba94f9699757ed7103f72f095793640a (patch)
tree9e5d70c552fa1834f4aeb22e0509095499cf92eb
parentc2d8490ce4cfacf3fe5a54487ef24b0e851470f1 (diff)
downloaduboot-43e1b61dba94f9699757ed7103f72f095793640a.zip
uboot-43e1b61dba94f9699757ed7103f72f095793640a.tar.gz
uboot-43e1b61dba94f9699757ed7103f72f095793640a.tar.bz2
pwm: add pwm drvier base on DM [1/1]
PD#SWPL-5800 Problem: There is no PWM driver here. Solution: Add pwm drvier base on DM for g12a/b, tl1. Verify: test pass on g12a_u211 tl1_x309 Change-Id: Ie66ee460a6130ad67a4d1869fbd152dee3775c9a Signed-off-by: Bichao Zheng <bichao.zheng@amlogic.com> Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
Diffstat
-rw-r--r--board/amlogic/configs/g12a_u200_v1.h4
-rw-r--r--board/amlogic/configs/g12a_u211_v1.h4
-rw-r--r--board/amlogic/configs/g12a_u212_v1.h4
-rw-r--r--board/amlogic/configs/g12a_u220_v1.h4
-rw-r--r--board/amlogic/configs/g12a_u221_v1.h4
-rw-r--r--board/amlogic/configs/g12b_skt_v1.h5
-rw-r--r--board/amlogic/configs/g12b_w400_v1.h5
-rw-r--r--board/amlogic/configs/g12b_w411_v1.h5
-rw-r--r--board/amlogic/g12a_skt_v1/g12a_skt_v1.c22
-rw-r--r--board/amlogic/g12a_u200_v1/g12a_u200_v1.c22
-rw-r--r--board/amlogic/g12a_u211_v1/g12a_u211_v1.c22
-rw-r--r--board/amlogic/g12a_u212_v1/g12a_u212_v1.c22
-rw-r--r--board/amlogic/g12a_u220_v1/g12a_u220_v1.c22
-rw-r--r--board/amlogic/g12a_u221_v1/g12a_u221_v1.c22
-rw-r--r--board/amlogic/g12b_skt_v1/g12b_skt_v1.c22
-rw-r--r--board/amlogic/g12b_w400_v1/g12b_w400_v1.c22
-rw-r--r--board/amlogic/g12b_w411_v1/g12b_w411_v1.c22
-rw-r--r--drivers/pwm/Makefile6
-rw-r--r--drivers/pwm/pwm-meson.c518
-rw-r--r--drivers/pwm/pwm-meson.h45
-rw-r--r--drivers/pwm/pwm-uclass.c76
-rw-r--r--include/amlogic/pwm.h43
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/pwm.h130
24 files changed, 1051 insertions, 1 deletions
diff --git a/board/amlogic/configs/g12a_u200_v1.h b/board/amlogic/configs/g12a_u200_v1.h
index d10951f..9417306 100644
--- a/board/amlogic/configs/g12a_u200_v1.h
+++ b/board/amlogic/configs/g12a_u200_v1.h
@@ -575,6 +575,10 @@
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12a_u211_v1.h b/board/amlogic/configs/g12a_u211_v1.h
index 00dbba0..cdf29b9 100644
--- a/board/amlogic/configs/g12a_u211_v1.h
+++ b/board/amlogic/configs/g12a_u211_v1.h
@@ -567,6 +567,10 @@
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12a_u212_v1.h b/board/amlogic/configs/g12a_u212_v1.h
index 886e636..efd5cdb 100644
--- a/board/amlogic/configs/g12a_u212_v1.h
+++ b/board/amlogic/configs/g12a_u212_v1.h
@@ -569,6 +569,10 @@
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12a_u220_v1.h b/board/amlogic/configs/g12a_u220_v1.h
index f20d638..2b1f8b9 100644
--- a/board/amlogic/configs/g12a_u220_v1.h
+++ b/board/amlogic/configs/g12a_u220_v1.h
@@ -565,6 +565,10 @@
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12a_u221_v1.h b/board/amlogic/configs/g12a_u221_v1.h
index 6a0676e..34e75a8 100644
--- a/board/amlogic/configs/g12a_u221_v1.h
+++ b/board/amlogic/configs/g12a_u221_v1.h
@@ -568,6 +568,10 @@
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12b_skt_v1.h b/board/amlogic/configs/g12b_skt_v1.h
index d4e6d02..d4cb57b 100644
--- a/board/amlogic/configs/g12b_skt_v1.h
+++ b/board/amlogic/configs/g12b_skt_v1.h
@@ -511,6 +511,11 @@
#define CONFIG_SYS_I2C_AML 1
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12b_w400_v1.h b/board/amlogic/configs/g12b_w400_v1.h
index d3df895..428602a 100644
--- a/board/amlogic/configs/g12b_w400_v1.h
+++ b/board/amlogic/configs/g12b_w400_v1.h
@@ -567,6 +567,11 @@
#define CONFIG_SYS_I2C_AML 1
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/configs/g12b_w411_v1.h b/board/amlogic/configs/g12b_w411_v1.h
index a1b2fe8..e28ca98 100644
--- a/board/amlogic/configs/g12b_w411_v1.h
+++ b/board/amlogic/configs/g12b_w411_v1.h
@@ -571,6 +571,11 @@
#define CONFIG_SYS_I2C_AML 1
#define CONFIG_SYS_I2C_SPEED 400000
#endif
+
+/* PWM DM driver*/
+#define CONFIG_DM_PWM
+#define CONFIG_PWM_MESON
+
#define CONFIG_EFUSE 1
/* commands */
diff --git a/board/amlogic/g12a_skt_v1/g12a_skt_v1.c b/board/amlogic/g12a_skt_v1/g12a_skt_v1.c
index 5100553..15a7500 100644
--- a/board/amlogic/g12a_skt_v1/g12a_skt_v1.c
+++ b/board/amlogic/g12a_skt_v1/g12a_skt_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#include <dm.h>
#ifdef CONFIG_AML_VPU
#include <vpu.h>
@@ -598,6 +602,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
int board_init(void)
{
//Please keep CONFIG_AML_V2_FACTORY_BURN at first place of board_init
diff --git a/board/amlogic/g12a_u200_v1/g12a_u200_v1.c b/board/amlogic/g12a_u200_v1/g12a_u200_v1.c
index 78dd59c..7675539 100644
--- a/board/amlogic/g12a_u200_v1/g12a_u200_v1.c
+++ b/board/amlogic/g12a_u200_v1/g12a_u200_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -576,6 +580,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
int board_init(void)
{
sys_led_init();
diff --git a/board/amlogic/g12a_u211_v1/g12a_u211_v1.c b/board/amlogic/g12a_u211_v1/g12a_u211_v1.c
index 3ad6d4f..07b56cd 100644
--- a/board/amlogic/g12a_u211_v1/g12a_u211_v1.c
+++ b/board/amlogic/g12a_u211_v1/g12a_u211_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -571,6 +575,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
int board_init(void)
{
//Please keep CONFIG_AML_V2_FACTORY_BURN at first place of board_init
diff --git a/board/amlogic/g12a_u212_v1/g12a_u212_v1.c b/board/amlogic/g12a_u212_v1/g12a_u212_v1.c
index fec5fdb..1836757 100644
--- a/board/amlogic/g12a_u212_v1/g12a_u212_v1.c
+++ b/board/amlogic/g12a_u212_v1/g12a_u212_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -571,6 +575,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
int board_init(void)
{
//Please keep CONFIG_AML_V2_FACTORY_BURN at first place of board_init
diff --git a/board/amlogic/g12a_u220_v1/g12a_u220_v1.c b/board/amlogic/g12a_u220_v1/g12a_u220_v1.c
index d1f2610..e7f166c 100644
--- a/board/amlogic/g12a_u220_v1/g12a_u220_v1.c
+++ b/board/amlogic/g12a_u220_v1/g12a_u220_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -578,6 +582,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
extern void aml_pwm_cal_init(int mode);
int board_init(void)
diff --git a/board/amlogic/g12a_u221_v1/g12a_u221_v1.c b/board/amlogic/g12a_u221_v1/g12a_u221_v1.c
index c0f6e10..20a3381 100644
--- a/board/amlogic/g12a_u221_v1/g12a_u221_v1.c
+++ b/board/amlogic/g12a_u221_v1/g12a_u221_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -577,6 +581,24 @@ void set_i2c_ao_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
extern void aml_pwm_cal_init(int mode);
int board_init(void)
diff --git a/board/amlogic/g12b_skt_v1/g12b_skt_v1.c b/board/amlogic/g12b_skt_v1/g12b_skt_v1.c
index e049ce7..1f3fa78 100644
--- a/board/amlogic/g12b_skt_v1/g12b_skt_v1.c
+++ b/board/amlogic/g12b_skt_v1/g12b_skt_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -608,6 +612,24 @@ void set_i2c_m1_pinmux(void)
}
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
extern void aml_pwm_cal_init(int mode);
int board_init(void)
diff --git a/board/amlogic/g12b_w400_v1/g12b_w400_v1.c b/board/amlogic/g12b_w400_v1/g12b_w400_v1.c
index 2e727e5..ef9559f 100644
--- a/board/amlogic/g12b_w400_v1/g12b_w400_v1.c
+++ b/board/amlogic/g12b_w400_v1/g12b_w400_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -609,6 +613,24 @@ void set_i2c_m1_pinmux(void)
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
extern void aml_pwm_cal_init(int mode);
int board_init(void)
diff --git a/board/amlogic/g12b_w411_v1/g12b_w411_v1.c b/board/amlogic/g12b_w411_v1/g12b_w411_v1.c
index 98bf5c5..ffc2ea6 100644
--- a/board/amlogic/g12b_w411_v1/g12b_w411_v1.c
+++ b/board/amlogic/g12b_w411_v1/g12b_w411_v1.c
@@ -33,6 +33,10 @@
#ifdef CONFIG_SYS_I2C_MESON
#include <amlogic/i2c.h>
#endif
+#ifdef CONFIG_PWM_MESON
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#endif
#ifdef CONFIG_AML_VPU
#include <vpu.h>
#endif
@@ -609,6 +613,24 @@ void set_i2c_m1_pinmux(void)
#endif /*end CONFIG_SYS_I2C_MESON*/
+#ifdef CONFIG_PWM_MESON
+static const struct meson_pwm_platdata pwm_data[] = {
+ { PWM_AB, 0xffd1b000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_CD, 0xffd1a000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWM_EF, 0xffd19000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_AB, 0xff807000, IS_DOUBLE_CHANNEL, IS_BLINK },
+ { PWMAO_CD, 0xff802000, IS_DOUBLE_CHANNEL, IS_BLINK },
+};
+
+U_BOOT_DEVICES(meson_pwm) = {
+ { "amlogic,general-pwm", &pwm_data[0] },
+ { "amlogic,general-pwm", &pwm_data[1] },
+ { "amlogic,general-pwm", &pwm_data[2] },
+ { "amlogic,general-pwm", &pwm_data[3] },
+ { "amlogic,general-pwm", &pwm_data[4] },
+};
+#endif /*end CONFIG_PWM_MESON*/
+
extern void aml_pwm_cal_init(int mode);
int board_init(void)
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index c0c4883..8e06cd8 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -9,5 +9,9 @@
#
#ccflags-y += -DDEBUG
+ifdef CONFIG_DM_PWM
+obj-y += pwm-uclass.o
+obj-$(CONFIG_PWM_MESON) += pwm-meson.o
+endif
-obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o
+obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o \ No newline at end of file
diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c
new file mode 100644
index 0000000..8f1cb71
--- a/dev/null
+++ b/drivers/pwm/pwm-meson.c
@@ -0,0 +1,518 @@
+/*
+ * Pwm controller driver for Amlogic Meson SOC
+ *
+ * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
+ * Auther: Bichao Zheng <bichao.zheng@amlogic.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ or MIT)
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pwm.h>
+#include <amlogic/pwm.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#include <linux/sizes.h>
+#include <div64.h>
+#include <amlogic/pwm.h>
+#include "pwm-meson.h"
+
+#define pwm_info(fmt, args...) \
+ printf("[info]%s: " fmt, __func__, ## args)
+
+#define pwm_err(fmt, args...) \
+ printf("[error]%s: " fmt, __func__, ## args)
+
+struct meson_pwm_priv{
+ struct meson_pwm_reg *regs;
+ struct meson_pwm_state *pwm_state;
+ bool is_double_channel;
+ bool is_blink;
+};
+
+static u64 meson_pwm_clock_get_rate(void)
+{
+ return 24000000;
+}
+
+static int pwm_meson_get_polarity(struct udevice *dev, uint channel)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+#if 0
+ struct meson_pwm_reg *regs = priv->regs;
+
+ unsigned int tmp, val;
+
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM2:
+ val = 0x1 << 26;
+ break;
+
+ case MESON_PWM1:
+ case MESON_PWM3:
+ val = 0x1 << 27;
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ return -EINVAL;
+ }
+
+ tmp = readl(&regs->miscr);
+ tmp = tmp & val;
+ if (tmp == 0)
+ return 0;
+ else
+ return 1;
+#else
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+
+ return pwm_state[channel].polarity;
+#endif
+}
+
+static void pwm_constant_enable(struct udevice *dev, uint channel)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM2:
+ setbits_le32(&regs->miscr, 1 << 28);
+ break;
+
+ case MESON_PWM1:
+ case MESON_PWM3:
+ setbits_le32(&regs->miscr, 1 << 29);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ break;
+ }
+}
+
+static void pwm_constant_disable(struct udevice *dev, uint channel)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM2:
+ clrbits_le32(&regs->miscr, 1 << 28);
+ break;
+
+ case MESON_PWM1:
+ case MESON_PWM3:
+ clrbits_le32(&regs->miscr, 1 << 29);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ break;
+ }
+}
+
+static void pwm_meson_config(struct udevice *dev, unsigned channel)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+
+ switch (channel) {
+ case MESON_PWM0:
+ /*set div and clock enable*/
+ setbits_le32(&regs->miscr, (pwm_state[channel].pre_div << 8 | 1 << 15));
+ /*set duty*/
+ writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->dar);
+ break;
+
+ case MESON_PWM1:
+ /*set div and clock enable*/
+ setbits_le32(&regs->miscr, (pwm_state[channel].pre_div << 16 | 1 << 23));
+ /*set duty*/
+ writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->dbr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void pwm_meson_config_ext(struct udevice *dev, unsigned channel)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+
+ switch (channel) {
+ case MESON_PWM2:
+ /*set div and clock enable*/
+ /*setbits_le32(&regs->miscr, (pwm_state[channel].pre_div << 8 | 1 << 15));*/
+ /*set duty*/
+ writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->da2r);
+ break;
+
+ case MESON_PWM3:
+ /*set div and clock enable*/
+ /*setbits_le32(&regs->miscr, (pwm_state[channel].pre_div << 16 | 1 << 23));*/
+ /*set duty*/
+ writel((pwm_state[channel].hi << 16 | pwm_state[channel].lo), &regs->db2r);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int meson_pwm_cacl(struct udevice *dev, uint channel, uint period,
+ uint duty)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+ unsigned int pre_div, cnt, duty_cnt, inv;
+ unsigned long fin_freq = -1;
+ u64 fin_ps;
+
+ inv = pwm_meson_get_polarity(dev, channel);
+ if (inv)
+ duty = period - duty;
+
+ fin_freq = meson_pwm_clock_get_rate();
+ fin_ps = (u64)NSEC_PER_SEC * 1000;
+ do_div(fin_ps, fin_freq);
+
+ for (pre_div = 0; pre_div < 0x7f; pre_div++) {
+ cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000,
+ fin_ps * (pre_div + 1));
+ if (cnt <= 0xffff)
+ break;
+ }
+
+ if (pre_div >= 0x7f) {
+ pwm_err("unable to get period pre_div\n");
+ return -EINVAL;
+ }
+
+ if (duty == period) {
+ pwm_state[channel].pre_div = pre_div;
+ pwm_state[channel].hi = cnt;
+ pwm_state[channel].lo = 0;
+ } else if (duty == 0) {
+ pwm_state[channel].pre_div = pre_div;
+ pwm_state[channel].hi = 0;
+ pwm_state[channel].lo = cnt;
+ } else {
+ /* Then check is we can have the duty with the same pre_div */
+ duty_cnt = DIV_ROUND_CLOSEST_ULL((u64)duty * 1000,
+ fin_ps * (pre_div + 1));
+ if (duty_cnt > 0xffff) {
+ pwm_err("unable to get duty cycle\n");
+ return -EINVAL;
+ }
+
+ if (duty_cnt == 0)
+ duty_cnt = 1;
+
+ if (cnt == duty_cnt)
+ duty_cnt -= 1;
+
+ pwm_state[channel].pre_div = pre_div;
+ pwm_state[channel].hi = duty_cnt - 1;
+ pwm_state[channel].lo = cnt - duty_cnt - 1;
+ }
+
+ if (duty == period || duty == 0)
+ pwm_constant_enable(dev, channel);
+ else
+ pwm_constant_disable(dev, channel);
+
+ return 0;
+}
+
+static int meson_pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
+ uint duty_ns)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+
+ if ((!priv->is_double_channel) && (channel >= MESON_PWM2)) {
+ pwm_err("sub channel is not support\n");
+ return -EINVAL;
+ }
+
+ if ((duty_ns < 0) || (period_ns <= 0)) {
+ pwm_err("Not available duty_ns period_ns error\n");
+ return -EINVAL;
+ }
+
+ if (duty_ns > period_ns) {
+ pwm_err("Not available duty_ns period_ns error\n");
+ return -EINVAL;
+ }
+
+ if (pwm_state[channel].period != period_ns ||
+ pwm_state[channel].duty_cycle != duty_ns) {
+ meson_pwm_cacl(dev, channel, period_ns, duty_ns);
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM1:
+ pwm_meson_config(dev, channel);
+ break;
+
+ case MESON_PWM2:
+ case MESON_PWM3:
+ pwm_meson_config_ext(dev, channel);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ pwm_state[channel].period = period_ns;
+ pwm_state[channel].duty_cycle = duty_ns;
+
+ return 0;
+};
+
+static int meson_pwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+ struct meson_pwm_reg *regs = priv->regs;
+ unsigned int val, orig;
+
+ if (pwm_state[channel].enabled != enable) {
+
+ if ((!priv->is_double_channel) && (channel >= MESON_PWM2)) {
+ pwm_err("sub channel is not support\n");
+ return -EINVAL;
+ }
+
+ switch (channel) {
+ case MESON_PWM0:
+ val = 1 << 0;
+ break;
+ case MESON_PWM1:
+ val = 1 << 1;
+ break;
+ case MESON_PWM2:
+ val = 1 << 25;
+ break;
+ case MESON_PWM3:
+ val = 1 << 24;
+ break;
+ default:
+ pwm_err("channel is not legal\n");
+ return -EINVAL;
+ }
+
+ orig = readl(&regs->miscr);
+ if (enable)
+ orig |= val;
+ else
+ orig &= ~val;
+
+ writel(orig, &regs->miscr);
+ pwm_state[channel].enabled = 0;
+ }
+
+ return 0;
+}
+
+static int meson_pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_state *pwm_state = priv->pwm_state;
+#if 0
+ struct meson_pwm_reg *regs = priv->regs;
+
+ switch (channel) {
+ case MESON_PWM0:
+ if (polarity)
+ setbits_le32(&regs->miscr, 0x01 << 26);
+ else
+ clrbits_le32(&regs->miscr, 0x01 << 26);
+ break;
+
+ case MESON_PWM1:
+ if (polarity)
+ setbits_le32(&regs->miscr, 0x01 << 27);
+ else
+ clrbits_le32(&regs->miscr, 0x01 << 27);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ break;
+ }
+#endif
+ if (polarity)
+ pwm_state[channel].polarity = 1;
+ else
+ pwm_state[channel].polarity = 0;
+ return 0;
+};
+
+static int meson_pwm_set_times(struct udevice *dev, uint channel, uint times)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+
+ if (!priv->is_double_channel) {
+ pwm_err("times is not support\n");
+ return -EINVAL;
+ }
+
+ if ((times > 256) || (times <= 0)) {
+ pwm_err("Not available times error\n");
+ return -EINVAL;
+ }
+
+ switch (channel) {
+ case MESON_PWM0:
+ clrbits_le32(&regs->tr, 0xff << 24);
+ setbits_le32(&regs->tr, (times - 1) << 24);
+ break;
+
+ case MESON_PWM1:
+ clrbits_le32(&regs->tr, 0xff << 8);
+ setbits_le32(&regs->tr, (times - 1) << 8);
+ break;
+
+ case MESON_PWM2:
+ clrbits_le32(&regs->tr, 0xff << 16);
+ setbits_le32(&regs->tr, (times - 1) << 16);
+ break;
+
+ case MESON_PWM3:
+ clrbits_le32(&regs->tr, 0xff << 0);
+ setbits_le32(&regs->tr, (times - 1) << 0);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+static int meson_pwm_set_blink_times(struct udevice *dev, uint channel, uint times)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+
+ if (!priv->is_double_channel || !priv->is_blink) {
+ pwm_err("Blink is not support\n");
+ return -EINVAL;
+ }
+
+ if ((times > 16) || (times <= 0)) {
+ pwm_err("Not available times error\n");
+ return -EINVAL;
+ }
+
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM2:
+ clrbits_le32(&regs->br, 0xf);
+ setbits_le32(&regs->br, times - 1);
+ break;
+
+ case MESON_PWM1:
+ case MESON_PWM3:
+ clrbits_le32(&regs->br, 0xf << 4);
+ setbits_le32(&regs->br, (times - 1) << 4);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+static int meson_pwm_blink_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_reg *regs = priv->regs;
+
+ if (!priv->is_double_channel || !priv->is_blink) {
+ pwm_err("Blink is not support\n");
+ return -EINVAL;
+ }
+
+ switch (channel) {
+ case MESON_PWM0:
+ case MESON_PWM2:
+ if (enable)
+ setbits_le32(&regs->br, 1 << 8);
+ else
+ clrbits_le32(&regs->br, 1 << 8);
+ break;
+
+ case MESON_PWM1:
+ case MESON_PWM3:
+ if (enable)
+ setbits_le32(&regs->br, 1 << 9);
+ else
+ clrbits_le32(&regs->br, 1 << 9);
+ break;
+
+ default:
+ pwm_err("Id is invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+static int meson_pwm_probe(struct udevice *dev)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+ struct meson_pwm_platdata *plat = dev_get_platdata(dev);
+
+ priv->regs = (struct meson_pwm_reg *)plat->reg;
+ priv->pwm_state = (struct meson_pwm_state *)calloc(4, sizeof(struct meson_pwm_state));
+ priv->is_double_channel = plat->is_double_channel;
+ priv->is_blink = plat->is_blink;
+
+ return 0;
+}
+
+int meson_pwm_remove(struct udevice *dev)
+{
+ struct meson_pwm_priv *priv = dev_get_priv(dev);
+
+ free(priv->pwm_state);
+
+ return 0;
+}
+
+static const struct pwm_ops meson_pwm_ops = {
+ .set_config = meson_pwm_set_config,
+ .set_enable = meson_pwm_set_enable,
+ .set_invert = meson_pwm_set_invert,
+ .set_times = meson_pwm_set_times,
+ .set_blink_times = meson_pwm_set_blink_times,
+ .set_blink_enable = meson_pwm_blink_enable,
+};
+
+U_BOOT_DRIVER(meson_pwm) = {
+ .name = "amlogic,general-pwm",
+ .id = UCLASS_PWM,
+ .ops = &meson_pwm_ops,
+ .probe = meson_pwm_probe,
+ .remove = meson_pwm_remove,
+ .priv_auto_alloc_size = sizeof(struct meson_pwm_priv),
+};
diff --git a/drivers/pwm/pwm-meson.h b/drivers/pwm/pwm-meson.h
new file mode 100644
index 0000000..8146b13
--- a/dev/null
+++ b/drivers/pwm/pwm-meson.h
@@ -0,0 +1,45 @@
+#ifndef PWM_MESON_H
+#define PWM_MESON_H
+
+#define NSEC_PER_SEC 1000000000ULL
+
+struct meson_pwm_reg {
+ u32 dar;/* A/C/E Duty Register */
+ u32 dbr;/* B/D/F Duty Register */
+ u32 miscr;/* misc Register */
+ u32 dsr;/*DS Register*/
+ u32 tr;/*times Register*/
+ u32 da2r;/* A2/C2/E2 Duty Register */
+ u32 db2r;/* B2/D2/F2 Duty Register */
+ u32 br;/*Blink Register*/
+};
+
+enum pwm_polarity {
+ PWM_POLARITY_NORMAL,
+ PWM_POLARITY_INVERSED,
+};
+
+struct meson_pwm_state {
+ unsigned int period;
+ unsigned int duty_cycle;
+ unsigned int hi;
+ unsigned int lo;
+ unsigned int pre_div;
+ enum pwm_polarity polarity;
+ bool enabled;
+};
+
+/*
+ * Same as above but for u64 dividends. divisor must be a 32-bit
+ * number.
+ */
+#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \
+{ \
+ typeof(divisor) __d = divisor; \
+ unsigned long long _tmp = (x) + (__d) / 2; \
+ do_div(_tmp, __d); \
+ _tmp; \
+} \
+)
+
+#endif
diff --git a/drivers/pwm/pwm-uclass.c b/drivers/pwm/pwm-uclass.c
new file mode 100644
index 0000000..f9c4c96
--- a/dev/null
+++ b/drivers/pwm/pwm-uclass.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <pwm.h>
+#include <asm/errno.h>
+
+int pwm_set_invert(struct udevice *dev, uint channel, bool polarity)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_invert)
+ return -ENOSYS;
+
+ return ops->set_invert(dev, channel, polarity);
+}
+
+int pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
+ uint duty_ns)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_config)
+ return -ENOSYS;
+
+ return ops->set_config(dev, channel, period_ns, duty_ns);
+}
+
+int pwm_set_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_enable)
+ return -ENOSYS;
+
+ return ops->set_enable(dev, channel, enable);
+}
+#ifdef CONFIG_PWM_MESON
+int pwm_set_times(struct udevice *dev, uint channel, uint times)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_enable)
+ return -ENOSYS;
+
+ return ops->set_times(dev, channel, times);
+}
+
+int pwm_set_blink_times(struct udevice *dev, uint channel, uint times)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_enable)
+ return -ENOSYS;
+
+ return ops->set_blink_times(dev, channel, times);
+}
+
+int pwm_set_blink_enable(struct udevice *dev, uint channel, bool enable)
+{
+ struct pwm_ops *ops = pwm_get_ops(dev);
+
+ if (!ops->set_enable)
+ return -ENOSYS;
+
+ return ops->set_blink_enable(dev, channel, enable);
+}
+#endif
+UCLASS_DRIVER(pwm) = {
+ .id = UCLASS_PWM,
+ .name = "pwm",
+};
diff --git a/include/amlogic/pwm.h b/include/amlogic/pwm.h
new file mode 100644
index 0000000..9d741ff
--- a/dev/null
+++ b/include/amlogic/pwm.h
@@ -0,0 +1,43 @@
+/*
+ * Amlogic I2C controller Diver
+ *
+ * Copyright (C) 2018 Amlogic Corporation
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
+#ifndef __PWM_H__
+#define __PWM_H__
+
+/*
+ * @pwm_index: Controller Index.
+ * @reg: Controller registers address.
+ */
+
+#define MESON_PWM0 0
+#define MESON_PWM1 1
+#define MESON_PWM2 2
+#define MESON_PWM3 3
+
+#define NO_DOUBLE_CHANNEL 0
+#define IS_DOUBLE_CHANNEL 1
+#define NO_BLINK 0
+#define IS_BLINK 1
+
+enum {
+ PWM_AB = 0x0,
+ PWM_CD = 0x1,
+ PWM_EF = 0x2,
+ PWMAO_AB = 0x3,
+ PWMAO_CD = 0x4,
+};
+
+struct meson_pwm_platdata {
+ unsigned int pwm_index;
+ ulong reg;
+ bool is_double_channel;
+ bool is_blink;
+};
+
+#endif /* __PWM_H__ */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f17c3c2..5373938 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -33,6 +33,7 @@ enum uclass_id {
UCLASS_I2C, /* I2C bus */
UCLASS_I2C_GENERIC, /* Generic I2C device */
UCLASS_I2C_EEPROM, /* I2C EEPROM device */
+ UCLASS_PWM, /* Pulse-width modulator */
UCLASS_COUNT,
UCLASS_INVALID = -1,
diff --git a/include/pwm.h b/include/pwm.h
index f24f220..1a5b4d2 100644
--- a/include/pwm.h
+++ b/include/pwm.h
@@ -10,9 +10,139 @@
#ifndef _pwm_h_
#define _pwm_h_
+/* struct pwm_ops: Operations for the PWM uclass */
+struct pwm_ops {
+ /**
+ * set_config() - Set the PWM configuration
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @period_ns: PWM period in nanoseconds
+ * @duty_ns: PWM duty period in nanoseconds
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_config)(struct udevice *dev, uint channel, uint period_ns,
+ uint duty_ns);
+
+ /**
+ * set_enable() - Enable or disable the PWM
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @enable: true to enable, false to disable
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_enable)(struct udevice *dev, uint channel, bool enable);
+ /**
+ * set_invert() - Set the PWM invert
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @polarity: true to invert, false to keep normal polarity
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_invert)(struct udevice *dev, uint channel, bool polarity);
+#ifdef CONFIG_PWM_MESON
+ /**
+ * set_times() - Set the PWM times
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @times: dual channel to set times
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_times)(struct udevice *dev, uint channel, uint times);
+ /**
+ * set_blink_times() - Set the PWM blink times
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @times: set blink times
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_blink_times)(struct udevice *dev, uint channel, uint times);
+ /**
+ * set_blink_enable() - Enable or disable the PWM blink
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @enable: true to enable, false to disable
+ * @return 0 if OK, -ve on error
+ */
+ int (*set_blink_enable)(struct udevice *dev, uint channel, bool enable);
+#endif
+};
+
+#define pwm_get_ops(dev) ((struct pwm_ops *)(dev)->driver->ops)
+
+/**
+ * pwm_set_config() - Set the PWM configuration
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @period_ns: PWM period in nanoseconds
+ * @duty_ns: PWM duty period in nanoseconds
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_config(struct udevice *dev, uint channel, uint period_ns,
+ uint duty_ns);
+
+/**
+ * pwm_set_enable() - Enable or disable the PWM
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @enable: true to enable, false to disable
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_enable(struct udevice *dev, uint channel, bool enable);
+
+/**
+ * pwm_set_invert() - Set pwm default polarity
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @polarity: true to invert, false to keep normal polarity
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_invert(struct udevice *dev, uint channel, bool polarity);
+#ifdef CONFIG_PWM_MESON
+/**
+ * pwm_set_times() - Set the PWM times
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @times: dual channel to set times
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_times(struct udevice *dev, uint channel, uint times);
+
+/**
+ * pwm_set_blink_times() - Set the PWM blink times
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @times: set blink times
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_blink_times(struct udevice *dev, uint channel, uint times);
+
+/**
+ * pwm_set_blink_enable() - Enable or disable the PWM blink
+ *
+ * @dev: PWM device to update
+ * @channel: PWM channel to update
+ * @enable: true to enable, false to disable
+ * @return 0 if OK, -ve on error
+ */
+int pwm_set_blink_enable(struct udevice *dev, uint channel, bool enable);
+#endif
+/* Legacy interface */
+#ifndef CONFIG_DM_PWM
int pwm_init (int pwm_id, int div, int invert);
int pwm_config (int pwm_id, int duty_ns, int period_ns);
int pwm_enable (int pwm_id);
void pwm_disable (int pwm_id);
+#endif
#endif /* _pwm_h_ */