Skip to content

Commit ce08eae

Browse files
ShuFan Leegregkh
authored andcommitted
staging: typec: rt1711h typec chip driver
Richtek RT1711H Type-C chip driver that works with Type-C Port Controller Manager to provide USB PD and USB Type-C functionalities. Add definition of TCPC_CC_STATUS_TOGGLING. Signed-off-by: ShuFan Lee <shufan_lee@richtek.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0fd2060 commit ce08eae

File tree

4 files changed

+322
-0
lines changed

4 files changed

+322
-0
lines changed

drivers/staging/typec/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ config TYPEC_TCPCI
99
help
1010
Type-C Port Controller driver for TCPCI-compliant controller.
1111

12+
config TYPEC_RT1711H
13+
tristate "Richtek RT1711H Type-C chip driver"
14+
select TYPEC_TCPCI
15+
help
16+
Richtek RT1711H Type-C chip driver that works with
17+
Type-C Port Controller Manager to provide USB PD and USB
18+
Type-C functionalities.
19+
1220
endif
1321

1422
endmenu

drivers/staging/typec/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
2+
obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o

drivers/staging/typec/tcpci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
6060

6161
#define TCPC_CC_STATUS 0x1d
62+
#define TCPC_CC_STATUS_TOGGLING BIT(5)
6263
#define TCPC_CC_STATUS_TERM BIT(4)
6364
#define TCPC_CC_STATUS_CC2_SHIFT 2
6465
#define TCPC_CC_STATUS_CC2_MASK 0x3
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
// SPDX-License-Identifier: GPL-2.0+
2+
/*
3+
* Copyright (C) 2018, Richtek Technology Corporation
4+
*
5+
* Richtek RT1711H Type-C Chip Driver
6+
*/
7+
8+
#include <linux/kernel.h>
9+
#include <linux/module.h>
10+
#include <linux/i2c.h>
11+
#include <linux/interrupt.h>
12+
#include <linux/gpio/consumer.h>
13+
#include <linux/usb/tcpm.h>
14+
#include <linux/regmap.h>
15+
#include "tcpci.h"
16+
17+
#define RT1711H_VID 0x29CF
18+
#define RT1711H_PID 0x1711
19+
20+
#define RT1711H_RTCTRL8 0x9B
21+
22+
/* Autoidle timeout = (tout * 2 + 1) * 6.4ms */
23+
#define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \
24+
(((ck300) << 7) | ((ship_off) << 5) | \
25+
((auto_idle) << 3) | ((tout) & 0x07))
26+
27+
#define RT1711H_RTCTRL11 0x9E
28+
29+
/* I2C timeout = (tout + 1) * 12.5ms */
30+
#define RT1711H_RTCTRL11_SET(en, tout) \
31+
(((en) << 7) | ((tout) & 0x0F))
32+
33+
#define RT1711H_RTCTRL13 0xA0
34+
#define RT1711H_RTCTRL14 0xA1
35+
#define RT1711H_RTCTRL15 0xA2
36+
#define RT1711H_RTCTRL16 0xA3
37+
38+
struct rt1711h_chip {
39+
struct tcpci_data data;
40+
struct tcpci *tcpci;
41+
struct device *dev;
42+
};
43+
44+
static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val)
45+
{
46+
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
47+
}
48+
49+
static int rt1711h_write16(struct rt1711h_chip *chip, unsigned int reg, u16 val)
50+
{
51+
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
52+
}
53+
54+
static int rt1711h_read8(struct rt1711h_chip *chip, unsigned int reg, u8 *val)
55+
{
56+
return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
57+
}
58+
59+
static int rt1711h_write8(struct rt1711h_chip *chip, unsigned int reg, u8 val)
60+
{
61+
return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
62+
}
63+
64+
static const struct regmap_config rt1711h_regmap_config = {
65+
.reg_bits = 8,
66+
.val_bits = 8,
67+
68+
.max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */
69+
};
70+
71+
static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata)
72+
{
73+
return container_of(tdata, struct rt1711h_chip, data);
74+
}
75+
76+
static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
77+
{
78+
int ret;
79+
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
80+
81+
/* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */
82+
ret = rt1711h_write8(chip, RT1711H_RTCTRL8,
83+
RT1711H_RTCTRL8_SET(0, 1, 1, 2));
84+
if (ret < 0)
85+
return ret;
86+
87+
/* I2C reset : (val + 1) * 12.5ms */
88+
ret = rt1711h_write8(chip, RT1711H_RTCTRL11,
89+
RT1711H_RTCTRL11_SET(1, 0x0F));
90+
if (ret < 0)
91+
return ret;
92+
93+
/* tTCPCfilter : (26.7 * val) us */
94+
ret = rt1711h_write8(chip, RT1711H_RTCTRL14, 0x0F);
95+
if (ret < 0)
96+
return ret;
97+
98+
/* tDRP : (51.2 + 6.4 * val) ms */
99+
ret = rt1711h_write8(chip, RT1711H_RTCTRL15, 0x04);
100+
if (ret < 0)
101+
return ret;
102+
103+
/* dcSRC.DRP : 33% */
104+
return rt1711h_write16(chip, RT1711H_RTCTRL16, 330);
105+
}
106+
107+
static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata,
108+
bool enable)
109+
{
110+
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
111+
112+
return rt1711h_write8(chip, RT1711H_RTCTRL8,
113+
RT1711H_RTCTRL8_SET(0, 1, !enable, 2));
114+
}
115+
116+
static int rt1711h_start_drp_toggling(struct tcpci *tcpci,
117+
struct tcpci_data *tdata,
118+
enum typec_cc_status cc)
119+
{
120+
struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
121+
int ret;
122+
unsigned int reg = 0;
123+
124+
switch (cc) {
125+
default:
126+
case TYPEC_CC_RP_DEF:
127+
reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF <<
128+
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
129+
break;
130+
case TYPEC_CC_RP_1_5:
131+
reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
132+
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
133+
break;
134+
case TYPEC_CC_RP_3_0:
135+
reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
136+
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
137+
break;
138+
}
139+
140+
if (cc == TYPEC_CC_RD)
141+
reg |= (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
142+
(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
143+
else
144+
reg |= (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
145+
(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT);
146+
147+
ret = rt1711h_write8(chip, TCPC_ROLE_CTRL, reg);
148+
if (ret < 0)
149+
return ret;
150+
usleep_range(500, 1000);
151+
152+
return 0;
153+
}
154+
155+
static irqreturn_t rt1711h_irq(int irq, void *dev_id)
156+
{
157+
int ret;
158+
u16 alert;
159+
u8 status;
160+
struct rt1711h_chip *chip = dev_id;
161+
162+
if (!chip->tcpci)
163+
return IRQ_HANDLED;
164+
165+
ret = rt1711h_read16(chip, TCPC_ALERT, &alert);
166+
if (ret < 0)
167+
goto out;
168+
169+
if (alert & TCPC_ALERT_CC_STATUS) {
170+
ret = rt1711h_read8(chip, TCPC_CC_STATUS, &status);
171+
if (ret < 0)
172+
goto out;
173+
/* Clear cc change event triggered by starting toggling */
174+
if (status & TCPC_CC_STATUS_TOGGLING)
175+
rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS);
176+
}
177+
178+
out:
179+
return tcpci_irq(chip->tcpci);
180+
}
181+
182+
static int rt1711h_init_alert(struct rt1711h_chip *chip,
183+
struct i2c_client *client)
184+
{
185+
int ret;
186+
187+
/* Disable chip interrupts before requesting irq */
188+
ret = rt1711h_write16(chip, TCPC_ALERT_MASK, 0);
189+
if (ret < 0)
190+
return ret;
191+
192+
ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
193+
rt1711h_irq,
194+
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
195+
dev_name(chip->dev), chip);
196+
if (ret < 0)
197+
return ret;
198+
enable_irq_wake(client->irq);
199+
return 0;
200+
}
201+
202+
static int rt1711h_sw_reset(struct rt1711h_chip *chip)
203+
{
204+
int ret;
205+
206+
ret = rt1711h_write8(chip, RT1711H_RTCTRL13, 0x01);
207+
if (ret < 0)
208+
return ret;
209+
210+
usleep_range(1000, 2000);
211+
return 0;
212+
}
213+
214+
static int rt1711h_check_revision(struct i2c_client *i2c)
215+
{
216+
int ret;
217+
218+
ret = i2c_smbus_read_word_data(i2c, TCPC_VENDOR_ID);
219+
if (ret < 0)
220+
return ret;
221+
if (ret != RT1711H_VID) {
222+
dev_err(&i2c->dev, "vid is not correct, 0x%04x\n", ret);
223+
return -ENODEV;
224+
}
225+
ret = i2c_smbus_read_word_data(i2c, TCPC_PRODUCT_ID);
226+
if (ret < 0)
227+
return ret;
228+
if (ret != RT1711H_PID) {
229+
dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret);
230+
return -ENODEV;
231+
}
232+
return 0;
233+
}
234+
235+
static int rt1711h_probe(struct i2c_client *client,
236+
const struct i2c_device_id *i2c_id)
237+
{
238+
int ret;
239+
struct rt1711h_chip *chip;
240+
241+
ret = rt1711h_check_revision(client);
242+
if (ret < 0) {
243+
dev_err(&client->dev, "check vid/pid fail\n");
244+
return ret;
245+
}
246+
247+
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
248+
if (!chip)
249+
return -ENOMEM;
250+
251+
chip->data.regmap = devm_regmap_init_i2c(client,
252+
&rt1711h_regmap_config);
253+
if (IS_ERR(chip->data.regmap))
254+
return PTR_ERR(chip->data.regmap);
255+
256+
chip->dev = &client->dev;
257+
i2c_set_clientdata(client, chip);
258+
259+
ret = rt1711h_sw_reset(chip);
260+
if (ret < 0)
261+
return ret;
262+
263+
ret = rt1711h_init_alert(chip, client);
264+
if (ret < 0)
265+
return ret;
266+
267+
chip->data.init = rt1711h_init;
268+
chip->data.set_vconn = rt1711h_set_vconn;
269+
chip->data.start_drp_toggling = rt1711h_start_drp_toggling;
270+
chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
271+
if (IS_ERR_OR_NULL(chip->tcpci))
272+
return PTR_ERR(chip->tcpci);
273+
274+
return 0;
275+
}
276+
277+
static int rt1711h_remove(struct i2c_client *client)
278+
{
279+
struct rt1711h_chip *chip = i2c_get_clientdata(client);
280+
281+
tcpci_unregister_port(chip->tcpci);
282+
return 0;
283+
}
284+
285+
static const struct i2c_device_id rt1711h_id[] = {
286+
{ "rt1711h", 0 },
287+
{ }
288+
};
289+
MODULE_DEVICE_TABLE(i2c, rt1711h_id);
290+
291+
#ifdef CONFIG_OF
292+
static const struct of_device_id rt1711h_of_match[] = {
293+
{ .compatible = "richtek,rt1711h", },
294+
{},
295+
};
296+
MODULE_DEVICE_TABLE(of, rt1711h_of_match);
297+
#endif
298+
299+
static struct i2c_driver rt1711h_i2c_driver = {
300+
.driver = {
301+
.name = "rt1711h",
302+
.of_match_table = of_match_ptr(rt1711h_of_match),
303+
},
304+
.probe = rt1711h_probe,
305+
.remove = rt1711h_remove,
306+
.id_table = rt1711h_id,
307+
};
308+
module_i2c_driver(rt1711h_i2c_driver);
309+
310+
MODULE_AUTHOR("ShuFan Lee <shufan_lee@richtek.com>");
311+
MODULE_DESCRIPTION("RT1711H USB Type-C Port Controller Interface Driver");
312+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)