Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  Turris Mox Moxtet GPIO expander
0004  *
0005  *  Copyright (C) 2018 Marek BehĂșn <kabel@kernel.org>
0006  */
0007 
0008 #include <linux/bitops.h>
0009 #include <linux/gpio/driver.h>
0010 #include <linux/moxtet.h>
0011 #include <linux/module.h>
0012 
0013 #define MOXTET_GPIO_NGPIOS  12
0014 #define MOXTET_GPIO_INPUTS  4
0015 
0016 struct moxtet_gpio_desc {
0017     u16 in_mask;
0018     u16 out_mask;
0019 };
0020 
0021 static const struct moxtet_gpio_desc descs[] = {
0022     [TURRIS_MOX_MODULE_SFP] = {
0023         .in_mask = GENMASK(2, 0),
0024         .out_mask = GENMASK(5, 4),
0025     },
0026 };
0027 
0028 struct moxtet_gpio_chip {
0029     struct device           *dev;
0030     struct gpio_chip        gpio_chip;
0031     const struct moxtet_gpio_desc   *desc;
0032 };
0033 
0034 static int moxtet_gpio_get_value(struct gpio_chip *gc, unsigned int offset)
0035 {
0036     struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
0037     int ret;
0038 
0039     if (chip->desc->in_mask & BIT(offset)) {
0040         ret = moxtet_device_read(chip->dev);
0041     } else if (chip->desc->out_mask & BIT(offset)) {
0042         ret = moxtet_device_written(chip->dev);
0043         if (ret >= 0)
0044             ret <<= MOXTET_GPIO_INPUTS;
0045     } else {
0046         return -EINVAL;
0047     }
0048 
0049     if (ret < 0)
0050         return ret;
0051 
0052     return !!(ret & BIT(offset));
0053 }
0054 
0055 static void moxtet_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
0056                   int val)
0057 {
0058     struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
0059     int state;
0060 
0061     state = moxtet_device_written(chip->dev);
0062     if (state < 0)
0063         return;
0064 
0065     offset -= MOXTET_GPIO_INPUTS;
0066 
0067     if (val)
0068         state |= BIT(offset);
0069     else
0070         state &= ~BIT(offset);
0071 
0072     moxtet_device_write(chip->dev, state);
0073 }
0074 
0075 static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
0076 {
0077     struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
0078 
0079     /* All lines are hard wired to be either input or output, not both. */
0080     if (chip->desc->in_mask & BIT(offset))
0081         return GPIO_LINE_DIRECTION_IN;
0082     else if (chip->desc->out_mask & BIT(offset))
0083         return GPIO_LINE_DIRECTION_OUT;
0084     else
0085         return -EINVAL;
0086 }
0087 
0088 static int moxtet_gpio_direction_input(struct gpio_chip *gc,
0089                        unsigned int offset)
0090 {
0091     struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
0092 
0093     if (chip->desc->in_mask & BIT(offset))
0094         return 0;
0095     else if (chip->desc->out_mask & BIT(offset))
0096         return -ENOTSUPP;
0097     else
0098         return -EINVAL;
0099 }
0100 
0101 static int moxtet_gpio_direction_output(struct gpio_chip *gc,
0102                     unsigned int offset, int val)
0103 {
0104     struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
0105 
0106     if (chip->desc->out_mask & BIT(offset))
0107         moxtet_gpio_set_value(gc, offset, val);
0108     else if (chip->desc->in_mask & BIT(offset))
0109         return -ENOTSUPP;
0110     else
0111         return -EINVAL;
0112 
0113     return 0;
0114 }
0115 
0116 static int moxtet_gpio_probe(struct device *dev)
0117 {
0118     struct moxtet_gpio_chip *chip;
0119     struct device_node *nc = dev->of_node;
0120     int id;
0121 
0122     id = to_moxtet_device(dev)->id;
0123 
0124     if (id >= ARRAY_SIZE(descs)) {
0125         dev_err(dev, "%pOF Moxtet device id 0x%x is not supported by gpio-moxtet driver\n",
0126             nc, id);
0127         return -ENOTSUPP;
0128     }
0129 
0130     chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
0131     if (!chip)
0132         return -ENOMEM;
0133 
0134     chip->dev = dev;
0135     chip->gpio_chip.parent = dev;
0136     chip->desc = &descs[id];
0137 
0138     dev_set_drvdata(dev, chip);
0139 
0140     chip->gpio_chip.label = dev_name(dev);
0141     chip->gpio_chip.get_direction = moxtet_gpio_get_direction;
0142     chip->gpio_chip.direction_input = moxtet_gpio_direction_input;
0143     chip->gpio_chip.direction_output = moxtet_gpio_direction_output;
0144     chip->gpio_chip.get = moxtet_gpio_get_value;
0145     chip->gpio_chip.set = moxtet_gpio_set_value;
0146     chip->gpio_chip.base = -1;
0147 
0148     chip->gpio_chip.ngpio = MOXTET_GPIO_NGPIOS;
0149 
0150     chip->gpio_chip.can_sleep = true;
0151     chip->gpio_chip.owner = THIS_MODULE;
0152 
0153     return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip);
0154 }
0155 
0156 static const struct of_device_id moxtet_gpio_dt_ids[] = {
0157     { .compatible = "cznic,moxtet-gpio", },
0158     {},
0159 };
0160 MODULE_DEVICE_TABLE(of, moxtet_gpio_dt_ids);
0161 
0162 static const enum turris_mox_module_id moxtet_gpio_module_table[] = {
0163     TURRIS_MOX_MODULE_SFP,
0164     0,
0165 };
0166 
0167 static struct moxtet_driver moxtet_gpio_driver = {
0168     .driver = {
0169         .name       = "moxtet-gpio",
0170         .of_match_table = moxtet_gpio_dt_ids,
0171         .probe      = moxtet_gpio_probe,
0172     },
0173     .id_table = moxtet_gpio_module_table,
0174 };
0175 module_moxtet_driver(moxtet_gpio_driver);
0176 
0177 MODULE_AUTHOR("Marek Behun <kabel@kernel.org>");
0178 MODULE_DESCRIPTION("Turris Mox Moxtet GPIO expander");
0179 MODULE_LICENSE("GPL v2");