code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_ARCH_REGS_UART_H
#define __ASM_ARCH_REGS_UART_H

#include "pxa-regs.h"

/*
 * UARTs
 */

/* Full Function UART (FFUART) */
#define FFUART		FFRBR
#define FFRBR		__REG(0x40100000)  /* Receive Buffer Register (read only) */
#define FFTHR		__REG(0x40100000)  /* Transmit Holding Register (write only) */
#define FFIER		__REG(0x40100004)  /* Interrupt Enable Register (read/write) */
#define FFIIR		__REG(0x40100008)  /* Interrupt ID Register (read only) */
#define FFFCR		__REG(0x40100008)  /* FIFO Control Register (write only) */
#define FFLCR		__REG(0x4010000C)  /* Line Control Register (read/write) */
#define FFMCR		__REG(0x40100010)  /* Modem Control Register (read/write) */
#define FFLSR		__REG(0x40100014)  /* Line Status Register (read only) */
#define FFMSR		__REG(0x40100018)  /* Modem Status Register (read only) */
#define FFSPR		__REG(0x4010001C)  /* Scratch Pad Register (read/write) */
#define FFISR		__REG(0x40100020)  /* Infrared Selection Register (read/write) */
#define FFDLL		__REG(0x40100000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
#define FFDLH		__REG(0x40100004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */

/* Bluetooth UART (BTUART) */
#define BTUART		BTRBR
#define BTRBR		__REG(0x40200000)  /* Receive Buffer Register (read only) */
#define BTTHR		__REG(0x40200000)  /* Transmit Holding Register (write only) */
#define BTIER		__REG(0x40200004)  /* Interrupt Enable Register (read/write) */
#define BTIIR		__REG(0x40200008)  /* Interrupt ID Register (read only) */
#define BTFCR		__REG(0x40200008)  /* FIFO Control Register (write only) */
#define BTLCR		__REG(0x4020000C)  /* Line Control Register (read/write) */
#define BTMCR		__REG(0x40200010)  /* Modem Control Register (read/write) */
#define BTLSR		__REG(0x40200014)  /* Line Status Register (read only) */
#define BTMSR		__REG(0x40200018)  /* Modem Status Register (read only) */
#define BTSPR		__REG(0x4020001C)  /* Scratch Pad Register (read/write) */
#define BTISR		__REG(0x40200020)  /* Infrared Selection Register (read/write) */
#define BTDLL		__REG(0x40200000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
#define BTDLH		__REG(0x40200004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */

/* Standard UART (STUART) */
#define STUART		STRBR
#define STRBR		__REG(0x40700000)  /* Receive Buffer Register (read only) */
#define STTHR		__REG(0x40700000)  /* Transmit Holding Register (write only) */
#define STIER		__REG(0x40700004)  /* Interrupt Enable Register (read/write) */
#define STIIR		__REG(0x40700008)  /* Interrupt ID Register (read only) */
#define STFCR		__REG(0x40700008)  /* FIFO Control Register (write only) */
#define STLCR		__REG(0x4070000C)  /* Line Control Register (read/write) */
#define STMCR		__REG(0x40700010)  /* Modem Control Register (read/write) */
#define STLSR		__REG(0x40700014)  /* Line Status Register (read only) */
#define STMSR		__REG(0x40700018)  /* Reserved */
#define STSPR		__REG(0x4070001C)  /* Scratch Pad Register (read/write) */
#define STISR		__REG(0x40700020)  /* Infrared Selection Register (read/write) */
#define STDLL		__REG(0x40700000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
#define STDLH		__REG(0x40700004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */

/* Hardware UART (HWUART) */
#define HWUART		HWRBR
#define HWRBR		__REG(0x41600000)  /* Receive Buffer Register (read only) */
#define HWTHR		__REG(0x41600000)  /* Transmit Holding Register (write only) */
#define HWIER		__REG(0x41600004)  /* Interrupt Enable Register (read/write) */
#define HWIIR		__REG(0x41600008)  /* Interrupt ID Register (read only) */
#define HWFCR		__REG(0x41600008)  /* FIFO Control Register (write only) */
#define HWLCR		__REG(0x4160000C)  /* Line Control Register (read/write) */
#define HWMCR		__REG(0x41600010)  /* Modem Control Register (read/write) */
#define HWLSR		__REG(0x41600014)  /* Line Status Register (read only) */
#define HWMSR		__REG(0x41600018)  /* Modem Status Register (read only) */
#define HWSPR		__REG(0x4160001C)  /* Scratch Pad Register (read/write) */
#define HWISR		__REG(0x41600020)  /* Infrared Selection Register (read/write) */
#define HWFOR		__REG(0x41600024)  /* Receive FIFO Occupancy Register (read only) */
#define HWABR		__REG(0x41600028)  /* Auto-Baud Control Register (read/write) */
#define HWACR		__REG(0x4160002C)  /* Auto-Baud Count Register (read only) */
#define HWDLL		__REG(0x41600000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
#define HWDLH		__REG(0x41600004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */

#define IER_DMAE	(1 << 7)	/* DMA Requests Enable */
#define IER_UUE		(1 << 6)	/* UART Unit Enable */
#define IER_NRZE	(1 << 5)	/* NRZ coding Enable */
#define IER_RTIOE	(1 << 4)	/* Receiver Time Out Interrupt Enable */
#define IER_MIE		(1 << 3)	/* Modem Interrupt Enable */
#define IER_RLSE	(1 << 2)	/* Receiver Line Status Interrupt Enable */
#define IER_TIE		(1 << 1)	/* Transmit Data request Interrupt Enable */
#define IER_RAVIE	(1 << 0)	/* Receiver Data Available Interrupt Enable */

#define IIR_FIFOES1	(1 << 7)	/* FIFO Mode Enable Status */
#define IIR_FIFOES0	(1 << 6)	/* FIFO Mode Enable Status */
#define IIR_TOD		(1 << 3)	/* Time Out Detected */
#define IIR_IID2	(1 << 2)	/* Interrupt Source Encoded */
#define IIR_IID1	(1 << 1)	/* Interrupt Source Encoded */
#define IIR_IP		(1 << 0)	/* Interrupt Pending (active low) */

#define FCR_ITL2	(1 << 7)	/* Interrupt Trigger Level */
#define FCR_ITL1	(1 << 6)	/* Interrupt Trigger Level */
#define FCR_RESETTF	(1 << 2)	/* Reset Transmitter FIFO */
#define FCR_RESETRF	(1 << 1)	/* Reset Receiver FIFO */
#define FCR_TRFIFOE	(1 << 0)	/* Transmit and Receive FIFO Enable */
#define FCR_ITL_1	(0)
#define FCR_ITL_8	(FCR_ITL1)
#define FCR_ITL_16	(FCR_ITL2)
#define FCR_ITL_32	(FCR_ITL2|FCR_ITL1)

#define LCR_DLAB	(1 << 7)	/* Divisor Latch Access Bit */
#define LCR_SB		(1 << 6)	/* Set Break */
#define LCR_STKYP	(1 << 5)	/* Sticky Parity */
#define LCR_EPS		(1 << 4)	/* Even Parity Select */
#define LCR_PEN		(1 << 3)	/* Parity Enable */
#define LCR_STB		(1 << 2)	/* Stop Bit */
#define LCR_WLS1	(1 << 1)	/* Word Length Select */
#define LCR_WLS0	(1 << 0)	/* Word Length Select */

#define LSR_FIFOE	(1 << 7)	/* FIFO Error Status */
#define LSR_TEMT	(1 << 6)	/* Transmitter Empty */
#define LSR_TDRQ	(1 << 5)	/* Transmit Data Request */
#define LSR_BI		(1 << 4)	/* Break Interrupt */
#define LSR_FE		(1 << 3)	/* Framing Error */
#define LSR_PE		(1 << 2)	/* Parity Error */
#define LSR_OE		(1 << 1)	/* Overrun Error */
#define LSR_DR		(1 << 0)	/* Data Ready */

#define MCR_LOOP	(1 << 4)
#define MCR_OUT2	(1 << 3)	/* force MSR_DCD in loopback mode */
#define MCR_OUT1	(1 << 2)	/* force MSR_RI in loopback mode */
#define MCR_RTS		(1 << 1)	/* Request to Send */
#define MCR_DTR		(1 << 0)	/* Data Terminal Ready */

#define MSR_DCD		(1 << 7)	/* Data Carrier Detect */
#define MSR_RI		(1 << 6)	/* Ring Indicator */
#define MSR_DSR		(1 << 5)	/* Data Set Ready */
#define MSR_CTS		(1 << 4)	/* Clear To Send */
#define MSR_DDCD	(1 << 3)	/* Delta Data Carrier Detect */
#define MSR_TERI	(1 << 2)	/* Trailing Edge Ring Indicator */
#define MSR_DDSR	(1 << 1)	/* Delta Data Set Ready */
#define MSR_DCTS	(1 << 0)	/* Delta Clear To Send */

/*
 * IrSR (Infrared Selection Register)
 */
#define STISR_RXPL      (1 << 4)        /* Receive Data Polarity */
#define STISR_TXPL      (1 << 3)        /* Transmit Data Polarity */
#define STISR_XMODE     (1 << 2)        /* Transmit Pulse Width Select */
#define STISR_RCVEIR    (1 << 1)        /* Receiver SIR Enable */
#define STISR_XMITIR    (1 << 0)        /* Transmitter SIR Enable */

#endif /* __ASM_ARCH_REGS_UART_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <asm/proc-fns.h>
#include <asm/system_misc.h>

#include "regs-ost.h"
#include "reset.h"
#include "smemc.h"

static void do_hw_reset(void);

static int reset_gpio = -1;

int init_gpio_reset(int gpio, int output, int level)
{
	int rc;

	rc = gpio_request(gpio, "reset generator");
	if (rc) {
		printk(KERN_ERR "Can't request reset_gpio\n");
		goto out;
	}

	if (output)
		rc = gpio_direction_output(gpio, level);
	else
		rc = gpio_direction_input(gpio);
	if (rc) {
		printk(KERN_ERR "Can't configure reset_gpio\n");
		gpio_free(gpio);
		goto out;
	}

out:
	if (!rc)
		reset_gpio = gpio;

	return rc;
}

/*
 * Trigger GPIO reset.
 * This covers various types of logic connecting gpio pin
 * to RESET pins (nRESET or GPIO_RESET):
 */
static void do_gpio_reset(void)
{
	BUG_ON(reset_gpio == -1);

	/* drive it low */
	gpio_direction_output(reset_gpio, 0);
	mdelay(2);
	/* rising edge or drive high */
	gpio_set_value(reset_gpio, 1);
	mdelay(2);
	/* falling edge */
	gpio_set_value(reset_gpio, 0);

	/* give it some time */
	mdelay(10);

	WARN_ON(1);
	/* fallback */
	do_hw_reset();
}

static void do_hw_reset(void)
{
	/* Initialize the watchdog and let it fire */
	writel_relaxed(OWER_WME, OWER);
	writel_relaxed(OSSR_M3, OSSR);
	/* ... in 100 ms */
	writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3);
	/*
	 * SDRAM hangs on watchdog reset on Marvell PXA270 (erratum 71)
	 * we put SDRAM into self-refresh to prevent that
	 */
	while (1)
		writel_relaxed(MDREFR_SLFRSH, MDREFR);
}

void pxa_restart(enum reboot_mode mode, const char *cmd)
{
	local_irq_disable();
	local_fiq_disable();

	clear_reset_status(RESET_STATUS_ALL);

	switch (mode) {
	case REBOOT_SOFT:
		/* Jump into ROM at address 0 */
		soft_restart(0);
		break;
	case REBOOT_GPIO:
		do_gpio_reset();
		break;
	case REBOOT_HARD:
	default:
		do_hw_reset();
		break;
	}
}

repo_name: angery/linux


code:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_ARCH_RESET_H
#define __ASM_ARCH_RESET_H

#define RESET_STATUS_HARDWARE	(1 << 0)	/* Hardware Reset */
#define RESET_STATUS_WATCHDOG	(1 << 1)	/* Watchdog Reset */
#define RESET_STATUS_LOWPOWER	(1 << 2)	/* Low Power/Sleep Exit */
#define RESET_STATUS_GPIO	(1 << 3)	/* GPIO Reset */
#define RESET_STATUS_ALL	(0xf)

extern void clear_reset_status(unsigned int mask);
extern void pxa_register_wdt(unsigned int reset_status);

/**
 * init_gpio_reset() - register GPIO as reset generator
 * @gpio: gpio nr
 * @output: set gpio as output instead of input during normal work
 * @level: output level
 */
extern int init_gpio_reset(int gpio, int output, int level);

#endif /* __ASM_ARCH_RESET_H */


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  linux/arch/arm/mach-pxa/saar.c
 *
 *  Support for the Marvell PXA930 Handheld Platform (aka SAAR)
 *
 *  Copyright (C) 2007-2008 Marvell International Ltd.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h>
#include <linux/smc91x.h>
#include <linux/mfd/da903x.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/onenand.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>

#include "pxa930.h"
#include <linux/platform_data/video-pxafb.h>

#include "devices.h"
#include "generic.h"

#define GPIO_LCD_RESET		(16)

/* SAAR MFP configurations */
static mfp_cfg_t saar_mfp_cfg[] __initdata = {
	/* LCD */
	GPIO23_LCD_DD0,
	GPIO24_LCD_DD1,
	GPIO25_LCD_DD2,
	GPIO26_LCD_DD3,
	GPIO27_LCD_DD4,
	GPIO28_LCD_DD5,
	GPIO29_LCD_DD6,
	GPIO44_LCD_DD7,
	GPIO21_LCD_CS,
	GPIO22_LCD_VSYNC,
	GPIO17_LCD_FCLK_RD,
	GPIO18_LCD_LCLK_A0,
	GPIO19_LCD_PCLK_WR,
	GPIO16_GPIO, /* LCD reset */

	/* Ethernet */
	DF_nCS1_nCS3,
	GPIO97_GPIO,

	/* DFI */
	DF_INT_RnB_ND_INT_RnB,
	DF_nRE_nOE_ND_nRE,
	DF_nWE_ND_nWE,
	DF_CLE_nOE_ND_CLE,
	DF_nADV1_ALE_ND_ALE,
	DF_nADV2_ALE_nCS3,
	DF_nCS0_ND_nCS0,
	DF_IO0_ND_IO0,
	DF_IO1_ND_IO1,
	DF_IO2_ND_IO2,
	DF_IO3_ND_IO3,
	DF_IO4_ND_IO4,
	DF_IO5_ND_IO5,
	DF_IO6_ND_IO6,
	DF_IO7_ND_IO7,
	DF_IO8_ND_IO8,
	DF_IO9_ND_IO9,
	DF_IO10_ND_IO10,
	DF_IO11_ND_IO11,
	DF_IO12_ND_IO12,
	DF_IO13_ND_IO13,
	DF_IO14_ND_IO14,
	DF_IO15_ND_IO15,
};

#define SAAR_ETH_PHYS	(0x14000000)

