diff options
Diffstat (limited to 'chip/lm4/gpio.c')
-rw-r--r-- | chip/lm4/gpio.c | 385 |
1 files changed, 0 insertions, 385 deletions
diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c deleted file mode 100644 index 841bfdb214..0000000000 --- a/chip/lm4/gpio.c +++ /dev/null @@ -1,385 +0,0 @@ -/* Copyright 2012 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 Chrome EC */ - -#include "clock.h" -#include "common.h" -#include "gpio.h" -#include "hooks.h" -#include "registers.h" -#include "switch.h" -#include "task.h" -#include "timer.h" -#include "util.h" - -/* 0-terminated list of GPIO base addresses */ -static const uint32_t gpio_bases[] = { - LM4_GPIO_A, LM4_GPIO_B, LM4_GPIO_C, LM4_GPIO_D, - LM4_GPIO_E, LM4_GPIO_F, LM4_GPIO_G, LM4_GPIO_H, - LM4_GPIO_J, LM4_GPIO_K, LM4_GPIO_L, LM4_GPIO_M, - LM4_GPIO_N, LM4_GPIO_P, LM4_GPIO_Q, 0 -}; - -/** - * Find the index of a GPIO port base address - * - * This is used by the clock gating registers. - * - * @param port_base Base address to find (LM4_GPIO_[A-Q]) - * - * @return The index, or -1 if no match. - */ -static int find_gpio_port_index(uint32_t port_base) -{ - int i; - for (i = 0; gpio_bases[i]; i++) { - if (gpio_bases[i] == port_base) - return i; - } - return -1; -} - -void gpio_set_alternate_function(uint32_t port, uint32_t mask, - enum gpio_alternate_func func) -{ - int port_index = find_gpio_port_index(port); - int cgmask; - - /* Ignore (do nothing for) invalid port values */ - if (port_index < 0) - return; - - /* Enable the GPIO port in run and sleep. */ - cgmask = 1 << port_index; - clock_enable_peripheral(CGC_OFFSET_GPIO, cgmask, - CGC_MODE_RUN | CGC_MODE_SLEEP); - - if (func != GPIO_ALT_FUNC_NONE) { - int pctlmask = 0; - int i; - /* Expand mask from bits to nibbles */ - for (i = 0; i < 8; i++) { - if (mask & BIT(i)) - pctlmask |= 1 << (4 * i); - } - - LM4_GPIO_PCTL(port) = - (LM4_GPIO_PCTL(port) & ~(pctlmask * 0xf)) | - (pctlmask * func); - LM4_GPIO_AFSEL(port) |= mask; - } else { - LM4_GPIO_AFSEL(port) &= ~mask; - } -} - -test_mockable int gpio_get_level(enum gpio_signal signal) -{ - return LM4_GPIO_DATA(gpio_list[signal].port, - gpio_list[signal].mask) ? 1 : 0; -} - -void gpio_set_level(enum gpio_signal signal, int value) -{ - /* - * Ok to write 0xff because LM4_GPIO_DATA bit-masks only the bit - * we care about. - */ - LM4_GPIO_DATA(gpio_list[signal].port, - gpio_list[signal].mask) = (value ? 0xff : 0); -} - -void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags) -{ - /* - * Select open drain first, so that we don't glitch the signal - * when changing the line to an output. - */ - if (flags & GPIO_OPEN_DRAIN) - LM4_GPIO_ODR(port) |= mask; - else - LM4_GPIO_ODR(port) &= ~mask; - - if (flags & GPIO_OUTPUT) - LM4_GPIO_DIR(port) |= mask; - else - LM4_GPIO_DIR(port) &= ~mask; - - /* Handle pullup / pulldown */ - if (flags & GPIO_PULL_UP) { - LM4_GPIO_PUR(port) |= mask; - } else if (flags & GPIO_PULL_DOWN) { - LM4_GPIO_PDR(port) |= mask; - } else { - /* No pull up/down */ - LM4_GPIO_PUR(port) &= ~mask; - LM4_GPIO_PDR(port) &= ~mask; - } - - /* Set up interrupt type */ - if (flags & (GPIO_INT_F_LOW | GPIO_INT_F_HIGH)) - LM4_GPIO_IS(port) |= mask; - else - LM4_GPIO_IS(port) &= ~mask; - - if (flags & (GPIO_INT_F_RISING | GPIO_INT_F_HIGH)) - LM4_GPIO_IEV(port) |= mask; - else - LM4_GPIO_IEV(port) &= ~mask; - - /* Handle interrupting on both edges */ - if ((flags & GPIO_INT_F_RISING) && - (flags & GPIO_INT_F_FALLING)) - LM4_GPIO_IBE(port) |= mask; - else - LM4_GPIO_IBE(port) &= ~mask; - - if (flags & GPIO_ANALOG) - LM4_GPIO_DEN(port) &= ~mask; - else - LM4_GPIO_DEN(port) |= mask; - - /* Set level */ - if (flags & GPIO_HIGH) - LM4_GPIO_DATA(port, mask) = 0xff; - else if (flags & GPIO_LOW) - LM4_GPIO_DATA(port, mask) = 0; -} - -int gpio_enable_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_UNKNOWN; - - LM4_GPIO_IM(g->port) |= g->mask; - return EC_SUCCESS; -} - -int gpio_disable_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_UNKNOWN; - - LM4_GPIO_IM(g->port) &= ~g->mask; - return EC_SUCCESS; -} - -int gpio_clear_pending_interrupt(enum gpio_signal signal) -{ - const struct gpio_info *g = gpio_list + signal; - - /* Fail if no interrupt handler */ - if (signal >= GPIO_IH_COUNT) - return EC_ERROR_INVAL; - - LM4_GPIO_ICR(g->port) |= g->mask; - return EC_SUCCESS; -} - -#ifdef CONFIG_LOW_POWER_IDLE -/** - * Convert GPIO port to a mask that can be used to set the - * clock gate control register for GPIOs. - */ -static int gpio_port_to_clock_gate_mask(uint32_t gpio_port) -{ - int index = find_gpio_port_index(gpio_port); - - return index >= 0 ? BIT(index) : 0; -} -#endif - -void gpio_pre_init(void) -{ - const struct gpio_info *g = gpio_list; - int is_warm = 0; - int i; - - if (LM4_SYSTEM_RCGCGPIO == 0x7fff) { - /* This is a warm reboot */ - is_warm = 1; - } else { - /* - * Enable clocks to all the GPIO blocks since we use all of - * them as GPIOs in run and sleep modes. - */ - clock_enable_peripheral(CGC_OFFSET_GPIO, 0x7fff, - CGC_MODE_RUN | CGC_MODE_SLEEP); - } - - /* - * Disable GPIO commit control for PD7 and PF0, since we don't use the - * NMI pin function. - */ - LM4_GPIO_LOCK(LM4_GPIO_D) = LM4_GPIO_LOCK_UNLOCK; - LM4_GPIO_CR(LM4_GPIO_D) |= 0x80; - LM4_GPIO_LOCK(LM4_GPIO_D) = 0; - LM4_GPIO_LOCK(LM4_GPIO_F) = LM4_GPIO_LOCK_UNLOCK; - LM4_GPIO_CR(LM4_GPIO_F) |= 0x01; - LM4_GPIO_LOCK(LM4_GPIO_F) = 0; - - /* Clear SSI0 alternate function on PA2:5 */ - LM4_GPIO_AFSEL(LM4_GPIO_A) &= ~0x3c; - - /* Mask all GPIO interrupts */ - for (i = 0; gpio_bases[i]; i++) - LM4_GPIO_IM(gpio_bases[i]) = 0; - - /* Set all GPIOs to defaults */ - for (i = 0; i < GPIO_COUNT; i++, g++) { - int flags = g->flags; - - if (flags & GPIO_DEFAULT) - continue; - -#ifdef CONFIG_LOW_POWER_IDLE - /* - * Enable board specific GPIO ports to interrupt deep sleep by - * providing a clock to that port in deep sleep mode. - */ - if (flags & GPIO_INT_DSLEEP) { - clock_enable_peripheral(CGC_OFFSET_GPIO, - gpio_port_to_clock_gate_mask(g->port), - CGC_MODE_ALL); - } -#endif - - /* - * If this is a warm reboot, don't set the output levels or - * we'll shut off the main chipset. - */ - if (is_warm) - flags &= ~(GPIO_LOW | GPIO_HIGH); - - /* Set up GPIO based on flags */ - gpio_set_flags_by_mask(g->port, g->mask, flags); - - /* Use as GPIO, not alternate function */ - gpio_set_alternate_function(g->port, g->mask, - GPIO_ALT_FUNC_NONE); - } - -#ifdef CONFIG_LOW_POWER_IDLE - /* - * Enable KB scan row to interrupt deep sleep by providing a clock - * signal to that port in deep sleep mode. - */ - clock_enable_peripheral(CGC_OFFSET_GPIO, - gpio_port_to_clock_gate_mask(KB_SCAN_ROW_GPIO), - CGC_MODE_ALL); -#endif -} - -/* List of GPIO IRQs to enable. Don't automatically enable interrupts for - * the keyboard input GPIO bank - that's handled separately. Of course the - * bank is different for different systems. */ -static const uint8_t gpio_irqs[] = { - LM4_IRQ_GPIOA, LM4_IRQ_GPIOB, LM4_IRQ_GPIOC, LM4_IRQ_GPIOD, - LM4_IRQ_GPIOE, LM4_IRQ_GPIOF, LM4_IRQ_GPIOG, LM4_IRQ_GPIOH, - LM4_IRQ_GPIOJ, -#if defined(KB_SCAN_ROW_IRQ) && (KB_SCAN_ROW_IRQ != LM4_IRQ_GPIOK) - LM4_IRQ_GPIOK, -#endif - LM4_IRQ_GPIOL, LM4_IRQ_GPIOM, -#if defined(KB_SCAN_ROW_IRQ) && (KB_SCAN_ROW_IRQ != LM4_IRQ_GPION) - LM4_IRQ_GPION, -#endif - LM4_IRQ_GPIOP, LM4_IRQ_GPIOQ -}; - -static void gpio_init(void) -{ - int i; - - /* Enable IRQs now that pins are set up */ - for (i = 0; i < ARRAY_SIZE(gpio_irqs); i++) - task_enable_irq(gpio_irqs[i]); -} -DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT); - -/*****************************************************************************/ -/* Interrupt handlers */ - -/** - * Handle a GPIO interrupt. - * - * @param port GPIO port (LM4_GPIO_*) - * @param mis Masked interrupt status value for that port - */ -static void gpio_interrupt(int port, uint32_t mis) -{ - int i = 0; - const struct gpio_info *g = gpio_list; - - for (i = 0; i < GPIO_IH_COUNT && mis; i++, g++) { - if (port == g->port && (mis & g->mask)) { - gpio_irq_handlers[i](i); - mis &= ~g->mask; - } - } -} - -/** - * Handlers for each GPIO port. These read and clear the interrupt bits for - * the port, then call the main handler above. - */ -#define GPIO_IRQ_FUNC(irqfunc, gpiobase) \ - void irqfunc(void) \ - { \ - uint32_t mis = LM4_GPIO_MIS(gpiobase); \ - LM4_GPIO_ICR(gpiobase) = mis; \ - gpio_interrupt(gpiobase, mis); \ - } - -GPIO_IRQ_FUNC(__gpio_a_interrupt, LM4_GPIO_A); -GPIO_IRQ_FUNC(__gpio_b_interrupt, LM4_GPIO_B); -GPIO_IRQ_FUNC(__gpio_c_interrupt, LM4_GPIO_C); -GPIO_IRQ_FUNC(__gpio_d_interrupt, LM4_GPIO_D); -GPIO_IRQ_FUNC(__gpio_e_interrupt, LM4_GPIO_E); -GPIO_IRQ_FUNC(__gpio_f_interrupt, LM4_GPIO_F); -GPIO_IRQ_FUNC(__gpio_g_interrupt, LM4_GPIO_G); -GPIO_IRQ_FUNC(__gpio_h_interrupt, LM4_GPIO_H); -GPIO_IRQ_FUNC(__gpio_j_interrupt, LM4_GPIO_J); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_K) -GPIO_IRQ_FUNC(__gpio_k_interrupt, LM4_GPIO_K); -#endif -GPIO_IRQ_FUNC(__gpio_l_interrupt, LM4_GPIO_L); -GPIO_IRQ_FUNC(__gpio_m_interrupt, LM4_GPIO_M); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_N) -GPIO_IRQ_FUNC(__gpio_n_interrupt, LM4_GPIO_N); -#endif -GPIO_IRQ_FUNC(__gpio_p_interrupt, LM4_GPIO_P); -GPIO_IRQ_FUNC(__gpio_q_interrupt, LM4_GPIO_Q); - -#undef GPIO_IRQ_FUNC - -/* - * Declare IRQs. Nesting this macro inside the GPIO_IRQ_FUNC macro works - * poorly because DECLARE_IRQ() stringizes its inputs. - */ -DECLARE_IRQ(LM4_IRQ_GPIOA, __gpio_a_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOB, __gpio_b_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOC, __gpio_c_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOD, __gpio_d_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOE, __gpio_e_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOF, __gpio_f_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOG, __gpio_g_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOH, __gpio_h_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOJ, __gpio_j_interrupt, 1); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_K) -DECLARE_IRQ(LM4_IRQ_GPIOK, __gpio_k_interrupt, 1); -#endif -DECLARE_IRQ(LM4_IRQ_GPIOL, __gpio_l_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOM, __gpio_m_interrupt, 1); -#if defined(KB_SCAN_ROW_GPIO) && (KB_SCAN_ROW_GPIO != LM4_GPIO_N) -DECLARE_IRQ(LM4_IRQ_GPION, __gpio_n_interrupt, 1); -#endif -DECLARE_IRQ(LM4_IRQ_GPIOP, __gpio_p_interrupt, 1); -DECLARE_IRQ(LM4_IRQ_GPIOQ, __gpio_q_interrupt, 1); |