Source
x
* Thus presetting the output level before switching to output is _NOT_ possible.
// SPDX-License-Identifier: GPL-2.0
/*
* GPIO interface for Intel Poulsbo SCH
*
* Copyright (c) 2010 CompuLab Ltd
* Author: Denis Turischev <denis@compulab.co.il>
*/
struct sch_gpio {
struct gpio_chip chip;
spinlock_t lock;
unsigned short iobase;
unsigned short resume_base;
};
static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
unsigned reg)
{
unsigned base = 0;
if (gpio >= sch->resume_base) {
gpio -= sch->resume_base;
base += 0x20;
}
return base + reg + gpio / 8;
}
static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
{
if (gpio >= sch->resume_base)
gpio -= sch->resume_base;
return gpio % 8;
}
static int sch_gpio_reg_get(struct sch_gpio *sch, unsigned gpio, unsigned reg)
{
unsigned short offset, bit;
u8 reg_val;
offset = sch_gpio_offset(sch, gpio, reg);
bit = sch_gpio_bit(sch, gpio);
reg_val = !!(inb(sch->iobase + offset) & BIT(bit));
return reg_val;
}
static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned gpio, unsigned reg,
int val)
{
unsigned short offset, bit;
u8 reg_val;
offset = sch_gpio_offset(sch, gpio, reg);
bit = sch_gpio_bit(sch, gpio);
reg_val = inb(sch->iobase + offset);
if (val)
outb(reg_val | BIT(bit), sch->iobase + offset);
else
outb((reg_val & ~BIT(bit)), sch->iobase + offset);
}
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
struct sch_gpio *sch = gpiochip_get_data(gc);
spin_lock(&sch->lock);
sch_gpio_reg_set(sch, gpio_num, GIO, 1);
spin_unlock(&sch->lock);
return 0;
}
static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
{
struct sch_gpio *sch = gpiochip_get_data(gc);
return sch_gpio_reg_get(sch, gpio_num, GLV);