Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.9.4.
  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}