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