root/arch/m68k/coldfire/gpio.c
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Coldfire generic GPIO support.
 *
 * (C) Copyright 2009, Steven King <sfking@fdwdc.com>
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>

#include <linux/io.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include <asm/mcfgpio.h>

int __mcfgpio_get_value(unsigned gpio)
{
        return mcfgpio_read(__mcfgpio_ppdr(gpio)) & mcfgpio_bit(gpio);
}
EXPORT_SYMBOL(__mcfgpio_get_value);

void __mcfgpio_set_value(unsigned gpio, int value)
{
        if (gpio < MCFGPIO_SCR_START) {
                unsigned long flags;
                MCFGPIO_PORTTYPE data;

                local_irq_save(flags);
                data = mcfgpio_read(__mcfgpio_podr(gpio));
                if (value)
                        data |= mcfgpio_bit(gpio);
                else
                        data &= ~mcfgpio_bit(gpio);
                mcfgpio_write(data, __mcfgpio_podr(gpio));
                local_irq_restore(flags);
        } else {
                if (value)
                        mcfgpio_write(mcfgpio_bit(gpio),
                                        MCFGPIO_SETR_PORT(gpio));
                else
                        mcfgpio_write(~mcfgpio_bit(gpio),
                                        MCFGPIO_CLRR_PORT(gpio));
        }
}
EXPORT_SYMBOL(__mcfgpio_set_value);

int __mcfgpio_direction_input(unsigned gpio)
{
        unsigned long flags;
        MCFGPIO_PORTTYPE dir;

        local_irq_save(flags);
        dir = mcfgpio_read(__mcfgpio_pddr(gpio));
        dir &= ~mcfgpio_bit(gpio);
        mcfgpio_write(dir, __mcfgpio_pddr(gpio));
        local_irq_restore(flags);

        return 0;
}
EXPORT_SYMBOL(__mcfgpio_direction_input);

int __mcfgpio_direction_output(unsigned gpio, int value)
{
        unsigned long flags;
        MCFGPIO_PORTTYPE data;

        local_irq_save(flags);
        data = mcfgpio_read(__mcfgpio_pddr(gpio));
        data |= mcfgpio_bit(gpio);
        mcfgpio_write(data, __mcfgpio_pddr(gpio));

        /* now set the data to output */
        if (gpio < MCFGPIO_SCR_START) {
                data = mcfgpio_read(__mcfgpio_podr(gpio));
                if (value)
                        data |= mcfgpio_bit(gpio);
                else
                        data &= ~mcfgpio_bit(gpio);
                mcfgpio_write(data, __mcfgpio_podr(gpio));
        } else {
                 if (value)
                        mcfgpio_write(mcfgpio_bit(gpio),
                                        MCFGPIO_SETR_PORT(gpio));
                 else
                         mcfgpio_write(~mcfgpio_bit(gpio),
                                         MCFGPIO_CLRR_PORT(gpio));
        }
        local_irq_restore(flags);
        return 0;
}
EXPORT_SYMBOL(__mcfgpio_direction_output);

int __mcfgpio_request(unsigned gpio)
{
        return 0;
}
EXPORT_SYMBOL(__mcfgpio_request);

void __mcfgpio_free(unsigned gpio)
{
        __mcfgpio_direction_input(gpio);
}
EXPORT_SYMBOL(__mcfgpio_free);

#ifdef CONFIG_GPIOLIB

static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
        return __mcfgpio_direction_input(offset);
}

static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
{
        return !!__mcfgpio_get_value(offset);
}

static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                    int value)
{
        return __mcfgpio_direction_output(offset, value);
}

static int mcfgpio_set_value(struct gpio_chip *chip, unsigned int offset,
                             int value)
{
        __mcfgpio_set_value(offset, value);

        return 0;
}

static int mcfgpio_request(struct gpio_chip *chip, unsigned offset)
{
        return __mcfgpio_request(offset);
}

static void mcfgpio_free(struct gpio_chip *chip, unsigned offset)
{
        __mcfgpio_free(offset);
}

static int mcfgpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
#if defined(MCFGPIO_IRQ_MIN)
        if ((offset >= MCFGPIO_IRQ_MIN) && (offset < MCFGPIO_IRQ_MAX))
#else
        if (offset < MCFGPIO_IRQ_MAX)
#endif
                return MCFGPIO_IRQ_VECBASE + offset;
        else
                return -EINVAL;
}

static struct gpio_chip mcfgpio_chip = {
        .label                  = "mcfgpio",
        .request                = mcfgpio_request,
        .free                   = mcfgpio_free,
        .direction_input        = mcfgpio_direction_input,
        .direction_output       = mcfgpio_direction_output,
        .get                    = mcfgpio_get_value,
        .set                    = mcfgpio_set_value,
        .to_irq                 = mcfgpio_to_irq,
        .base                   = 0,
        .ngpio                  = MCFGPIO_PIN_MAX,
};

static int __init mcfgpio_sysinit(void)
{
        return gpiochip_add_data(&mcfgpio_chip, NULL);
}

core_initcall(mcfgpio_sysinit);
#endif