13d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov/* 23d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * Simple Memory-Mapped GPIOs 33d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * 43d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * Copyright (c) MontaVista Software, Inc. 2008. 53d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * 63d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * Author: Anton Vorontsov <avorontsov@ru.mvista.com> 73d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * 83d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * This program is free software; you can redistribute it and/or modify it 93d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * under the terms of the GNU General Public License as published by the 103d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * Free Software Foundation; either version 2 of the License, or (at your 113d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * option) any later version. 123d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov */ 133d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 143d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/init.h> 153d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/kernel.h> 163d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/spinlock.h> 173d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/types.h> 183d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/ioport.h> 193d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/io.h> 203d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/of.h> 213d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/of_gpio.h> 223d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <linux/gpio.h> 235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 243d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include <asm/prom.h> 253d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov#include "simple_gpio.h" 263d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 273d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstruct u8_gpio_chip { 283d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct of_mm_gpio_chip mm_gc; 293d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov spinlock_t lock; 303d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 313d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov /* shadowed data register to clear/set bits safely */ 323d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8 data; 333d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov}; 343d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 353d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic struct u8_gpio_chip *to_u8_gpio_chip(struct of_mm_gpio_chip *mm_gc) 363d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 373d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return container_of(mm_gc, struct u8_gpio_chip, mm_gc); 383d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 393d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 403d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic u8 u8_pin2mask(unsigned int pin) 413d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 423d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return 1 << (8 - 1 - pin); 433d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 443d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 453d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic int u8_gpio_get(struct gpio_chip *gc, unsigned int gpio) 463d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 473d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 483d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 493d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return in_8(mm_gc->regs) & u8_pin2mask(gpio); 503d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 513d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 523d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic void u8_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 533d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 543d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); 553d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); 563d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov unsigned long flags; 573d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 583d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov spin_lock_irqsave(&u8_gc->lock, flags); 593d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 603d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov if (val) 613d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8_gc->data |= u8_pin2mask(gpio); 623d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov else 633d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8_gc->data &= ~u8_pin2mask(gpio); 643d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 653d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov out_8(mm_gc->regs, u8_gc->data); 663d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 673d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov spin_unlock_irqrestore(&u8_gc->lock, flags); 683d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 693d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 703d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic int u8_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 713d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 723d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return 0; 733d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 743d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 753d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic int u8_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 763d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 773d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8_gpio_set(gc, gpio, val); 783d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return 0; 793d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 803d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 813d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic void u8_gpio_save_regs(struct of_mm_gpio_chip *mm_gc) 823d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 833d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct u8_gpio_chip *u8_gc = to_u8_gpio_chip(mm_gc); 843d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 853d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8_gc->data = in_8(mm_gc->regs); 863d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 873d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 883d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovstatic int __init u8_simple_gpiochip_add(struct device_node *np) 893d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 903d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov int ret; 913d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct u8_gpio_chip *u8_gc; 923d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct of_mm_gpio_chip *mm_gc; 933d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct gpio_chip *gc; 943d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 953d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov u8_gc = kzalloc(sizeof(*u8_gc), GFP_KERNEL); 963d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov if (!u8_gc) 973d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return -ENOMEM; 983d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 993d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov spin_lock_init(&u8_gc->lock); 1003d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1013d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov mm_gc = &u8_gc->mm_gc; 102a19e3da5bc5fc6c10ab73f310bea80f3845b4531Anton Vorontsov gc = &mm_gc->gc; 1033d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1043d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov mm_gc->save_regs = u8_gpio_save_regs; 1053d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov gc->ngpio = 8; 1063d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov gc->direction_input = u8_gpio_dir_in; 1073d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov gc->direction_output = u8_gpio_dir_out; 1083d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov gc->get = u8_gpio_get; 1093d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov gc->set = u8_gpio_set; 1103d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1113d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov ret = of_mm_gpiochip_add(np, mm_gc); 1123d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov if (ret) 1133d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov goto err; 1143d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return 0; 1153d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsoverr: 1163d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov kfree(u8_gc); 1173d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov return ret; 1183d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 1193d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1203d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsovvoid __init simple_gpiochip_init(const char *compatible) 1213d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov{ 1223d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct device_node *np; 1233d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1243d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov for_each_compatible_node(np, NULL, compatible) { 1253d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov int ret; 1263d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov struct resource r; 1273d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1283d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov ret = of_address_to_resource(np, 0, &r); 1293d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov if (ret) 1303d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov goto err; 1313d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov 1323d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov switch (resource_size(&r)) { 1333d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov case 1: 1343d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov ret = u8_simple_gpiochip_add(np); 1353d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov if (ret) 1363d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov goto err; 1373d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov break; 1383d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov default: 1393d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov /* 1403d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * Whenever you need support for GPIO bank width > 1, 1413d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * please just turn u8_ code into huge macros, and 1423d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov * construct needed uX_ code with it. 1433d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov */ 1443d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov ret = -ENOSYS; 1453d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov goto err; 1463d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov } 1473d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov continue; 1483d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsoverr: 1493d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov pr_err("%s: registration failed, status %d\n", 1503d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov np->full_name, ret); 1513d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov } 1523d64de9c50619d32eb71d993d23a50b98d12d3c0Anton Vorontsov} 153