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