static struct resource smc91x_resources[] = {
	[0] = {
		.start	= (SAAR_ETH_PHYS + 0x300),
		.end	= (SAAR_ETH_PHYS + 0xfffff),
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= PXA_GPIO_TO_IRQ(mfp_to_gpio(MFP_PIN_GPIO97)),
		.end	= PXA_GPIO_TO_IRQ(mfp_to_gpio(MFP_PIN_GPIO97)),
		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
	}
};

static struct smc91x_platdata saar_smc91x_info = {
	.flags	= SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_USE_DMA,
};

static struct platform_device smc91x_device = {
	.name		= "smc91x",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(smc91x_resources),
	.resource	= smc91x_resources,
	.dev		= {
		.platform_data = &saar_smc91x_info,
	},
};

#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
static uint16_t lcd_power_on[] = {
	/* single frame */
	SMART_CMD_NOOP,
	SMART_CMD(0x00),
	SMART_DELAY(0),

	SMART_CMD_NOOP,
	SMART_CMD(0x00),
	SMART_DELAY(0),

	SMART_CMD_NOOP,
	SMART_CMD(0x00),
	SMART_DELAY(0),

	SMART_CMD_NOOP,
	SMART_CMD(0x00),
	SMART_DELAY(10),

	/* calibration control */
	SMART_CMD(0x00),
	SMART_CMD(0xA4),
	SMART_DAT(0x80),
	SMART_DAT(0x01),
	SMART_DELAY(150),

	/*Power-On Init sequence*/
	SMART_CMD(0x00),	/* output ctrl */
	SMART_CMD(0x01),
	SMART_DAT(0x01),
	SMART_DAT(0x00),
	SMART_CMD(0x00),	/* wave ctrl */
	SMART_CMD(0x02),
	SMART_DAT(0x07),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x03),	/* entry mode */
	SMART_DAT(0xD0),
	SMART_DAT(0x30),
	SMART_CMD(0x00),
	SMART_CMD(0x08),	/* display ctrl 2 */
	SMART_DAT(0x08),
	SMART_DAT(0x08),
	SMART_CMD(0x00),
	SMART_CMD(0x09),	/* display ctrl 3 */
	SMART_DAT(0x04),
	SMART_DAT(0x2F),
	SMART_CMD(0x00),
	SMART_CMD(0x0A),	/* display ctrl 4 */
	SMART_DAT(0x00),
	SMART_DAT(0x08),
	SMART_CMD(0x00),
	SMART_CMD(0x0D),	/* Frame Marker position */
	SMART_DAT(0x00),
	SMART_DAT(0x08),
	SMART_CMD(0x00),
	SMART_CMD(0x60),	/* Driver output control */
	SMART_DAT(0x27),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x61),	/* Base image display control */
	SMART_DAT(0x00),
	SMART_DAT(0x01),
	SMART_CMD(0x00),
	SMART_CMD(0x30),	/* Y settings 30h-3Dh */
	SMART_DAT(0x07),
	SMART_DAT(0x07),
	SMART_CMD(0x00),
	SMART_CMD(0x31),
	SMART_DAT(0x00),
	SMART_DAT(0x07),
	SMART_CMD(0x00),
	SMART_CMD(0x32),	/* Timing(3), ASW HOLD=0.5CLK */
	SMART_DAT(0x04),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x33),	/* Timing(4), CKV ST=0CLK, CKV ED=1CLK */
	SMART_DAT(0x03),
	SMART_DAT(0x03),
	SMART_CMD(0x00),
	SMART_CMD(0x34),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x35),
	SMART_DAT(0x02),
	SMART_DAT(0x05),
	SMART_CMD(0x00),
	SMART_CMD(0x36),
	SMART_DAT(0x1F),
	SMART_DAT(0x1F),
	SMART_CMD(0x00),
	SMART_CMD(0x37),
	SMART_DAT(0x07),
	SMART_DAT(0x07),
	SMART_CMD(0x00),
	SMART_CMD(0x38),
	SMART_DAT(0x00),
	SMART_DAT(0x07),
	SMART_CMD(0x00),
	SMART_CMD(0x39),
	SMART_DAT(0x04),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x3A),
	SMART_DAT(0x03),
	SMART_DAT(0x03),
	SMART_CMD(0x00),
	SMART_CMD(0x3B),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00),
	SMART_CMD(0x3C),
	SMART_DAT(0x02),
	SMART_DAT(0x05),
	SMART_CMD(0x00),
	SMART_CMD(0x3D),
	SMART_DAT(0x1F),
	SMART_DAT(0x1F),
	SMART_CMD(0x00),	/* Display control 1 */
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x01),
	SMART_CMD(0x00),	/* Power control 5 */
	SMART_CMD(0x17),
	SMART_DAT(0x00),
	SMART_DAT(0x01),
	SMART_CMD(0x00),	/* Power control 1 */
	SMART_CMD(0x10),
	SMART_DAT(0x10),
	SMART_DAT(0xB0),
	SMART_CMD(0x00),	/* Power control 2 */
	SMART_CMD(0x11),
	SMART_DAT(0x01),
	SMART_DAT(0x30),
	SMART_CMD(0x00),	/* Power control 3 */
	SMART_CMD(0x12),
	SMART_DAT(0x01),
	SMART_DAT(0x9E),
	SMART_CMD(0x00),	/* Power control 4 */
	SMART_CMD(0x13),
	SMART_DAT(0x17),
	SMART_DAT(0x00),
	SMART_CMD(0x00),	/* Power control 3 */
	SMART_CMD(0x12),
	SMART_DAT(0x01),
	SMART_DAT(0xBE),
	SMART_DELAY(100),

	/* display mode : 240*320 */
	SMART_CMD(0x00),	/* RAM address set(H) 0*/
	SMART_CMD(0x20),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00),	/* RAM address set(V)   4*/
	SMART_CMD(0x21),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00),	/* Start of Window RAM address set(H) 8*/
	SMART_CMD(0x50),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00), 	/* End of Window RAM address set(H) 12*/
	SMART_CMD(0x51),
	SMART_DAT(0x00),
	SMART_DAT(0xEF),
	SMART_CMD(0x00),	/* Start of Window RAM address set(V) 16*/
	SMART_CMD(0x52),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00),	/* End of Window RAM address set(V) 20*/
	SMART_CMD(0x53),
	SMART_DAT(0x01),
	SMART_DAT(0x3F),
	SMART_CMD(0x00), 	/* Panel interface control 1 */
	SMART_CMD(0x90),
	SMART_DAT(0x00),
	SMART_DAT(0x1A),
	SMART_CMD(0x00), 	/* Panel interface control 2 */
	SMART_CMD(0x92),
	SMART_DAT(0x04),
	SMART_DAT(0x00),
	SMART_CMD(0x00), 	/* Panel interface control 3 */
	SMART_CMD(0x93),
	SMART_DAT(0x00),
	SMART_DAT(0x05),
	SMART_DELAY(20),
};

static uint16_t lcd_panel_on[] = {
	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x21),
	SMART_DELAY(1),

	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x61),
	SMART_DELAY(100),

	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x01),
	SMART_DAT(0x73),
	SMART_DELAY(1),
};

static uint16_t lcd_panel_off[] = {
	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x72),
	SMART_DELAY(40),

	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x01),
	SMART_DELAY(1),

	SMART_CMD(0x00),
	SMART_CMD(0x07),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_DELAY(1),
};

static uint16_t lcd_power_off[] = {
	SMART_CMD(0x00),
	SMART_CMD(0x10),
	SMART_DAT(0x00),
	SMART_DAT(0x80),

	SMART_CMD(0x00),
	SMART_CMD(0x11),
	SMART_DAT(0x01),
	SMART_DAT(0x60),

	SMART_CMD(0x00),
	SMART_CMD(0x12),
	SMART_DAT(0x01),
	SMART_DAT(0xAE),
	SMART_DELAY(40),

	SMART_CMD(0x00),
	SMART_CMD(0x10),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
};

static uint16_t update_framedata[] = {
	/* set display ram: 240*320 */
	SMART_CMD(0x00), /* RAM address set(H) 0*/
	SMART_CMD(0x20),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00), /* RAM address set(V) 4*/
	SMART_CMD(0x21),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00), /* Start of Window RAM address set(H) 8 */
	SMART_CMD(0x50),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00), /* End of Window RAM address set(H) 12 */
	SMART_CMD(0x51),
	SMART_DAT(0x00),
	SMART_DAT(0xEF),
	SMART_CMD(0x00), /* Start of Window RAM address set(V) 16 */
	SMART_CMD(0x52),
	SMART_DAT(0x00),
	SMART_DAT(0x00),
	SMART_CMD(0x00), /* End of Window RAM address set(V) 20 */
	SMART_CMD(0x53),
	SMART_DAT(0x01),
	SMART_DAT(0x3F),

	/* wait for vsync cmd before transferring frame data */
	SMART_CMD_WAIT_FOR_VSYNC,

	/* write ram */
	SMART_CMD(0x00),
	SMART_CMD(0x22),

	/* write frame data */
	SMART_CMD_WRITE_FRAME,
};

static void ltm022a97a_lcd_power(int on, struct fb_var_screeninfo *var)
{
	static int pin_requested = 0;
	struct fb_info *info = container_of(var, struct fb_info, var);
	int err;

	if (!pin_requested) {
		err = gpio_request(GPIO_LCD_RESET, "lcd reset");
		if (err) {
			pr_err("failed to request gpio for LCD reset\n");
			return;
		}

		gpio_direction_output(GPIO_LCD_RESET, 0);
		pin_requested = 1;
	}

	if (on) {
		gpio_set_value(GPIO_LCD_RESET, 0); msleep(100);
		gpio_set_value(GPIO_LCD_RESET, 1); msleep(10);

		pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_power_on));
		pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_panel_on));
	} else {
		pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_panel_off));
		pxafb_smart_queue(info, ARRAY_AND_SIZE(lcd_power_off));
	}

	err = pxafb_smart_flush(info);
	if (err)
		pr_err("%s: timed out\n", __func__);
}

static void ltm022a97a_update(struct fb_info *info)
{
	pxafb_smart_queue(info, ARRAY_AND_SIZE(update_framedata));
	pxafb_smart_flush(info);
}

static struct pxafb_mode_info toshiba_ltm022a97a_modes[] = {
	[0] = {
		.xres			= 240,
		.yres			= 320,
		.bpp			= 16,
		.a0csrd_set_hld		= 30,
		.a0cswr_set_hld		= 30,
		.wr_pulse_width		= 30,
		.rd_pulse_width 	= 30,
		.op_hold_time 		= 30,
		.cmd_inh_time		= 60,

		/* L_LCLK_A0 and L_LCLK_RD active low */
		.sync			= FB_SYNC_HOR_HIGH_ACT |
					  FB_SYNC_VERT_HIGH_ACT,
	},
};

static struct pxafb_mach_info saar_lcd_info = {
	.modes			= toshiba_ltm022a97a_modes,
	.num_modes		= 1,
	.lcd_conn		= LCD_SMART_PANEL_8BPP | LCD_PCLK_EDGE_FALL,
	.pxafb_lcd_power	= ltm022a97a_lcd_power,
	.smart_update		= ltm022a97a_update,
};

static void __init saar_init_lcd(void)
{
	pxa_set_fb_info(NULL, &saar_lcd_info);
}
#else
static inline void saar_init_lcd(void) {}
#endif

#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
static struct da9034_backlight_pdata saar_da9034_backlight = {
	.output_current	= 4,	/* 4mA */
};

static struct da903x_subdev_info saar_da9034_subdevs[] = {
	[0] = {
		.name		= "da903x-backlight",
		.id		= DA9034_ID_WLED,
		.platform_data	= &saar_da9034_backlight,
	},
};

static struct da903x_platform_data saar_da9034_info = {
	.num_subdevs	= ARRAY_SIZE(saar_da9034_subdevs),
	.subdevs	= saar_da9034_subdevs,
};

static struct i2c_board_info saar_i2c_info[] = {
	[0] = {
		.type		= "da9034",
		.addr		= 0x34,
		.platform_data	= &saar_da9034_info,
		.irq		= PXA_GPIO_TO_IRQ(mfp_to_gpio(MFP_PIN_GPIO83)),
	},
};

static void __init saar_init_i2c(void)
{
	pxa_set_i2c_info(NULL);
	i2c_register_board_info(0, ARRAY_AND_SIZE(saar_i2c_info));
}
#else
static inline void saar_init_i2c(void) {}
#endif

#if defined(CONFIG_MTD_ONENAND) || defined(CONFIG_MTD_ONENAND_MODULE)
static struct mtd_partition saar_onenand_partitions[] = {
	{
		.name		= "bootloader",
		.offset		= 0,
		.size		= SZ_1M,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "reserved",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_128K,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "reserved",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_8M,
		.mask_flags	= MTD_WRITEABLE,
	}, {
		.name		= "kernel",
		.offset		= MTDPART_OFS_APPEND,
		.size		= (SZ_2M + SZ_1M),
		.mask_flags	= 0,
	}, {
		.name		= "filesystem",
		.offset		= MTDPART_OFS_APPEND,
		.size		= SZ_32M + SZ_16M,
		.mask_flags	= 0,
	}
};

static struct onenand_platform_data saar_onenand_info = {
	.parts		= saar_onenand_partitions,
	.nr_parts	= ARRAY_SIZE(saar_onenand_partitions),
};

#define SMC_CS0_PHYS_BASE	(0x10000000)

