xref: /openbmc/linux/drivers/usb/typec/mux/fsa4480.c (revision 1dc24632)
1*1dc24632SBjorn Andersson // SPDX-License-Identifier: GPL-2.0
2*1dc24632SBjorn Andersson /*
3*1dc24632SBjorn Andersson  * Copyright (C) 2021-2022 Linaro Ltd.
4*1dc24632SBjorn Andersson  * Copyright (C) 2018-2020 The Linux Foundation
5*1dc24632SBjorn Andersson  */
6*1dc24632SBjorn Andersson 
7*1dc24632SBjorn Andersson #include <linux/bits.h>
8*1dc24632SBjorn Andersson #include <linux/i2c.h>
9*1dc24632SBjorn Andersson #include <linux/kernel.h>
10*1dc24632SBjorn Andersson #include <linux/module.h>
11*1dc24632SBjorn Andersson #include <linux/mutex.h>
12*1dc24632SBjorn Andersson #include <linux/regmap.h>
13*1dc24632SBjorn Andersson #include <linux/usb/typec_dp.h>
14*1dc24632SBjorn Andersson #include <linux/usb/typec_mux.h>
15*1dc24632SBjorn Andersson 
16*1dc24632SBjorn Andersson #define FSA4480_SWITCH_ENABLE	0x04
17*1dc24632SBjorn Andersson #define FSA4480_SWITCH_SELECT	0x05
18*1dc24632SBjorn Andersson #define FSA4480_SWITCH_STATUS1	0x07
19*1dc24632SBjorn Andersson #define FSA4480_SLOW_L		0x08
20*1dc24632SBjorn Andersson #define FSA4480_SLOW_R		0x09
21*1dc24632SBjorn Andersson #define FSA4480_SLOW_MIC	0x0a
22*1dc24632SBjorn Andersson #define FSA4480_SLOW_SENSE	0x0b
23*1dc24632SBjorn Andersson #define FSA4480_SLOW_GND	0x0c
24*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_R	0x0d
25*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_MIC	0x0e
26*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_SENSE	0x0f
27*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_AGND	0x10
28*1dc24632SBjorn Andersson #define FSA4480_RESET		0x1e
29*1dc24632SBjorn Andersson #define FSA4480_MAX_REGISTER	0x1f
30*1dc24632SBjorn Andersson 
31*1dc24632SBjorn Andersson #define FSA4480_ENABLE_DEVICE	BIT(7)
32*1dc24632SBjorn Andersson #define FSA4480_ENABLE_SBU	GENMASK(6, 5)
33*1dc24632SBjorn Andersson #define FSA4480_ENABLE_USB	GENMASK(4, 3)
34*1dc24632SBjorn Andersson 
35*1dc24632SBjorn Andersson #define FSA4480_SEL_SBU_REVERSE	GENMASK(6, 5)
36*1dc24632SBjorn Andersson #define FSA4480_SEL_USB		GENMASK(4, 3)
37*1dc24632SBjorn Andersson 
38*1dc24632SBjorn Andersson struct fsa4480 {
39*1dc24632SBjorn Andersson 	struct i2c_client *client;
40*1dc24632SBjorn Andersson 
41*1dc24632SBjorn Andersson 	/* used to serialize concurrent change requests */
42*1dc24632SBjorn Andersson 	struct mutex lock;
43*1dc24632SBjorn Andersson 
44*1dc24632SBjorn Andersson 	struct typec_switch_dev *sw;
45*1dc24632SBjorn Andersson 	struct typec_mux_dev *mux;
46*1dc24632SBjorn Andersson 
47*1dc24632SBjorn Andersson 	struct regmap *regmap;
48*1dc24632SBjorn Andersson 
49*1dc24632SBjorn Andersson 	u8 cur_enable;
50*1dc24632SBjorn Andersson 	u8 cur_select;
51*1dc24632SBjorn Andersson };
52*1dc24632SBjorn Andersson 
53*1dc24632SBjorn Andersson static const struct regmap_config fsa4480_regmap_config = {
54*1dc24632SBjorn Andersson 	.reg_bits = 8,
55*1dc24632SBjorn Andersson 	.val_bits = 8,
56*1dc24632SBjorn Andersson 	.max_register = FSA4480_MAX_REGISTER,
57*1dc24632SBjorn Andersson 	/* Accesses only done under fsa4480->lock */
58*1dc24632SBjorn Andersson 	.disable_locking = true,
59*1dc24632SBjorn Andersson };
60*1dc24632SBjorn Andersson 
61*1dc24632SBjorn Andersson static int fsa4480_switch_set(struct typec_switch_dev *sw,
62*1dc24632SBjorn Andersson 			      enum typec_orientation orientation)
63*1dc24632SBjorn Andersson {
64*1dc24632SBjorn Andersson 	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
65*1dc24632SBjorn Andersson 	u8 new_sel;
66*1dc24632SBjorn Andersson 
67*1dc24632SBjorn Andersson 	mutex_lock(&fsa->lock);
68*1dc24632SBjorn Andersson 	new_sel = FSA4480_SEL_USB;
69*1dc24632SBjorn Andersson 	if (orientation == TYPEC_ORIENTATION_REVERSE)
70*1dc24632SBjorn Andersson 		new_sel |= FSA4480_SEL_SBU_REVERSE;
71*1dc24632SBjorn Andersson 
72*1dc24632SBjorn Andersson 	if (new_sel == fsa->cur_select)
73*1dc24632SBjorn Andersson 		goto out_unlock;
74*1dc24632SBjorn Andersson 
75*1dc24632SBjorn Andersson 	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
76*1dc24632SBjorn Andersson 		/* Disable SBU output while re-configuring the switch */
77*1dc24632SBjorn Andersson 		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE,
78*1dc24632SBjorn Andersson 			     fsa->cur_enable & ~FSA4480_ENABLE_SBU);
79*1dc24632SBjorn Andersson 
80*1dc24632SBjorn Andersson 		/* 35us to allow the SBU switch to turn off */
81*1dc24632SBjorn Andersson 		usleep_range(35, 1000);
82*1dc24632SBjorn Andersson 	}
83*1dc24632SBjorn Andersson 
84*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, new_sel);
85*1dc24632SBjorn Andersson 	fsa->cur_select = new_sel;
86*1dc24632SBjorn Andersson 
87*1dc24632SBjorn Andersson 	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
88*1dc24632SBjorn Andersson 		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
89*1dc24632SBjorn Andersson 
90*1dc24632SBjorn Andersson 		/* 15us to allow the SBU switch to turn on again */
91*1dc24632SBjorn Andersson 		usleep_range(15, 1000);
92*1dc24632SBjorn Andersson 	}
93*1dc24632SBjorn Andersson 
94*1dc24632SBjorn Andersson out_unlock:
95*1dc24632SBjorn Andersson 	mutex_unlock(&fsa->lock);
96*1dc24632SBjorn Andersson 
97*1dc24632SBjorn Andersson 	return 0;
98*1dc24632SBjorn Andersson }
99*1dc24632SBjorn Andersson 
100*1dc24632SBjorn Andersson static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
101*1dc24632SBjorn Andersson {
102*1dc24632SBjorn Andersson 	struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
103*1dc24632SBjorn Andersson 	u8 new_enable;
104*1dc24632SBjorn Andersson 
105*1dc24632SBjorn Andersson 	mutex_lock(&fsa->lock);
106*1dc24632SBjorn Andersson 
107*1dc24632SBjorn Andersson 	new_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
108*1dc24632SBjorn Andersson 	if (state->mode >= TYPEC_DP_STATE_A)
109*1dc24632SBjorn Andersson 		new_enable |= FSA4480_ENABLE_SBU;
110*1dc24632SBjorn Andersson 
111*1dc24632SBjorn Andersson 	if (new_enable == fsa->cur_enable)
112*1dc24632SBjorn Andersson 		goto out_unlock;
113*1dc24632SBjorn Andersson 
114*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, new_enable);
115*1dc24632SBjorn Andersson 	fsa->cur_enable = new_enable;
116*1dc24632SBjorn Andersson 
117*1dc24632SBjorn Andersson 	if (new_enable & FSA4480_ENABLE_SBU) {
118*1dc24632SBjorn Andersson 		/* 15us to allow the SBU switch to turn off */
119*1dc24632SBjorn Andersson 		usleep_range(15, 1000);
120*1dc24632SBjorn Andersson 	}
121*1dc24632SBjorn Andersson 
122*1dc24632SBjorn Andersson out_unlock:
123*1dc24632SBjorn Andersson 	mutex_unlock(&fsa->lock);
124*1dc24632SBjorn Andersson 
125*1dc24632SBjorn Andersson 	return 0;
126*1dc24632SBjorn Andersson }
127*1dc24632SBjorn Andersson 
128*1dc24632SBjorn Andersson static int fsa4480_probe(struct i2c_client *client)
129*1dc24632SBjorn Andersson {
130*1dc24632SBjorn Andersson 	struct device *dev = &client->dev;
131*1dc24632SBjorn Andersson 	struct typec_switch_desc sw_desc = { };
132*1dc24632SBjorn Andersson 	struct typec_mux_desc mux_desc = { };
133*1dc24632SBjorn Andersson 	struct fsa4480 *fsa;
134*1dc24632SBjorn Andersson 
135*1dc24632SBjorn Andersson 	fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL);
136*1dc24632SBjorn Andersson 	if (!fsa)
137*1dc24632SBjorn Andersson 		return -ENOMEM;
138*1dc24632SBjorn Andersson 
139*1dc24632SBjorn Andersson 	fsa->client = client;
140*1dc24632SBjorn Andersson 	mutex_init(&fsa->lock);
141*1dc24632SBjorn Andersson 
142*1dc24632SBjorn Andersson 	fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
143*1dc24632SBjorn Andersson 	if (IS_ERR(fsa->regmap))
144*1dc24632SBjorn Andersson 		return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
145*1dc24632SBjorn Andersson 
146*1dc24632SBjorn Andersson 	fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
147*1dc24632SBjorn Andersson 	fsa->cur_select = FSA4480_SEL_USB;
148*1dc24632SBjorn Andersson 
149*1dc24632SBjorn Andersson 	/* set default settings */
150*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00);
151*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SLOW_R, 0x00);
152*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SLOW_MIC, 0x00);
153*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SLOW_SENSE, 0x00);
154*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SLOW_GND, 0x00);
155*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_DELAY_L_R, 0x00);
156*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00);
157*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00);
158*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09);
159*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, fsa->cur_select);
160*1dc24632SBjorn Andersson 	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
161*1dc24632SBjorn Andersson 
162*1dc24632SBjorn Andersson 	sw_desc.drvdata = fsa;
163*1dc24632SBjorn Andersson 	sw_desc.fwnode = dev_fwnode(dev);
164*1dc24632SBjorn Andersson 	sw_desc.set = fsa4480_switch_set;
165*1dc24632SBjorn Andersson 
166*1dc24632SBjorn Andersson 	fsa->sw = typec_switch_register(dev, &sw_desc);
167*1dc24632SBjorn Andersson 	if (IS_ERR(fsa->sw))
168*1dc24632SBjorn Andersson 		return dev_err_probe(dev, PTR_ERR(fsa->sw), "failed to register typec switch\n");
169*1dc24632SBjorn Andersson 
170*1dc24632SBjorn Andersson 	mux_desc.drvdata = fsa;
171*1dc24632SBjorn Andersson 	mux_desc.fwnode = dev_fwnode(dev);
172*1dc24632SBjorn Andersson 	mux_desc.set = fsa4480_mux_set;
173*1dc24632SBjorn Andersson 
174*1dc24632SBjorn Andersson 	fsa->mux = typec_mux_register(dev, &mux_desc);
175*1dc24632SBjorn Andersson 	if (IS_ERR(fsa->mux)) {
176*1dc24632SBjorn Andersson 		typec_switch_unregister(fsa->sw);
177*1dc24632SBjorn Andersson 		return dev_err_probe(dev, PTR_ERR(fsa->mux), "failed to register typec mux\n");
178*1dc24632SBjorn Andersson 	}
179*1dc24632SBjorn Andersson 
180*1dc24632SBjorn Andersson 	i2c_set_clientdata(client, fsa);
181*1dc24632SBjorn Andersson 	return 0;
182*1dc24632SBjorn Andersson }
183*1dc24632SBjorn Andersson 
184*1dc24632SBjorn Andersson static int fsa4480_remove(struct i2c_client *client)
185*1dc24632SBjorn Andersson {
186*1dc24632SBjorn Andersson 	struct fsa4480 *fsa = i2c_get_clientdata(client);
187*1dc24632SBjorn Andersson 
188*1dc24632SBjorn Andersson 	typec_mux_unregister(fsa->mux);
189*1dc24632SBjorn Andersson 	typec_switch_unregister(fsa->sw);
190*1dc24632SBjorn Andersson 
191*1dc24632SBjorn Andersson 	return 0;
192*1dc24632SBjorn Andersson }
193*1dc24632SBjorn Andersson 
194*1dc24632SBjorn Andersson static const struct i2c_device_id fsa4480_table[] = {
195*1dc24632SBjorn Andersson 	{ "fsa4480" },
196*1dc24632SBjorn Andersson 	{ }
197*1dc24632SBjorn Andersson };
198*1dc24632SBjorn Andersson MODULE_DEVICE_TABLE(i2c, fsa4480_table);
199*1dc24632SBjorn Andersson 
200*1dc24632SBjorn Andersson static const struct of_device_id fsa4480_of_table[] = {
201*1dc24632SBjorn Andersson 	{ .compatible = "fcs,fsa4480" },
202*1dc24632SBjorn Andersson 	{ }
203*1dc24632SBjorn Andersson };
204*1dc24632SBjorn Andersson MODULE_DEVICE_TABLE(of, fsa4480_of_table);
205*1dc24632SBjorn Andersson 
206*1dc24632SBjorn Andersson static struct i2c_driver fsa4480_driver = {
207*1dc24632SBjorn Andersson 	.driver = {
208*1dc24632SBjorn Andersson 		.name = "fsa4480",
209*1dc24632SBjorn Andersson 		.of_match_table = fsa4480_of_table,
210*1dc24632SBjorn Andersson 	},
211*1dc24632SBjorn Andersson 	.probe_new	= fsa4480_probe,
212*1dc24632SBjorn Andersson 	.remove		= fsa4480_remove,
213*1dc24632SBjorn Andersson 	.id_table	= fsa4480_table,
214*1dc24632SBjorn Andersson };
215*1dc24632SBjorn Andersson module_i2c_driver(fsa4480_driver);
216*1dc24632SBjorn Andersson 
217*1dc24632SBjorn Andersson MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver");
218*1dc24632SBjorn Andersson MODULE_LICENSE("GPL v2");
219