Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.16 222 lines 5.5 kB view raw
1/* 2 * linux/drivers/gpio/gpio-mb86s7x.c 3 * 4 * Copyright (C) 2015 Fujitsu Semiconductor Limited 5 * Copyright (C) 2015 Linaro Ltd. 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, version 2 of the License. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/io.h> 18#include <linux/init.h> 19#include <linux/clk.h> 20#include <linux/module.h> 21#include <linux/err.h> 22#include <linux/errno.h> 23#include <linux/ioport.h> 24#include <linux/of_device.h> 25#include <linux/gpio/driver.h> 26#include <linux/platform_device.h> 27#include <linux/spinlock.h> 28#include <linux/slab.h> 29 30/* 31 * Only first 8bits of a register correspond to each pin, 32 * so there are 4 registers for 32 pins. 33 */ 34#define PDR(x) (0x0 + x / 8 * 4) 35#define DDR(x) (0x10 + x / 8 * 4) 36#define PFR(x) (0x20 + x / 8 * 4) 37 38#define OFFSET(x) BIT((x) % 8) 39 40struct mb86s70_gpio_chip { 41 struct gpio_chip gc; 42 void __iomem *base; 43 struct clk *clk; 44 spinlock_t lock; 45}; 46 47static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio) 48{ 49 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 50 unsigned long flags; 51 u32 val; 52 53 spin_lock_irqsave(&gchip->lock, flags); 54 55 val = readl(gchip->base + PFR(gpio)); 56 val &= ~OFFSET(gpio); 57 writel(val, gchip->base + PFR(gpio)); 58 59 spin_unlock_irqrestore(&gchip->lock, flags); 60 61 return 0; 62} 63 64static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio) 65{ 66 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 67 unsigned long flags; 68 u32 val; 69 70 spin_lock_irqsave(&gchip->lock, flags); 71 72 val = readl(gchip->base + PFR(gpio)); 73 val |= OFFSET(gpio); 74 writel(val, gchip->base + PFR(gpio)); 75 76 spin_unlock_irqrestore(&gchip->lock, flags); 77} 78 79static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) 80{ 81 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 82 unsigned long flags; 83 unsigned char val; 84 85 spin_lock_irqsave(&gchip->lock, flags); 86 87 val = readl(gchip->base + DDR(gpio)); 88 val &= ~OFFSET(gpio); 89 writel(val, gchip->base + DDR(gpio)); 90 91 spin_unlock_irqrestore(&gchip->lock, flags); 92 93 return 0; 94} 95 96static int mb86s70_gpio_direction_output(struct gpio_chip *gc, 97 unsigned gpio, int value) 98{ 99 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 100 unsigned long flags; 101 unsigned char val; 102 103 spin_lock_irqsave(&gchip->lock, flags); 104 105 val = readl(gchip->base + PDR(gpio)); 106 if (value) 107 val |= OFFSET(gpio); 108 else 109 val &= ~OFFSET(gpio); 110 writel(val, gchip->base + PDR(gpio)); 111 112 val = readl(gchip->base + DDR(gpio)); 113 val |= OFFSET(gpio); 114 writel(val, gchip->base + DDR(gpio)); 115 116 spin_unlock_irqrestore(&gchip->lock, flags); 117 118 return 0; 119} 120 121static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio) 122{ 123 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 124 125 return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio)); 126} 127 128static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value) 129{ 130 struct mb86s70_gpio_chip *gchip = gpiochip_get_data(gc); 131 unsigned long flags; 132 unsigned char val; 133 134 spin_lock_irqsave(&gchip->lock, flags); 135 136 val = readl(gchip->base + PDR(gpio)); 137 if (value) 138 val |= OFFSET(gpio); 139 else 140 val &= ~OFFSET(gpio); 141 writel(val, gchip->base + PDR(gpio)); 142 143 spin_unlock_irqrestore(&gchip->lock, flags); 144} 145 146static int mb86s70_gpio_probe(struct platform_device *pdev) 147{ 148 struct mb86s70_gpio_chip *gchip; 149 struct resource *res; 150 int ret; 151 152 gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL); 153 if (gchip == NULL) 154 return -ENOMEM; 155 156 platform_set_drvdata(pdev, gchip); 157 158 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 159 gchip->base = devm_ioremap_resource(&pdev->dev, res); 160 if (IS_ERR(gchip->base)) 161 return PTR_ERR(gchip->base); 162 163 gchip->clk = devm_clk_get(&pdev->dev, NULL); 164 if (IS_ERR(gchip->clk)) 165 return PTR_ERR(gchip->clk); 166 167 ret = clk_prepare_enable(gchip->clk); 168 if (ret) 169 return ret; 170 171 spin_lock_init(&gchip->lock); 172 173 gchip->gc.direction_output = mb86s70_gpio_direction_output; 174 gchip->gc.direction_input = mb86s70_gpio_direction_input; 175 gchip->gc.request = mb86s70_gpio_request; 176 gchip->gc.free = mb86s70_gpio_free; 177 gchip->gc.get = mb86s70_gpio_get; 178 gchip->gc.set = mb86s70_gpio_set; 179 gchip->gc.label = dev_name(&pdev->dev); 180 gchip->gc.ngpio = 32; 181 gchip->gc.owner = THIS_MODULE; 182 gchip->gc.parent = &pdev->dev; 183 gchip->gc.base = -1; 184 185 ret = gpiochip_add_data(&gchip->gc, gchip); 186 if (ret) { 187 dev_err(&pdev->dev, "couldn't register gpio driver\n"); 188 clk_disable_unprepare(gchip->clk); 189 } 190 191 return ret; 192} 193 194static int mb86s70_gpio_remove(struct platform_device *pdev) 195{ 196 struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev); 197 198 gpiochip_remove(&gchip->gc); 199 clk_disable_unprepare(gchip->clk); 200 201 return 0; 202} 203 204static const struct of_device_id mb86s70_gpio_dt_ids[] = { 205 { .compatible = "fujitsu,mb86s70-gpio" }, 206 { /* sentinel */ } 207}; 208MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids); 209 210static struct platform_driver mb86s70_gpio_driver = { 211 .driver = { 212 .name = "mb86s70-gpio", 213 .of_match_table = mb86s70_gpio_dt_ids, 214 }, 215 .probe = mb86s70_gpio_probe, 216 .remove = mb86s70_gpio_remove, 217}; 218module_platform_driver(mb86s70_gpio_driver); 219 220MODULE_DESCRIPTION("MB86S7x GPIO Driver"); 221MODULE_ALIAS("platform:mb86s70-gpio"); 222MODULE_LICENSE("GPL");