diff --git a/board/sunxi/Makefile b/board/sunxi/Makefile index c4e13f8c38d..6a8a2f5b42f 100644 --- a/board/sunxi/Makefile +++ b/board/sunxi/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_SUN7I_GMAC) += gmac.o obj-$(CONFIG_MACH_SUN4I) += dram_sun4i_auto.o obj-$(CONFIG_MACH_SUN5I) += dram_sun5i_auto.o obj-$(CONFIG_MACH_SUN7I) += dram_sun5i_auto.o +obj-$(CONFIG_MACH_SUN50I) += lradc.o diff --git a/board/sunxi/board.c b/board/sunxi/board.c index 6de4b53b11a..2bedf7a16ab 100644 --- a/board/sunxi/board.c +++ b/board/sunxi/board.c @@ -39,6 +39,7 @@ #include #include #include +#include "lradc.h" #if defined CONFIG_VIDEO_LCD_PANEL_I2C && !(defined CONFIG_SPL_BUILD) /* So that we can use pin names in Kconfig and sunxi_name_to_gpio() */ @@ -622,6 +623,12 @@ void sunxi_board_init(void) { int power_failed = 0; +#ifdef CONFIG_MACH_SUN50I + // we init the lradc in SPL to get the ADC started early to have + // a valid sample when U-Boot main binary gets executed. + lradc_enable(); +#endif + #ifdef CONFIG_PINEPHONE_LEDS /* PD18:G PD19:R PD20:B */ gpio_request(SUNXI_GPD(18), "led:green"); @@ -905,6 +912,17 @@ int misc_init_r(void) env_set("mmc_bootdev", "1"); } +#ifdef CONFIG_MACH_SUN50I + int key = lradc_get_pressed_key(); + if (key == KEY_VOLUMEDOWN) + env_set("volume_key", "down"); + else if (key == KEY_VOLUMEUP) + env_set("volume_key", "up"); + + // no longer needed + lradc_disable(); +#endif + setup_environment(gd->fdt_blob); #ifdef CONFIG_USB_ETHER diff --git a/board/sunxi/lradc.c b/board/sunxi/lradc.c new file mode 100644 index 00000000000..693b198e251 --- /dev/null +++ b/board/sunxi/lradc.c @@ -0,0 +1,81 @@ +#include +#include +#include "lradc.h" + +#define LRADC_BASE 0x1c21800 + +#define LRADC_CTRL (LRADC_BASE + 0x00) +#define LRADC_INTC (LRADC_BASE + 0x04) +#define LRADC_INTS (LRADC_BASE + 0x08) +#define LRADC_DATA0 (LRADC_BASE + 0x0c) +#define LRADC_DATA1 (LRADC_BASE + 0x10) + +/* LRADC_CTRL bits */ +#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */ +#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */ +#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */ +#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */ +#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */ +#define HOLD_KEY_EN(x) ((x) << 7) +#define HOLD_EN(x) ((x) << 6) +#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */ +#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */ +#define ENABLE(x) ((x) << 0) + +/* LRADC_INTC and LRADC_INTS bits */ +#define CHAN1_KEYUP_IRQ BIT(12) +#define CHAN1_ALRDY_HOLD_IRQ BIT(11) +#define CHAN1_HOLD_IRQ BIT(10) +#define CHAN1_KEYDOWN_IRQ BIT(9) +#define CHAN1_DATA_IRQ BIT(8) +#define CHAN0_KEYUP_IRQ BIT(4) +#define CHAN0_ALRDY_HOLD_IRQ BIT(3) +#define CHAN0_HOLD_IRQ BIT(2) +#define CHAN0_KEYDOWN_IRQ BIT(1) +#define CHAN0_DATA_IRQ BIT(0) + +// this is for PinePhone only + +int lradc_get_pressed_key(void) +{ + uint32_t val; + uint32_t vref = 3000000 * 2 / 3; + + val = readl(LRADC_DATA0) & 0x3f; + val = val * vref / 63; + +// printf("lradc=%u\n", val); + + if (val < 200000) // 158730 + return KEY_VOLUMEUP; + else if (val < 400000) // 349206 + return KEY_VOLUMEDOWN; + + return 0; +} + +void lradc_enable(void) +{ + // aldo3 is always on and defaults to 3V + + writel(0xffffffff, LRADC_INTS); + writel(0, LRADC_INTC); + + /* + * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to + * stabilize on press, wait (1 + 1) * 4 ms for key release + */ + writel(FIRST_CONVERT_DLY(0) | LEVELA_B_CNT(0) | HOLD_EN(0) | + SAMPLE_RATE(0) | ENABLE(1), LRADC_CTRL); + +} + +void lradc_disable(void) +{ + writel(0xffffffff, LRADC_INTS); + writel(0, LRADC_INTC); + + /* Disable lradc, leave other settings unchanged */ + writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) | + SAMPLE_RATE(2), LRADC_CTRL); +} diff --git a/board/sunxi/lradc.h b/board/sunxi/lradc.h new file mode 100644 index 00000000000..c908401b5bf --- /dev/null +++ b/board/sunxi/lradc.h @@ -0,0 +1,11 @@ +#pragma once + +enum { + KEY_NONE = 0, + KEY_VOLUMEDOWN = 1, + KEY_VOLUMEUP = 2, +}; + +int lradc_get_pressed_key(void); +void lradc_enable(void); +void lradc_disable(void);