static struct resource saar_resource_onenand[] = {
	[0] = {
		.start	= SMC_CS0_PHYS_BASE,
		.end	= SMC_CS0_PHYS_BASE + SZ_1M,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device saar_device_onenand = {
	.name		= "onenand-flash",
	.id		= -1,
	.dev		= {
		.platform_data	= &saar_onenand_info,
	},
	.resource	= saar_resource_onenand,
	.num_resources	= ARRAY_SIZE(saar_resource_onenand),
};

static void __init saar_init_onenand(void)
{
	platform_device_register(&saar_device_onenand);
}
#else
static void __init saar_init_onenand(void) {}
#endif

static void __init saar_init(void)
{
	/* initialize MFP configurations */
	pxa3xx_mfp_config(ARRAY_AND_SIZE(saar_mfp_cfg));

	pxa_set_ffuart_info(NULL);
	pxa_set_btuart_info(NULL);
	pxa_set_stuart_info(NULL);

	platform_device_register(&smc91x_device);
	saar_init_onenand();

	saar_init_i2c();
	saar_init_lcd();
}

MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
	/* Maintainer: Eric Miao <eric.miao@marvell.com> */
	.atag_offset    = 0x100,
	.map_io         = pxa3xx_map_io,
	.nr_irqs	= PXA_NR_IRQS,
	.init_irq       = pxa3xx_init_irq,
	.handle_irq       = pxa3xx_handle_irq,
	.init_time	= pxa_timer_init,
	.init_machine   = saar_init,
	.restart	= pxa_restart,
MACHINE_END


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
 * series of PDAs
 *
 * Copyright (c) 2004-2005 Richard Purdie
 *
 * Based on code written by Sharp for 2.4 kernels
 */

#undef DEBUG

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/apm-emulation.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/leds.h>
#include <linux/suspend.h>
#include <linux/gpio.h>
#include <linux/io.h>

#include <asm/mach-types.h>
#include "pm.h"
#include "pxa2xx-regs.h"
#include "regs-rtc.h"
#include "sharpsl_pm.h"

/*
 * Constants
 */
#define SHARPSL_CHARGE_ON_TIME_INTERVAL        (msecs_to_jiffies(1*60*1000))  /* 1 min */
#define SHARPSL_CHARGE_FINISH_TIME             (msecs_to_jiffies(10*60*1000)) /* 10 min */
#define SHARPSL_BATCHK_TIME                    (msecs_to_jiffies(15*1000))    /* 15 sec */
#define SHARPSL_BATCHK_TIME_SUSPEND            (60*10)                        /* 10 min */

#define SHARPSL_WAIT_CO_TIME                   15  /* 15 sec */
#define SHARPSL_WAIT_DISCHARGE_ON              100 /* 100 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP   10  /* 10 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT   10  /* 10 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN   10  /* 10 msec */
#define SHARPSL_CHARGE_WAIT_TIME               15  /* 15 msec */
#define SHARPSL_CHARGE_CO_CHECK_TIME           5   /* 5 msec */
#define SHARPSL_CHARGE_RETRY_CNT               1   /* eqv. 10 min */

/*
 * Prototypes
 */
#ifdef CONFIG_PM
static int sharpsl_off_charge_battery(void);
static int sharpsl_check_battery_voltage(void);
#endif
static int sharpsl_check_battery_temp(void);
static int sharpsl_ac_check(void);
static int sharpsl_average_value(int ad);
static void sharpsl_average_clear(void);
static void sharpsl_charge_toggle(struct work_struct *private_);
static void sharpsl_battery_thread(struct work_struct *private_);

/*
 * Variables
 */
struct sharpsl_pm_status sharpsl_pm;
static DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
static DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);

struct battery_thresh sharpsl_battery_levels_acin[] = {
	{ 213, 100},
	{ 212,  98},
	{ 211,  95},
	{ 210,  93},
	{ 209,  90},
	{ 208,  88},
	{ 207,  85},
	{ 206,  83},
	{ 205,  80},
	{ 204,  78},
	{ 203,  75},
	{ 202,  73},
	{ 201,  70},
	{ 200,  68},
	{ 199,  65},
	{ 198,  63},
	{ 197,  60},
	{ 196,  58},
	{ 195,  55},
	{ 194,  53},
	{ 193,  50},
	{ 192,  48},
	{ 192,  45},
	{ 191,  43},
	{ 191,  40},
	{ 190,  38},
	{ 190,  35},
	{ 189,  33},
	{ 188,  30},
	{ 187,  28},
	{ 186,  25},
	{ 185,  23},
	{ 184,  20},
	{ 183,  18},
	{ 182,  15},
	{ 181,  13},
	{ 180,  10},
	{ 179,   8},
	{ 178,   5},
	{   0,   0},
};

struct battery_thresh sharpsl_battery_levels_noac[] = {
	{ 213, 100},
	{ 212,  98},
	{ 211,  95},
	{ 210,  93},
	{ 209,  90},
	{ 208,  88},
	{ 207,  85},
	{ 206,  83},
	{ 205,  80},
	{ 204,  78},
	{ 203,  75},
	{ 202,  73},
	{ 201,  70},
	{ 200,  68},
	{ 199,  65},
	{ 198,  63},
	{ 197,  60},
	{ 196,  58},
	{ 195,  55},
	{ 194,  53},
	{ 193,  50},
	{ 192,  48},
	{ 191,  45},
	{ 190,  43},
	{ 189,  40},
	{ 188,  38},
	{ 187,  35},
	{ 186,  33},
	{ 185,  30},
	{ 184,  28},
	{ 183,  25},
	{ 182,  23},
	{ 181,  20},
	{ 180,  18},
	{ 179,  15},
	{ 178,  13},
	{ 177,  10},
	{ 176,   8},
	{ 175,   5},
	{   0,   0},
};

/* MAX1111 Commands */
#define MAXCTRL_PD0      (1u << 0)
#define MAXCTRL_PD1      (1u << 1)
#define MAXCTRL_SGL      (1u << 2)
#define MAXCTRL_UNI      (1u << 3)
#define MAXCTRL_SEL_SH   4
#define MAXCTRL_STR      (1u << 7)

extern int max1111_read_channel(int);
/*
 * Read MAX1111 ADC
 */
int sharpsl_pm_pxa_read_max1111(int channel)
{
	/* Ugly, better move this function into another module */
	if (machine_is_tosa())
	    return 0;

	/* max1111 accepts channels from 0-3, however,
	 * it is encoded from 0-7 here in the code.
	 */
	return max1111_read_channel(channel >> 1);
}

static int get_percentage(int voltage)
{
	int i = sharpsl_pm.machinfo->bat_levels - 1;
	int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
	struct battery_thresh *thresh;

	if (sharpsl_pm.charge_mode == CHRG_ON)
		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
	else
		thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;

	while (i > 0 && (voltage > thresh[i].voltage))
		i--;

	return thresh[i].percentage;
}

static int get_apm_status(int voltage)
{
	int low_thresh, high_thresh;

	if (sharpsl_pm.charge_mode == CHRG_ON) {
		high_thresh = sharpsl_pm.machinfo->status_high_acin;
		low_thresh = sharpsl_pm.machinfo->status_low_acin;
	} else {
		high_thresh = sharpsl_pm.machinfo->status_high_noac;
		low_thresh = sharpsl_pm.machinfo->status_low_noac;
	}

	if (voltage >= high_thresh)
		return APM_BATTERY_STATUS_HIGH;
	if (voltage >= low_thresh)
		return APM_BATTERY_STATUS_LOW;
	return APM_BATTERY_STATUS_CRITICAL;
}

void sharpsl_battery_kick(void)
{
	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
}
EXPORT_SYMBOL(sharpsl_battery_kick);

static void sharpsl_battery_thread(struct work_struct *private_)
{
	int voltage, percent, apm_status, i;

	if (!sharpsl_pm.machinfo)
		return;

	sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);

	/* Corgi cannot confirm when battery fully charged so periodically kick! */
	if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
			&& time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
		schedule_delayed_work(&toggle_charger, 0);

	for (i = 0; i < 5; i++) {
		voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
		if (voltage > 0)
			break;
	}
	if (voltage <= 0) {
		voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
		dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
	}

	voltage = sharpsl_average_value(voltage);
	apm_status = get_apm_status(voltage);
	percent = get_percentage(voltage);

	/* At low battery voltages, the voltage has a tendency to start
	   creeping back up so we try to avoid this here */
	if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE)
	    || (apm_status == APM_BATTERY_STATUS_HIGH)
	    || percent <= sharpsl_pm.battstat.mainbat_percent) {
		sharpsl_pm.battstat.mainbat_voltage = voltage;
		sharpsl_pm.battstat.mainbat_status = apm_status;
		sharpsl_pm.battstat.mainbat_percent = percent;
	}

	dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
			sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);

	/* Suspend if critical battery level */
	if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
	     && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
	     && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
		dev_err(sharpsl_pm.dev, "Fatal Off\n");
		apm_queue_event(APM_CRITICAL_SUSPEND);
	}

	schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
}

void sharpsl_pm_led(int val)
{
	if (val == SHARPSL_LED_ERROR) {
		dev_err(sharpsl_pm.dev, "Charging Error!\n");
	} else if (val == SHARPSL_LED_ON) {
		dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
		led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
	} else {
		dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
		led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
	}
}

static void sharpsl_charge_on(void)
{
	dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");

	sharpsl_pm.full_count = 0;
	sharpsl_pm.charge_mode = CHRG_ON;
	schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
	schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
}

static void sharpsl_charge_off(void)
{
	dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");

	sharpsl_pm.machinfo->charge(0);
	sharpsl_pm_led(SHARPSL_LED_OFF);
	sharpsl_pm.charge_mode = CHRG_OFF;

	schedule_delayed_work(&sharpsl_bat, 0);
}

static void sharpsl_charge_error(void)
{
	sharpsl_pm_led(SHARPSL_LED_ERROR);
	sharpsl_pm.machinfo->charge(0);
	sharpsl_pm.charge_mode = CHRG_ERROR;
}

static void sharpsl_charge_toggle(struct work_struct *private_)
{
	dev_dbg(sharpsl_pm.dev, "Toggling Charger at time: %lx\n", jiffies);

	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
		sharpsl_charge_off();
		return;
	} else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
		sharpsl_charge_error();
		return;
	}

	sharpsl_pm_led(SHARPSL_LED_ON);
	sharpsl_pm.machinfo->charge(0);
	mdelay(SHARPSL_CHARGE_WAIT_TIME);
	sharpsl_pm.machinfo->charge(1);

	sharpsl_pm.charge_start_time = jiffies;
}

static void sharpsl_ac_timer(struct timer_list *unused)
{
	int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);

	dev_dbg(sharpsl_pm.dev, "AC Status: %d\n", acin);

	sharpsl_average_clear();
	if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
		sharpsl_charge_on();
	else if (sharpsl_pm.charge_mode == CHRG_ON)
		sharpsl_charge_off();

	schedule_delayed_work(&sharpsl_bat, 0);
}

static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
{
	/* Delay the event slightly to debounce */
	/* Must be a smaller delay than the chrg_full_isr below */
	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));

	return IRQ_HANDLED;
}

static void sharpsl_chrg_full_timer(struct timer_list *unused)
{
	dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);

	sharpsl_pm.full_count++;

	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
		dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
		if (sharpsl_pm.charge_mode == CHRG_ON)
			sharpsl_charge_off();
	} else if (sharpsl_pm.full_count < 2) {
		dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
		schedule_delayed_work(&toggle_charger, 0);
	} else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
		dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
		schedule_delayed_work(&toggle_charger, 0);
	} else {
		sharpsl_charge_off();
		sharpsl_pm.charge_mode = CHRG_DONE;
		dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
	}
}

/* Charging Finished Interrupt (Not present on Corgi) */
/* Can trigger at the same time as an AC status change so
   delay until after that has been processed */
static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
{
	if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
		return IRQ_HANDLED;

	/* delay until after any ac interrupt */
	mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));

	return IRQ_HANDLED;
}

static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
{
	int is_fatal = 0;

	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
		dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
		is_fatal = 1;
	}

	if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
		dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
		is_fatal = 1;
	}

	if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
		sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
		apm_queue_event(APM_CRITICAL_SUSPEND);
	}

	return IRQ_HANDLED;
}

/*
 * Maintain an average of the last 10 readings
 */
#define SHARPSL_CNV_VALUE_NUM    10
static int sharpsl_ad_index;

static void sharpsl_average_clear(void)
{
	sharpsl_ad_index = 0;
}

static int sharpsl_average_value(int ad)
{
	int i, ad_val = 0;
	static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];

	if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
		sharpsl_ad_index = 0;
		return ad;
	}

	sharpsl_ad[sharpsl_ad_index] = ad;
	sharpsl_ad_index++;
	if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
		for (i = 0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
			sharpsl_ad[i] = sharpsl_ad[i+1];
		sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
	}
	for (i = 0; i < sharpsl_ad_index; i++)
		ad_val += sharpsl_ad[i];

	return ad_val / sharpsl_ad_index;
}

/*
 * Take an array of 5 integers, remove the maximum and minimum values
 * and return the average.
 */
static int get_select_val(int *val)
{
	int i, j, k, temp, sum = 0;

	/* Find MAX val */
	temp = val[0];
	j = 0;
	for (i = 1; i < 5; i++) {
		if (temp < val[i]) {
			temp = val[i];
			j = i;
		}
	}

	/* Find MIN val */
	temp = val[4];
	k = 4;
	for (i = 3; i >= 0; i--) {
		if (temp > val[i]) {
			temp = val[i];
			k = i;
		}
	}

	for (i = 0; i < 5; i++)
		if (i != j && i != k)
			sum += val[i];

	dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]);

	return sum/3;
}

static int sharpsl_check_battery_temp(void)
{
	int val, i, buff[5];

	/* Check battery temperature */
	for (i = 0; i < 5; i++) {
		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
		sharpsl_pm.machinfo->measure_temp(1);
		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
		sharpsl_pm.machinfo->measure_temp(0);
	}

	val = get_select_val(buff);

	dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
	if (val > sharpsl_pm.machinfo->charge_on_temp) {
		printk(KERN_WARNING "Not charging: temperature out of limits.\n");
		return -1;
	}

	return 0;
}

#ifdef CONFIG_PM
static int sharpsl_check_battery_voltage(void)
{
	int val, i, buff[5];

	/* disable charge, enable discharge */
	sharpsl_pm.machinfo->charge(0);
	sharpsl_pm.machinfo->discharge(1);
	mdelay(SHARPSL_WAIT_DISCHARGE_ON);

	if (sharpsl_pm.machinfo->discharge1)
		sharpsl_pm.machinfo->discharge1(1);

	/* Check battery voltage */
	for (i = 0; i < 5; i++) {
		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
	}

	if (sharpsl_pm.machinfo->discharge1)
		sharpsl_pm.machinfo->discharge1(0);

	sharpsl_pm.machinfo->discharge(0);

	val = get_select_val(buff);
	dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);

	if (val < sharpsl_pm.machinfo->charge_on_volt)
		return -1;

	return 0;
}
#endif

static int sharpsl_ac_check(void)
{
	int temp, i, buff[5];

	for (i = 0; i < 5; i++) {
		buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
		mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
	}

	temp = get_select_val(buff);
	dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n", temp);

	if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
		dev_err(sharpsl_pm.dev, "Error: AC check failed: voltage %d.\n", temp);
		return -1;
	}

	return 0;
}

#ifdef CONFIG_PM
static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
{
	sharpsl_pm.flags |= SHARPSL_SUSPENDED;
	flush_delayed_work(&toggle_charger);
	flush_delayed_work(&sharpsl_bat);

	if (sharpsl_pm.charge_mode == CHRG_ON)
		sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
	else
		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;

	return 0;
}

static int sharpsl_pm_resume(struct platform_device *pdev)
{
	/* Clear the reset source indicators as they break the bootloader upon reboot */
	RCSR = 0x0f;
	sharpsl_average_clear();
	sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
	sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;

	return 0;
}

static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
{
	dev_dbg(sharpsl_pm.dev, "Time is: %08x\n", RCNR);

	dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n", sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
	/* not charging and AC-IN! */

	if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
		dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
		sharpsl_pm.charge_mode = CHRG_OFF;
		sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
		sharpsl_off_charge_battery();
	}

	sharpsl_pm.machinfo->presuspend();

	PEDR = 0xffffffff; /* clear it */

	sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
	if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
		RTSR &= RTSR_ALE;
		RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
		dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n", RTAR);
		sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
	} else if (alarm_enable) {
		RTSR &= RTSR_ALE;
		RTAR = alarm_time;
		dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n", RTAR);
	} else {
		dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
	}

	pxa_pm_enter(state);

	sharpsl_pm.machinfo->postsuspend();

	dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n", PEDR);
}

