| 1 | |
| 2 | |
| 3 | * GPIO-controlled multiplexer driver
|
| 4 | *
|
| 5 | * Copyright (C) 2017 Axentia Technologies AB
|
| 6 | *
|
| 7 | * Author: Peter Rosin <[email protected]>
|
| 8 |
|
| 9 |
|
| 10 | #include <linux/bitmap.h>
|
| 11 | #include <linux/err.h>
|
| 12 | #include <linux/gpio/consumer.h>
|
| 13 | #include <linux/module.h>
|
| 14 | #include <linux/mux/driver.h>
|
| 15 | #include <linux/platform_device.h>
|
| 16 | #include <linux/property.h>
|
| 17 | #include <linux/regulator/consumer.h>
|
| 18 |
|
| 19 | struct mux_gpio {
|
| 20 | struct gpio_descs *gpios;
|
| 21 | };
|
| 22 |
|
| 23 | static int mux_gpio_set(struct mux_control *mux, int state)
|
| 24 | {
|
| 25 | struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip);
|
| 26 | DECLARE_BITMAP(values, BITS_PER_TYPE(state));
|
| 27 | u32 value = state;
|
| 28 |
|
| 29 | bitmap_from_arr32(values, &value, BITS_PER_TYPE(value));
|
| 30 |
|
| 31 | gpiod_multi_set_value_cansleep(mux_gpio->gpios, values);
|
| 32 |
|
| 33 | return 0;
|
| 34 | }
|
| 35 |
|
| 36 | static const struct mux_control_ops mux_gpio_ops = {
|
| 37 | .set = mux_gpio_set,
|
| 38 | };
|
| 39 |
|
| 40 | static const struct of_device_id mux_gpio_dt_ids[] = {
|
| 41 | { .compatible = "gpio-mux", },
|
| 42 | { }
|
| 43 | };
|
| 44 | MODULE_DEVICE_TABLE(of, mux_gpio_dt_ids);
|
| 45 |
|
| 46 | static int mux_gpio_probe(struct platform_device *pdev)
|
| 47 | {
|
| 48 | struct device *dev = &pdev->dev;
|
| 49 | struct mux_chip *mux_chip;
|
| 50 | struct mux_gpio *mux_gpio;
|
| 51 | int pins;
|
| 52 | s32 idle_state;
|
| 53 | int ret;
|
| 54 |
|
| 55 | pins = gpiod_count(dev, "mux");
|
| 56 | if (pins < 0)
|
| 57 | return pins;
|
| 58 |
|
| 59 | mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio));
|
| 60 | if (IS_ERR(mux_chip))
|
| 61 | return PTR_ERR(mux_chip);
|
| 62 |
|
| 63 | mux_gpio = mux_chip_priv(mux_chip);
|
| 64 | mux_chip->ops = &mux_gpio_ops;
|
| 65 |
|
| 66 | mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW);
|
| 67 | if (IS_ERR(mux_gpio->gpios))
|
| 68 | return dev_err_probe(dev, PTR_ERR(mux_gpio->gpios),
|
| 69 | "failed to get gpios\n");
|
| 70 | WARN_ON(pins != mux_gpio->gpios->ndescs);
|
| 71 | mux_chip->mux->states = BIT(pins);
|
| 72 |
|
| 73 | ret = device_property_read_u32(dev, "idle-state", (u32 *)&idle_state);
|
| 74 | if (ret >= 0 && idle_state != MUX_IDLE_AS_IS) {
|
| 75 | if (idle_state < 0 || idle_state >= mux_chip->mux->states) {
|
| 76 | dev_err(dev, "invalid idle-state %u\n", idle_state);
|
| 77 | return -EINVAL;
|
| 78 | }
|
| 79 |
|
| 80 | mux_chip->mux->idle_state = idle_state;
|
| 81 | }
|
| 82 |
|
| 83 | ret = devm_regulator_get_enable_optional(dev, "mux");
|
| 84 | if (ret && ret != -ENODEV)
|
| 85 | return dev_err_probe(dev, ret, "failed to get/enable mux supply\n");
|
| 86 |
|
| 87 | ret = devm_mux_chip_register(dev, mux_chip);
|
| 88 | if (ret < 0)
|
| 89 | return ret;
|
| 90 |
|
| 91 | dev_info(dev, "%u-way mux-controller registered\n",
|
| 92 | mux_chip->mux->states);
|
| 93 |
|
| 94 | return 0;
|
| 95 | }
|
| 96 |
|
| 97 | static struct platform_driver mux_gpio_driver = {
|
| 98 | .driver = {
|
| 99 | .name = "gpio-mux",
|
| 100 | .of_match_table = mux_gpio_dt_ids,
|
| 101 | },
|
| 102 | .probe = mux_gpio_probe,
|
| 103 | };
|
| 104 | module_platform_driver(mux_gpio_driver);
|
| 105 |
|
| 106 | MODULE_DESCRIPTION("GPIO-controlled multiplexer driver");
|
| 107 | MODULE_AUTHOR("Peter Rosin <[email protected]>");
|
| 108 | MODULE_LICENSE("GPL v2");
|