173 lines
3.8 KiB
C
173 lines
3.8 KiB
C
|
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||
|
* Use of this source code is governed by a BSD-style license that can be
|
||
|
* found in the LICENSE file.
|
||
|
*/
|
||
|
|
||
|
/* GPIO module for ISH */
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "gpio.h"
|
||
|
#include "hooks.h"
|
||
|
#include "registers.h"
|
||
|
#include "system.h"
|
||
|
#include "task.h"
|
||
|
#include "timer.h"
|
||
|
#include "util.h"
|
||
|
|
||
|
#define ISH_TOTAL_GPIO_PINS 8
|
||
|
|
||
|
test_mockable int gpio_get_level(enum gpio_signal signal)
|
||
|
{
|
||
|
const struct gpio_info *g = gpio_list + signal;
|
||
|
|
||
|
/* Unimplemented GPIOs shouldn't do anything */
|
||
|
if (g->port == DUMMY_GPIO_BANK)
|
||
|
return 0;
|
||
|
|
||
|
return !!(ISH_GPIO_GPLR & g->mask);
|
||
|
}
|
||
|
|
||
|
void gpio_set_level(enum gpio_signal signal, int value)
|
||
|
{
|
||
|
const struct gpio_info *g = gpio_list + signal;
|
||
|
|
||
|
/* Unimplemented GPIOs shouldn't do anything */
|
||
|
if (g->port == DUMMY_GPIO_BANK)
|
||
|
return;
|
||
|
|
||
|
if (value)
|
||
|
ISH_GPIO_GPSR |= g->mask;
|
||
|
else
|
||
|
ISH_GPIO_GPCR |= g->mask;
|
||
|
}
|
||
|
|
||
|
void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
|
||
|
{
|
||
|
/* Unimplemented GPIOs shouldn't do anything */
|
||
|
if (port == DUMMY_GPIO_BANK)
|
||
|
return;
|
||
|
|
||
|
/* ISH does not support level-trigger interrupts; only edge. */
|
||
|
if (flags & (GPIO_INT_F_HIGH | GPIO_INT_F_LOW)) {
|
||
|
ccprintf("\n\nISH does not support level trigger GPIO for %d "
|
||
|
"0x%02x!\n\n",
|
||
|
port, mask);
|
||
|
}
|
||
|
|
||
|
/* ISH 3 can't support both rising and falling edge */
|
||
|
if (IS_ENABLED(CHIP_FAMILY_ISH3) &&
|
||
|
(flags & GPIO_INT_F_RISING) && (flags & GPIO_INT_F_FALLING)) {
|
||
|
ccprintf("\n\nISH 2/3 does not support both rising & falling "
|
||
|
"edge for %d 0x%02x\n\n",
|
||
|
port, mask);
|
||
|
}
|
||
|
|
||
|
/* GPSR/GPCR Output high/low */
|
||
|
if (flags & GPIO_HIGH) /* Output high */
|
||
|
ISH_GPIO_GPSR |= mask;
|
||
|
else if (flags & GPIO_LOW) /* output low */
|
||
|
ISH_GPIO_GPCR |= mask;
|
||
|
|
||
|
/* GPDR pin direction 1 = output, 0 = input*/
|
||
|
if (flags & GPIO_OUTPUT)
|
||
|
ISH_GPIO_GPDR |= mask;
|
||
|
else /* GPIO_INPUT or un-configured */
|
||
|
ISH_GPIO_GPDR &= ~mask;
|
||
|
|
||
|
/* Interrupt is asserted on rising edge */
|
||
|
if (flags & GPIO_INT_F_RISING)
|
||
|
ISH_GPIO_GRER |= mask;
|
||
|
else
|
||
|
ISH_GPIO_GRER &= ~mask;
|
||
|
|
||
|
/* Interrupt is asserted on falling edge */
|
||
|
if (flags & GPIO_INT_F_FALLING)
|
||
|
ISH_GPIO_GFER |= mask;
|
||
|
else
|
||
|
ISH_GPIO_GFER &= ~mask;
|
||
|
}
|
||
|
|
||
|
int gpio_enable_interrupt(enum gpio_signal signal)
|
||
|
{
|
||
|
const struct gpio_info *g = gpio_list + signal;
|
||
|
|
||
|
/* Unimplemented GPIOs shouldn't do anything */
|
||
|
if (g->port == DUMMY_GPIO_BANK)
|
||
|
return EC_SUCCESS;
|
||
|
|
||
|
ISH_GPIO_GIMR |= g->mask;
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int gpio_disable_interrupt(enum gpio_signal signal)
|
||
|
{
|
||
|
const struct gpio_info *g = gpio_list + signal;
|
||
|
|
||
|
ISH_GPIO_GIMR &= ~g->mask;
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
int gpio_clear_pending_interrupt(enum gpio_signal signal)
|
||
|
{
|
||
|
const struct gpio_info *g = gpio_list + signal;
|
||
|
|
||
|
ISH_GPIO_GISR = g->mask;
|
||
|
return EC_SUCCESS;
|
||
|
}
|
||
|
|
||
|
void gpio_pre_init(void)
|
||
|
{
|
||
|
int i;
|
||
|
int flags;
|
||
|
int is_warm = system_is_reboot_warm();
|
||
|
const struct gpio_info *g = gpio_list;
|
||
|
|
||
|
for (i = 0; i < GPIO_COUNT; i++, g++) {
|
||
|
|
||
|
flags = g->flags;
|
||
|
|
||
|
if (flags & GPIO_DEFAULT)
|
||
|
continue;
|
||
|
|
||
|
/*
|
||
|
* If this is a warm reboot, don't set the output levels
|
||
|
* or we'll shut off the AP.
|
||
|
*/
|
||
|
if (is_warm)
|
||
|
flags &= ~(GPIO_LOW | GPIO_HIGH);
|
||
|
|
||
|
gpio_set_flags_by_mask(g->port, g->mask, flags);
|
||
|
}
|
||
|
|
||
|
/* disable GPIO interrupts */
|
||
|
ISH_GPIO_GIMR = 0;
|
||
|
/* clear pending GPIO interrupts */
|
||
|
ISH_GPIO_GISR = 0xFFFFFFFF;
|
||
|
}
|
||
|
|
||
|
static void gpio_init(void)
|
||
|
{
|
||
|
task_enable_irq(ISH_GPIO_IRQ);
|
||
|
}
|
||
|
DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);
|
||
|
|
||
|
static void gpio_interrupt(void)
|
||
|
{
|
||
|
int i;
|
||
|
const struct gpio_info *g = gpio_list;
|
||
|
uint32_t gisr = ISH_GPIO_GISR;
|
||
|
uint32_t gimr = ISH_GPIO_GIMR;
|
||
|
|
||
|
/* mask off any not enabled pins */
|
||
|
gisr &= gimr;
|
||
|
|
||
|
for (i = 0; i < GPIO_IH_COUNT; i++, g++) {
|
||
|
if (gisr & g->mask) {
|
||
|
/* write 1 to clear interrupt status bit */
|
||
|
ISH_GPIO_GISR = g->mask;
|
||
|
gpio_irq_handlers[i](i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
DECLARE_IRQ(ISH_GPIO_IRQ, gpio_interrupt);
|