cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio.c (3088B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/sh/boards/mach-x3proto/gpio.c
      4 *
      5 * Renesas SH-X3 Prototype Baseboard GPIO Support.
      6 *
      7 * Copyright (C) 2010 - 2012  Paul Mundt
      8 */
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#include <linux/init.h>
     12#include <linux/interrupt.h>
     13#include <linux/gpio/driver.h>
     14#include <linux/irq.h>
     15#include <linux/kernel.h>
     16#include <linux/spinlock.h>
     17#include <linux/irqdomain.h>
     18#include <linux/io.h>
     19#include <mach/ilsel.h>
     20#include <mach/hardware.h>
     21
     22#define KEYCTLR	0xb81c0000
     23#define KEYOUTR	0xb81c0002
     24#define KEYDETR 0xb81c0004
     25
     26static DEFINE_SPINLOCK(x3proto_gpio_lock);
     27static struct irq_domain *x3proto_irq_domain;
     28
     29static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
     30{
     31	unsigned long flags;
     32	unsigned int data;
     33
     34	spin_lock_irqsave(&x3proto_gpio_lock, flags);
     35	data = __raw_readw(KEYCTLR);
     36	data |= (1 << gpio);
     37	__raw_writew(data, KEYCTLR);
     38	spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
     39
     40	return 0;
     41}
     42
     43static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
     44{
     45	return !!(__raw_readw(KEYDETR) & (1 << gpio));
     46}
     47
     48static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
     49{
     50	int virq;
     51
     52	if (gpio < chip->ngpio)
     53		virq = irq_create_mapping(x3proto_irq_domain, gpio);
     54	else
     55		virq = -ENXIO;
     56
     57	return virq;
     58}
     59
     60static void x3proto_gpio_irq_handler(struct irq_desc *desc)
     61{
     62	struct irq_data *data = irq_desc_get_irq_data(desc);
     63	struct irq_chip *chip = irq_data_get_irq_chip(data);
     64	unsigned long mask;
     65	int pin;
     66
     67	chip->irq_mask_ack(data);
     68
     69	mask = __raw_readw(KEYDETR);
     70	for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
     71		generic_handle_domain_irq(x3proto_irq_domain, pin);
     72
     73	chip->irq_unmask(data);
     74}
     75
     76struct gpio_chip x3proto_gpio_chip = {
     77	.label			= "x3proto-gpio",
     78	.direction_input	= x3proto_gpio_direction_input,
     79	.get			= x3proto_gpio_get,
     80	.to_irq			= x3proto_gpio_to_irq,
     81	.base			= -1,
     82	.ngpio			= NR_BASEBOARD_GPIOS,
     83};
     84
     85static int x3proto_gpio_irq_map(struct irq_domain *domain, unsigned int virq,
     86				irq_hw_number_t hwirq)
     87{
     88	irq_set_chip_and_handler_name(virq, &dummy_irq_chip, handle_simple_irq,
     89				      "gpio");
     90
     91	return 0;
     92}
     93
     94static struct irq_domain_ops x3proto_gpio_irq_ops = {
     95	.map	= x3proto_gpio_irq_map,
     96	.xlate	= irq_domain_xlate_twocell,
     97};
     98
     99int __init x3proto_gpio_setup(void)
    100{
    101	int ilsel, ret;
    102
    103	ilsel = ilsel_enable(ILSEL_KEY);
    104	if (unlikely(ilsel < 0))
    105		return ilsel;
    106
    107	ret = gpiochip_add_data(&x3proto_gpio_chip, NULL);
    108	if (unlikely(ret))
    109		goto err_gpio;
    110
    111	x3proto_irq_domain = irq_domain_add_linear(NULL, NR_BASEBOARD_GPIOS,
    112						   &x3proto_gpio_irq_ops, NULL);
    113	if (unlikely(!x3proto_irq_domain))
    114		goto err_irq;
    115
    116	pr_info("registering '%s' support, handling GPIOs %u -> %u, "
    117		"bound to IRQ %u\n",
    118		x3proto_gpio_chip.label, x3proto_gpio_chip.base,
    119		x3proto_gpio_chip.base + x3proto_gpio_chip.ngpio,
    120		ilsel);
    121
    122	irq_set_chained_handler(ilsel, x3proto_gpio_irq_handler);
    123	irq_set_irq_wake(ilsel, 1);
    124
    125	return 0;
    126
    127err_irq:
    128	gpiochip_remove(&x3proto_gpio_chip);
    129	ret = 0;
    130err_gpio:
    131	synchronize_irq(ilsel);
    132
    133	ilsel_disable(ILSEL_KEY);
    134
    135	return ret;
    136}