File Index
Files and directories
Sign in
FILE

gpio-sbu-mux.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/mux/gpio-sbu-mux.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2022 Linaro Ltd.
  4 */
  5
  6#include <linux/device.h>
  7#include <linux/module.h>
  8#include <linux/mutex.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/platform_device.h>
 11#include <linux/usb/typec_dp.h>
 12#include <linux/usb/typec_mux.h>
 13
 14struct gpio_sbu_mux {
 15	struct gpio_desc *enable_gpio;
 16	struct gpio_desc *select_gpio;
 17
 18	struct typec_switch_dev *sw;
 19	struct typec_mux_dev *mux;
 20
 21	struct mutex lock; /* protect enabled and swapped */
 22	bool enabled;
 23	bool swapped;
 24};
 25
 26static int gpio_sbu_switch_set(struct typec_switch_dev *sw,
 27			       enum typec_orientation orientation)
 28{
 29	struct gpio_sbu_mux *sbu_mux = typec_switch_get_drvdata(sw);
 30	bool enabled;
 31	bool swapped;
 32
 33	mutex_lock(&sbu_mux->lock);
 34
 35	enabled = sbu_mux->enabled;
 36	swapped = sbu_mux->swapped;
 37
 38	switch (orientation) {
 39	case TYPEC_ORIENTATION_NONE:
 40		enabled = false;
 41		break;
 42	case TYPEC_ORIENTATION_NORMAL:
 43		swapped = false;
 44		break;
 45	case TYPEC_ORIENTATION_REVERSE:
 46		swapped = true;
 47		break;
 48	}
 49
 50	if (enabled != sbu_mux->enabled)
 51		gpiod_set_value_cansleep(sbu_mux->enable_gpio, enabled);
 52
 53	if (swapped != sbu_mux->swapped)
 54		gpiod_set_value_cansleep(sbu_mux->select_gpio, swapped);
 55
 56	sbu_mux->enabled = enabled;
 57	sbu_mux->swapped = swapped;
 58
 59	mutex_unlock(&sbu_mux->lock);
 60
 61	return 0;
 62}
 63
 64static int gpio_sbu_mux_set(struct typec_mux_dev *mux,
 65			    struct typec_mux_state *state)
 66{
 67	struct gpio_sbu_mux *sbu_mux = typec_mux_get_drvdata(mux);
 68
 69	if (!sbu_mux->enable_gpio)
 70		return -EOPNOTSUPP;
 71
 72	mutex_lock(&sbu_mux->lock);
 73
 74	switch (state->mode) {
 75	case TYPEC_STATE_SAFE:
 76	case TYPEC_STATE_USB:
 77		sbu_mux->enabled = false;
 78		break;
 79	case TYPEC_DP_STATE_C:
 80	case TYPEC_DP_STATE_D:
 81	case TYPEC_DP_STATE_E:
 82		sbu_mux->enabled = true;
 83		break;
 84	default:
 85		break;
 86	}
 87
 88	gpiod_set_value_cansleep(sbu_mux->enable_gpio, sbu_mux->enabled);
 89
 90	mutex_unlock(&sbu_mux->lock);
 91
 92	return 0;
 93}
 94
 95static int gpio_sbu_mux_probe(struct platform_device *pdev)
 96{
 97	struct typec_switch_desc sw_desc = { };
 98	struct typec_mux_desc mux_desc = { };
 99	struct device *dev = &pdev->dev;
100	struct gpio_sbu_mux *sbu_mux;
101
102	sbu_mux = devm_kzalloc(dev, sizeof(*sbu_mux), GFP_KERNEL);
103	if (!sbu_mux)
104		return -ENOMEM;
105
106	mutex_init(&sbu_mux->lock);
107
108	sbu_mux->enable_gpio = devm_gpiod_get_optional(dev, "enable",
109						       GPIOD_OUT_LOW);
110	if (IS_ERR(sbu_mux->enable_gpio))
111		return dev_err_probe(dev, PTR_ERR(sbu_mux->enable_gpio),
112				     "unable to acquire enable gpio\n");
113
114	sbu_mux->select_gpio = devm_gpiod_get(dev, "select", GPIOD_OUT_LOW);
115	if (IS_ERR(sbu_mux->select_gpio))
116		return dev_err_probe(dev, PTR_ERR(sbu_mux->select_gpio),
117				     "unable to acquire select gpio\n");
118
119	sw_desc.drvdata = sbu_mux;
120	sw_desc.fwnode = dev_fwnode(dev);
121	sw_desc.set = gpio_sbu_switch_set;
122
123	sbu_mux->sw = typec_switch_register(dev, &sw_desc);
124	if (IS_ERR(sbu_mux->sw))
125		return dev_err_probe(dev, PTR_ERR(sbu_mux->sw),
126				     "failed to register typec switch\n");
127
128	mux_desc.drvdata = sbu_mux;
129	mux_desc.fwnode = dev_fwnode(dev);
130	mux_desc.set = gpio_sbu_mux_set;
131
132	sbu_mux->mux = typec_mux_register(dev, &mux_desc);
133	if (IS_ERR(sbu_mux->mux)) {
134		typec_switch_unregister(sbu_mux->sw);
135		return dev_err_probe(dev, PTR_ERR(sbu_mux->mux),
136				     "failed to register typec mux\n");
137	}
138
139	platform_set_drvdata(pdev, sbu_mux);
140
141	return 0;
142}
143
144static void gpio_sbu_mux_remove(struct platform_device *pdev)
145{
146	struct gpio_sbu_mux *sbu_mux = platform_get_drvdata(pdev);
147
148	gpiod_set_value_cansleep(sbu_mux->enable_gpio, 0);
149
150	typec_mux_unregister(sbu_mux->mux);
151	typec_switch_unregister(sbu_mux->sw);
152}
153
154static const struct of_device_id gpio_sbu_mux_match[] = {
155	{ .compatible = "gpio-sbu-mux", },
156	{}
157};
158MODULE_DEVICE_TABLE(of, gpio_sbu_mux_match);
159
160static struct platform_driver gpio_sbu_mux_driver = {
161	.probe = gpio_sbu_mux_probe,
162	.remove = gpio_sbu_mux_remove,
163	.driver = {
164		.name = "gpio_sbu_mux",
165		.of_match_table = gpio_sbu_mux_match,
166	},
167};
168module_platform_driver(gpio_sbu_mux_driver);
169
170MODULE_DESCRIPTION("GPIO based SBU mux driver");
171MODULE_LICENSE("GPL");
~/ Read-only file preview.