1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4
5 #include <drv/pwm.h>
6 #include <aos/pwm_core.h>
7 #include "hal_pwm.h"
8 #include "hal_gpio.h"
9 #include "hal_trace.h"
10 #include "hal_iomux.h"
11 #include "hal_cmu.h"
12 #include "pmu.h"
13
14 #define NS_PER_SEC (1000000000UL)
15 #define DIV_ROUND_CLOSEST(x, divisor)( \
16 { \
17 typeof(x) __x = x; \
18 typeof(divisor) __d = divisor; \
19 (((typeof(x))-1) > 0 || \
20 ((typeof(divisor))-1) > 0 || \
21 (((__x) > 0) == ((__d) > 0))) ? \
22 (((__x) + ((__d) / 2)) / (__d)) : \
23 (((__x) - ((__d) / 2)) / (__d)); \
24 } \
25 )
26 typedef struct {
27 aos_pwm_t aos_pwm;
28 void *priv;
29 } haas1000_pwm_t;
30
31 #define _HAL_PWM_MAX_NUM 4
32 static struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux_pwm[_HAL_PWM_MAX_NUM] = {
33 { HAL_IOMUX_PIN_P2_6, HAL_IOMUX_FUNC_PWM0, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENALBE },
34 { HAL_IOMUX_PIN_P2_7, HAL_IOMUX_FUNC_PWM1, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENALBE },
35 { HAL_IOMUX_PIN_P2_4, HAL_IOMUX_FUNC_PWM2, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENALBE },
36 { HAL_IOMUX_PIN_P2_5, HAL_IOMUX_FUNC_PWM3, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENALBE },
37 };
38
39 static uint8_t pwm_chan[_HAL_PWM_MAX_NUM] = {0};
haas1000_pwm_uninit(haas1000_pwm_t * pwm)40 static void haas1000_pwm_uninit(haas1000_pwm_t *pwm)
41 {
42 return;
43 }
44
haas1000_pwm_out_config(haas1000_pwm_t * pwm,uint32_t channel,uint32_t period_ns,uint32_t pulse_width_ns,csi_pwm_polarity_t polarity)45 int haas1000_pwm_out_config(haas1000_pwm_t *pwm, uint32_t channel, uint32_t period_ns,
46 uint32_t pulse_width_ns, csi_pwm_polarity_t polarity)
47 {
48 struct HAL_PWM_CFG_T cfg;
49
50 if (channel >= _HAL_PWM_MAX_NUM)
51 return 0;
52 if (pwm_chan[channel] == 0) {
53 hal_iomux_init(&pinmux_pwm[channel], 1);
54 hal_gpio_pin_set_dir(pinmux_pwm[channel].pin, HAL_GPIO_DIR_OUT, 1);
55 }
56 pwm_chan[channel] = 1;
57 if (period_ns == 0) {
58 hal_pwm_disable(channel);
59 } else {
60 cfg.freq = DIV_ROUND_CLOSEST(NS_PER_SEC, period_ns);
61 cfg.ratio = DIV_ROUND_CLOSEST(((uint64_t)pulse_width_ns) * 100, period_ns);
62 cfg.inv = polarity;
63 cfg.sleep_on = false;
64 hal_pwm_enable(channel, &cfg);
65 }
66 return 0;
67 }
68
haas1000_pwm_out_start(haas1000_pwm_t * pwm_dev,uint32_t channel)69 static int haas1000_pwm_out_start(haas1000_pwm_t *pwm_dev, uint32_t channel)
70 {
71 return 0;
72 }
73
haas1000_pwm_out_stop(haas1000_pwm_t * pwm_dev,uint32_t channel)74 static int haas1000_pwm_out_stop(haas1000_pwm_t *pwm_dev, uint32_t channel)
75 {
76 uint32_t pwm_chan = channel;
77 hal_pwm_disable(pwm_chan);
78 return 0;
79 }
80
haas1000_pwm_unregister(aos_pwm_t * pwm)81 static void haas1000_pwm_unregister(aos_pwm_t *pwm)
82 {
83 haas1000_pwm_t *pwm_dev = aos_container_of(pwm, haas1000_pwm_t, aos_pwm);
84
85 haas1000_pwm_uninit(pwm_dev);
86 }
87
haas1000_pwm_startup(aos_pwm_t * pwm)88 static int haas1000_pwm_startup(aos_pwm_t *pwm)
89 {
90 return 0;
91 }
92
haas1000_pwm_shutdown(aos_pwm_t * pwm)93 static void haas1000_pwm_shutdown(aos_pwm_t *pwm)
94 {
95 haas1000_pwm_t *pwm_dev = aos_container_of(pwm, haas1000_pwm_t, aos_pwm);
96 haas1000_pwm_out_stop(pwm_dev, pwm_dev->aos_pwm.dev.id);
97 }
98
haas1000_pwm_apply(aos_pwm_t * pwm,aos_pwm_attr_t const * attr)99 static int haas1000_pwm_apply(aos_pwm_t *pwm, aos_pwm_attr_t const *attr)
100 {
101 uint32_t period;
102 uint32_t duty_cycle;
103
104 haas1000_pwm_t *pwm_dev = aos_container_of(pwm, haas1000_pwm_t, aos_pwm);
105 period = attr->period;
106 duty_cycle = attr->duty_cycle;
107 haas1000_pwm_out_config(pwm_dev, pwm_dev->aos_pwm.dev.id,
108 period, duty_cycle, attr->polarity);
109 if (attr->enabled)
110 haas1000_pwm_out_start(pwm_dev, pwm_dev->aos_pwm.dev.id);
111 else
112 haas1000_pwm_out_stop(pwm_dev, pwm_dev->aos_pwm.dev.id);
113 return 0;
114 }
115
116 static const aos_pwm_ops_t haas1000_pwm_ops = {
117 .unregister = haas1000_pwm_unregister,
118 .apply = haas1000_pwm_apply,
119 .shutdown = haas1000_pwm_shutdown,
120 .startup = haas1000_pwm_startup
121 };
haas1000_pwm_init(void)122 static int haas1000_pwm_init(void)
123 {
124 int ret;
125 static haas1000_pwm_t pwm_dev[CONFIG_PWM_NUM];
126 int i;
127 for (i = 0; i < CONFIG_PWM_NUM; i++) {
128 pwm_dev[i].aos_pwm.dev.id = i;
129 pwm_dev[i].aos_pwm.ops = &haas1000_pwm_ops;
130 ret = aos_pwm_register(&(pwm_dev[i].aos_pwm));
131 if (ret != 0) {
132 return ret;
133 }
134 }
135 return 0;
136 }
137
138 LEVEL1_DRIVER_ENTRY(haas1000_pwm_init)
139