1 /*
2 * Copyright (c) 2023 The Chromium OS Authors.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/device.h>
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/adc.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/usb_c/usbc.h>
13 #include <zephyr/drivers/pwm.h>
14
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(power_ctrl, LOG_LEVEL_DBG);
17
18 #include "power_ctrl.h"
19
20 #define PORT1_DCDC_DETECT_NODE DT_PATH(dcdc_detect)
21
22 #define PORT1_SOURCE_EN_NODE DT_NODELABEL(source_en)
23 #define PORT1_DCDC_EN_NODE DT_NODELABEL(dcdc_en)
24 #define PORT1_PWM_CTL_NODE DT_NODELABEL(pwm_ctl)
25 #define PORT1_VCONN1_EN_NODE DT_NODELABEL(vconn1_en)
26 #define PORT1_VCONN2_EN_NODE DT_NODELABEL(vconn2_en)
27
28 /* DCDC Voltage is 19V and setting min threshold to 18V */
29 #define MIN_DCDC_DETECT_MV 18000
30
31 #define PWM_FOR_15V 45000
32 #define PWM_FOR_9V 30000
33 #define PWM_FOR_5V 21500
34 #define PWM_FOR_0V 0
35
36 static const struct gpio_dt_spec source_en = GPIO_DT_SPEC_GET(PORT1_SOURCE_EN_NODE, gpios);
37 static const struct gpio_dt_spec dcdc_en = GPIO_DT_SPEC_GET(PORT1_DCDC_EN_NODE, gpios);
38
39 static const struct gpio_dt_spec vconn1_en = GPIO_DT_SPEC_GET(PORT1_VCONN1_EN_NODE, gpios);
40 static const struct gpio_dt_spec vconn2_en = GPIO_DT_SPEC_GET(PORT1_VCONN2_EN_NODE, gpios);
41
42 static const struct pwm_dt_spec pwm_ctl = PWM_DT_SPEC_GET(PORT1_PWM_CTL_NODE);
43
vconn_ctrl_set(enum vconn_t v)44 int vconn_ctrl_set(enum vconn_t v)
45 {
46 switch (v) {
47 case VCONN_OFF:
48 gpio_pin_set_dt(&vconn1_en, 0);
49 gpio_pin_set_dt(&vconn2_en, 0);
50 break;
51 case VCONN1_ON:
52 gpio_pin_set_dt(&vconn1_en, 1);
53 gpio_pin_set_dt(&vconn2_en, 0);
54 break;
55 case VCONN2_ON:
56 gpio_pin_set_dt(&vconn1_en, 0);
57 gpio_pin_set_dt(&vconn2_en, 1);
58 break;
59 };
60
61 return 0;
62 }
63
source_ctrl_set(enum source_t v)64 int source_ctrl_set(enum source_t v)
65 {
66 uint32_t pwmv;
67
68 switch (v) {
69 case SOURCE_0V:
70 pwmv = PWM_FOR_0V;
71 break;
72 case SOURCE_5V:
73 pwmv = PWM_FOR_5V;
74 break;
75 case SOURCE_9V:
76 pwmv = PWM_FOR_9V;
77 break;
78 case SOURCE_15V:
79 pwmv = PWM_FOR_15V;
80 break;
81 default:
82 pwmv = PWM_FOR_0V;
83 }
84
85 return pwm_set_pulse_dt(&pwm_ctl, pwmv);
86 }
87
power_ctrl_init(void)88 static int power_ctrl_init(void)
89 {
90 int ret;
91
92 if (!device_is_ready(source_en.port)) {
93 LOG_ERR("Error: Source Enable device %s is not ready\n",
94 source_en.port->name);
95 return -ENOENT;
96 }
97
98 if (!device_is_ready(dcdc_en.port)) {
99 LOG_ERR("Error: DCDC Enable device %s is not ready\n",
100 dcdc_en.port->name);
101 return -ENOENT;
102 }
103
104 if (!device_is_ready(vconn1_en.port)) {
105 LOG_ERR("Error: VCONN1 Enable device %s is not ready\n",
106 vconn1_en.port->name);
107 return -ENOENT;
108 }
109
110 if (!device_is_ready(vconn2_en.port)) {
111 LOG_ERR("Error: VCONN2 Enable device %s is not ready\n",
112 vconn2_en.port->name);
113 return -ENOENT;
114 }
115
116 if (!device_is_ready(pwm_ctl.dev)) {
117 LOG_ERR("Error: PWM CTL device is not ready\n");
118 return -ENOENT;
119 }
120
121 ret = gpio_pin_configure_dt(&source_en, GPIO_OUTPUT);
122 if (ret != 0) {
123 LOG_ERR("Error %d: failed to configure Source Enable device %s pin %d\n",
124 ret, source_en.port->name, source_en.pin);
125 return ret;
126 }
127
128 ret = gpio_pin_configure_dt(&dcdc_en, GPIO_OUTPUT);
129 if (ret != 0) {
130 LOG_ERR("Error %d: failed to configure DCDC Enable device %s pin %d\n",
131 ret, dcdc_en.port->name, dcdc_en.pin);
132 return ret;
133 }
134
135 ret = gpio_pin_configure_dt(&vconn1_en, GPIO_OUTPUT | GPIO_OPEN_DRAIN);
136 if (ret != 0) {
137 LOG_ERR("Error %d: failed to configure VCONN1 Enable device %s pin %d\n",
138 ret, vconn1_en.port->name, vconn1_en.pin);
139 return ret;
140 }
141
142 ret = gpio_pin_configure_dt(&vconn2_en, GPIO_OUTPUT | GPIO_OPEN_DRAIN);
143 if (ret != 0) {
144 LOG_ERR("Error %d: failed to configure VCONN2 Enable device %s pin %d\n",
145 ret, vconn2_en.port->name, vconn1_en.pin);
146 return ret;
147 }
148
149 ret = gpio_pin_set_dt(&source_en, 1);
150 if (ret != 0) {
151 LOG_ERR("Error %d: failed to enable source\n", ret);
152 return ret;
153 }
154
155 ret = gpio_pin_set_dt(&dcdc_en, 1);
156 if (ret != 0) {
157 LOG_ERR("Error %d: failed to enable dcdc converter\n", ret);
158 return ret;
159 }
160
161 vconn_ctrl_set(VCONN_OFF);
162
163 ret = source_ctrl_set(SOURCE_0V);
164 if (ret != 0) {
165 LOG_ERR("Error %d: failed to set VBUS to 0V\n", ret);
166 return ret;
167 }
168
169 return 0;
170 }
171
172 SYS_INIT(power_ctrl_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
173