xref: /OK3568_Linux_fs/u-boot/drivers/power/power_delivery/tcpci_husb311.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2021 Rockchip Co.,Ltd.
4  * Author: Wang Jie <dave.wang@rock-chips.com>
5  *
6  * Hynetek Husb311 Type-C Chip Driver
7  */
8 
9 #include <dm.h>
10 #include <i2c.h>
11 #include <asm/gpio.h>
12 #include <power/power_delivery/tcpm.h>
13 #include <power/power_delivery/power_delivery.h>
14 #include "tcpci.h"
15 
16 #define HUSB311_VID		0x2E99
17 #define HUSB311_PID		0x0311
18 #define HUSB311_TCPC_I2C_RESET	0x9E
19 #define HUSB311_TCPC_SOFTRESET	0xA0
20 #define HUSB311_TCPC_FILTER	0xA1
21 #define HUSB311_TCPC_TDRP	0xA2
22 #define HUSB311_TCPC_DCSRCDRP	0xA3
23 #define HUSB311_I2C_RETRY_MAX_CNT 3
24 
25 struct husb311_chip {
26 	struct udevice *udev;
27 	struct tcpci_data data;
28 	struct tcpci *tcpci;
29 };
30 
husb311_read16(struct husb311_chip * chip,unsigned int reg)31 static int husb311_read16(struct husb311_chip *chip, unsigned int reg)
32 {
33 	int ret = 0;
34 	u8 buffer[2];
35 
36 	ret = dm_i2c_read(chip->udev, reg, buffer, 2);
37 	if (ret < 0) {
38 		printf("%s: cannot read %02x, ret=%d\n",
39 			__func__, reg, ret);
40 		return ret;
41 	}
42 	ret = ((buffer[1] << 8) & 0xFF00) + (buffer[0] & 0xFF);
43 
44 	return ret;
45 }
46 
husb311_write8(struct husb311_chip * chip,unsigned int reg,u8 val)47 static int husb311_write8(struct husb311_chip *chip, unsigned int reg, u8 val)
48 {
49 	int ret = 0;
50 	int i;
51 
52 	for (i = 0; i < HUSB311_I2C_RETRY_MAX_CNT; i++) {
53 		ret = dm_i2c_write(chip->udev, reg, &val, 1);
54 		if (!ret)
55 			break;
56 		else
57 			udelay(200);
58 	}
59 
60 	if (ret)
61 		printf("%s: cannot write 0x%02x to 0x%02x, ret=%d\n",
62 			__func__, val, reg, ret);
63 
64 	return ret;
65 }
66 
husb311_write16(struct husb311_chip * chip,unsigned int reg,u16 val)67 static int husb311_write16(struct husb311_chip *chip, unsigned int reg, u16 val)
68 {
69 	int ret = 0;
70 	u8 buffer[2];
71 
72 	buffer[0] = val & 0xFF;
73 	buffer[1] = (val >> 8) & 0xFF;
74 	ret = dm_i2c_write(chip->udev, reg, buffer, 2);
75 	if (ret)
76 		printf("%s: cannot write 0x%02x, len=%d, ret=%d\n",
77 			__func__, reg, 2, ret);
78 
79 	return ret;
80 }
81 
tdata_to_husb311(struct tcpci_data * tdata)82 static struct husb311_chip *tdata_to_husb311(struct tcpci_data *tdata)
83 {
84 	return container_of(tdata, struct husb311_chip, data);
85 }
86 
husb311_sw_reset(struct husb311_chip * chip)87 static int husb311_sw_reset(struct husb311_chip *chip)
88 {
89 	/* soft reset */
90 	return husb311_write8(chip, HUSB311_TCPC_SOFTRESET, 0x01);
91 }
92 
husb311_init(struct tcpci * tcpci,struct tcpci_data * tdata)93 static int husb311_init(struct tcpci *tcpci, struct tcpci_data *tdata)
94 {
95 	int ret;
96 	struct husb311_chip *chip = tdata_to_husb311(tdata);
97 
98 	/* I2C reset : (val + 1) * 12.5ms */
99 	ret = husb311_write8(chip, HUSB311_TCPC_I2C_RESET, 0x8F);
100 	/* tTCPCfilter : (26.7 * val) us */
101 	ret |= husb311_write8(chip, HUSB311_TCPC_FILTER, 0x0F);
102 	/* tDRP : (51.2 + 6.4 * val) ms */
103 	ret |= husb311_write8(chip, HUSB311_TCPC_TDRP, 0x04);
104 	/* dcSRC.DRP : 33% */
105 	ret |= husb311_write16(chip, HUSB311_TCPC_DCSRCDRP, 330);
106 
107 	if (ret)
108 		printf("%s: fail to init registers(%d)\n", __func__, ret);
109 
110 	return ret;
111 }
112 
husb311_check_revision(struct husb311_chip * chip)113 static int husb311_check_revision(struct husb311_chip *chip)
114 {
115 	int ret;
116 
117 	ret = husb311_read16(chip, TCPC_VENDOR_ID);
118 	if (ret < 0) {
119 		printf("%s: fail to read Vendor id(%d)\n", __func__, ret);
120 		return ret;
121 	}
122 
123 	if (ret != HUSB311_VID) {
124 		printf("%s: vid is not correct, 0x%04x\n", __func__, ret);
125 		return -ENODEV;
126 	}
127 
128 	ret = husb311_read16(chip, TCPC_PRODUCT_ID);
129 	if (ret < 0) {
130 		printf("%s: fail to read Product id(%d)\n", __func__, ret);
131 		return ret;
132 	}
133 
134 	if (ret != HUSB311_PID) {
135 		printf("%s: pid is not correct, 0x%04x\n", __func__, ret);
136 		return -ENODEV;
137 	}
138 
139 	return 0;
140 }
141 
husb311_probe(struct udevice * dev)142 static int husb311_probe(struct udevice *dev)
143 {
144 	int ret;
145 	struct husb311_chip *chip = dev_get_priv(dev);
146 
147 	chip->udev = dev;
148 
149 	ret = husb311_check_revision(chip);
150 	if (ret < 0) {
151 		printf("%s: check vid/pid fail(%d)\n", __func__, ret);
152 		return ret;
153 	}
154 
155 	ret = husb311_sw_reset(chip);
156 	if (ret) {
157 		printf("%s: fail to soft reset, ret = %d\n", __func__, ret);
158 		return ret;
159 	}
160 
161 	chip->data.init = husb311_init;
162 	chip->tcpci = tcpci_register_port(chip->udev, &chip->data);
163 	if (IS_ERR(chip->tcpci))
164 		return PTR_ERR(chip->tcpci);
165 
166 	return 0;
167 }
168 
husb311_remove(struct udevice * dev)169 static int husb311_remove(struct udevice *dev)
170 {
171 	struct husb311_chip *chip = dev_get_priv(dev);
172 	int ret = 0;
173 
174 	printf("PD chip husb311 remove\n");
175 	/* Disable chip interrupts before unregistering port */
176 	ret = husb311_write16(chip, TCPC_ALERT_MASK, 0);
177 	if (ret < 0)
178 		return ret;
179 
180 	tcpci_unregister_port(chip->tcpci);
181 
182 	return 0;
183 }
184 
husb311_get_voltage(struct udevice * dev)185 static int husb311_get_voltage(struct udevice *dev)
186 {
187 	struct husb311_chip *chip = dev_get_priv(dev);
188 
189 	return tcpci_get_voltage_fun(chip->tcpci);
190 }
191 
husb311_get_current(struct udevice * dev)192 static int husb311_get_current(struct udevice *dev)
193 {
194 	struct husb311_chip *chip = dev_get_priv(dev);
195 
196 	return tcpci_get_current_fun(chip->tcpci);
197 }
198 
husb311_get_online(struct udevice * dev)199 static int husb311_get_online(struct udevice *dev)
200 {
201 	struct husb311_chip *chip = dev_get_priv(dev);
202 
203 	return tcpci_get_online_fun(chip->tcpci);
204 }
205 
206 static struct dm_power_delivery_ops husb311_ops = {
207 	.get_voltage = husb311_get_voltage,
208 	.get_current = husb311_get_current,
209 	.get_online = husb311_get_online,
210 };
211 
212 static const struct udevice_id husb311_ids[] = {
213 	{ .compatible = "hynetek,husb311" },
214 	{},
215 };
216 
217 U_BOOT_DRIVER(husb311) = {
218 	.name = "husb311",
219 	.id = UCLASS_PD,
220 	.of_match = husb311_ids,
221 	.ops = &husb311_ops,
222 	.probe = husb311_probe,
223 	.remove = husb311_remove,
224 	.priv_auto_alloc_size = sizeof(struct husb311_chip),
225 };
226 
227 MODULE_AUTHOR("Wang Jie <dave.wang@rock-chips.com>");
228 MODULE_DESCRIPTION("Husb311 USB Type-C Port Controller Interface Driver");
229 MODULE_LICENSE("GPL v2");
230