|
@@ -3,14 +3,20 @@
|
|
|
*
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
*
|
|
|
+ * Change Logs:
|
|
|
+ * Date Author Notes
|
|
|
+ * 2015-06-19 ItsEddy add gpio driver support
|
|
|
+ * 2022-09-14 YangZhongQing full gpio driver support
|
|
|
+ * I referred AM335X_StarterWare_02_00_01_01
|
|
|
*/
|
|
|
|
|
|
-
|
|
|
+#include <ctype.h>
|
|
|
#include <rthw.h>
|
|
|
#include <rtthread.h>
|
|
|
#include <rtdevice.h>
|
|
|
|
|
|
#include <am33xx.h>
|
|
|
+#include <interrupt.h>
|
|
|
#include "gpio.h"
|
|
|
|
|
|
#ifdef RT_USING_PIN
|
|
@@ -20,12 +26,31 @@
|
|
|
#define GPIO_PIN_LOW (0x0)
|
|
|
#define GPIO_PIN_HIGH (0x1)
|
|
|
|
|
|
-#define GPIO_CLEARDATAOUT (0x190)
|
|
|
-#define GPIO_SETDATAOUT (0x194)
|
|
|
-#define GPIO_DATAIN (0x138)
|
|
|
-#define GPIO_OE (0x134)
|
|
|
+/* Values denoting the Interrupt Line number to be used. */
|
|
|
+#define GPIO_INT_LINE_1 (0x0)
|
|
|
+#define GPIO_INT_LINE_2 (0x1)
|
|
|
+
|
|
|
+#define GPIO_REVISION (0x0)
|
|
|
+#define GPIO_SYSCONFIG (0x10)
|
|
|
+#define GPIO_IRQSTATUS_RAW(n) (0x24 + (n * 4))
|
|
|
+#define GPIO_IRQSTATUS(n) (0x2C + (n * 4))
|
|
|
+#define GPIO_IRQSTATUS_SET(n) (0x34 + (n * 4))
|
|
|
+#define GPIO_IRQSTATUS_CLR(n) (0x3C + (n * 4))
|
|
|
+#define GPIO_IRQWAKEN(n) (0x44 + (n * 4))
|
|
|
+#define GPIO_SYSSTATUS (0x114)
|
|
|
+#define GPIO_CTRL (0x130)
|
|
|
+#define GPIO_OE (0x134)
|
|
|
+#define GPIO_DATAIN (0x138)
|
|
|
+#define GPIO_DATAOUT (0x13C)
|
|
|
+#define GPIO_LEVELDETECT(n) (0x140 + (n * 4))
|
|
|
+#define GPIO_RISINGDETECT (0x148)
|
|
|
+#define GPIO_FALLINGDETECT (0x14C)
|
|
|
+#define GPIO_DEBOUNCENABLE (0x150)
|
|
|
+#define GPIO_DEBOUNCINGTIME (0x154)
|
|
|
+#define GPIO_CLEARDATAOUT (0x190)
|
|
|
+#define GPIO_SETDATAOUT (0x194)
|
|
|
|
|
|
-static rt_base_t GPIO_BASE[] =
|
|
|
+static const rt_base_t GPIO_BASE[] =
|
|
|
{
|
|
|
AM33XX_GPIO_0_REGS,
|
|
|
AM33XX_GPIO_1_REGS,
|
|
@@ -33,6 +58,85 @@ static rt_base_t GPIO_BASE[] =
|
|
|
AM33XX_GPIO_3_REGS
|
|
|
};
|
|
|
|
|
|
+#define GPIO_INT0x GPIO_INT0A
|
|
|
+#define GPIO_INT1x GPIO_INT1A
|
|
|
+#define GPIO_INT2x GPIO_INT2A
|
|
|
+#define GPIO_INT3x GPIO_INT3A
|
|
|
+static const rt_uint8_t GPIO_INTx[] = {GPIO_INT0x, GPIO_INT1x, GPIO_INT2x, GPIO_INT3x};
|
|
|
+
|
|
|
+// auto determine which int line
|
|
|
+#define GPIO_INT0_LINE ((GPIO_INT0x == GPIO_INT0A) ? GPIO_INT_LINE_1 : GPIO_INT_LINE_2)
|
|
|
+#define GPIO_INT1_LINE ((GPIO_INT1x == GPIO_INT1A) ? GPIO_INT_LINE_1 : GPIO_INT_LINE_2)
|
|
|
+#define GPIO_INT2_LINE ((GPIO_INT2x == GPIO_INT2A) ? GPIO_INT_LINE_1 : GPIO_INT_LINE_2)
|
|
|
+#define GPIO_INT3_LINE ((GPIO_INT3x == GPIO_INT3A) ? GPIO_INT_LINE_1 : GPIO_INT_LINE_2)
|
|
|
+static const rt_uint8_t GPIO_INT_LINEx[] = {GPIO_INT0_LINE, GPIO_INT1_LINE, GPIO_INT2_LINE, GPIO_INT3_LINE};
|
|
|
+
|
|
|
+struct am33xx_pin_irq_hdr
|
|
|
+{
|
|
|
+ void (*hdr)(void *args);
|
|
|
+ void *args;
|
|
|
+};
|
|
|
+
|
|
|
+struct am33xx_gpio_irq_param
|
|
|
+{
|
|
|
+ struct am33xx_pin_irq_hdr hdr_tab[32];
|
|
|
+};
|
|
|
+
|
|
|
+static struct am33xx_gpio_irq_param GPIO_PARAMx[sizeof(GPIO_BASE) / sizeof(GPIO_BASE[0])];
|
|
|
+
|
|
|
+rt_inline void am33xx_gpio_hdr(rt_base_t base, rt_base_t int_line, void *param)
|
|
|
+{
|
|
|
+ struct am33xx_gpio_irq_param *irq_param = param;
|
|
|
+ struct am33xx_pin_irq_hdr *irq_hdr;
|
|
|
+ int pinNumber;
|
|
|
+ rt_ubase_t irqstatus;
|
|
|
+
|
|
|
+ irqstatus = REG32(base + GPIO_IRQSTATUS(int_line));
|
|
|
+ REG32(base + GPIO_IRQSTATUS(int_line)) = irqstatus;
|
|
|
+
|
|
|
+ for (pinNumber = 0; pinNumber < sizeof(irq_param->hdr_tab); pinNumber++)
|
|
|
+ {
|
|
|
+ if (irqstatus & 0x1)
|
|
|
+ {
|
|
|
+ irq_hdr = &irq_param->hdr_tab[pinNumber];
|
|
|
+ if (irq_hdr->hdr)
|
|
|
+ irq_hdr->hdr(irq_hdr->args);
|
|
|
+ // if the last one, exit immediately
|
|
|
+ if (irqstatus == 0x1)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ irqstatus >>= 1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void am33xx_gpio0_isr(int vector, void *param)
|
|
|
+{
|
|
|
+ am33xx_gpio_hdr(AM33XX_GPIO_0_REGS, GPIO_INT0_LINE, param);
|
|
|
+}
|
|
|
+
|
|
|
+static void am33xx_gpio1_isr(int vector, void *param)
|
|
|
+{
|
|
|
+ am33xx_gpio_hdr(AM33XX_GPIO_1_REGS, GPIO_INT1_LINE, param);
|
|
|
+}
|
|
|
+
|
|
|
+static void am33xx_gpio2_isr(int vector, void *param)
|
|
|
+{
|
|
|
+ am33xx_gpio_hdr(AM33XX_GPIO_2_REGS, GPIO_INT2_LINE, param);
|
|
|
+}
|
|
|
+
|
|
|
+static void am33xx_gpio3_isr(int vector, void *param)
|
|
|
+{
|
|
|
+ am33xx_gpio_hdr(AM33XX_GPIO_3_REGS, GPIO_INT3_LINE, param);
|
|
|
+}
|
|
|
+
|
|
|
+static const rt_isr_handler_t GPIO_ISRx[] =
|
|
|
+{
|
|
|
+ am33xx_gpio0_isr,
|
|
|
+ am33xx_gpio1_isr,
|
|
|
+ am33xx_gpio2_isr,
|
|
|
+ am33xx_gpio3_isr,
|
|
|
+};
|
|
|
+
|
|
|
static void am33xx_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t mode)
|
|
|
{
|
|
|
RT_ASSERT(pin >= 0 && pin < 128);
|
|
@@ -40,11 +144,11 @@ static void am33xx_pin_mode(struct rt_device *device, rt_base_t pin, rt_base_t m
|
|
|
rt_base_t gpiox = pin >> 5;
|
|
|
rt_base_t pinNumber = pin & 0x1F;
|
|
|
|
|
|
- if(PIN_MODE_OUTPUT == mode)
|
|
|
+ if (PIN_MODE_OUTPUT == mode)
|
|
|
{
|
|
|
reg(GPIO_BASE[gpiox] + GPIO_OE) &= ~(1 << pinNumber);
|
|
|
}
|
|
|
- else if(PIN_MODE_INPUT == mode)
|
|
|
+ else if (PIN_MODE_INPUT == mode)
|
|
|
{
|
|
|
reg(GPIO_BASE[gpiox] + GPIO_OE) |= (1 << pinNumber);
|
|
|
}
|
|
@@ -56,7 +160,7 @@ static void am33xx_pin_write(struct rt_device *device, rt_base_t pin, rt_base_t
|
|
|
rt_base_t gpiox = pin >> 5;
|
|
|
rt_base_t pinNumber = pin & 0x1F;
|
|
|
|
|
|
- if(GPIO_PIN_HIGH == value)
|
|
|
+ if (GPIO_PIN_HIGH == value)
|
|
|
{
|
|
|
reg(GPIO_BASE[gpiox] + GPIO_SETDATAOUT) = (1 << pinNumber);
|
|
|
}
|
|
@@ -75,20 +179,196 @@ static int am33xx_pin_read(struct rt_device *device, rt_base_t pin)
|
|
|
return reg(GPIO_BASE[gpiox] + GPIO_DATAIN) & (1 << pinNumber) ? 1 : 0;
|
|
|
}
|
|
|
|
|
|
-static struct rt_pin_ops am33xx_pin_ops =
|
|
|
+static rt_err_t am33xx_pin_attach_irq(struct rt_device *device, rt_int32_t pin,
|
|
|
+ rt_uint32_t mode, void (*hdr)(void *args), void *args)
|
|
|
+{
|
|
|
+ RT_ASSERT(pin >= 0 && pin < 128);
|
|
|
+ rt_base_t gpiox = pin >> 5;
|
|
|
+ rt_base_t pinNumber = pin & 0x1F;
|
|
|
+ rt_base_t baseAdd = GPIO_BASE[gpiox];
|
|
|
+ struct am33xx_pin_irq_hdr *irq_hdr = &GPIO_PARAMx[gpiox].hdr_tab[pinNumber];
|
|
|
+ rt_base_t level;
|
|
|
+
|
|
|
+ level = rt_hw_interrupt_disable();
|
|
|
+
|
|
|
+ if (irq_hdr->hdr != RT_NULL)
|
|
|
+ {
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
+ return -RT_EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ irq_hdr->hdr = hdr;
|
|
|
+ irq_hdr->args = args;
|
|
|
+
|
|
|
+ switch (mode)
|
|
|
+ {
|
|
|
+ case PIN_IRQ_MODE_RISING:
|
|
|
+ /* Enabling rising edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_RISINGDETECT) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling falling edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_FALLINGDETECT) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic LOW level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(0)) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic HIGH level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(1)) &= ~(1 << pinNumber);
|
|
|
+ break;
|
|
|
+ case PIN_IRQ_MODE_FALLING:
|
|
|
+ /* Disabling rising edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_RISINGDETECT) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Enabling falling edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_FALLINGDETECT) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic LOW level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(0)) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic HIGH level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(1)) &= ~(1 << pinNumber);
|
|
|
+ break;
|
|
|
+ case PIN_IRQ_MODE_RISING_FALLING:
|
|
|
+ /* Enabling rising edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_RISINGDETECT) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Enabling falling edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_FALLINGDETECT) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic LOW level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(0)) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic HIGH level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(1)) &= ~(1 << pinNumber);
|
|
|
+ break;
|
|
|
+ case PIN_IRQ_MODE_HIGH_LEVEL:
|
|
|
+ /* Disabling logic LOW level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(0)) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Enabling logic HIGH level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(1)) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling rising edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_RISINGDETECT) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling falling edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_FALLINGDETECT) &= ~(1 << pinNumber);
|
|
|
+ break;
|
|
|
+ case PIN_IRQ_MODE_LOW_LEVEL:
|
|
|
+ /* Enabling logic LOW level detect interrupt geenration. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(0)) |= (1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling logic HIGH level detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_LEVELDETECT(1)) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling rising edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_RISINGDETECT) &= ~(1 << pinNumber);
|
|
|
+
|
|
|
+ /* Disabling falling edge detect interrupt generation. */
|
|
|
+ REG32(baseAdd + GPIO_FALLINGDETECT) &= ~(1 << pinNumber);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static rt_err_t am33xx_pin_detach_irq(struct rt_device *device, rt_int32_t pin)
|
|
|
+{
|
|
|
+ RT_ASSERT(pin >= 0 && pin < 128);
|
|
|
+ rt_base_t gpiox = pin >> 5;
|
|
|
+ rt_base_t pinNumber = pin & 0x1F;
|
|
|
+ struct am33xx_pin_irq_hdr *irq_hdr = &GPIO_PARAMx[gpiox].hdr_tab[pinNumber];
|
|
|
+ rt_base_t level;
|
|
|
+
|
|
|
+ level = rt_hw_interrupt_disable();
|
|
|
+
|
|
|
+ irq_hdr->hdr = RT_NULL;
|
|
|
+ irq_hdr->args = RT_NULL;
|
|
|
+
|
|
|
+ rt_hw_interrupt_enable(level);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static rt_err_t am33xx_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled)
|
|
|
+{
|
|
|
+ RT_ASSERT(pin >= 0 && pin < 128);
|
|
|
+ rt_base_t gpiox = pin >> 5;
|
|
|
+ rt_base_t pinNumber = pin & 0x1F;
|
|
|
+ rt_base_t baseAdd = GPIO_BASE[gpiox];
|
|
|
+ rt_base_t intLine = GPIO_INT_LINEx[gpiox];
|
|
|
+
|
|
|
+ if (enabled == PIN_IRQ_ENABLE)
|
|
|
+ REG32(baseAdd + GPIO_IRQSTATUS_SET(intLine)) = (1 << pinNumber);
|
|
|
+ else
|
|
|
+ REG32(baseAdd + GPIO_IRQSTATUS_CLR(intLine)) = (1 << pinNumber);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// name format: P0.0, range: GPIO0_[31:0] ... GPIO5_[31:0]
|
|
|
+static rt_base_t am33xx_pin_get(const char *name)
|
|
|
+{
|
|
|
+ rt_base_t gpiox;
|
|
|
+ rt_base_t pinNumber;
|
|
|
+
|
|
|
+ if (!isdigit((int)name[1]))
|
|
|
+ return -RT_EINVAL;
|
|
|
+ gpiox = name[1] - '0';
|
|
|
+
|
|
|
+ if (name[2] != '.')
|
|
|
+ return -RT_EINVAL;
|
|
|
+
|
|
|
+ if (!isdigit((int)name[3]))
|
|
|
+ return -RT_EINVAL;
|
|
|
+ pinNumber = name[3] - '0';
|
|
|
+
|
|
|
+ if (name[4] == '\0')
|
|
|
+ goto done;
|
|
|
+ else if (!isdigit((int)name[4]))
|
|
|
+ return -RT_EINVAL;
|
|
|
+
|
|
|
+ pinNumber *= 10;
|
|
|
+ pinNumber += name[4] - '0';
|
|
|
+
|
|
|
+ if (name[5] != '\0')
|
|
|
+ return -RT_EINVAL;
|
|
|
+
|
|
|
+done:
|
|
|
+ if (pinNumber > 0x1F)
|
|
|
+ return -RT_EINVAL;
|
|
|
+
|
|
|
+ return GET_PIN(gpiox, pinNumber);
|
|
|
+}
|
|
|
+
|
|
|
+static const struct rt_pin_ops am33xx_pin_ops =
|
|
|
{
|
|
|
am33xx_pin_mode,
|
|
|
am33xx_pin_write,
|
|
|
am33xx_pin_read,
|
|
|
- RT_NULL,
|
|
|
- RT_NULL,
|
|
|
- RT_NULL,
|
|
|
- RT_NULL,
|
|
|
+ am33xx_pin_attach_irq,
|
|
|
+ am33xx_pin_detach_irq,
|
|
|
+ am33xx_pin_irq_enable,
|
|
|
+ am33xx_pin_get,
|
|
|
};
|
|
|
|
|
|
int rt_hw_gpio_init(void)
|
|
|
{
|
|
|
- rt_device_pin_register("gpio", &am33xx_pin_ops , RT_NULL);
|
|
|
+ int vector;
|
|
|
+ rt_base_t gpiox;
|
|
|
+ char name[RT_NAME_MAX];
|
|
|
+
|
|
|
+ for (gpiox = 0; gpiox < 4; gpiox++)
|
|
|
+ {
|
|
|
+ rt_snprintf(name, sizeof(name), "%s%d", "gpio", gpiox);
|
|
|
+ vector = GPIO_INTx[gpiox];
|
|
|
+
|
|
|
+ rt_hw_interrupt_install(vector, GPIO_ISRx[gpiox], &GPIO_PARAMx[gpiox], name);
|
|
|
+ rt_hw_interrupt_control(vector, 0, 0);
|
|
|
+ rt_hw_interrupt_umask(vector);
|
|
|
+ }
|
|
|
+
|
|
|
+ rt_device_pin_register("gpio", &am33xx_pin_ops, RT_NULL);
|
|
|
return 0;
|
|
|
}
|
|
|
INIT_BOARD_EXPORT(rt_hw_gpio_init);
|