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