static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
{
	if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable)) {
		if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
			dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
			corgi_goto_sleep(alarm_time, alarm_enable, state);
			return 1;
		}
		if (sharpsl_off_charge_battery()) {
			dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
			corgi_goto_sleep(alarm_time, alarm_enable, state);
			return 1;
		}
		dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
	}

	if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) ||
	    (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)))	{
		dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
		corgi_goto_sleep(alarm_time, alarm_enable, state);
		return 1;
	}

	return 0;
}

static int corgi_pxa_pm_enter(suspend_state_t state)
{
	unsigned long alarm_time = RTAR;
	unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);

	dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");

	corgi_goto_sleep(alarm_time, alarm_status, state);

	while (corgi_enter_suspend(alarm_time, alarm_status, state))
		{}

	if (sharpsl_pm.machinfo->earlyresume)
		sharpsl_pm.machinfo->earlyresume();

	dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");

	return 0;
}

static int sharpsl_off_charge_error(void)
{
	dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
	sharpsl_pm.machinfo->charge(0);
	sharpsl_pm_led(SHARPSL_LED_ERROR);
	sharpsl_pm.charge_mode = CHRG_ERROR;
	return 1;
}

/*
 * Charging Control while suspended
 * Return 1 - go straight to sleep
 * Return 0 - sleep or wakeup depending on other factors
 */
static int sharpsl_off_charge_battery(void)
{
	int time;

	dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);

	if (sharpsl_pm.charge_mode == CHRG_OFF) {
		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");

		/* AC Check */
		if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
			return sharpsl_off_charge_error();

		/* Start Charging */
		sharpsl_pm_led(SHARPSL_LED_ON);
		sharpsl_pm.machinfo->charge(0);
		mdelay(SHARPSL_CHARGE_WAIT_TIME);
		sharpsl_pm.machinfo->charge(1);

		sharpsl_pm.charge_mode = CHRG_ON;
		sharpsl_pm.full_count = 0;

		return 1;
	} else if (sharpsl_pm.charge_mode != CHRG_ON) {
		return 1;
	}

	if (sharpsl_pm.full_count == 0) {
		int time;

		dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");

		if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
			return sharpsl_off_charge_error();

		sharpsl_pm.machinfo->charge(0);
		mdelay(SHARPSL_CHARGE_WAIT_TIME);
		sharpsl_pm.machinfo->charge(1);
		sharpsl_pm.charge_mode = CHRG_ON;

		mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);

		time = RCNR;
		while (1) {
			/* Check if any wakeup event had occurred */
			if (sharpsl_pm.machinfo->charger_wakeup())
				return 0;
			/* Check for timeout */
			if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
				return 1;
			if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
				dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
				sharpsl_pm.full_count++;
				sharpsl_pm.machinfo->charge(0);
				mdelay(SHARPSL_CHARGE_WAIT_TIME);
				sharpsl_pm.machinfo->charge(1);
				return 1;
			}
		}
	}

	dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");

	mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);

	time = RCNR;
	while (1) {
		/* Check if any wakeup event had occurred */
		if (sharpsl_pm.machinfo->charger_wakeup())
			return 0;
		/* Check for timeout */
		if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
			if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
				dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
				sharpsl_pm.full_count = 0;
			}
			sharpsl_pm.full_count++;
			return 1;
		}
		if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
			dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
			sharpsl_pm_led(SHARPSL_LED_OFF);
			sharpsl_pm.machinfo->charge(0);
			sharpsl_pm.charge_mode = CHRG_DONE;
			return 1;
		}
	}
}
#else
#define sharpsl_pm_suspend	NULL
#define sharpsl_pm_resume	NULL
#endif

static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", sharpsl_pm.battstat.mainbat_percent);
}

static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "%d\n", sharpsl_pm.battstat.mainbat_voltage);
}

static DEVICE_ATTR_RO(battery_percentage);
static DEVICE_ATTR_RO(battery_voltage);

extern void (*apm_get_power_status)(struct apm_power_info *);

static void sharpsl_apm_get_power_status(struct apm_power_info *info)
{
	info->ac_line_status = sharpsl_pm.battstat.ac_status;

	if (sharpsl_pm.charge_mode == CHRG_ON)
		info->battery_status = APM_BATTERY_STATUS_CHARGING;
	else
		info->battery_status = sharpsl_pm.battstat.mainbat_status;

	info->battery_flag = (1 << info->battery_status);
	info->battery_life = sharpsl_pm.battstat.mainbat_percent;
}

#ifdef CONFIG_PM
static const struct platform_suspend_ops sharpsl_pm_ops = {
	.prepare	= pxa_pm_prepare,
	.finish		= pxa_pm_finish,
	.enter		= corgi_pxa_pm_enter,
	.valid		= suspend_valid_only_mem,
};
#endif

static int sharpsl_pm_probe(struct platform_device *pdev)
{
	int ret, irq;

	if (!pdev->dev.platform_data)
		return -EINVAL;

	sharpsl_pm.dev = &pdev->dev;
	sharpsl_pm.machinfo = pdev->dev.platform_data;
	sharpsl_pm.charge_mode = CHRG_OFF;
	sharpsl_pm.flags = 0;

	timer_setup(&sharpsl_pm.ac_timer, sharpsl_ac_timer, 0);

	timer_setup(&sharpsl_pm.chrg_full_timer, sharpsl_chrg_full_timer, 0);

	led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);

	sharpsl_pm.machinfo->init();

	gpio_request(sharpsl_pm.machinfo->gpio_acin, "AC IN");
	gpio_direction_input(sharpsl_pm.machinfo->gpio_acin);
	gpio_request(sharpsl_pm.machinfo->gpio_batfull, "Battery Full");
	gpio_direction_input(sharpsl_pm.machinfo->gpio_batfull);
	gpio_request(sharpsl_pm.machinfo->gpio_batlock, "Battery Lock");
	gpio_direction_input(sharpsl_pm.machinfo->gpio_batlock);

	/* Register interrupt handlers */
	irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_acin);
	if (request_irq(irq, sharpsl_ac_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) {
		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
	}

	irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batlock);
	if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) {
		dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
	}

	if (sharpsl_pm.machinfo->gpio_fatal) {
		irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_fatal);
		if (request_irq(irq, sharpsl_fatal_isr, IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) {
			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
		}
	}

	if (sharpsl_pm.machinfo->batfull_irq) {
		/* Register interrupt handler. */
		irq = gpio_to_irq(sharpsl_pm.machinfo->gpio_batfull);
		if (request_irq(irq, sharpsl_chrg_full_isr, IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) {
			dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", irq);
		}
	}

	ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
	ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
	if (ret != 0)
		dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);

	apm_get_power_status = sharpsl_apm_get_power_status;

#ifdef CONFIG_PM
	suspend_set_ops(&sharpsl_pm_ops);
#endif

	mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));

	return 0;
}

