Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.8-rc2 147 lines 3.2 kB view raw
1/* 2 * Simple Memory-Mapped GPIOs 3 * 4 * Copyright (c) MontaVista Software, Inc. 2008. 5 * 6 * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14#include <linux/init.h> 15#include <linux/kernel.h> 16#include <linux/spinlock.h> 17#include <linux/types.h> 18#include <linux/ioport.h> 19#include <linux/io.h> 20#include <linux/of.h> 21#include <linux/of_gpio.h> 22#include <linux/gpio/driver.h> 23#include <linux/slab.h> 24#include <asm/prom.h> 25#include "simple_gpio.h" 26 27struct u8_gpio_chip { 28 struct of_mm_gpio_chip mm_gc; 29 spinlock_t lock; 30 31 /* shadowed data register to clear/set bits safely */ 32 u8 data; 33}; 34 35static u8 u8_pin2mask(unsigned int pin) 36{ 37 return 1 << (8 - 1 - pin); 38} 39 40static int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) 41{ 42 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 43 44 return !!(in_8(mm_gc->regs) & u8_pin2mask(gpio)); 45} 46 47static void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 48{ 49 struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 50 struct u8_gpio_chip *u8_gc = gpiochip_get_data(gc); 51 unsigned long flags; 52 53 spin_lock_irqsave(&u8_gc->lock, flags); 54 55 if (val) 56 u8_gc->data |= u8_pin2mask(gpio); 57 else 58 u8_gc->data &= ~u8_pin2mask(gpio); 59 60 out_8(mm_gc->regs, u8_gc->data); 61 62 spin_unlock_irqrestore(&u8_gc->lock, flags); 63} 64 65static int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 66{ 67 return 0; 68} 69 70static int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 71{ 72 u8_gpio_set(gc, gpio, val); 73 return 0; 74} 75 76static void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) 77{ 78 struct u8_gpio_chip *u8_gc = gpiochip_get_data(&mm_gc->gc); 79 80 u8_gc->data = in_8(mm_gc->regs); 81} 82 83static int __init u8_simple_gpiochip_add(struct device_node *np) 84{ 85 int ret; 86 struct u8_gpio_chip *u8_gc; 87 struct of_mm_gpio_chip *mm_gc; 88 struct gpio_chip *gc; 89 90 u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL); 91 if (!u8_gc) 92 return -ENOMEM; 93 94 spin_lock_init(&u8_gc->lock); 95 96 mm_gc = &u8_gc->mm_gc; 97 gc = &mm_gc->gc; 98 99 mm_gc->save_regs = u8_gpio_save_regs; 100 gc->ngpio = 8; 101 gc->direction_input = u8_gpio_dir_in; 102 gc->direction_output = u8_gpio_dir_out; 103 gc->get = u8_gpio_get; 104 gc->set = u8_gpio_set; 105 106 ret = of_mm_gpiochip_add_data(np, mm_gc, u8_gc); 107 if (ret) 108 goto err; 109 return 0; 110err: 111 kfree(u8_gc); 112 return ret; 113} 114 115void __init simple_gpiochip_init(const char *compatible) 116{ 117 struct device_node *np; 118 119 for_each_compatible_node(np, NULL, compatible) { 120 int ret; 121 struct resource r; 122 123 ret = of_address_to_resource(np, 0, &r); 124 if (ret) 125 goto err; 126 127 switch (resource_size(&r)) { 128 case 1: 129 ret = u8_simple_gpiochip_add(np); 130 if (ret) 131 goto err; 132 break; 133 default: 134 /* 135 * Whenever you need support for GPIO bank width > 1, 136 * please just turn u8_ code into huge macros, and 137 * construct needed uX_ code with it. 138 */ 139 ret = -ENOSYS; 140 goto err; 141 } 142 continue; 143err: 144 pr_err("%s: registration failed, status %d\n", 145 np->full_name, ret); 146 } 147}