0001
0002
0003 #include <linux/types.h>
0004 #include <linux/io.h>
0005 #include <linux/bits.h>
0006 #include <linux/gpio/driver.h>
0007 #include <linux/mod_devicetable.h>
0008 #include <linux/module.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/property.h>
0011
0012 #define AIROHA_GPIO_MAX 32
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 struct airoha_gpio_ctrl {
0023 struct gpio_chip gc;
0024 void __iomem *data;
0025 void __iomem *dir[2];
0026 void __iomem *output;
0027 };
0028
0029 static struct airoha_gpio_ctrl *gc_to_ctrl(struct gpio_chip *gc)
0030 {
0031 return container_of(gc, struct airoha_gpio_ctrl, gc);
0032 }
0033
0034 static int airoha_dir_set(struct gpio_chip *gc, unsigned int gpio,
0035 int val, int out)
0036 {
0037 struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
0038 u32 dir = ioread32(ctrl->dir[gpio / 16]);
0039 u32 output = ioread32(ctrl->output);
0040 u32 mask = BIT((gpio % 16) * 2);
0041
0042 if (out) {
0043 dir |= mask;
0044 output |= BIT(gpio);
0045 } else {
0046 dir &= ~mask;
0047 output &= ~BIT(gpio);
0048 }
0049
0050 iowrite32(dir, ctrl->dir[gpio / 16]);
0051
0052 if (out)
0053 gc->set(gc, gpio, val);
0054
0055 iowrite32(output, ctrl->output);
0056
0057 return 0;
0058 }
0059
0060 static int airoha_dir_out(struct gpio_chip *gc, unsigned int gpio,
0061 int val)
0062 {
0063 return airoha_dir_set(gc, gpio, val, 1);
0064 }
0065
0066 static int airoha_dir_in(struct gpio_chip *gc, unsigned int gpio)
0067 {
0068 return airoha_dir_set(gc, gpio, 0, 0);
0069 }
0070
0071 static int airoha_get_dir(struct gpio_chip *gc, unsigned int gpio)
0072 {
0073 struct airoha_gpio_ctrl *ctrl = gc_to_ctrl(gc);
0074 u32 dir = ioread32(ctrl->dir[gpio / 16]);
0075 u32 mask = BIT((gpio % 16) * 2);
0076
0077 return (dir & mask) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
0078 }
0079
0080 static int airoha_gpio_probe(struct platform_device *pdev)
0081 {
0082 struct device *dev = &pdev->dev;
0083 struct airoha_gpio_ctrl *ctrl;
0084 int err;
0085
0086 ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
0087 if (!ctrl)
0088 return -ENOMEM;
0089
0090 ctrl->data = devm_platform_ioremap_resource(pdev, 0);
0091 if (IS_ERR(ctrl->data))
0092 return PTR_ERR(ctrl->data);
0093
0094 ctrl->dir[0] = devm_platform_ioremap_resource(pdev, 1);
0095 if (IS_ERR(ctrl->dir[0]))
0096 return PTR_ERR(ctrl->dir[0]);
0097
0098 ctrl->dir[1] = devm_platform_ioremap_resource(pdev, 2);
0099 if (IS_ERR(ctrl->dir[1]))
0100 return PTR_ERR(ctrl->dir[1]);
0101
0102 ctrl->output = devm_platform_ioremap_resource(pdev, 3);
0103 if (IS_ERR(ctrl->output))
0104 return PTR_ERR(ctrl->output);
0105
0106 err = bgpio_init(&ctrl->gc, dev, 4, ctrl->data, NULL,
0107 NULL, NULL, NULL, 0);
0108 if (err)
0109 return dev_err_probe(dev, err, "unable to init generic GPIO");
0110
0111 ctrl->gc.ngpio = AIROHA_GPIO_MAX;
0112 ctrl->gc.owner = THIS_MODULE;
0113 ctrl->gc.direction_output = airoha_dir_out;
0114 ctrl->gc.direction_input = airoha_dir_in;
0115 ctrl->gc.get_direction = airoha_get_dir;
0116
0117 return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
0118 }
0119
0120 static const struct of_device_id airoha_gpio_of_match[] = {
0121 { .compatible = "airoha,en7523-gpio" },
0122 { }
0123 };
0124 MODULE_DEVICE_TABLE(of, airoha_gpio_of_match);
0125
0126 static struct platform_driver airoha_gpio_driver = {
0127 .driver = {
0128 .name = "airoha-gpio",
0129 .of_match_table = airoha_gpio_of_match,
0130 },
0131 .probe = airoha_gpio_probe,
0132 };
0133 module_platform_driver(airoha_gpio_driver);
0134
0135 MODULE_DESCRIPTION("Airoha GPIO support");
0136 MODULE_AUTHOR("John Crispin <john@phrozen.org>");
0137 MODULE_LICENSE("GPL v2");