diff options
| -rw-r--r-- | Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt | 21 | ||||
| -rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
| -rw-r--r-- | drivers/gpio/gpio-etraxfs.c | 176 |
4 files changed, 206 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt new file mode 100644 index 000000000000..abf4db736c6e --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | Axis ETRAX FS General I/O controller bindings | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible: | ||
| 6 | - "axis,etraxfs-gio" | ||
| 7 | - reg: Physical base address and length of the controller's registers. | ||
| 8 | - #gpio-cells: Should be 3 | ||
| 9 | - The first cell is the gpio offset number. | ||
| 10 | - The second cell is reserved and is currently unused. | ||
| 11 | - The third cell is the port number (hex). | ||
| 12 | - gpio-controller: Marks the device node as a GPIO controller. | ||
| 13 | |||
| 14 | Example: | ||
| 15 | |||
| 16 | gio: gpio@b001a000 { | ||
| 17 | compatible = "axis,etraxfs-gio"; | ||
| 18 | reg = <0xb001a000 0x1000>; | ||
| 19 | gpio-controller; | ||
| 20 | #gpio-cells = <3>; | ||
| 21 | }; | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d86de6ae0a0e..ab9084648509 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
| @@ -167,6 +167,14 @@ config GPIO_EP93XX | |||
| 167 | depends on ARCH_EP93XX | 167 | depends on ARCH_EP93XX |
| 168 | select GPIO_GENERIC | 168 | select GPIO_GENERIC |
| 169 | 169 | ||
| 170 | config GPIO_ETRAXFS | ||
| 171 | bool "Axis ETRAX FS General I/O" | ||
| 172 | depends on CRIS || COMPILE_TEST | ||
| 173 | depends on OF | ||
| 174 | select GPIO_GENERIC | ||
| 175 | help | ||
| 176 | Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. | ||
| 177 | |||
| 170 | config GPIO_F7188X | 178 | config GPIO_F7188X |
| 171 | tristate "F71869, F71869A, F71882FG and F71889F GPIO support" | 179 | tristate "F71869, F71869A, F71882FG and F71889F GPIO support" |
| 172 | depends on X86 | 180 | depends on X86 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 893bbffc313a..f82cd678ce08 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
| @@ -33,6 +33,7 @@ obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o | |||
| 33 | obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o | 33 | obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o |
| 34 | obj-$(CONFIG_GPIO_EM) += gpio-em.o | 34 | obj-$(CONFIG_GPIO_EM) += gpio-em.o |
| 35 | obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o | 35 | obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o |
| 36 | obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o | ||
| 36 | obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o | 37 | obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o |
| 37 | obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o | 38 | obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o |
| 38 | obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o | 39 | obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o |
diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c new file mode 100644 index 000000000000..28071f4a5672 --- /dev/null +++ b/drivers/gpio/gpio-etraxfs.c | |||
| @@ -0,0 +1,176 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/init.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/of_gpio.h> | ||
| 5 | #include <linux/io.h> | ||
| 6 | #include <linux/platform_device.h> | ||
| 7 | #include <linux/basic_mmio_gpio.h> | ||
| 8 | |||
| 9 | #define ETRAX_FS_rw_pa_dout 0 | ||
| 10 | #define ETRAX_FS_r_pa_din 4 | ||
| 11 | #define ETRAX_FS_rw_pa_oe 8 | ||
| 12 | #define ETRAX_FS_rw_intr_cfg 12 | ||
| 13 | #define ETRAX_FS_rw_intr_mask 16 | ||
| 14 | #define ETRAX_FS_rw_ack_intr 20 | ||
| 15 | #define ETRAX_FS_r_intr 24 | ||
| 16 | #define ETRAX_FS_rw_pb_dout 32 | ||
| 17 | #define ETRAX_FS_r_pb_din 36 | ||
| 18 | #define ETRAX_FS_rw_pb_oe 40 | ||
| 19 | #define ETRAX_FS_rw_pc_dout 48 | ||
| 20 | #define ETRAX_FS_r_pc_din 52 | ||
| 21 | #define ETRAX_FS_rw_pc_oe 56 | ||
| 22 | #define ETRAX_FS_rw_pd_dout 64 | ||
| 23 | #define ETRAX_FS_r_pd_din 68 | ||
| 24 | #define ETRAX_FS_rw_pd_oe 72 | ||
| 25 | #define ETRAX_FS_rw_pe_dout 80 | ||
| 26 | #define ETRAX_FS_r_pe_din 84 | ||
| 27 | #define ETRAX_FS_rw_pe_oe 88 | ||
| 28 | |||
| 29 | struct etraxfs_gpio_port { | ||
| 30 | const char *label; | ||
| 31 | unsigned int oe; | ||
| 32 | unsigned int dout; | ||
| 33 | unsigned int din; | ||
| 34 | unsigned int ngpio; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct etraxfs_gpio_info { | ||
| 38 | unsigned int num_ports; | ||
| 39 | const struct etraxfs_gpio_port *ports; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = { | ||
| 43 | { | ||
| 44 | .label = "A", | ||
| 45 | .ngpio = 8, | ||
| 46 | .oe = ETRAX_FS_rw_pa_oe, | ||
| 47 | .dout = ETRAX_FS_rw_pa_dout, | ||
| 48 | .din = ETRAX_FS_r_pa_din, | ||
| 49 | }, | ||
| 50 | { | ||
| 51 | .label = "B", | ||
| 52 | .ngpio = 18, | ||
| 53 | .oe = ETRAX_FS_rw_pb_oe, | ||
| 54 | .dout = ETRAX_FS_rw_pb_dout, | ||
| 55 | .din = ETRAX_FS_r_pb_din, | ||
| 56 | }, | ||
| 57 | { | ||
| 58 | .label = "C", | ||
| 59 | .ngpio = 18, | ||
| 60 | .oe = ETRAX_FS_rw_pc_oe, | ||
| 61 | .dout = ETRAX_FS_rw_pc_dout, | ||
| 62 | .din = ETRAX_FS_r_pc_din, | ||
| 63 | }, | ||
| 64 | { | ||
| 65 | .label = "D", | ||
| 66 | .ngpio = 18, | ||
| 67 | .oe = ETRAX_FS_rw_pd_oe, | ||
| 68 | .dout = ETRAX_FS_rw_pd_dout, | ||
| 69 | .din = ETRAX_FS_r_pd_din, | ||
| 70 | }, | ||
| 71 | { | ||
| 72 | .label = "E", | ||
| 73 | .ngpio = 18, | ||
| 74 | .oe = ETRAX_FS_rw_pe_oe, | ||
| 75 | .dout = ETRAX_FS_rw_pe_dout, | ||
| 76 | .din = ETRAX_FS_r_pe_din, | ||
| 77 | }, | ||
| 78 | }; | ||
| 79 | |||
| 80 | static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { | ||
| 81 | .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports), | ||
| 82 | .ports = etraxfs_gpio_etraxfs_ports, | ||
| 83 | }; | ||
| 84 | |||
| 85 | static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, | ||
| 86 | const struct of_phandle_args *gpiospec, | ||
| 87 | u32 *flags) | ||
| 88 | { | ||
| 89 | /* | ||
| 90 | * Port numbers are A to E, and the properties are integers, so we | ||
| 91 | * specify them as 0xA - 0xE. | ||
| 92 | */ | ||
| 93 | if (gc->label[0] - 'A' + 0xA != gpiospec->args[2]) | ||
| 94 | return -EINVAL; | ||
| 95 | |||
| 96 | return of_gpio_simple_xlate(gc, gpiospec, flags); | ||
| 97 | } | ||
| 98 | |||
| 99 | static const struct of_device_id etraxfs_gpio_of_table[] = { | ||
| 100 | { | ||
| 101 | .compatible = "axis,etraxfs-gio", | ||
| 102 | .data = &etraxfs_gpio_etraxfs, | ||
| 103 | }, | ||
| 104 | {}, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static int etraxfs_gpio_probe(struct platform_device *pdev) | ||
| 108 | { | ||
| 109 | struct device *dev = &pdev->dev; | ||
| 110 | const struct etraxfs_gpio_info *info; | ||
| 111 | const struct of_device_id *match; | ||
| 112 | struct bgpio_chip *chips; | ||
| 113 | struct resource *res; | ||
| 114 | void __iomem *regs; | ||
| 115 | int ret; | ||
| 116 | int i; | ||
| 117 | |||
| 118 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 119 | regs = devm_ioremap_resource(dev, res); | ||
| 120 | if (!regs) | ||
| 121 | return -ENOMEM; | ||
| 122 | |||
| 123 | match = of_match_node(etraxfs_gpio_of_table, dev->of_node); | ||
| 124 | if (!match) | ||
| 125 | return -EINVAL; | ||
| 126 | |||
| 127 | info = match->data; | ||
| 128 | |||
| 129 | chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL); | ||
| 130 | if (!chips) | ||
| 131 | return -ENOMEM; | ||
| 132 | |||
| 133 | for (i = 0; i < info->num_ports; i++) { | ||
| 134 | struct bgpio_chip *bgc = &chips[i]; | ||
| 135 | const struct etraxfs_gpio_port *port = &info->ports[i]; | ||
| 136 | |||
| 137 | ret = bgpio_init(bgc, dev, 4, | ||
| 138 | regs + port->din, /* dat */ | ||
| 139 | regs + port->dout, /* set */ | ||
| 140 | NULL, /* clr */ | ||
| 141 | regs + port->oe, /* dirout */ | ||
| 142 | NULL, /* dirin */ | ||
| 143 | BGPIOF_UNREADABLE_REG_SET); | ||
| 144 | if (ret) | ||
| 145 | return ret; | ||
| 146 | |||
| 147 | bgc->gc.ngpio = port->ngpio; | ||
| 148 | bgc->gc.label = port->label; | ||
| 149 | |||
| 150 | bgc->gc.of_node = dev->of_node; | ||
| 151 | bgc->gc.of_gpio_n_cells = 3; | ||
| 152 | bgc->gc.of_xlate = etraxfs_gpio_of_xlate; | ||
| 153 | |||
| 154 | ret = gpiochip_add(&bgc->gc); | ||
| 155 | if (ret) | ||
| 156 | dev_err(dev, "Unable to register port %s\n", | ||
| 157 | bgc->gc.label); | ||
| 158 | } | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static struct platform_driver etraxfs_gpio_driver = { | ||
| 164 | .driver = { | ||
| 165 | .name = "etraxfs-gpio", | ||
| 166 | .of_match_table = of_match_ptr(etraxfs_gpio_of_table), | ||
| 167 | }, | ||
| 168 | .probe = etraxfs_gpio_probe, | ||
| 169 | }; | ||
| 170 | |||
| 171 | static int __init etraxfs_gpio_init(void) | ||
| 172 | { | ||
| 173 | return platform_driver_register(&etraxfs_gpio_driver); | ||
| 174 | } | ||
| 175 | |||
| 176 | device_initcall(etraxfs_gpio_init); | ||
