FILE
gpio-sbu-mux.c
File preview with syntax highlighting.
linux-6.19.14/drivers/usb/typec/mux/gpio-sbu-mux.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.