static int sharpsl_pm_remove(struct platform_device *pdev)
{
	suspend_set_ops(NULL);

	device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
	device_remove_file(&pdev->dev, &dev_attr_battery_voltage);

	led_trigger_unregister_simple(sharpsl_charge_led_trigger);

	free_irq(gpio_to_irq(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr);
	free_irq(gpio_to_irq(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr);

	if (sharpsl_pm.machinfo->gpio_fatal)
		free_irq(gpio_to_irq(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr);

	if (sharpsl_pm.machinfo->batfull_irq)
		free_irq(gpio_to_irq(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr);

	gpio_free(sharpsl_pm.machinfo->gpio_batlock);
	gpio_free(sharpsl_pm.machinfo->gpio_batfull);
	gpio_free(sharpsl_pm.machinfo->gpio_acin);

	if (sharpsl_pm.machinfo->exit)
		sharpsl_pm.machinfo->exit();

	del_timer_sync(&sharpsl_pm.chrg_full_timer);
	del_timer_sync(&sharpsl_pm.ac_timer);

	return 0;
}

static struct platform_driver sharpsl_pm_driver = {
	.probe		= sharpsl_pm_probe,
	.remove		= sharpsl_pm_remove,
	.suspend	= sharpsl_pm_suspend,
	.resume		= sharpsl_pm_resume,
	.driver		= {
		.name		= "sharpsl-pm",
	},
};

static int sharpsl_pm_init(void)
{
	return platform_driver_register(&sharpsl_pm_driver);
}

static void sharpsl_pm_exit(void)
{
	platform_driver_unregister(&sharpsl_pm_driver);
}

late_initcall(sharpsl_pm_init);
module_exit(sharpsl_pm_exit);


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * SharpSL Battery/PM Driver
 *
 * Copyright (c) 2004-2005 Richard Purdie
 */
#ifndef _MACH_SHARPSL_PM
#define _MACH_SHARPSL_PM

struct sharpsl_charger_machinfo {
	void (*init)(void);
	void (*exit)(void);
	int gpio_acin;
	int gpio_batfull;
	int batfull_irq;
	int gpio_batlock;
	int gpio_fatal;
	void (*discharge)(int);
	void (*discharge1)(int);
	void (*charge)(int);
	void (*measure_temp)(int);
	void (*presuspend)(void);
	void (*postsuspend)(void);
	void (*earlyresume)(void);
	unsigned long (*read_devdata)(int);
#define SHARPSL_BATT_VOLT       1
#define SHARPSL_BATT_TEMP       2
#define SHARPSL_ACIN_VOLT       3
#define SHARPSL_STATUS_ACIN     4
#define SHARPSL_STATUS_LOCK     5
#define SHARPSL_STATUS_CHRGFULL 6
#define SHARPSL_STATUS_FATAL    7
	bool (*charger_wakeup)(void);
	int (*should_wakeup)(unsigned int resume_on_alarm);
	void (*backlight_limit)(int);
	int (*backlight_get_status) (void);
	int charge_on_volt;
	int charge_on_temp;
	int charge_acin_high;
	int charge_acin_low;
	int fatal_acin_volt;
	int fatal_noacin_volt;
	int bat_levels;
	struct battery_thresh *bat_levels_noac;
	struct battery_thresh *bat_levels_acin;
	struct battery_thresh *bat_levels_noac_bl;
	struct battery_thresh *bat_levels_acin_bl;
	int status_high_acin;
	int status_low_acin;
	int status_high_noac;
	int status_low_noac;
};

struct battery_thresh {
	int voltage;
	int percentage;
};

struct battery_stat {
	int ac_status;         /* APM AC Present/Not Present */
	int mainbat_status;    /* APM Main Battery Status */
	int mainbat_percent;   /* Main Battery Percentage Charge */
	int mainbat_voltage;   /* Main Battery Voltage */
};

struct sharpsl_pm_status {
	struct device *dev;
	struct timer_list ac_timer;
	struct timer_list chrg_full_timer;

	int charge_mode;
#define CHRG_ERROR    (-1)
#define CHRG_OFF      (0)
#define CHRG_ON       (1)
#define CHRG_DONE     (2)

	unsigned int flags;
#define SHARPSL_SUSPENDED       (1 << 0)  /* Device is Suspended */
#define SHARPSL_ALARM_ACTIVE    (1 << 1)  /* Alarm is for charging event (not user) */
#define SHARPSL_BL_LIMIT        (1 << 2)  /* Backlight Intensity Limited */
#define SHARPSL_APM_QUEUED      (1 << 3)  /* APM Event Queued */
#define SHARPSL_DO_OFFLINE_CHRG (1 << 4)  /* Trigger the offline charger */

	int full_count;
	unsigned long charge_start_time;
	struct sharpsl_charger_machinfo *machinfo;
	struct battery_stat battstat;
};

extern struct sharpsl_pm_status sharpsl_pm;

extern struct battery_thresh sharpsl_battery_levels_acin[];
extern struct battery_thresh sharpsl_battery_levels_noac[];

#define SHARPSL_LED_ERROR  2
#define SHARPSL_LED_ON     1
#define SHARPSL_LED_OFF    0

void sharpsl_battery_kick(void);
void sharpsl_pm_led(int val);

/* MAX1111 Channel Definitions */
#define MAX1111_BATT_VOLT   4u
#define MAX1111_BATT_TEMP   2u
#define MAX1111_ACIN_VOLT   6u
int sharpsl_pm_pxa_read_max1111(int channel);

void corgi_lcd_limit_intensity(int limit);
#endif


code:
/*
 * Low-level PXA250/210 sleep/wakeUp support
 *
 * Initial SA1110 code:
 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
 *
 * Adapted for PXA by Nicolas Pitre:
 * Copyright (c) 2002 Monta Vista Software, Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License.
 */

#include <linux/linkage.h>
#include <asm/assembler.h>
#include "smemc.h"
#include "pxa2xx-regs.h"

#define MDREFR_KDIV	0x200a4000	// all banks
#define CCCR_SLEEP	0x00000107	// L=7 2N=2 A=0 PPDIS=0 CPDIS=0
#define CCCR_N_MASK     0x00000380
#define CCCR_M_MASK     0x00000060
#define CCCR_L_MASK     0x0000001f
		.text

#ifdef CONFIG_PXA3xx
/*
 * pxa3xx_finish_suspend() - forces CPU into sleep state (S2D3C4)
 */
ENTRY(pxa3xx_finish_suspend)
	mov	r0, #0x06		@ S2D3C4 mode
	mcr	p14, 0, r0, c7, c0, 0	@ enter sleep

20:	b	20b			@ waiting for sleep
#endif /* CONFIG_PXA3xx */

#ifdef CONFIG_PXA27x
/*
 * pxa27x_finish_suspend()
 *
 * Forces CPU into sleep state.
 *
 * r0 = value for PWRMODE M field for desired sleep state
 */
ENTRY(pxa27x_finish_suspend)
	@ Put the processor to sleep
	@ (also workaround for sighting 28071)

	@ prepare value for sleep mode
	mov	r1, r0				@ sleep mode

	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
	mov	r2, #UNCACHED_PHYS_0

	@ prepare SDRAM refresh settings
	ldr	r4, =MDREFR
	ldr	r5, [r4]

	@ enable SDRAM self-refresh mode
	orr	r5, r5, #MDREFR_SLFRSH

	@ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50)
	ldr	r6, =MDREFR_KDIV
	orr	r5, r5, r6

	@ Intel PXA270 Specification Update notes problems sleeping
	@ with core operating above 91 MHz
	@ (see Errata 50, ...processor does not exit from sleep...)

	ldr	r6, =CCCR
	ldr	r8, [r6]		@ keep original value for resume

	ldr	r7, =CCCR_SLEEP		@ prepare CCCR sleep value
	mov	r0, #0x2		@ prepare value for CLKCFG

	@ align execution to a cache line
	b	pxa_cpu_do_suspend
#endif

#ifdef CONFIG_PXA25x
/*
 * pxa25x_finish_suspend()
 *
 * Forces CPU into sleep state.
 *
 * r0 = value for PWRMODE M field for desired sleep state
 */

ENTRY(pxa25x_finish_suspend)
	@ prepare value for sleep mode
	mov	r1, r0				@ sleep mode

	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
	mov	r2, #UNCACHED_PHYS_0

	@ prepare SDRAM refresh settings
	ldr	r4, =MDREFR
	ldr	r5, [r4]

	@ enable SDRAM self-refresh mode
	orr	r5, r5, #MDREFR_SLFRSH

	@ Intel PXA255 Specification Update notes problems
	@ about suspending with PXBus operating above 133MHz
	@ (see Errata 31, GPIO output signals, ... unpredictable in sleep
	@
	@ We keep the change-down close to the actual suspend on SDRAM
	@ as possible to eliminate messing about with the refresh clock
	@ as the system will restore with the original speed settings
	@
	@ Ben Dooks, 13-Sep-2004

	ldr	r6, =CCCR
	ldr	r8, [r6]		@ keep original value for resume

	@ ensure x1 for run and turbo mode with memory clock
	bic	r7, r8, #CCCR_M_MASK | CCCR_N_MASK
	orr	r7, r7, #(1<<5) | (2<<7)

	@ check that the memory frequency is within limits
	and	r14, r7, #CCCR_L_MASK
	teq	r14, #1
	bicne	r7, r7, #CCCR_L_MASK
	orrne	r7, r7, #1			@@ 99.53MHz

	@ get ready for the change

	@ note, turbo is not preserved over sleep so there is no
	@ point in preserving it here. we save it on the stack with the
	@ other CP registers instead.
	mov	r0, #0
	mcr	p14, 0, r0, c6, c0, 0
	orr	r0, r0, #2			@ initiate change bit
	b	pxa_cpu_do_suspend
#endif

	.ltorg
	.align	5
pxa_cpu_do_suspend:

	@ All needed values are now in registers.
	@ These last instructions should be in cache

	@ initiate the frequency change...
	str	r7, [r6]
	mcr	p14, 0, r0, c6, c0, 0

	@ restore the original cpu speed value for resume
	str	r8, [r6]

	@ need 6 13-MHz cycles before changing PWRMODE
	@ just set frequency to 91-MHz... 6*91/13 = 42

	mov	r0, #42
10:	subs	r0, r0, #1
	bne	10b

	@ Do not reorder...
	@ Intel PXA270 Specification Update notes problems performing
	@ external accesses after SDRAM is put in self-refresh mode
	@ (see Errata 38 ...hangs when entering self-refresh mode)

	@ force address lines low by reading at physical address 0
	ldr	r3, [r2]

	@ put SDRAM into self-refresh
	str	r5, [r4]

	@ enter sleep mode
	mcr	p14, 0, r1, c7, c0, 0		@ PWRMODE

20:	b	20b				@ loop waiting for sleep


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * Static Memory Controller
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>
#include <linux/soc/pxa/cpu.h>

#include "smemc.h"
#include <linux/soc/pxa/smemc.h>

#ifdef CONFIG_PM
static unsigned long msc[2];
static unsigned long sxcnfg, memclkcfg;
static unsigned long csadrcfg[4];

static int pxa3xx_smemc_suspend(void)
{
	msc[0] = __raw_readl(MSC0);
	msc[1] = __raw_readl(MSC1);
	sxcnfg = __raw_readl(SXCNFG);
	memclkcfg = __raw_readl(MEMCLKCFG);
	csadrcfg[0] = __raw_readl(CSADRCFG0);
	csadrcfg[1] = __raw_readl(CSADRCFG1);
	csadrcfg[2] = __raw_readl(CSADRCFG2);
	csadrcfg[3] = __raw_readl(CSADRCFG3);

	return 0;
}

static void pxa3xx_smemc_resume(void)
{
	__raw_writel(msc[0], MSC0);
	__raw_writel(msc[1], MSC1);
	__raw_writel(sxcnfg, SXCNFG);
	__raw_writel(memclkcfg, MEMCLKCFG);
	__raw_writel(csadrcfg[0], CSADRCFG0);
	__raw_writel(csadrcfg[1], CSADRCFG1);
	__raw_writel(csadrcfg[2], CSADRCFG2);
	__raw_writel(csadrcfg[3], CSADRCFG3);
	/* CSMSADRCFG wakes up in its default state (0), so we need to set it */
	__raw_writel(0x2, CSMSADRCFG);
}

static struct syscore_ops smemc_syscore_ops = {
	.suspend	= pxa3xx_smemc_suspend,
	.resume		= pxa3xx_smemc_resume,
};

static int __init smemc_init(void)
{
	if (cpu_is_pxa3xx()) {
		/*
		 * The only documentation we have on the
		 * Chip Select Configuration Register (CSMSADRCFG) is that
		 * it must be programmed to 0x2.
		 * Moreover, in the bit definitions, the second bit
		 * (CSMSADRCFG[1]) is called "SETALWAYS".
		 * Other bits are reserved in this register.
		 */
		__raw_writel(0x2, CSMSADRCFG);

		register_syscore_ops(&smemc_syscore_ops);
	}

	return 0;
}
subsys_initcall(smemc_init);
#endif

static const unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
unsigned int pxa3xx_smemc_get_memclkdiv(void)
{
	unsigned long memclkcfg = __raw_readl(MEMCLKCFG);

	return	df_clkdiv[(memclkcfg >> 16) & 0x3];
}


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Static memory controller register definitions for PXA CPUs
 *
 * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
 */

#ifndef __SMEMC_REGS_H
#define __SMEMC_REGS_H

#define PXA2XX_SMEMC_BASE	0x48000000
#define PXA3XX_SMEMC_BASE	0x4a000000
#define SMEMC_VIRT		IOMEM(0xf6000000)

#define MDCNFG		(SMEMC_VIRT + 0x00)  /* SDRAM Configuration Register 0 */
#define MDREFR		(SMEMC_VIRT + 0x04)  /* SDRAM Refresh Control Register */
#define MSC0		(SMEMC_VIRT + 0x08)  /* Static Memory Control Register 0 */
#define MSC1		(SMEMC_VIRT + 0x0C)  /* Static Memory Control Register 1 */
#define MSC2		(SMEMC_VIRT + 0x10)  /* Static Memory Control Register 2 */
#define MECR		(SMEMC_VIRT + 0x14)  /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */
#define SXLCR		(SMEMC_VIRT + 0x18)  /* LCR value to be written to SDRAM-Timing Synchronous Flash */
#define SXCNFG		(SMEMC_VIRT + 0x1C)  /* Synchronous Static Memory Control Register */
#define SXMRS		(SMEMC_VIRT + 0x24)  /* MRS value to be written to Synchronous Flash or SMROM */
#define MCMEM0		(SMEMC_VIRT + 0x28)  /* Card interface Common Memory Space Socket 0 Timing */
#define MCMEM1		(SMEMC_VIRT + 0x2C)  /* Card interface Common Memory Space Socket 1 Timing */
#define MCATT0		(SMEMC_VIRT + 0x30)  /* Card interface Attribute Space Socket 0 Timing Configuration */
#define MCATT1		(SMEMC_VIRT + 0x34)  /* Card interface Attribute Space Socket 1 Timing Configuration */
#define MCIO0		(SMEMC_VIRT + 0x38)  /* Card interface I/O Space Socket 0 Timing Configuration */
#define MCIO1		(SMEMC_VIRT + 0x3C)  /* Card interface I/O Space Socket 1 Timing Configuration */
#define MDMRS		(SMEMC_VIRT + 0x40)  /* MRS value to be written to SDRAM */
#define BOOT_DEF	(SMEMC_VIRT + 0x44)  /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */
#define MEMCLKCFG	(SMEMC_VIRT + 0x68)  /* Clock Configuration */
#define CSADRCFG0	(SMEMC_VIRT + 0x80)  /* Address Configuration Register for CS0 */
#define CSADRCFG1	(SMEMC_VIRT + 0x84)  /* Address Configuration Register for CS1 */
#define CSADRCFG2	(SMEMC_VIRT + 0x88)  /* Address Configuration Register for CS2 */
#define CSADRCFG3	(SMEMC_VIRT + 0x8C)  /* Address Configuration Register for CS3 */
#define CSMSADRCFG	(SMEMC_VIRT + 0xA0)  /* Chip Select Configuration Register */

/*
 * More handy macros for PCMCIA
 *
 * Arg is socket number
 */
#define MCMEM(s)	(SMEMC_VIRT + 0x28 + ((s)<<2))  /* Card interface Common Memory Space Socket s Timing */
#define MCATT(s)	(SMEMC_VIRT + 0x30 + ((s)<<2))  /* Card interface Attribute Space Socket s Timing Configuration */
#define MCIO(s)		(SMEMC_VIRT + 0x38 + ((s)<<2))  /* Card interface I/O Space Socket s Timing Configuration */

/* MECR register defines */
#define MECR_NOS	(1 << 0)	/* Number Of Sockets: 0 -> 1 sock, 1 -> 2 sock */
#define MECR_CIT	(1 << 1)	/* Card Is There: 0 -> no card, 1 -> card inserted */

#define MDCNFG_DE0	(1 << 0)	/* SDRAM Bank 0 Enable */
#define MDCNFG_DE1	(1 << 1)	/* SDRAM Bank 1 Enable */
#define MDCNFG_DE2	(1 << 16)	/* SDRAM Bank 2 Enable */
#define MDCNFG_DE3	(1 << 17)	/* SDRAM Bank 3 Enable */

#define MDREFR_K0DB4	(1 << 29)	/* SDCLK0 Divide by 4 Control/Status */
#define MDREFR_K2FREE	(1 << 25)	/* SDRAM Free-Running Control */
#define MDREFR_K1FREE	(1 << 24)	/* SDRAM Free-Running Control */
#define MDREFR_K0FREE	(1 << 23)	/* SDRAM Free-Running Control */
#define MDREFR_SLFRSH	(1 << 22)	/* SDRAM Self-Refresh Control/Status */
#define MDREFR_APD	(1 << 20)	/* SDRAM/SSRAM Auto-Power-Down Enable */
#define MDREFR_K2DB2	(1 << 19)	/* SDCLK2 Divide by 2 Control/Status */
#define MDREFR_K2RUN	(1 << 18)	/* SDCLK2 Run Control/Status */
#define MDREFR_K1DB2	(1 << 17)	/* SDCLK1 Divide by 2 Control/Status */
#define MDREFR_K1RUN	(1 << 16)	/* SDCLK1 Run Control/Status */
#define MDREFR_E1PIN	(1 << 15)	/* SDCKE1 Level Control/Status */
#define MDREFR_K0DB2	(1 << 14)	/* SDCLK0 Divide by 2 Control/Status */
#define MDREFR_K0RUN	(1 << 13)	/* SDCLK0 Run Control/Status */
#define MDREFR_E0PIN	(1 << 12)	/* SDCKE0 Level Control/Status */

#endif


code:
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Support for Sharp SL-Cxx00 Series of PDAs
 * Models: SL-C3000 (Spitz), SL-C1000 (Akita) and SL-C3100 (Borzoi)
 *
 * Copyright (c) 2005 Richard Purdie
 *
 * Based on Sharp's 2.4 kernel patches/lubbock.c
 */

#include <linux/kernel.h>
#include <linux/module.h>	/* symbol_get ; symbol_put */
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/leds.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h>
#include <linux/platform_data/pca953x.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/spi/corgi_lcd.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h>
#include <linux/mtd/physmap.h>
#include <linux/input/matrix_keypad.h>
#include <linux/regulator/machine.h>
#include <linux/io.h>
#include <linux/reboot.h>
#include <linux/memblock.h>

#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/scoop.h>

#include "pxa27x.h"
#include "pxa27x-udc.h"
#include "reset.h"
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/video-pxafb.h>
#include "spitz.h"
#include "sharpsl_pm.h"
#include "smemc.h"

#include "generic.h"
#include "devices.h"

/******************************************************************************
 * Pin configuration
 ******************************************************************************/
static unsigned long spitz_pin_config[] __initdata = {
	/* Chip Selects */
	GPIO78_nCS_2,	/* SCOOP #2 */
	GPIO79_nCS_3,	/* NAND */
	GPIO80_nCS_4,	/* SCOOP #1 */

	/* LCD - 16bpp Active TFT */
	GPIOxx_LCD_TFT_16BPP,

	/* PC Card */
	GPIO48_nPOE,
	GPIO49_nPWE,
	GPIO50_nPIOR,
	GPIO51_nPIOW,
	GPIO85_nPCE_1,
	GPIO54_nPCE_2,
	GPIO55_nPREG,
	GPIO56_nPWAIT,
	GPIO57_nIOIS16,
	GPIO104_PSKTSEL,

	/* I2S */
	GPIO28_I2S_BITCLK_OUT,
	GPIO29_I2S_SDATA_IN,
	GPIO30_I2S_SDATA_OUT,
	GPIO31_I2S_SYNC,

	/* MMC */
	GPIO32_MMC_CLK,
	GPIO112_MMC_CMD,
	GPIO92_MMC_DAT_0,
	GPIO109_MMC_DAT_1,
	GPIO110_MMC_DAT_2,
	GPIO111_MMC_DAT_3,

	/* GPIOs */
	GPIO9_GPIO,	/* SPITZ_GPIO_nSD_DETECT */
	GPIO16_GPIO,	/* SPITZ_GPIO_SYNC */
	GPIO81_GPIO,	/* SPITZ_GPIO_nSD_WP */
	GPIO41_GPIO,	/* SPITZ_GPIO_USB_CONNECT */
	GPIO37_GPIO,	/* SPITZ_GPIO_USB_HOST */
	GPIO35_GPIO,	/* SPITZ_GPIO_USB_DEVICE */
	GPIO22_GPIO,	/* SPITZ_GPIO_HSYNC */
	GPIO94_GPIO,	/* SPITZ_GPIO_CF_CD */
	GPIO105_GPIO,	/* SPITZ_GPIO_CF_IRQ */
	GPIO106_GPIO,	/* SPITZ_GPIO_CF2_IRQ */

	/* GPIO matrix keypad */
	GPIO88_GPIO,	/* column 0 */
	GPIO23_GPIO,	/* column 1 */
	GPIO24_GPIO,	/* column 2 */
	GPIO25_GPIO,	/* column 3 */
	GPIO26_GPIO,	/* column 4 */
	GPIO27_GPIO,	/* column 5 */
	GPIO52_GPIO,	/* column 6 */
	GPIO103_GPIO,	/* column 7 */
	GPIO107_GPIO,	/* column 8 */
	GPIO108_GPIO,	/* column 9 */
	GPIO114_GPIO,	/* column 10 */
	GPIO12_GPIO,	/* row 0 */
	GPIO17_GPIO,	/* row 1 */
	GPIO91_GPIO,	/* row 2 */
	GPIO34_GPIO,	/* row 3 */
	GPIO36_GPIO,	/* row 4 */
	GPIO38_GPIO,	/* row 5 */
	GPIO39_GPIO,	/* row 6 */

	/* I2C */
	GPIO117_I2C_SCL,
	GPIO118_I2C_SDA,

	GPIO0_GPIO | WAKEUP_ON_EDGE_RISE,	/* SPITZ_GPIO_KEY_INT */
	GPIO1_GPIO | WAKEUP_ON_EDGE_FALL,	/* SPITZ_GPIO_RESET */
};

/******************************************************************************
 * Scoop GPIO expander
 ******************************************************************************/
#if defined(CONFIG_SHARP_SCOOP) || defined(CONFIG_SHARP_SCOOP_MODULE)
/* SCOOP Device #1 */
static struct resource spitz_scoop_1_resources[] = {
	[0] = {
		.start		= 0x10800000,
		.end		= 0x10800fff,
		.flags		= IORESOURCE_MEM,
	},
};

static struct scoop_config spitz_scoop_1_setup = {
	.io_dir		= SPITZ_SCP_IO_DIR,
	.io_out		= SPITZ_SCP_IO_OUT,
	.suspend_clr	= SPITZ_SCP_SUS_CLR,
	.suspend_set	= SPITZ_SCP_SUS_SET,
	.gpio_base	= SPITZ_SCP_GPIO_BASE,
};

struct platform_device spitz_scoop_1_device = {
	.name		= "sharp-scoop",
	.id		= 0,
	.dev		= {
		.platform_data	= &spitz_scoop_1_setup,
	},
	.num_resources	= ARRAY_SIZE(spitz_scoop_1_resources),
	.resource	= spitz_scoop_1_resources,
};

/* SCOOP Device #2 */
static struct resource spitz_scoop_2_resources[] = {
	[0] = {
		.start		= 0x08800040,
		.end		= 0x08800fff,
		.flags		= IORESOURCE_MEM,
	},
};

static struct scoop_config spitz_scoop_2_setup = {
	.io_dir		= SPITZ_SCP2_IO_DIR,
	.io_out		= SPITZ_SCP2_IO_OUT,
	.suspend_clr	= SPITZ_SCP2_SUS_CLR,
	.suspend_set	= SPITZ_SCP2_SUS_SET,
	.gpio_base	= SPITZ_SCP2_GPIO_BASE,
};

struct platform_device spitz_scoop_2_device = {
	.name		= "sharp-scoop",
	.id		= 1,
	.dev		= {
		.platform_data	= &spitz_scoop_2_setup,
	},
	.num_resources	= ARRAY_SIZE(spitz_scoop_2_resources),
	.resource	= spitz_scoop_2_resources,
};

static void __init spitz_scoop_init(void)
{
	platform_device_register(&spitz_scoop_1_device);

	/* Akita doesn't have the second SCOOP chip */
	if (!machine_is_akita())
		platform_device_register(&spitz_scoop_2_device);
}

/* Power control is shared with between one of the CF slots and SD */
static void __maybe_unused spitz_card_pwr_ctrl(uint8_t enable, uint8_t new_cpr)
{
	unsigned short cpr;
	unsigned long flags;

	if (new_cpr & 0x7) {
		gpio_set_value(SPITZ_GPIO_CF_POWER, 1);
		mdelay(5);
	}

	local_irq_save(flags);

	cpr = read_scoop_reg(&spitz_scoop_1_device.dev, SCOOP_CPR);

	if (enable & new_cpr)
		cpr |= new_cpr;
	else
		cpr &= ~enable;

	write_scoop_reg(&spitz_scoop_1_device.dev, SCOOP_CPR, cpr);

	local_irq_restore(flags);

	if (!(cpr & 0x7)) {
		mdelay(1);
		gpio_set_value(SPITZ_GPIO_CF_POWER, 0);
	}
}

#else
static inline void spitz_scoop_init(void) {}
static inline void spitz_card_pwr_ctrl(uint8_t enable, uint8_t new_cpr) {}
#endif

/******************************************************************************
 * PCMCIA
 ******************************************************************************/
#if defined(CONFIG_PCMCIA_PXA2XX) || defined(CONFIG_PCMCIA_PXA2XX_MODULE)
static void spitz_pcmcia_pwr(struct device *scoop, uint16_t cpr, int nr)
{
	/* Only need to override behaviour for slot 0 */
	if (nr == 0)
		spitz_card_pwr_ctrl(
			cpr & (SCOOP_CPR_CF_3V | SCOOP_CPR_CF_XV), cpr);
	else
		write_scoop_reg(scoop, SCOOP_CPR, cpr);
}

static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = {
	{
		.dev		= &spitz_scoop_1_device.dev,
		.irq		= SPITZ_IRQ_GPIO_CF_IRQ,
		.cd_irq		= SPITZ_IRQ_GPIO_CF_CD,
		.cd_irq_str	= "PCMCIA0 CD",
	}, {
		.dev		= &spitz_scoop_2_device.dev,
		.irq		= SPITZ_IRQ_GPIO_CF2_IRQ,
		.cd_irq		= -1,
	},
};

static struct scoop_pcmcia_config spitz_pcmcia_config = {
	.devs		= &spitz_pcmcia_scoop[0],
	.num_devs	= 2,
	.power_ctrl	= spitz_pcmcia_pwr,
};

static void __init spitz_pcmcia_init(void)
{
	/* Akita has only one PCMCIA slot used */
	if (machine_is_akita())
		spitz_pcmcia_config.num_devs = 1;

	platform_scoop_config = &spitz_pcmcia_config;
}
#else
static inline void spitz_pcmcia_init(void) {}
#endif

/******************************************************************************
 * GPIO keyboard
 ******************************************************************************/
#if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE)

#define SPITZ_KEY_CALENDAR	KEY_F1
#define SPITZ_KEY_ADDRESS	KEY_F2
#define SPITZ_KEY_FN		KEY_F3
#define SPITZ_KEY_CANCEL	KEY_F4
#define SPITZ_KEY_EXOK		KEY_F5
#define SPITZ_KEY_EXCANCEL	KEY_F6
#define SPITZ_KEY_EXJOGDOWN	KEY_F7
#define SPITZ_KEY_EXJOGUP	KEY_F8
#define SPITZ_KEY_JAP1		KEY_LEFTALT
#define SPITZ_KEY_JAP2		KEY_RIGHTCTRL
#define SPITZ_KEY_SYNC		KEY_F9
#define SPITZ_KEY_MAIL		KEY_F10
#define SPITZ_KEY_OK		KEY_F11
#define SPITZ_KEY_MENU		KEY_F12

static const uint32_t spitz_keymap[] = {
	KEY(0, 0, KEY_LEFTCTRL),
	KEY(0, 1, KEY_1),
	KEY(0, 2, KEY_3),
	KEY(0, 3, KEY_5),
	KEY(0, 4, KEY_6),
	KEY(0, 5, KEY_7),
	KEY(0, 6, KEY_9),
	KEY(0, 7, KEY_0),
	KEY(0, 8, KEY_BACKSPACE),
	KEY(0, 9, SPITZ_KEY_EXOK),	/* EXOK */
	KEY(0, 10, SPITZ_KEY_EXCANCEL),	/* EXCANCEL */
	KEY(1, 1, KEY_2),
	KEY(1, 2, KEY_4),
	KEY(1, 3, KEY_R),
	KEY(1, 4, KEY_Y),
	KEY(1, 5, KEY_8),
	KEY(1, 6, KEY_I),
	KEY(1, 7, KEY_O),
	KEY(1, 8, KEY_P),
	KEY(1, 9, SPITZ_KEY_EXJOGDOWN),	/* EXJOGDOWN */
	KEY(1, 10, SPITZ_KEY_EXJOGUP),	/* EXJOGUP */
	KEY(2, 0, KEY_TAB),
	KEY(2, 1, KEY_Q),
	KEY(2, 2, KEY_E),
	KEY(2, 3, KEY_T),
	KEY(2, 4, KEY_G),
	KEY(2, 5, KEY_U),
	KEY(2, 6, KEY_J),
	KEY(2, 7, KEY_K),
	KEY(3, 0, SPITZ_KEY_ADDRESS),	/* ADDRESS */
	KEY(3, 1, KEY_W),
	KEY(3, 2, KEY_S),
	KEY(3, 3, KEY_F),
	KEY(3, 4, KEY_V),
	KEY(3, 5, KEY_H),
	KEY(3, 6, KEY_M),
	KEY(3, 7, KEY_L),
	KEY(3, 9, KEY_RIGHTSHIFT),
	KEY(4, 0, SPITZ_KEY_CALENDAR),	/* CALENDAR */
	KEY(4, 1, KEY_A),
	KEY(4, 2, KEY_D),
	KEY(4, 3, KEY_C),
	KEY(4, 4, KEY_B),
	KEY(4, 5, KEY_N),
	KEY(4, 6, KEY_DOT),
	KEY(4, 8, KEY_ENTER),
	KEY(4, 9, KEY_LEFTSHIFT),
	KEY(5, 0, SPITZ_KEY_MAIL),	/* MAIL */
	KEY(5, 1, KEY_Z),
	KEY(5, 2, KEY_X),
	KEY(5, 3, KEY_MINUS),
	KEY(5, 4, KEY_SPACE),
	KEY(5, 5, KEY_COMMA),
	KEY(5, 7, KEY_UP),
	KEY(5, 10, SPITZ_KEY_FN),	/* FN */
	KEY(6, 0, KEY_SYSRQ),
	KEY(6, 1, SPITZ_KEY_JAP1),	/* JAP1 */
	KEY(6, 2, SPITZ_KEY_JAP2),	/* JAP2 */
	KEY(6, 3, SPITZ_KEY_CANCEL),	/* CANCEL */
	KEY(6, 4, SPITZ_KEY_OK),	/* OK */
	KEY(6, 5, SPITZ_KEY_MENU),	/* MENU */
	KEY(6, 6, KEY_LEFT),
	KEY(6, 7, KEY_DOWN),
	KEY(6, 8, KEY_RIGHT),
};

static const struct matrix_keymap_data spitz_keymap_data = {
	.keymap		= spitz_keymap,
	.keymap_size	= ARRAY_SIZE(spitz_keymap),
};

static const uint32_t spitz_row_gpios[] =
		{ 12, 17, 91, 34, 36, 38, 39 };
static const uint32_t spitz_col_gpios[] =
		{ 88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114 };

static struct matrix_keypad_platform_data spitz_mkp_pdata = {
	.keymap_data		= &spitz_keymap_data,
	.row_gpios		= spitz_row_gpios,
	.col_gpios		= spitz_col_gpios,
	.num_row_gpios		= ARRAY_SIZE(spitz_row_gpios),
	.num_col_gpios		= ARRAY_SIZE(spitz_col_gpios),
	.col_scan_delay_us	= 10,
	.debounce_ms		= 10,
	.wakeup			= 1,
};

static struct platform_device spitz_mkp_device = {
	.name		= "matrix-keypad",
	.id		= -1,
	.dev		= {
		.platform_data	= &spitz_mkp_pdata,
	},
};

static void __init spitz_mkp_init(void)
{
	platform_device_register(&spitz_mkp_device);
}
#else
static inline void spitz_mkp_init(void) {}
#endif

/******************************************************************************
 * GPIO keys
 ******************************************************************************/
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
static struct gpio_keys_button spitz_gpio_keys[] = {
	{
		.type	= EV_PWR,
		.code	= KEY_SUSPEND,
		.gpio	= SPITZ_GPIO_ON_KEY,
		.desc	= "On Off",
		.wakeup	= 1,
	},
	/* Two buttons detecting the lid state */
	{
		.type	= EV_SW,
		.code	= 0,
		.gpio	= SPITZ_GPIO_SWA,
		.desc	= "Display Down",
	},
	{
		.type	= EV_SW,
		.code	= 1,
		.gpio	= SPITZ_GPIO_SWB,
		.desc	= "Lid Closed",
	},
};

static struct gpio_keys_platform_data spitz_gpio_keys_platform_data = {
	.buttons	= spitz_gpio_keys,
	.nbuttons	= ARRAY_SIZE(spitz_gpio_keys),
};

static struct platform_device spitz_gpio_keys_device = {
	.name	= "gpio-keys",
	.id	= -1,
	.dev	= {
		.platform_data	= &spitz_gpio_keys_platform_data,
	},
};

static void __init spitz_keys_init(void)
{
	platform_device_register(&spitz_gpio_keys_device);
}
#else
static inline void spitz_keys_init(void) {}
#endif

/******************************************************************************
 * LEDs
 ******************************************************************************/
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
static struct gpio_led spitz_gpio_leds[] = {
	{
		.name			= "spitz:amber:charge",
		.default_trigger	= "sharpsl-charge",
		.gpio			= SPITZ_GPIO_LED_ORANGE,
	},
	{
		.name			= "spitz:green:hddactivity",
		.default_trigger	= "disk-activity",
		.gpio			= SPITZ_GPIO_LED_GREEN,
	},
};

static struct gpio_led_platform_data spitz_gpio_leds_info = {
	.leds		= spitz_gpio_leds,
	.num_leds	= ARRAY_SIZE(spitz_gpio_leds),
};

static struct platform_device spitz_led_device = {
	.name		= "leds-gpio",
	.id		= -1,
	.dev		= {
		.platform_data	= &spitz_gpio_leds_info,
	},
};

static void __init spitz_leds_init(void)
{
	platform_device_register(&spitz_led_device);
}
#else
static inline void spitz_leds_init(void) {}
#endif

/******************************************************************************
 * SSP Devices
 ******************************************************************************/
#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
static void spitz_ads7846_wait_for_hsync(void)
{
	while (gpio_get_value(SPITZ_GPIO_HSYNC))
		cpu_relax();

	while (!gpio_get_value(SPITZ_GPIO_HSYNC))
		cpu_relax();
}

static struct ads7846_platform_data spitz_ads7846_info = {
	.model			= 7846,
	.vref_delay_usecs	= 100,
	.x_plate_ohms		= 419,
	.y_plate_ohms		= 486,
	.pressure_max		= 1024,
	.gpio_pendown		= SPITZ_GPIO_TP_INT,
	.wait_for_sync		= spitz_ads7846_wait_for_hsync,
};

static void spitz_bl_kick_battery(void)
{
	void (*kick_batt)(void);

	kick_batt = symbol_get(sharpsl_battery_kick);
	if (kick_batt) {
		kick_batt();
		symbol_put(sharpsl_battery_kick);
	}
}

static struct gpiod_lookup_table spitz_lcdcon_gpio_table = {
	.dev_id = "spi2.1",
	.table = {
		GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_CONT,
			    "BL_CONT", GPIO_ACTIVE_LOW),
		GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_BACKLIGHT_ON,
			    "BL_ON", GPIO_ACTIVE_HIGH),
		{ },
	},
};

static struct gpiod_lookup_table akita_lcdcon_gpio_table = {
	.dev_id = "spi2.1",
	.table = {
		GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_CONT,
			    "BL_CONT", GPIO_ACTIVE_LOW),
		GPIO_LOOKUP("gpio-pxa", AKITA_GPIO_BACKLIGHT_ON,
			    "BL_ON", GPIO_ACTIVE_HIGH),
		{ },
	},
};

static struct corgi_lcd_platform_data spitz_lcdcon_info = {
	.init_mode		= CORGI_LCD_MODE_VGA,
	.max_intensity		= 0x2f,
	.default_intensity	= 0x1f,
	.limit_mask		= 0x0b,
	.kick_battery		= spitz_bl_kick_battery,
};

static struct spi_board_info spitz_spi_devices[] = {
	{
		.modalias		= "ads7846",
		.max_speed_hz		= 1200000,
		.bus_num		= 2,
		.chip_select		= 0,
		.platform_data		= &spitz_ads7846_info,
		.irq			= PXA_GPIO_TO_IRQ(SPITZ_GPIO_TP_INT),
	}, {
		.modalias		= "corgi-lcd",
		.max_speed_hz		= 50000,
		.bus_num		= 2,
		.chip_select		= 1,
		.platform_data		= &spitz_lcdcon_info,
	}, {
		.modalias		= "max1111",
		.max_speed_hz		= 450000,
		.bus_num		= 2,
		.chip_select		= 2,
	},
};

static struct pxa2xx_spi_controller spitz_spi_info = {
	.num_chipselect	= 3,
};

static struct gpiod_lookup_table spitz_spi_gpio_table = {
	.dev_id = "spi2",
	.table = {
		GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_ADS7846_CS, "cs", 0, GPIO_ACTIVE_LOW),
		GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_LCDCON_CS, "cs", 1, GPIO_ACTIVE_LOW),
		GPIO_LOOKUP_IDX("gpio-pxa", SPITZ_GPIO_MAX1111_CS, "cs", 2, GPIO_ACTIVE_LOW),
		{ },
	},
};

