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