18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for Compaq iPAQ H3100 and H3600 handheld computers (common code) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks) 68c2ecf20Sopenharmony_ci * Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/machine.h> 118c2ecf20Sopenharmony_ci#include <linux/gpio.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio_keys.h> 138c2ecf20Sopenharmony_ci#include <linux/input.h> 148c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 158c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_data/gpio-htc-egpio.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_data/sa11x0-serial.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/mach/flash.h> 228c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <mach/h3xxx.h> 258c2ecf20Sopenharmony_ci#include <mach/irqs.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "generic.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * H3xxx flash support 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistatic struct mtd_partition h3xxx_partitions[] = { 338c2ecf20Sopenharmony_ci { 348c2ecf20Sopenharmony_ci .name = "H3XXX boot firmware", 358c2ecf20Sopenharmony_ci .size = 0x00040000, 368c2ecf20Sopenharmony_ci .offset = 0, 378c2ecf20Sopenharmony_ci .mask_flags = MTD_WRITEABLE, /* force read-only */ 388c2ecf20Sopenharmony_ci }, { 398c2ecf20Sopenharmony_ci .name = "H3XXX rootfs", 408c2ecf20Sopenharmony_ci .size = MTDPART_SIZ_FULL, 418c2ecf20Sopenharmony_ci .offset = 0x00040000, 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic void h3xxx_set_vpp(int vpp) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci gpio_set_value(H3XXX_EGPIO_VPP_ON, vpp); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int h3xxx_flash_init(void) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci int err = gpio_request(H3XXX_EGPIO_VPP_ON, "Flash Vpp"); 538c2ecf20Sopenharmony_ci if (err) { 548c2ecf20Sopenharmony_ci pr_err("%s: can't request H3XXX_EGPIO_VPP_ON\n", __func__); 558c2ecf20Sopenharmony_ci return err; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci err = gpio_direction_output(H3XXX_EGPIO_VPP_ON, 0); 598c2ecf20Sopenharmony_ci if (err) 608c2ecf20Sopenharmony_ci gpio_free(H3XXX_EGPIO_VPP_ON); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return err; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic void h3xxx_flash_exit(void) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci gpio_free(H3XXX_EGPIO_VPP_ON); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic struct flash_platform_data h3xxx_flash_data = { 718c2ecf20Sopenharmony_ci .map_name = "cfi_probe", 728c2ecf20Sopenharmony_ci .set_vpp = h3xxx_set_vpp, 738c2ecf20Sopenharmony_ci .init = h3xxx_flash_init, 748c2ecf20Sopenharmony_ci .exit = h3xxx_flash_exit, 758c2ecf20Sopenharmony_ci .parts = h3xxx_partitions, 768c2ecf20Sopenharmony_ci .nr_parts = ARRAY_SIZE(h3xxx_partitions), 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct resource h3xxx_flash_resource = 808c2ecf20Sopenharmony_ci DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * H3xxx uart support 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (port->mapbase == _Ser3UTCR0) { 898c2ecf20Sopenharmony_ci if (!gpio_request(H3XXX_EGPIO_RS232_ON, "RS232 transceiver")) { 908c2ecf20Sopenharmony_ci gpio_direction_output(H3XXX_EGPIO_RS232_ON, !state); 918c2ecf20Sopenharmony_ci gpio_free(H3XXX_EGPIO_RS232_ON); 928c2ecf20Sopenharmony_ci } else { 938c2ecf20Sopenharmony_ci pr_err("%s: can't request H3XXX_EGPIO_RS232_ON\n", 948c2ecf20Sopenharmony_ci __func__); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * Enable/Disable wake up events for this serial port. 1018c2ecf20Sopenharmony_ci * Obviously, we only support this on the normal COM port. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_cistatic int h3xxx_uart_set_wake(struct uart_port *port, u_int enable) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int err = -EINVAL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (port->mapbase == _Ser3UTCR0) { 1088c2ecf20Sopenharmony_ci if (enable) 1098c2ecf20Sopenharmony_ci PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */ 1108c2ecf20Sopenharmony_ci else 1118c2ecf20Sopenharmony_ci PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */ 1128c2ecf20Sopenharmony_ci err = 0; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return err; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic struct sa1100_port_fns h3xxx_port_fns __initdata = { 1188c2ecf20Sopenharmony_ci .pm = h3xxx_uart_pm, 1198c2ecf20Sopenharmony_ci .set_wake = h3xxx_uart_set_wake, 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic struct gpiod_lookup_table h3xxx_uart3_gpio_table = { 1238c2ecf20Sopenharmony_ci .dev_id = "sa11x0-uart.3", 1248c2ecf20Sopenharmony_ci .table = { 1258c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_DCD, "dcd", GPIO_ACTIVE_LOW), 1268c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_CTS, "cts", GPIO_ACTIVE_LOW), 1278c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_RTS, "rts", GPIO_ACTIVE_LOW), 1288c2ecf20Sopenharmony_ci { }, 1298c2ecf20Sopenharmony_ci }, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* 1338c2ecf20Sopenharmony_ci * EGPIO 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic struct resource egpio_resources[] = { 1378c2ecf20Sopenharmony_ci [0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4), 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic struct htc_egpio_chip egpio_chips[] = { 1418c2ecf20Sopenharmony_ci [0] = { 1428c2ecf20Sopenharmony_ci .reg_start = 0, 1438c2ecf20Sopenharmony_ci .gpio_base = H3XXX_EGPIO_BASE, 1448c2ecf20Sopenharmony_ci .num_gpios = 16, 1458c2ecf20Sopenharmony_ci .direction = HTC_EGPIO_OUTPUT, 1468c2ecf20Sopenharmony_ci .initial_values = 0x0080, /* H3XXX_EGPIO_RS232_ON */ 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic struct htc_egpio_platform_data egpio_info = { 1518c2ecf20Sopenharmony_ci .reg_width = 16, 1528c2ecf20Sopenharmony_ci .bus_width = 16, 1538c2ecf20Sopenharmony_ci .chip = egpio_chips, 1548c2ecf20Sopenharmony_ci .num_chips = ARRAY_SIZE(egpio_chips), 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic struct platform_device h3xxx_egpio = { 1588c2ecf20Sopenharmony_ci .name = "htc-egpio", 1598c2ecf20Sopenharmony_ci .id = -1, 1608c2ecf20Sopenharmony_ci .resource = egpio_resources, 1618c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(egpio_resources), 1628c2ecf20Sopenharmony_ci .dev = { 1638c2ecf20Sopenharmony_ci .platform_data = &egpio_info, 1648c2ecf20Sopenharmony_ci }, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * GPIO keys 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic struct gpio_keys_button h3xxx_button_table[] = { 1728c2ecf20Sopenharmony_ci { 1738c2ecf20Sopenharmony_ci .code = KEY_POWER, 1748c2ecf20Sopenharmony_ci .gpio = H3XXX_GPIO_PWR_BUTTON, 1758c2ecf20Sopenharmony_ci .desc = "Power Button", 1768c2ecf20Sopenharmony_ci .active_low = 1, 1778c2ecf20Sopenharmony_ci .type = EV_KEY, 1788c2ecf20Sopenharmony_ci .wakeup = 1, 1798c2ecf20Sopenharmony_ci }, { 1808c2ecf20Sopenharmony_ci .code = KEY_ENTER, 1818c2ecf20Sopenharmony_ci .gpio = H3XXX_GPIO_ACTION_BUTTON, 1828c2ecf20Sopenharmony_ci .active_low = 1, 1838c2ecf20Sopenharmony_ci .desc = "Action button", 1848c2ecf20Sopenharmony_ci .type = EV_KEY, 1858c2ecf20Sopenharmony_ci .wakeup = 0, 1868c2ecf20Sopenharmony_ci }, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic struct gpio_keys_platform_data h3xxx_keys_data = { 1908c2ecf20Sopenharmony_ci .buttons = h3xxx_button_table, 1918c2ecf20Sopenharmony_ci .nbuttons = ARRAY_SIZE(h3xxx_button_table), 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic struct platform_device h3xxx_keys = { 1958c2ecf20Sopenharmony_ci .name = "gpio-keys", 1968c2ecf20Sopenharmony_ci .id = -1, 1978c2ecf20Sopenharmony_ci .dev = { 1988c2ecf20Sopenharmony_ci .platform_data = &h3xxx_keys_data, 1998c2ecf20Sopenharmony_ci }, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic struct resource h3xxx_micro_resources[] = { 2038c2ecf20Sopenharmony_ci DEFINE_RES_MEM(0x80010000, SZ_4K), 2048c2ecf20Sopenharmony_ci DEFINE_RES_MEM(0x80020000, SZ_4K), 2058c2ecf20Sopenharmony_ci DEFINE_RES_IRQ(IRQ_Ser1UART), 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistruct platform_device h3xxx_micro_asic = { 2098c2ecf20Sopenharmony_ci .name = "ipaq-h3xxx-micro", 2108c2ecf20Sopenharmony_ci .id = -1, 2118c2ecf20Sopenharmony_ci .resource = h3xxx_micro_resources, 2128c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(h3xxx_micro_resources), 2138c2ecf20Sopenharmony_ci}; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic struct platform_device *h3xxx_devices[] = { 2168c2ecf20Sopenharmony_ci &h3xxx_egpio, 2178c2ecf20Sopenharmony_ci &h3xxx_keys, 2188c2ecf20Sopenharmony_ci &h3xxx_micro_asic, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic struct gpiod_lookup_table h3xxx_pcmcia_gpio_table = { 2228c2ecf20Sopenharmony_ci .dev_id = "sa11x0-pcmcia", 2238c2ecf20Sopenharmony_ci .table = { 2248c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_CD0, 2258c2ecf20Sopenharmony_ci "pcmcia0-detect", GPIO_ACTIVE_LOW), 2268c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_IRQ0, 2278c2ecf20Sopenharmony_ci "pcmcia0-ready", GPIO_ACTIVE_HIGH), 2288c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_CD1, 2298c2ecf20Sopenharmony_ci "pcmcia1-detect", GPIO_ACTIVE_LOW), 2308c2ecf20Sopenharmony_ci GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_IRQ1, 2318c2ecf20Sopenharmony_ci "pcmcia1-ready", GPIO_ACTIVE_HIGH), 2328c2ecf20Sopenharmony_ci { }, 2338c2ecf20Sopenharmony_ci }, 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_civoid __init h3xxx_mach_init(void) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci gpiod_add_lookup_table(&h3xxx_pcmcia_gpio_table); 2398c2ecf20Sopenharmony_ci gpiod_add_lookup_table(&h3xxx_uart3_gpio_table); 2408c2ecf20Sopenharmony_ci sa1100_register_uart_fns(&h3xxx_port_fns); 2418c2ecf20Sopenharmony_ci sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1); 2428c2ecf20Sopenharmony_ci platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices)); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic struct map_desc h3600_io_desc[] __initdata = { 2468c2ecf20Sopenharmony_ci { /* static memory bank 2 CS#2 */ 2478c2ecf20Sopenharmony_ci .virtual = H3600_BANK_2_VIRT, 2488c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(SA1100_CS2_PHYS), 2498c2ecf20Sopenharmony_ci .length = 0x02800000, 2508c2ecf20Sopenharmony_ci .type = MT_DEVICE 2518c2ecf20Sopenharmony_ci }, { /* static memory bank 4 CS#4 */ 2528c2ecf20Sopenharmony_ci .virtual = H3600_BANK_4_VIRT, 2538c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(SA1100_CS4_PHYS), 2548c2ecf20Sopenharmony_ci .length = 0x00800000, 2558c2ecf20Sopenharmony_ci .type = MT_DEVICE 2568c2ecf20Sopenharmony_ci }, { /* EGPIO 0 CS#5 */ 2578c2ecf20Sopenharmony_ci .virtual = H3600_EGPIO_VIRT, 2588c2ecf20Sopenharmony_ci .pfn = __phys_to_pfn(H3600_EGPIO_PHYS), 2598c2ecf20Sopenharmony_ci .length = 0x01000000, 2608c2ecf20Sopenharmony_ci .type = MT_DEVICE 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/* 2658c2ecf20Sopenharmony_ci * Common map_io initialization 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_civoid __init h3xxx_map_io(void) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci sa1100_map_io(); 2718c2ecf20Sopenharmony_ci iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc)); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci sa1100_register_uart(0, 3); /* Common serial port */ 2748c2ecf20Sopenharmony_ci// sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */ 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Ensure those pins are outputs and driving low */ 2778c2ecf20Sopenharmony_ci PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; 2788c2ecf20Sopenharmony_ci PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Configure suspend conditions */ 2818c2ecf20Sopenharmony_ci PGSR = 0; 2828c2ecf20Sopenharmony_ci PCFR = PCFR_OPDE; 2838c2ecf20Sopenharmony_ci PSDR = 0; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci GPCR = 0x0fffffff; /* All outputs are set low by default */ 2868c2ecf20Sopenharmony_ci GPDR = 0; /* Configure all GPIOs as input */ 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 289