static void __init spitz_spi_init(void)
{
	if (machine_is_akita())
		gpiod_add_lookup_table(&akita_lcdcon_gpio_table);
	else
		gpiod_add_lookup_table(&spitz_lcdcon_gpio_table);

	gpiod_add_lookup_table(&spitz_spi_gpio_table);
	pxa2xx_set_spi_info(2, &spitz_spi_info);
	spi_register_board_info(ARRAY_AND_SIZE(spitz_spi_devices));
}
#else
static inline void spitz_spi_init(void) {}
#endif

/******************************************************************************
 * SD/MMC card controller
 ******************************************************************************/
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
/*
 * NOTE: The card detect interrupt isn't debounced so we delay it by 250ms to
 * give the card a chance to fully insert/eject.
 */
static int spitz_mci_setpower(struct device *dev, unsigned int vdd)
{
	struct pxamci_platform_data* p_d = dev->platform_data;

	if ((1 << vdd) & p_d->ocr_mask)
		spitz_card_pwr_ctrl(SCOOP_CPR_SD_3V, SCOOP_CPR_SD_3V);
	else
		spitz_card_pwr_ctrl(SCOOP_CPR_SD_3V, 0x0);

	return 0;
}

static struct pxamci_platform_data spitz_mci_platform_data = {
	.detect_delay_ms	= 250,
	.ocr_mask		= MMC_VDD_32_33|MMC_VDD_33_34,
	.setpower		= spitz_mci_setpower,
};

