File Index
Files and directories
Sign in
FILE

tcpci_rt1711h.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/tcpm/tcpci_rt1711h.c C
  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/bitfield.h>
  9#include <linux/bits.h>
 10#include <linux/kernel.h>
 11#include <linux/mod_devicetable.h>
 12#include <linux/module.h>
 13#include <linux/i2c.h>
 14#include <linux/interrupt.h>
 15#include <linux/gpio/consumer.h>
 16#include <linux/usb/tcpci.h>
 17#include <linux/usb/tcpm.h>
 18#include <linux/regmap.h>
 19#include <linux/regulator/consumer.h>
 20
 21#define RT1711H_VID		0x29CF
 22#define RT1711H_PID		0x1711
 23#define RT1711H_DID		0x2171
 24#define RT1715_DID		0x2173
 25
 26#define RT1711H_PHYCTRL1	0x80
 27#define RT1711H_PHYCTRL2	0x81
 28
 29#define RT1711H_RTCTRL4		0x93
 30/* rx threshold of rd/rp: 1b0 for level 0.4V/0.7V, 1b1 for 0.35V/0.75V */
 31#define RT1711H_BMCIO_RXDZSEL	BIT(0)
 32
 33#define RT1711H_RTCTRL8		0x9B
 34/* Autoidle timeout = (tout * 2 + 1) * 6.4ms */
 35#define RT1711H_RTCTRL8_SET(ck300, ship_off, auto_idle, tout) \
 36			    (((ck300) << 7) | ((ship_off) << 5) | \
 37			    ((auto_idle) << 3) | ((tout) & 0x07))
 38#define RT1711H_AUTOIDLEEN	BIT(3)
 39#define RT1711H_ENEXTMSG	BIT(4)
 40
 41#define RT1711H_RTCTRL11	0x9E
 42
 43/* I2C timeout = (tout + 1) * 12.5ms */
 44#define RT1711H_RTCTRL11_SET(en, tout) \
 45			     (((en) << 7) | ((tout) & 0x0F))
 46
 47#define RT1711H_RTCTRL13	0xA0
 48#define RT1711H_RTCTRL14	0xA1
 49#define RT1711H_RTCTRL15	0xA2
 50#define RT1711H_RTCTRL16	0xA3
 51
 52#define RT1711H_RTCTRL18	0xAF
 53/* 1b0 as fixed rx threshold of rd/rp 0.55V, 1b1 depends on RTCRTL4[0] */
 54#define BMCIO_RXDZEN	BIT(0)
 55
 56struct rt1711h_chip_info {
 57	u32 rxdz_sel;
 58	u16 did;
 59	bool enable_pd30_extended_message;
 60};
 61
 62struct rt1711h_chip {
 63	struct tcpci_data data;
 64	struct tcpci *tcpci;
 65	struct device *dev;
 66	struct regulator *vbus;
 67	const struct rt1711h_chip_info *info;
 68	bool src_en;
 69};
 70
 71static int rt1711h_read16(struct rt1711h_chip *chip, unsigned int reg, u16 *val)
 72{
 73	return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u16));
 74}
 75
 76static int rt1711h_write16(struct rt1711h_chip *chip, unsigned int reg, u16 val)
 77{
 78	return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u16));
 79}
 80
 81static int rt1711h_read8(struct rt1711h_chip *chip, unsigned int reg, u8 *val)
 82{
 83	return regmap_raw_read(chip->data.regmap, reg, val, sizeof(u8));
 84}
 85
 86static int rt1711h_write8(struct rt1711h_chip *chip, unsigned int reg, u8 val)
 87{
 88	return regmap_raw_write(chip->data.regmap, reg, &val, sizeof(u8));
 89}
 90
 91static const struct regmap_config rt1711h_regmap_config = {
 92	.reg_bits = 8,
 93	.val_bits = 8,
 94
 95	.max_register = 0xFF, /* 0x80 .. 0xFF are vendor defined */
 96};
 97
 98static struct rt1711h_chip *tdata_to_rt1711h(struct tcpci_data *tdata)
 99{
100	return container_of(tdata, struct rt1711h_chip, data);
101}
102
103static int rt1711h_init(struct tcpci *tcpci, struct tcpci_data *tdata)
104{
105	struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
106	struct regmap *regmap = chip->data.regmap;
107	int ret;
108
109	/* CK 300K from 320K, shipping off, auto_idle enable, tout = 32ms */
110	ret = rt1711h_write8(chip, RT1711H_RTCTRL8,
111			     RT1711H_RTCTRL8_SET(0, 1, 1, 2));
112	if (ret < 0)
113		return ret;
114
115	/* Enable PD30 extended message for RT1715 */
116	if (chip->info->enable_pd30_extended_message) {
117		ret = regmap_update_bits(regmap, RT1711H_RTCTRL8,
118					 RT1711H_ENEXTMSG, RT1711H_ENEXTMSG);
119		if (ret < 0)
120			return ret;
121	}
122
123	/* I2C reset : (val + 1) * 12.5ms */
124	ret = rt1711h_write8(chip, RT1711H_RTCTRL11,
125			     RT1711H_RTCTRL11_SET(1, 0x0F));
126	if (ret < 0)
127		return ret;
128
129	/* tTCPCfilter : (26.7 * val) us */
130	ret = rt1711h_write8(chip, RT1711H_RTCTRL14, 0x0F);
131	if (ret < 0)
132		return ret;
133
134	/*  tDRP : (51.2 + 6.4 * val) ms */
135	ret = rt1711h_write8(chip, RT1711H_RTCTRL15, 0x04);
136	if (ret < 0)
137		return ret;
138
139	/* dcSRC.DRP : 33% */
140	ret = rt1711h_write16(chip, RT1711H_RTCTRL16, 330);
141	if (ret < 0)
142		return ret;
143
144	/* Enable phy discard retry, retry count 7, rx filter deglitch 100 us */
145	ret = rt1711h_write8(chip, RT1711H_PHYCTRL1, 0xF1);
146	if (ret < 0)
147		return ret;
148
149	/* Decrease wait time of BMC-encoded 1 bit from 2.67us to 2.55us */
150	/* wait time : (val * .4167) us */
151	return rt1711h_write8(chip, RT1711H_PHYCTRL2, 62);
152}
153
154static int rt1711h_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata,
155			    bool src, bool snk)
156{
157	struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
158	int ret;
159
160	if (chip->src_en == src)
161		return 0;
162
163	if (src)
164		ret = regulator_enable(chip->vbus);
165	else
166		ret = regulator_disable(chip->vbus);
167
168	if (!ret)
169		chip->src_en = src;
170	return ret;
171}
172
173static int rt1711h_set_vconn(struct tcpci *tcpci, struct tcpci_data *tdata,
174			     bool enable)
175{
176	struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
177
178	return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL8,
179				  RT1711H_AUTOIDLEEN, enable ? 0 : RT1711H_AUTOIDLEEN);
180}
181
182/*
183 * Selects the CC PHY noise filter voltage level according to the remote current
184 * CC voltage level.
185 *
186 * @status: The port's current cc status read from IC
187 * Return 0 if writes succeed; failure code otherwise
188 */
189static inline int rt1711h_init_cc_params(struct rt1711h_chip *chip, u8 status)
190{
191	int ret, cc1, cc2;
192	u8 role = 0;
193	u32 rxdz_en, rxdz_sel;
194
195	ret = rt1711h_read8(chip, TCPC_ROLE_CTRL, &role);
196	if (ret < 0)
197		return ret;
198
199	cc1 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC1, status),
200				status & TCPC_CC_STATUS_TERM ||
201				tcpc_presenting_rd(role, CC1));
202	cc2 = tcpci_to_typec_cc(FIELD_GET(TCPC_CC_STATUS_CC2, status),
203				status & TCPC_CC_STATUS_TERM ||
204				tcpc_presenting_rd(role, CC2));
205
206	if ((cc1 >= TYPEC_CC_RP_1_5 && cc2 < TYPEC_CC_RP_DEF) ||
207	    (cc2 >= TYPEC_CC_RP_1_5 && cc1 < TYPEC_CC_RP_DEF)) {
208		rxdz_en = BMCIO_RXDZEN;
209		rxdz_sel = chip->info->rxdz_sel;
210	} else {
211		rxdz_en = 0;
212		rxdz_sel = RT1711H_BMCIO_RXDZSEL;
213	}
214
215	ret = regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL18,
216				 BMCIO_RXDZEN, rxdz_en);
217	if (ret < 0)
218		return ret;
219
220	return regmap_update_bits(chip->data.regmap, RT1711H_RTCTRL4,
221				  RT1711H_BMCIO_RXDZSEL, rxdz_sel);
222}
223
224static int rt1711h_start_drp_toggling(struct tcpci *tcpci,
225				      struct tcpci_data *tdata,
226				      enum typec_cc_status cc)
227{
228	struct rt1711h_chip *chip = tdata_to_rt1711h(tdata);
229	int ret;
230	unsigned int reg = 0;
231
232	switch (cc) {
233	default:
234	case TYPEC_CC_RP_DEF:
235		reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL,
236				  TCPC_ROLE_CTRL_RP_VAL_DEF);
237		break;
238	case TYPEC_CC_RP_1_5:
239		reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL,
240				  TCPC_ROLE_CTRL_RP_VAL_1_5);
241		break;
242	case TYPEC_CC_RP_3_0:
243		reg |= FIELD_PREP(TCPC_ROLE_CTRL_RP_VAL,
244				  TCPC_ROLE_CTRL_RP_VAL_3_0);
245		break;
246	}
247
248	if (cc == TYPEC_CC_RD)
249		reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RD)
250			| FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RD));
251	else
252		reg |= (FIELD_PREP(TCPC_ROLE_CTRL_CC1, TCPC_ROLE_CTRL_CC_RP)
253			| FIELD_PREP(TCPC_ROLE_CTRL_CC2, TCPC_ROLE_CTRL_CC_RP));
254
255	ret = rt1711h_write8(chip, TCPC_ROLE_CTRL, reg);
256	if (ret < 0)
257		return ret;
258	usleep_range(500, 1000);
259
260	return 0;
261}
262
263static irqreturn_t rt1711h_irq(int irq, void *dev_id)
264{
265	int ret;
266	u16 alert;
267	u8 status;
268	struct rt1711h_chip *chip = dev_id;
269
270	if (!chip->tcpci)
271		return IRQ_HANDLED;
272
273	ret = rt1711h_read16(chip, TCPC_ALERT, &alert);
274	if (ret < 0)
275		goto out;
276
277	if (alert & TCPC_ALERT_CC_STATUS) {
278		ret = rt1711h_read8(chip, TCPC_CC_STATUS, &status);
279		if (ret < 0)
280			goto out;
281		/* Clear cc change event triggered by starting toggling */
282		if (status & TCPC_CC_STATUS_TOGGLING)
283			rt1711h_write8(chip, TCPC_ALERT, TCPC_ALERT_CC_STATUS);
284		else
285			rt1711h_init_cc_params(chip, status);
286	}
287
288out:
289	return tcpci_irq(chip->tcpci);
290}
291
292static int rt1711h_sw_reset(struct rt1711h_chip *chip)
293{
294	int ret;
295
296	ret = rt1711h_write8(chip, RT1711H_RTCTRL13, 0x01);
297	if (ret < 0)
298		return ret;
299
300	usleep_range(1000, 2000);
301	return 0;
302}
303
304static int rt1711h_check_revision(struct i2c_client *i2c, struct rt1711h_chip *chip)
305{
306	int ret;
307
308	ret = i2c_smbus_read_word_data(i2c, TCPC_VENDOR_ID);
309	if (ret < 0)
310		return ret;
311	if (ret != RT1711H_VID) {
312		dev_err(&i2c->dev, "vid is not correct, 0x%04x\n", ret);
313		return -ENODEV;
314	}
315	ret = i2c_smbus_read_word_data(i2c, TCPC_PRODUCT_ID);
316	if (ret < 0)
317		return ret;
318	if (ret != RT1711H_PID) {
319		dev_err(&i2c->dev, "pid is not correct, 0x%04x\n", ret);
320		return -ENODEV;
321	}
322	ret = i2c_smbus_read_word_data(i2c, TCPC_BCD_DEV);
323	if (ret < 0)
324		return ret;
325	if (ret != chip->info->did) {
326		dev_err(&i2c->dev, "did is not correct, 0x%04x\n", ret);
327		return -ENODEV;
328	}
329	dev_dbg(&i2c->dev, "did is 0x%04x\n", ret);
330	return ret;
331}
332
333static int rt1711h_probe(struct i2c_client *client)
334{
335	int ret;
336	struct rt1711h_chip *chip;
337	const u16 alert_mask = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_DISCARDED |
338			       TCPC_ALERT_TX_FAILED | TCPC_ALERT_RX_HARD_RST |
339			       TCPC_ALERT_RX_STATUS | TCPC_ALERT_POWER_STATUS |
340			       TCPC_ALERT_CC_STATUS | TCPC_ALERT_RX_BUF_OVF |
341			       TCPC_ALERT_FAULT;
342
343	chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
344	if (!chip)
345		return -ENOMEM;
346
347	chip->info = i2c_get_match_data(client);
348
349	ret = rt1711h_check_revision(client, chip);
350	if (ret < 0) {
351		dev_err(&client->dev, "check vid/pid fail\n");
352		return ret;
353	}
354
355	chip->data.regmap = devm_regmap_init_i2c(client,
356						 &rt1711h_regmap_config);
357	if (IS_ERR(chip->data.regmap))
358		return PTR_ERR(chip->data.regmap);
359
360	chip->dev = &client->dev;
361	i2c_set_clientdata(client, chip);
362
363	ret = rt1711h_sw_reset(chip);
364	if (ret < 0)
365		return ret;
366
367	/* Disable chip interrupts before requesting irq */
368	ret = rt1711h_write16(chip, TCPC_ALERT_MASK, 0);
369	if (ret < 0)
370		return ret;
371
372	chip->vbus = devm_regulator_get(&client->dev, "vbus");
373	if (IS_ERR(chip->vbus))
374		return PTR_ERR(chip->vbus);
375
376	chip->data.init = rt1711h_init;
377	chip->data.set_vbus = rt1711h_set_vbus;
378	chip->data.set_vconn = rt1711h_set_vconn;
379	chip->data.start_drp_toggling = rt1711h_start_drp_toggling;
380	chip->tcpci = tcpci_register_port(chip->dev, &chip->data);
381	if (IS_ERR_OR_NULL(chip->tcpci))
382		return PTR_ERR(chip->tcpci);
383
384	ret = devm_request_threaded_irq(chip->dev, client->irq, NULL,
385					rt1711h_irq,
386					IRQF_ONESHOT | IRQF_TRIGGER_LOW,
387					dev_name(chip->dev), chip);
388	if (ret < 0)
389		return ret;
390
391	/* Enable alert interrupts */
392	ret = rt1711h_write16(chip, TCPC_ALERT_MASK, alert_mask);
393	if (ret < 0)
394		return ret;
395
396	enable_irq_wake(client->irq);
397
398	return 0;
399}
400
401static void rt1711h_remove(struct i2c_client *client)
402{
403	struct rt1711h_chip *chip = i2c_get_clientdata(client);
404
405	tcpci_unregister_port(chip->tcpci);
406}
407
408static const struct rt1711h_chip_info rt1711h = {
409	.did = RT1711H_DID,
410};
411
412static const struct rt1711h_chip_info rt1715 = {
413	.rxdz_sel = RT1711H_BMCIO_RXDZSEL,
414	.did = RT1715_DID,
415	.enable_pd30_extended_message = true,
416};
417
418static const struct i2c_device_id rt1711h_id[] = {
419	{ "rt1711h", (kernel_ulong_t)&rt1711h },
420	{ "rt1715", (kernel_ulong_t)&rt1715 },
421	{}
422};
423MODULE_DEVICE_TABLE(i2c, rt1711h_id);
424
425static const struct of_device_id rt1711h_of_match[] = {
426	{ .compatible = "richtek,rt1711h", .data = &rt1711h },
427	{ .compatible = "richtek,rt1715", .data = &rt1715 },
428	{}
429};
430MODULE_DEVICE_TABLE(of, rt1711h_of_match);
431
432static struct i2c_driver rt1711h_i2c_driver = {
433	.driver = {
434		.name = "rt1711h",
435		.of_match_table = rt1711h_of_match,
436	},
437	.probe = rt1711h_probe,
438	.remove = rt1711h_remove,
439	.id_table = rt1711h_id,
440};
441module_i2c_driver(rt1711h_i2c_driver);
442
443MODULE_AUTHOR("ShuFan Lee <shufan_lee@richtek.com>");
444MODULE_DESCRIPTION("RT1711H USB Type-C Port Controller Interface Driver");
445MODULE_LICENSE("GPL");
~/ Read-only file preview.