File Index
Files and directories
Sign in
FILE

fsa4480.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/mux/fsa4480.c C
  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#include <linux/regulator/consumer.h>
 16
 17#define FSA4480_DEVICE_ID	0x00
 18 #define FSA4480_DEVICE_ID_VENDOR_ID	GENMASK(7, 6)
 19 #define FSA4480_DEVICE_ID_VERSION_ID	GENMASK(5, 3)
 20 #define FSA4480_DEVICE_ID_REV_ID	GENMASK(2, 0)
 21#define FSA4480_SWITCH_ENABLE	0x04
 22#define FSA4480_SWITCH_SELECT	0x05
 23#define FSA4480_SWITCH_STATUS1	0x07
 24#define FSA4480_SLOW_L		0x08
 25#define FSA4480_SLOW_R		0x09
 26#define FSA4480_SLOW_MIC	0x0a
 27#define FSA4480_SLOW_SENSE	0x0b
 28#define FSA4480_SLOW_GND	0x0c
 29#define FSA4480_DELAY_L_R	0x0d
 30#define FSA4480_DELAY_L_MIC	0x0e
 31#define FSA4480_DELAY_L_SENSE	0x0f
 32#define FSA4480_DELAY_L_AGND	0x10
 33#define FSA4480_FUNCTION_ENABLE	0x12
 34#define FSA4480_RESET		0x1e
 35#define FSA4480_MAX_REGISTER	0x1f
 36
 37#define FSA4480_ENABLE_DEVICE	BIT(7)
 38#define FSA4480_ENABLE_SBU	GENMASK(6, 5)
 39#define FSA4480_ENABLE_USB	GENMASK(4, 3)
 40#define FSA4480_ENABLE_SENSE	BIT(2)
 41#define FSA4480_ENABLE_MIC	BIT(1)
 42#define FSA4480_ENABLE_AGND	BIT(0)
 43
 44#define FSA4480_SEL_SBU_REVERSE	GENMASK(6, 5)
 45#define FSA4480_SEL_USB		GENMASK(4, 3)
 46#define FSA4480_SEL_SENSE	BIT(2)
 47#define FSA4480_SEL_MIC		BIT(1)
 48#define FSA4480_SEL_AGND	BIT(0)
 49
 50#define FSA4480_ENABLE_AUTO_JACK_DETECT	BIT(0)
 51
 52struct fsa4480 {
 53	struct i2c_client *client;
 54
 55	/* used to serialize concurrent change requests */
 56	struct mutex lock;
 57
 58	struct typec_switch_dev *sw;
 59	struct typec_mux_dev *mux;
 60
 61	struct regmap *regmap;
 62
 63	enum typec_orientation orientation;
 64	unsigned long mode;
 65	unsigned int svid;
 66
 67	u8 cur_enable;
 68	bool swap_sbu_lanes;
 69};
 70
 71static const struct regmap_config fsa4480_regmap_config = {
 72	.reg_bits = 8,
 73	.val_bits = 8,
 74	.max_register = FSA4480_MAX_REGISTER,
 75	/* Accesses only done under fsa4480->lock */
 76	.disable_locking = true,
 77};
 78
 79static int fsa4480_set(struct fsa4480 *fsa)
 80{
 81	bool reverse = (fsa->orientation == TYPEC_ORIENTATION_REVERSE);
 82	u8 enable = FSA4480_ENABLE_DEVICE;
 83	u8 sel = 0;
 84
 85	if (fsa->swap_sbu_lanes)
 86		reverse = !reverse;
 87
 88	/* USB Mode */
 89	if (fsa->mode < TYPEC_STATE_MODAL ||
 90	    (!fsa->svid && (fsa->mode == TYPEC_MODE_USB2 ||
 91			    fsa->mode == TYPEC_MODE_USB3))) {
 92		enable |= FSA4480_ENABLE_USB;
 93		sel = FSA4480_SEL_USB;
 94	} else if (fsa->svid) {
 95		switch (fsa->mode) {
 96		/* DP Only */
 97		case TYPEC_DP_STATE_C:
 98		case TYPEC_DP_STATE_E:
 99			enable |= FSA4480_ENABLE_SBU;
100			if (reverse)
101				sel = FSA4480_SEL_SBU_REVERSE;
102			break;
103
104		/* DP + USB */
105		case TYPEC_DP_STATE_D:
106		case TYPEC_DP_STATE_F:
107			enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_SBU;
108			sel = FSA4480_SEL_USB;
109			if (reverse)
110				sel |= FSA4480_SEL_SBU_REVERSE;
111			break;
112
113		default:
114			return -EOPNOTSUPP;
115		}
116	} else if (fsa->mode == TYPEC_MODE_AUDIO) {
117		/* Audio Accessory Mode, setup to auto Jack Detection */
118		enable |= FSA4480_ENABLE_USB | FSA4480_ENABLE_AGND;
119	} else
120		return -EOPNOTSUPP;
121
122	if (fsa->cur_enable & FSA4480_ENABLE_SBU) {
123		/* Disable SBU output while re-configuring the switch */
124		regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE,
125			     fsa->cur_enable & ~FSA4480_ENABLE_SBU);
126
127		/* 35us to allow the SBU switch to turn off */
128		usleep_range(35, 1000);
129	}
130
131	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, sel);
132	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, enable);
133
134	/* Start AUDIO JACK DETECTION to setup MIC, AGND & Sense muxes */
135	if (enable & FSA4480_ENABLE_AGND)
136		regmap_write(fsa->regmap, FSA4480_FUNCTION_ENABLE,
137			     FSA4480_ENABLE_AUTO_JACK_DETECT);
138
139	if (enable & FSA4480_ENABLE_SBU) {
140		/* 15us to allow the SBU switch to turn on again */
141		usleep_range(15, 1000);
142	}
143
144	fsa->cur_enable = enable;
145
146	return 0;
147}
148
149static int fsa4480_switch_set(struct typec_switch_dev *sw,
150			      enum typec_orientation orientation)
151{
152	struct fsa4480 *fsa = typec_switch_get_drvdata(sw);
153	int ret = 0;
154
155	mutex_lock(&fsa->lock);
156
157	if (fsa->orientation != orientation) {
158		fsa->orientation = orientation;
159
160		ret = fsa4480_set(fsa);
161	}
162
163	mutex_unlock(&fsa->lock);
164
165	return ret;
166}
167
168static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
169{
170	struct fsa4480 *fsa = typec_mux_get_drvdata(mux);
171	int ret = 0;
172
173	mutex_lock(&fsa->lock);
174
175	if (fsa->mode != state->mode) {
176		fsa->mode = state->mode;
177
178		if (state->alt)
179			fsa->svid = state->alt->svid;
180		else
181			fsa->svid = 0; // No SVID
182
183		ret = fsa4480_set(fsa);
184	}
185
186	mutex_unlock(&fsa->lock);
187
188	return ret;
189}
190
191enum {
192	NORMAL_LANE_MAPPING,
193	INVERT_LANE_MAPPING,
194};
195
196#define DATA_LANES_COUNT	2
197
198static const int supported_data_lane_mapping[][DATA_LANES_COUNT] = {
199	[NORMAL_LANE_MAPPING] = { 0, 1 },
200	[INVERT_LANE_MAPPING] = { 1, 0 },
201};
202
203static int fsa4480_parse_data_lanes_mapping(struct fsa4480 *fsa)
204{
205	struct fwnode_handle *ep;
206	u32 data_lanes[DATA_LANES_COUNT];
207	int ret, i, j;
208
209	ep = fwnode_graph_get_next_endpoint(dev_fwnode(&fsa->client->dev), NULL);
210	if (!ep)
211		return 0;
212
213	ret = fwnode_property_read_u32_array(ep, "data-lanes", data_lanes, DATA_LANES_COUNT);
214	if (ret == -EINVAL)
215		/* Property isn't here, consider default mapping */
216		goto out_done;
217	if (ret) {
218		dev_err(&fsa->client->dev, "invalid data-lanes property: %d\n", ret);
219		goto out_error;
220	}
221
222	for (i = 0; i < ARRAY_SIZE(supported_data_lane_mapping); i++) {
223		for (j = 0; j < DATA_LANES_COUNT; j++) {
224			if (data_lanes[j] != supported_data_lane_mapping[i][j])
225				break;
226		}
227
228		if (j == DATA_LANES_COUNT)
229			break;
230	}
231
232	switch (i) {
233	case NORMAL_LANE_MAPPING:
234		break;
235	case INVERT_LANE_MAPPING:
236		fsa->swap_sbu_lanes = true;
237		break;
238	default:
239		dev_err(&fsa->client->dev, "invalid data-lanes mapping\n");
240		ret = -EINVAL;
241		goto out_error;
242	}
243
244out_done:
245	ret = 0;
246
247out_error:
248	fwnode_handle_put(ep);
249
250	return ret;
251}
252
253static int fsa4480_probe(struct i2c_client *client)
254{
255	struct device *dev = &client->dev;
256	struct typec_switch_desc sw_desc = { };
257	struct typec_mux_desc mux_desc = { };
258	struct fsa4480 *fsa;
259	int val = 0;
260	int ret;
261
262	fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL);
263	if (!fsa)
264		return -ENOMEM;
265
266	fsa->client = client;
267	mutex_init(&fsa->lock);
268
269	ret = fsa4480_parse_data_lanes_mapping(fsa);
270	if (ret)
271		return ret;
272
273	fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config);
274	if (IS_ERR(fsa->regmap))
275		return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n");
276
277	ret = devm_regulator_get_enable_optional(dev, "vcc");
278	if (ret && ret != -ENODEV)
279		return dev_err_probe(dev, ret, "Failed to get regulator\n");
280
281	ret = regmap_read(fsa->regmap, FSA4480_DEVICE_ID, &val);
282	if (ret)
283		return dev_err_probe(dev, -ENODEV, "FSA4480 not found\n");
284
285	dev_dbg(dev, "Found FSA4480 v%lu.%lu (Vendor ID = %lu)\n",
286		FIELD_GET(FSA4480_DEVICE_ID_VERSION_ID, val),
287		FIELD_GET(FSA4480_DEVICE_ID_REV_ID, val),
288		FIELD_GET(FSA4480_DEVICE_ID_VENDOR_ID, val));
289
290	/* Safe mode */
291	fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB;
292	fsa->mode = TYPEC_STATE_SAFE;
293	fsa->orientation = TYPEC_ORIENTATION_NONE;
294
295	/* set default settings */
296	regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00);
297	regmap_write(fsa->regmap, FSA4480_SLOW_R, 0x00);
298	regmap_write(fsa->regmap, FSA4480_SLOW_MIC, 0x00);
299	regmap_write(fsa->regmap, FSA4480_SLOW_SENSE, 0x00);
300	regmap_write(fsa->regmap, FSA4480_SLOW_GND, 0x00);
301	regmap_write(fsa->regmap, FSA4480_DELAY_L_R, 0x00);
302	regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00);
303	regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00);
304	regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09);
305	regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, FSA4480_SEL_USB);
306	regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable);
307
308	sw_desc.drvdata = fsa;
309	sw_desc.fwnode = dev_fwnode(dev);
310	sw_desc.set = fsa4480_switch_set;
311
312	fsa->sw = typec_switch_register(dev, &sw_desc);
313	if (IS_ERR(fsa->sw))
314		return dev_err_probe(dev, PTR_ERR(fsa->sw), "failed to register typec switch\n");
315
316	mux_desc.drvdata = fsa;
317	mux_desc.fwnode = dev_fwnode(dev);
318	mux_desc.set = fsa4480_mux_set;
319
320	fsa->mux = typec_mux_register(dev, &mux_desc);
321	if (IS_ERR(fsa->mux)) {
322		typec_switch_unregister(fsa->sw);
323		return dev_err_probe(dev, PTR_ERR(fsa->mux), "failed to register typec mux\n");
324	}
325
326	i2c_set_clientdata(client, fsa);
327	return 0;
328}
329
330static void fsa4480_remove(struct i2c_client *client)
331{
332	struct fsa4480 *fsa = i2c_get_clientdata(client);
333
334	typec_mux_unregister(fsa->mux);
335	typec_switch_unregister(fsa->sw);
336}
337
338static const struct i2c_device_id fsa4480_table[] = {
339	{ "fsa4480" },
340	{ }
341};
342MODULE_DEVICE_TABLE(i2c, fsa4480_table);
343
344static const struct of_device_id fsa4480_of_table[] = {
345	{ .compatible = "fcs,fsa4480" },
346	{ }
347};
348MODULE_DEVICE_TABLE(of, fsa4480_of_table);
349
350static struct i2c_driver fsa4480_driver = {
351	.driver = {
352		.name = "fsa4480",
353		.of_match_table = fsa4480_of_table,
354	},
355	.probe		= fsa4480_probe,
356	.remove		= fsa4480_remove,
357	.id_table	= fsa4480_table,
358};
359module_i2c_driver(fsa4480_driver);
360
361MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver");
362MODULE_LICENSE("GPL v2");
~/ Read-only file preview.