static struct gpiod_lookup_table spitz_mci_gpio_table = {
	.dev_id = "pxa2xx-mci.0",
	.table = {
		GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_DETECT,
			    "cd", GPIO_ACTIVE_LOW),
		GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_WP,
			    "wp", GPIO_ACTIVE_LOW),
		{ },
	},
};

static void __init spitz_mmc_init(void)
{
	gpiod_add_lookup_table(&spitz_mci_gpio_table);
	pxa_set_mci_info(&spitz_mci_platform_data);
}
#else
static inline void spitz_mmc_init(void) {}
#endif

/******************************************************************************
 * USB Host
 ******************************************************************************/
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static int spitz_ohci_init(struct device *dev)
{
	int err;

	err = gpio_request(SPITZ_GPIO_USB_HOST, "USB_HOST");
	if (err)
		return err;

	/* Only Port 2 is connected, setup USB Port 2 Output Control Register */
	UP2OCR = UP2OCR_HXS | UP2OCR_HXOE | UP2OCR_DPPDE | UP2OCR_DMPDE;

	return gpio_direction_output(SPITZ_GPIO_USB_HOST, 1);
}

static void spitz_ohci_exit(struct device *dev)
{
	gpio_free(SPITZ_GPIO_USB_HOST);
}

static struct pxaohci_platform_data spitz_ohci_platform_data = {
	.port_mode	= PMM_NPS_MODE,
	.init		= spitz_ohci_init,
	.exit		= spitz_ohci_exit,
	.flags		= ENABLE_PORT_ALL | NO_OC_PROTECTION,
	.power_budget	= 150,
};

static void __init spitz_uhc_init(void)
{
	pxa_set_ohci_info(&spitz_ohci_platform_data);
}
#else
static inline void spitz_uhc_init(void) {}
#endif

/******************************************************************************
 * IrDA
 ******************************************************************************/
#if defined(CONFIG_PXA_FICP) || defined(CONFIG_PXA_FICP_MODULE)
static struct pxaficp_platform_data spitz_ficp_platform_data = {
	.transceiver_cap	= IR_SIRMODE | IR_OFF,
};

static void __init spitz_irda_init(void)
{
	if (machine_is_akita())
		spitz_ficp_platform_data.gpio_pwdown = AKITA_GPIO_IR_ON;
	else
		spitz_ficp_platform_data.gpio_pwdown = SPITZ_GPIO_IR_ON;

	pxa_set_ficp_info(&spitz_ficp_platform_data);
}
#else
static inline void spitz_irda_init(void) {}
#endif

/******************************************************************************
 * Framebuffer
 ******************************************************************************/
#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
static struct pxafb_mode_info spitz_pxafb_modes[] = {
	{
		.pixclock       = 19231,
		.xres           = 480,
		.yres           = 640,
		.bpp            = 16,
		.hsync_len      = 40,
		.left_margin    = 46,
		.right_margin   = 125,
		.vsync_len      = 3,
		.upper_margin   = 1,
		.lower_margin   = 0,
		.sync           = 0,
	}, {
		.pixclock       = 134617,
		.xres           = 240,
		.yres           = 320,
		.bpp            = 16,
		.hsync_len      = 20,
		.left_margin    = 20,
		.right_margin   = 46,
		.vsync_len      = 2,
		.upper_margin   = 1,
		.lower_margin   = 0,
		.sync           = 0,
	},
};

static struct pxafb_mach_info spitz_pxafb_info = {
	.modes          = spitz_pxafb_modes,
	.num_modes      = ARRAY_SIZE(spitz_pxafb_modes),
	.fixed_modes    = 1,
	.lcd_conn	= LCD_COLOR_TFT_16BPP | LCD_ALTERNATE_MAPPING,
};

static void __init spitz_lcd_init(void)
{
	pxa_set_fb_info(NULL, &spitz_pxafb_info);
}
#else
static inline void spitz_lcd_init(void) {}
#endif

/******************************************************************************
 * NAND Flash
 ******************************************************************************/
#if defined(CONFIG_MTD_NAND_SHARPSL) || defined(CONFIG_MTD_NAND_SHARPSL_MODULE)
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };

static struct nand_bbt_descr spitz_nand_bbt = {
	.options	= 0,
	.offs		= 4,
	.len		= 2,
	.pattern	= scan_ff_pattern
};

static int akita_ooblayout_ecc(struct mtd_info *mtd, int section,
			       struct mtd_oob_region *oobregion)
{
	if (section > 12)
		return -ERANGE;

	switch (section % 3) {
	case 0:
		oobregion->offset = 5;
		oobregion->length = 1;
		break;

	case 1:
		oobregion->offset = 1;
		oobregion->length = 3;
		break;

	case 2:
		oobregion->offset = 6;
		oobregion->length = 2;
		break;
	}

	oobregion->offset += (section / 3) * 0x10;

	return 0;
}

static int akita_ooblayout_free(struct mtd_info *mtd, int section,
				struct mtd_oob_region *oobregion)
{
	if (section)
		return -ERANGE;

	oobregion->offset = 8;
	oobregion->length = 9;

	return 0;
}

static const struct mtd_ooblayout_ops akita_ooblayout_ops = {
	.ecc = akita_ooblayout_ecc,
	.free = akita_ooblayout_free,
};

static const char * const probes[] = {
	"cmdlinepart",
	"ofpart",
	"sharpslpart",
	NULL,
};

static struct sharpsl_nand_platform_data spitz_nand_pdata = {
	.badblock_pattern	= &spitz_nand_bbt,
	.part_parsers		= probes,
};

static struct resource spitz_nand_resources[] = {
	{
		.start	= PXA_CS3_PHYS,
		.end	= PXA_CS3_PHYS + SZ_4K - 1,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device spitz_nand_device = {
	.name		= "sharpsl-nand",
	.id		= -1,
	.resource	= spitz_nand_resources,
	.num_resources	= ARRAY_SIZE(spitz_nand_resources),
	.dev		= {
		.platform_data	= &spitz_nand_pdata,
	}
};

static void __init spitz_nand_init(void)
{
	if (machine_is_akita() || machine_is_borzoi()) {
		spitz_nand_bbt.len = 1;
		spitz_nand_pdata.ecc_layout = &akita_ooblayout_ops;
	}

	platform_device_register(&spitz_nand_device);
}
#else
static inline void spitz_nand_init(void) {}
#endif

/******************************************************************************
 * NOR Flash
 ******************************************************************************/
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
static struct mtd_partition spitz_rom_parts[] = {
	{
		.name	="Boot PROM Filesystem",
		.offset	= 0x00140000,
		.size	= MTDPART_SIZ_FULL,
	},
};

static struct physmap_flash_data spitz_rom_data = {
	.width		= 2,
	.nr_parts	= ARRAY_SIZE(spitz_rom_parts),
	.parts		= spitz_rom_parts,
};

static struct resource spitz_rom_resources[] = {
	{
		.start	= PXA_CS0_PHYS,
		.end	= PXA_CS0_PHYS + SZ_8M - 1,
		.flags	= IORESOURCE_MEM,
	},
};

static struct platform_device spitz_rom_device = {
	.name		= "physmap-flash",
	.id		= -1,
	.resource	= spitz_rom_resources,
	.num_resources	= ARRAY_SIZE(spitz_rom_resources),
	.dev		= {
		.platform_data	= &spitz_rom_data,
	},
};

static void __init spitz_nor_init(void)
{
	platform_device_register(&spitz_rom_device);
}
#else
static inline void spitz_nor_init(void) {}
#endif

/******************************************************************************
 * I2C devices
 ******************************************************************************/
#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
static struct pca953x_platform_data akita_pca953x_pdata = {
	.gpio_base		= AKITA_IOEXP_GPIO_BASE,
};

static struct i2c_board_info spitz_i2c_devs[] = {
	{
		.type		= "wm8750",
		.addr		= 0x1b,
	}, {
		.type		= "max7310",
		.addr		= 0x18,
		.platform_data	= &akita_pca953x_pdata,
	},
};

static struct regulator_consumer_supply isl6271a_consumers[] = {
	REGULATOR_SUPPLY("vcc_core", NULL),
};

static struct regulator_init_data isl6271a_info[] = {
	{
		.constraints = {
			.name		= "vcc_core range",
			.min_uV		= 850000,
			.max_uV		= 1600000,
			.always_on	= 1,
			.valid_ops_mask	= REGULATOR_CHANGE_VOLTAGE,
		},
	.consumer_supplies	= isl6271a_consumers,
	.num_consumer_supplies	= ARRAY_SIZE(isl6271a_consumers),
	}
};

static struct i2c_board_info spitz_pi2c_devs[] = {
	{
		.type		= "isl6271a",
		.addr		= 0x0c,
		.platform_data	= &isl6271a_info,
	},
};

static void __init spitz_i2c_init(void)
{
	int size = ARRAY_SIZE(spitz_i2c_devs);

	/* Only Akita has the max7310 chip */
	if (!machine_is_akita())
		size--;

	pxa_set_i2c_info(NULL);
	pxa27x_set_i2c_power_info(NULL);
	i2c_register_board_info(0, spitz_i2c_devs, size);
	i2c_register_board_info(1, ARRAY_AND_SIZE(spitz_pi2c_devs));
}
#else
static inline void spitz_i2c_init(void) {}
#endif

static struct gpiod_lookup_table spitz_audio_gpio_table = {
	.dev_id = "spitz-audio",
	.table = {
		GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE,
			    "mute-l", GPIO_ACTIVE_HIGH),
		GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE,
			    "mute-r", GPIO_ACTIVE_HIGH),
		GPIO_LOOKUP("sharp-scoop.1", SPITZ_GPIO_MIC_BIAS - SPITZ_SCP2_GPIO_BASE,
			    "mic", GPIO_ACTIVE_HIGH),
		{ },
	},
};

static struct gpiod_lookup_table akita_audio_gpio_table = {
	.dev_id = "spitz-audio",
	.table = {
		GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_L - SPITZ_SCP_GPIO_BASE,
			    "mute-l", GPIO_ACTIVE_HIGH),
		GPIO_LOOKUP("sharp-scoop.0", SPITZ_GPIO_MUTE_R - SPITZ_SCP_GPIO_BASE,
			    "mute-r", GPIO_ACTIVE_HIGH),
		GPIO_LOOKUP("i2c-max7310", AKITA_GPIO_MIC_BIAS - AKITA_IOEXP_GPIO_BASE,
			    "mic", GPIO_ACTIVE_HIGH),
		{ },
	},
};

/******************************************************************************
 * Audio devices
 ******************************************************************************/
static inline void spitz_audio_init(void)
{
	if (machine_is_akita())
		gpiod_add_lookup_table(&akita_audio_gpio_table);
	else
		gpiod_add_lookup_table(&spitz_audio_gpio_table);

	platform_device_register_simple("spitz-audio", -1, NULL, 0);
}

/******************************************************************************
 * Machine init
 ******************************************************************************/
static void spitz_poweroff(void)
{
	pxa_restart(REBOOT_GPIO, NULL);
}

static void spitz_restart(enum reboot_mode mode, const char *cmd)
{
	uint32_t msc0 = __raw_readl(MSC0);
	/* Bootloader magic for a reboot */
	if ((msc0 & 0xffff0000) == 0x7ff00000)
		__raw_writel((msc0 & 0xffff) | 0x7ee00000, MSC0);

	spitz_poweroff();
}

static void __init spitz_init(void)
{
	init_gpio_reset(SPITZ_GPIO_ON_RESET, 1, 0);
	pm_power_off = spitz_poweroff;

	PMCR = 0x00;

	/* Stop 3.6MHz and drive HIGH to PCMCIA and CS */
	PCFR |= PCFR_OPDE;

	pxa2xx_mfp_config(ARRAY_AND_SIZE(spitz_pin_config));

	pxa_set_ffuart_info(NULL);
	pxa_set_btuart_info(NULL);
	pxa_set_stuart_info(NULL);

	spitz_spi_init();
	spitz_scoop_init();
	spitz_mkp_init();
	spitz_keys_init();
	spitz_leds_init();
	spitz_mmc_init();
	spitz_pcmcia_init();
	spitz_irda_init();
	spitz_uhc_init();
	spitz_lcd_init();
	spitz_nor_init();
	spitz_nand_init();
	spitz_i2c_init();
	spitz_audio_init();

	regulator_has_full_constraints();
}

