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