1*2b03d9a4SJonas Jelonek // SPDX-License-Identifier: GPL-2.0 2*2b03d9a4SJonas Jelonek /* 3*2b03d9a4SJonas Jelonek * GPIO line mux which acts as virtual gpiochip and provides a 1-to-many 4*2b03d9a4SJonas Jelonek * mapping between virtual GPIOs and a real GPIO + multiplexer. 5*2b03d9a4SJonas Jelonek * 6*2b03d9a4SJonas Jelonek * Copyright (c) 2025 Jonas Jelonek <jelonek.jonas@gmail.com> 7*2b03d9a4SJonas Jelonek */ 8*2b03d9a4SJonas Jelonek 9*2b03d9a4SJonas Jelonek #include <linux/gpio/consumer.h> 10*2b03d9a4SJonas Jelonek #include <linux/gpio/driver.h> 11*2b03d9a4SJonas Jelonek #include <linux/mod_devicetable.h> 12*2b03d9a4SJonas Jelonek #include <linux/mutex.h> 13*2b03d9a4SJonas Jelonek #include <linux/mux/consumer.h> 14*2b03d9a4SJonas Jelonek #include <linux/platform_device.h> 15*2b03d9a4SJonas Jelonek 16*2b03d9a4SJonas Jelonek #define MUX_SELECT_DELAY_US 100 17*2b03d9a4SJonas Jelonek 18*2b03d9a4SJonas Jelonek struct gpio_lmux { 19*2b03d9a4SJonas Jelonek struct gpio_chip gc; 20*2b03d9a4SJonas Jelonek struct mux_control *mux; 21*2b03d9a4SJonas Jelonek struct gpio_desc *muxed_gpio; 22*2b03d9a4SJonas Jelonek 23*2b03d9a4SJonas Jelonek u32 num_gpio_mux_states; 24*2b03d9a4SJonas Jelonek unsigned int gpio_mux_states[] __counted_by(num_gpio_mux_states); 25*2b03d9a4SJonas Jelonek }; 26*2b03d9a4SJonas Jelonek 27*2b03d9a4SJonas Jelonek static int gpio_lmux_gpio_get(struct gpio_chip *gc, unsigned int offset) 28*2b03d9a4SJonas Jelonek { 29*2b03d9a4SJonas Jelonek struct gpio_lmux *glm = gpiochip_get_data(gc); 30*2b03d9a4SJonas Jelonek int ret; 31*2b03d9a4SJonas Jelonek 32*2b03d9a4SJonas Jelonek ret = mux_control_select_delay(glm->mux, glm->gpio_mux_states[offset], 33*2b03d9a4SJonas Jelonek MUX_SELECT_DELAY_US); 34*2b03d9a4SJonas Jelonek if (ret < 0) 35*2b03d9a4SJonas Jelonek return ret; 36*2b03d9a4SJonas Jelonek 37*2b03d9a4SJonas Jelonek ret = gpiod_get_raw_value_cansleep(glm->muxed_gpio); 38*2b03d9a4SJonas Jelonek mux_control_deselect(glm->mux); 39*2b03d9a4SJonas Jelonek return ret; 40*2b03d9a4SJonas Jelonek } 41*2b03d9a4SJonas Jelonek 42*2b03d9a4SJonas Jelonek static int gpio_lmux_gpio_get_direction(struct gpio_chip *gc, 43*2b03d9a4SJonas Jelonek unsigned int offset) 44*2b03d9a4SJonas Jelonek { 45*2b03d9a4SJonas Jelonek return GPIO_LINE_DIRECTION_IN; 46*2b03d9a4SJonas Jelonek } 47*2b03d9a4SJonas Jelonek 48*2b03d9a4SJonas Jelonek static int gpio_lmux_probe(struct platform_device *pdev) 49*2b03d9a4SJonas Jelonek { 50*2b03d9a4SJonas Jelonek struct device *dev = &pdev->dev; 51*2b03d9a4SJonas Jelonek struct gpio_lmux *glm; 52*2b03d9a4SJonas Jelonek unsigned int ngpio; 53*2b03d9a4SJonas Jelonek size_t size; 54*2b03d9a4SJonas Jelonek int ret; 55*2b03d9a4SJonas Jelonek 56*2b03d9a4SJonas Jelonek ngpio = device_property_count_u32(dev, "gpio-line-mux-states"); 57*2b03d9a4SJonas Jelonek if (!ngpio) 58*2b03d9a4SJonas Jelonek return -EINVAL; 59*2b03d9a4SJonas Jelonek 60*2b03d9a4SJonas Jelonek size = struct_size(glm, gpio_mux_states, ngpio); 61*2b03d9a4SJonas Jelonek glm = devm_kzalloc(dev, size, GFP_KERNEL); 62*2b03d9a4SJonas Jelonek if (!glm) 63*2b03d9a4SJonas Jelonek return -ENOMEM; 64*2b03d9a4SJonas Jelonek 65*2b03d9a4SJonas Jelonek glm->gc.base = -1; 66*2b03d9a4SJonas Jelonek glm->gc.can_sleep = true; 67*2b03d9a4SJonas Jelonek glm->gc.fwnode = dev_fwnode(dev); 68*2b03d9a4SJonas Jelonek glm->gc.label = dev_name(dev); 69*2b03d9a4SJonas Jelonek glm->gc.ngpio = ngpio; 70*2b03d9a4SJonas Jelonek glm->gc.owner = THIS_MODULE; 71*2b03d9a4SJonas Jelonek glm->gc.parent = dev; 72*2b03d9a4SJonas Jelonek 73*2b03d9a4SJonas Jelonek glm->gc.get = gpio_lmux_gpio_get; 74*2b03d9a4SJonas Jelonek glm->gc.get_direction = gpio_lmux_gpio_get_direction; 75*2b03d9a4SJonas Jelonek 76*2b03d9a4SJonas Jelonek glm->mux = devm_mux_control_get(dev, NULL); 77*2b03d9a4SJonas Jelonek if (IS_ERR(glm->mux)) 78*2b03d9a4SJonas Jelonek return dev_err_probe(dev, PTR_ERR(glm->mux), 79*2b03d9a4SJonas Jelonek "could not get mux controller\n"); 80*2b03d9a4SJonas Jelonek 81*2b03d9a4SJonas Jelonek glm->muxed_gpio = devm_gpiod_get(dev, "muxed", GPIOD_IN); 82*2b03d9a4SJonas Jelonek if (IS_ERR(glm->muxed_gpio)) 83*2b03d9a4SJonas Jelonek return dev_err_probe(dev, PTR_ERR(glm->muxed_gpio), 84*2b03d9a4SJonas Jelonek "could not get muxed-gpio\n"); 85*2b03d9a4SJonas Jelonek 86*2b03d9a4SJonas Jelonek glm->num_gpio_mux_states = ngpio; 87*2b03d9a4SJonas Jelonek ret = device_property_read_u32_array(dev, "gpio-line-mux-states", 88*2b03d9a4SJonas Jelonek &glm->gpio_mux_states[0], ngpio); 89*2b03d9a4SJonas Jelonek if (ret) 90*2b03d9a4SJonas Jelonek return dev_err_probe(dev, ret, "could not get mux states\n"); 91*2b03d9a4SJonas Jelonek 92*2b03d9a4SJonas Jelonek ret = devm_gpiochip_add_data(dev, &glm->gc, glm); 93*2b03d9a4SJonas Jelonek if (ret) 94*2b03d9a4SJonas Jelonek return dev_err_probe(dev, ret, "failed to add gpiochip\n"); 95*2b03d9a4SJonas Jelonek 96*2b03d9a4SJonas Jelonek return 0; 97*2b03d9a4SJonas Jelonek } 98*2b03d9a4SJonas Jelonek 99*2b03d9a4SJonas Jelonek static const struct of_device_id gpio_lmux_of_match[] = { 100*2b03d9a4SJonas Jelonek { .compatible = "gpio-line-mux" }, 101*2b03d9a4SJonas Jelonek { } 102*2b03d9a4SJonas Jelonek }; 103*2b03d9a4SJonas Jelonek MODULE_DEVICE_TABLE(of, gpio_lmux_of_match); 104*2b03d9a4SJonas Jelonek 105*2b03d9a4SJonas Jelonek static struct platform_driver gpio_lmux_driver = { 106*2b03d9a4SJonas Jelonek .driver = { 107*2b03d9a4SJonas Jelonek .name = "gpio-line-mux", 108*2b03d9a4SJonas Jelonek .of_match_table = gpio_lmux_of_match, 109*2b03d9a4SJonas Jelonek }, 110*2b03d9a4SJonas Jelonek .probe = gpio_lmux_probe, 111*2b03d9a4SJonas Jelonek }; 112*2b03d9a4SJonas Jelonek module_platform_driver(gpio_lmux_driver); 113*2b03d9a4SJonas Jelonek 114*2b03d9a4SJonas Jelonek MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>"); 115*2b03d9a4SJonas Jelonek MODULE_DESCRIPTION("GPIO line mux driver"); 116*2b03d9a4SJonas Jelonek MODULE_LICENSE("GPL"); 117