static void __init spitz_fixup(struct tag *tags, char **cmdline)
{
	sharpsl_save_param();
	memblock_add(0xa0000000, SZ_64M);
}

#ifdef CONFIG_MACH_SPITZ
MACHINE_START(SPITZ, "SHARP Spitz")
	.fixup		= spitz_fixup,
	.map_io		= pxa27x_map_io,
	.nr_irqs	= PXA_NR_IRQS,
	.init_irq	= pxa27x_init_irq,
	.handle_irq	= pxa27x_handle_irq,
	.init_machine	= spitz_init,
	.init_time	= pxa_timer_init,
	.restart	= spitz_restart,
MACHINE_END
#endif

#ifdef CONFIG_MACH_BORZOI
MACHINE_START(BORZOI, "SHARP Borzoi")
	.fixup		= spitz_fixup,
	.map_io		= pxa27x_map_io,
	.nr_irqs	= PXA_NR_IRQS,
	.init_irq	= pxa27x_init_irq,
	.handle_irq	= pxa27x_handle_irq,
	.init_machine	= spitz_init,
	.init_time	= pxa_timer_init,
	.restart	= spitz_restart,
MACHINE_END
#endif

#ifdef CONFIG_MACH_AKITA
MACHINE_START(AKITA, "SHARP Akita")
	.fixup		= spitz_fixup,
	.map_io		= pxa27x_map_io,
	.nr_irqs	= PXA_NR_IRQS,
	.init_irq	= pxa27x_init_irq,
	.handle_irq	= pxa27x_handle_irq,
	.init_machine	= spitz_init,
	.init_time	= pxa_timer_init,
	.restart	= spitz_restart,
MACHINE_END
#endif


code:
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Hardware specific definitions for SL-Cx000 series of PDAs
 *
 * Copyright (c) 2005 Alexander Wykes
 * Copyright (c) 2005 Richard Purdie
 *
 * Based on Sharp's 2.4 kernel patches
 */
#ifndef __ASM_ARCH_SPITZ_H
#define __ASM_ARCH_SPITZ_H  1
#endif

#include "irqs.h" /* PXA_NR_BUILTIN_GPIO, PXA_GPIO_TO_IRQ */
#include <linux/fb.h>

/* Spitz/Akita GPIOs */

#define SPITZ_GPIO_KEY_INT         (0) /* Key Interrupt */
#define SPITZ_GPIO_RESET           (1)
#define SPITZ_GPIO_nSD_DETECT      (9)
#define SPITZ_GPIO_TP_INT          (11) /* Touch Panel interrupt */
#define SPITZ_GPIO_AK_INT          (13) /* Remote Control */
#define SPITZ_GPIO_ADS7846_CS      (14)
#define SPITZ_GPIO_SYNC            (16)
#define SPITZ_GPIO_MAX1111_CS      (20)
#define SPITZ_GPIO_FATAL_BAT       (21)
#define SPITZ_GPIO_HSYNC           (22)
#define SPITZ_GPIO_nSD_CLK         (32)
#define SPITZ_GPIO_USB_DEVICE      (35)
#define SPITZ_GPIO_USB_HOST        (37)
#define SPITZ_GPIO_USB_CONNECT     (41)
#define SPITZ_GPIO_LCDCON_CS       (53)
#define SPITZ_GPIO_nPCE            (54)
#define SPITZ_GPIO_nSD_WP          (81)
#define SPITZ_GPIO_ON_RESET        (89)
#define SPITZ_GPIO_BAT_COVER       (90)
#define SPITZ_GPIO_CF_CD           (94)
#define SPITZ_GPIO_ON_KEY          (95)
#define SPITZ_GPIO_SWA             (97)
#define SPITZ_GPIO_SWB             (96)
#define SPITZ_GPIO_CHRG_FULL       (101)
#define SPITZ_GPIO_CO              (101)
#define SPITZ_GPIO_CF_IRQ          (105)
#define SPITZ_GPIO_AC_IN           (115)
#define SPITZ_GPIO_HP_IN           (116)

/* Spitz Only GPIOs */

#define SPITZ_GPIO_CF2_IRQ         (106) /* CF slot1 Ready */
#define SPITZ_GPIO_CF2_CD          (93)

/* Spitz/Akita Keyboard Definitions */

#define SPITZ_KEY_STROBE_NUM         (11)
#define SPITZ_KEY_SENSE_NUM          (7)
#define SPITZ_GPIO_G0_STROBE_BIT     0x0f800000
#define SPITZ_GPIO_G1_STROBE_BIT     0x00100000
#define SPITZ_GPIO_G2_STROBE_BIT     0x01000000
#define SPITZ_GPIO_G3_STROBE_BIT     0x00041880
#define SPITZ_GPIO_G0_SENSE_BIT      0x00021000
#define SPITZ_GPIO_G1_SENSE_BIT      0x000000d4
#define SPITZ_GPIO_G2_SENSE_BIT      0x08000000
#define SPITZ_GPIO_G3_SENSE_BIT      0x00000000

#define SPITZ_GPIO_KEY_STROBE0       88
#define SPITZ_GPIO_KEY_STROBE1       23
#define SPITZ_GPIO_KEY_STROBE2       24
#define SPITZ_GPIO_KEY_STROBE3       25
#define SPITZ_GPIO_KEY_STROBE4       26
#define SPITZ_GPIO_KEY_STROBE5       27
#define SPITZ_GPIO_KEY_STROBE6       52
#define SPITZ_GPIO_KEY_STROBE7       103
#define SPITZ_GPIO_KEY_STROBE8       107
#define SPITZ_GPIO_KEY_STROBE9       108
#define SPITZ_GPIO_KEY_STROBE10      114

#define SPITZ_GPIO_KEY_SENSE0        12
#define SPITZ_GPIO_KEY_SENSE1        17
#define SPITZ_GPIO_KEY_SENSE2        91
#define SPITZ_GPIO_KEY_SENSE3        34
#define SPITZ_GPIO_KEY_SENSE4        36
#define SPITZ_GPIO_KEY_SENSE5        38
#define SPITZ_GPIO_KEY_SENSE6        39

/* Spitz Scoop Device (No. 1) GPIOs */
/* Suspend States in comments */
#define SPITZ_SCP_LED_GREEN     SCOOP_GPCR_PA11  /* Keep */
#define SPITZ_SCP_JK_B          SCOOP_GPCR_PA12  /* Keep */
#define SPITZ_SCP_CHRG_ON       SCOOP_GPCR_PA13  /* Keep */
#define SPITZ_SCP_MUTE_L        SCOOP_GPCR_PA14  /* Low */
#define SPITZ_SCP_MUTE_R        SCOOP_GPCR_PA15  /* Low */
#define SPITZ_SCP_CF_POWER      SCOOP_GPCR_PA16  /* Keep */
#define SPITZ_SCP_LED_ORANGE    SCOOP_GPCR_PA17  /* Keep */
#define SPITZ_SCP_JK_A          SCOOP_GPCR_PA18  /* Low */
#define SPITZ_SCP_ADC_TEMP_ON   SCOOP_GPCR_PA19  /* Low */

#define SPITZ_SCP_IO_DIR      (SPITZ_SCP_JK_B | SPITZ_SCP_CHRG_ON | \
                               SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | \
                               SPITZ_SCP_CF_POWER | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
#define SPITZ_SCP_IO_OUT      (SPITZ_SCP_CHRG_ON | SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R)
#define SPITZ_SCP_SUS_CLR     (SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON)
#define SPITZ_SCP_SUS_SET     0

#define SPITZ_SCP_GPIO_BASE	(PXA_NR_BUILTIN_GPIO)
#define SPITZ_GPIO_LED_GREEN	(SPITZ_SCP_GPIO_BASE + 0)
#define SPITZ_GPIO_JK_B		(SPITZ_SCP_GPIO_BASE + 1)
#define SPITZ_GPIO_CHRG_ON	(SPITZ_SCP_GPIO_BASE + 2)
#define SPITZ_GPIO_MUTE_L	(SPITZ_SCP_GPIO_BASE + 3)
#define SPITZ_GPIO_MUTE_R	(SPITZ_SCP_GPIO_BASE + 4)
#define SPITZ_GPIO_CF_POWER	(SPITZ_SCP_GPIO_BASE + 5)
#define SPITZ_GPIO_LED_ORANGE	(SPITZ_SCP_GPIO_BASE + 6)
#define SPITZ_GPIO_JK_A		(SPITZ_SCP_GPIO_BASE + 7)
#define SPITZ_GPIO_ADC_TEMP_ON	(SPITZ_SCP_GPIO_BASE + 8)

/* Spitz Scoop Device (No. 2) GPIOs */
/* Suspend States in comments */
#define SPITZ_SCP2_IR_ON           SCOOP_GPCR_PA11  /* High */
#define SPITZ_SCP2_AKIN_PULLUP     SCOOP_GPCR_PA12  /* Keep */
#define SPITZ_SCP2_RESERVED_1      SCOOP_GPCR_PA13  /* High */
#define SPITZ_SCP2_RESERVED_2      SCOOP_GPCR_PA14  /* Low */
#define SPITZ_SCP2_RESERVED_3      SCOOP_GPCR_PA15  /* Low */
#define SPITZ_SCP2_RESERVED_4      SCOOP_GPCR_PA16  /* Low */
#define SPITZ_SCP2_BACKLIGHT_CONT  SCOOP_GPCR_PA17  /* Low */
#define SPITZ_SCP2_BACKLIGHT_ON    SCOOP_GPCR_PA18  /* Low */
#define SPITZ_SCP2_MIC_BIAS        SCOOP_GPCR_PA19  /* Low */

#define SPITZ_SCP2_IO_DIR (SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1 | \
                           SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
                           SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)

#define SPITZ_SCP2_IO_OUT   (SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1)
#define SPITZ_SCP2_SUS_CLR  (SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \
                             SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS)
#define SPITZ_SCP2_SUS_SET  (SPITZ_SCP2_IR_ON | SPITZ_SCP2_RESERVED_1)

#define SPITZ_SCP2_GPIO_BASE		(PXA_NR_BUILTIN_GPIO + 12)
#define SPITZ_GPIO_IR_ON		(SPITZ_SCP2_GPIO_BASE + 0)
#define SPITZ_GPIO_AKIN_PULLUP		(SPITZ_SCP2_GPIO_BASE + 1)
#define SPITZ_GPIO_RESERVED_1		(SPITZ_SCP2_GPIO_BASE + 2)
#define SPITZ_GPIO_RESERVED_2		(SPITZ_SCP2_GPIO_BASE + 3)
#define SPITZ_GPIO_RESERVED_3		(SPITZ_SCP2_GPIO_BASE + 4)
#define SPITZ_GPIO_RESERVED_4		(SPITZ_SCP2_GPIO_BASE + 5)
#define SPITZ_GPIO_BACKLIGHT_CONT	(SPITZ_SCP2_GPIO_BASE + 6)
#define SPITZ_GPIO_BACKLIGHT_ON		(SPITZ_SCP2_GPIO_BASE + 7)
#define SPITZ_GPIO_MIC_BIAS		(SPITZ_SCP2_GPIO_BASE + 8)

/* Akita IO Expander GPIOs */
#define AKITA_IOEXP_GPIO_BASE		(PXA_NR_BUILTIN_GPIO + 12)
#define AKITA_GPIO_RESERVED_0		(AKITA_IOEXP_GPIO_BASE + 0)
#define AKITA_GPIO_RESERVED_1		(AKITA_IOEXP_GPIO_BASE + 1)
#define AKITA_GPIO_MIC_BIAS		(AKITA_IOEXP_GPIO_BASE + 2)
#define AKITA_GPIO_BACKLIGHT_ON		(AKITA_IOEXP_GPIO_BASE + 3)
#define AKITA_GPIO_BACKLIGHT_CONT	(AKITA_IOEXP_GPIO_BASE + 4)
#define AKITA_GPIO_AKIN_PULLUP		(AKITA_IOEXP_GPIO_BASE + 5)
#define AKITA_GPIO_IR_ON		(AKITA_IOEXP_GPIO_BASE + 6)
#define AKITA_GPIO_RESERVED_7		(AKITA_IOEXP_GPIO_BASE + 7)

/* Spitz IRQ Definitions */

#define SPITZ_IRQ_GPIO_KEY_INT        PXA_GPIO_TO_IRQ(SPITZ_GPIO_KEY_INT)
#define SPITZ_IRQ_GPIO_AC_IN          PXA_GPIO_TO_IRQ(SPITZ_GPIO_AC_IN)
#define SPITZ_IRQ_GPIO_AK_INT         PXA_GPIO_TO_IRQ(SPITZ_GPIO_AK_INT)
#define SPITZ_IRQ_GPIO_HP_IN          PXA_GPIO_TO_IRQ(SPITZ_GPIO_HP_IN)
#define SPITZ_IRQ_GPIO_TP_INT         PXA_GPIO_TO_IRQ(SPITZ_GPIO_TP_INT)
#define SPITZ_IRQ_GPIO_SYNC           PXA_GPIO_TO_IRQ(SPITZ_GPIO_SYNC)
#define SPITZ_IRQ_GPIO_ON_KEY         PXA_GPIO_TO_IRQ(SPITZ_GPIO_ON_KEY)
#define SPITZ_IRQ_GPIO_SWA            PXA_GPIO_TO_IRQ(SPITZ_GPIO_SWA)
#define SPITZ_IRQ_GPIO_SWB            PXA_GPIO_TO_IRQ(SPITZ_GPIO_SWB)
#define SPITZ_IRQ_GPIO_BAT_COVER      PXA_GPIO_TO_IRQ(SPITZ_GPIO_BAT_COVER)
#define SPITZ_IRQ_GPIO_FATAL_BAT      PXA_GPIO_TO_IRQ(SPITZ_GPIO_FATAL_BAT)
#define SPITZ_IRQ_GPIO_CO             PXA_GPIO_TO_IRQ(SPITZ_GPIO_CO)
#define SPITZ_IRQ_GPIO_CF_IRQ         PXA_GPIO_TO_IRQ(SPITZ_GPIO_CF_IRQ)
#define SPITZ_IRQ_GPIO_CF_CD          PXA_GPIO_TO_IRQ(SPITZ_GPIO_CF_CD)
#define SPITZ_IRQ_GPIO_CF2_IRQ        PXA_GPIO_TO_IRQ(SPITZ_GPIO_CF2_IRQ)
#define SPITZ_IRQ_GPIO_nSD_INT        PXA_GPIO_TO_IRQ(SPITZ_GPIO_nSD_INT)
#define SPITZ_IRQ_GPIO_nSD_DETECT     PXA_GPIO_TO_IRQ(SPITZ_GPIO_nSD_DETECT)

/*
 * Shared data structures
 */
extern struct platform_device spitzssp_device;
extern struct sharpsl_charger_machinfo spitz_pm_machinfo;