Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig ARCH_SA1100
bool "SA11x0 Implementations"
depends on ARCH_MULTI_V4 && !(ARCH_MULTI_V4T || ARCH_MULTI_V5)
depends on !(ARCH_MOXART || ARCH_GEMINI)
depends on ATAGS
depends on CPU_LITTLE_ENDIAN
depends on MMU
select ARCH_NO_SG_CHAIN
select ARCH_MTD_XIP
select CLKSRC_MMIO
select CLKSRC_PXA
select CPU_FREQ
select CPU_SA1100
select GPIOLIB
select GPIOLIB_LEGACY
select IRQ_DOMAIN
select ISA
select NEED_MACH_MEMORY_H
help
Support for StrongARM 11x0 based boards.
if ARCH_SA1100
config SA1100_ASSABET
bool "Assabet"
select ARM_SA1110_CPUFREQ
select GPIO_REG
select LEDS_GPIO_REGISTER
select REGULATOR
select REGULATOR_FIXED_VOLTAGE
help
Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
Microprocessor Development Board (also known as the Assabet).
config ASSABET_NEPONSET
bool "Include support for Neponset"
depends on SA1100_ASSABET
select SA1111
help
Say Y here if you are using the Intel(R) StrongARM(R) SA-1110
Microprocessor Development Board (Assabet) with the SA-1111
Development Board (Nepon).
config SA1100_COLLIE
bool "Sharp Zaurus SL5500"
# FIXME: select ARM_SA11x0_CPUFREQ
select SHARP_LOCOMO
select SHARP_PARAM
select SHARP_SCOOP
help
Say Y here to support the Sharp Zaurus SL5500 PDAs.
config SA1100_H3600
bool "Compaq iPAQ H3600/H3700"
select ARM_SA1110_CPUFREQ
select HTC_EGPIO
select MFD_IPAQ_MICRO
help
Say Y here if you intend to run this kernel on the Compaq iPAQ
H3600 and H3700 handheld computers.
config SA1100_JORNADA720
bool "HP Jornada 720"
# FIXME: select ARM_SA11x0_CPUFREQ
select SA1111
help
Say Y here if you want to build a kernel for the HP Jornada 720
handheld computer. See
<http://h10025.www1.hp.com/ewfrf/wc/product?product=61677&cc=us&lc=en&dlc=en&product=61677#>
config SA1100_JORNADA720_SSP
bool "HP Jornada 720 Extended SSP driver"
depends on SA1100_JORNADA720
select SA1100_SSP
help
Say Y here if you have a HP Jornada 7xx handheld computer and you
want to access devices connected to the MCU. Those include the
keyboard, touchscreen, backlight and battery. This driver also activates
the generic SSP which it extends.
config SA1100_SSP
tristate "Generic PIO SSP"
help
Say Y here to enable support for the generic PIO SSP driver.
This isn't for audio support, but for attached sensors and
other devices, eg for BadgePAD 4 sensor support.
endif
+20
View File
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#
# Common support
obj-y := clock.o generic.o #nmi-oopser.o
# Specific board support
obj-$(CONFIG_SA1100_ASSABET) += assabet.o
obj-$(CONFIG_ASSABET_NEPONSET) += neponset.o
obj-$(CONFIG_SA1100_COLLIE) += collie.o
obj-$(CONFIG_SA1100_H3600) += h3600.o h3xxx.o
obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o
obj-$(CONFIG_SA1100_JORNADA720_SSP) += jornada720_ssp.o
# Miscellaneous functions
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_SA1100_SSP) += ssp.o
+745
View File
@@ -0,0 +1,745 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/assabet.c
*
* Author: Nicolas Pitre
*
* This file contains all Assabet-specific tweaks.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/ioport.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/leds.h>
#include <linux/slab.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgtable-hwdef.h>
#include <asm/tlbflush.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/assabet.h>
#include <linux/platform_data/mfd-mcp-sa11x0.h>
#include <mach/irqs.h>
#include "generic.h"
#define ASSABET_BCR_DB1110 \
(ASSABET_BCR_SPK_OFF | \
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_IRDA_MD0)
#define ASSABET_BCR_DB1111 \
(ASSABET_BCR_SPK_OFF | \
ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED | \
ASSABET_BCR_RS232EN | ASSABET_BCR_LCD_12RGB | \
ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_STEREO_LB | \
ASSABET_BCR_IRDA_MD0 | ASSABET_BCR_CF_RST)
unsigned long SCR_value = ASSABET_SCR_INIT;
EXPORT_SYMBOL(SCR_value);
static struct gpio_chip *assabet_bcr_gc;
static const char *assabet_names[] = {
"cf_pwr", "cf_gfx_reset", "nsoft_reset", "irda_fsel",
"irda_md0", "irda_md1", "stereo_loopback", "ncf_bus_on",
"audio_pwr_on", "light_pwr_on", "lcd16data", "lcd_pwr_on",
"rs232_on", "nred_led", "ngreen_led", "vib_on",
"com_dtr", "com_rts", "radio_wake_mod", "i2c_enab",
"tvir_enab", "qmute", "radio_pwr_on", "spkr_off",
"rs232_valid", "com_dcd", "com_cts", "com_dsr",
"radio_cts", "radio_dsr", "radio_dcd", "radio_ri",
};
/* The old deprecated interface */
void ASSABET_BCR_frob(unsigned int mask, unsigned int val)
{
unsigned long m = mask, v = val;
assabet_bcr_gc->set_multiple(assabet_bcr_gc, &m, &v);
}
EXPORT_SYMBOL(ASSABET_BCR_frob);
static void __init assabet_init_gpio(void __iomem *reg, u32 def_val)
{
struct gpio_chip *gc;
writel_relaxed(def_val, reg);
gc = gpio_reg_init(NULL, reg, -1, 32, "assabet", 0xff000000, def_val,
assabet_names, NULL, NULL);
if (IS_ERR(gc))
return;
assabet_bcr_gc = gc;
}
/*
* The codec reset goes to three devices, so we need to release
* the rest when any one of these requests it. However, that
* causes the ADV7171 to consume around 100mA - more than half
* the LCD-blanked power.
*
* With the ADV7171, LCD and backlight enabled, we go over
* budget on the MAX846 Li-Ion charger, and if no Li-Ion battery
* is connected, the Assabet crashes.
*/
#define RST_UCB1X00 (1 << 0)
#define RST_UDA1341 (1 << 1)
#define RST_ADV7171 (1 << 2)
#define SDA GPIO_GPIO(15)
#define SCK GPIO_GPIO(18)
#define MOD GPIO_GPIO(17)
static void adv7171_start(void)
{
GPSR = SCK;
udelay(1);
GPSR = SDA;
udelay(2);
GPCR = SDA;
}
static void adv7171_stop(void)
{
GPSR = SCK;
udelay(2);
GPSR = SDA;
udelay(1);
}
static void adv7171_send(unsigned byte)
{
unsigned i;
for (i = 0; i < 8; i++, byte <<= 1) {
GPCR = SCK;
udelay(1);
if (byte & 0x80)
GPSR = SDA;
else
GPCR = SDA;
udelay(1);
GPSR = SCK;
udelay(1);
}
GPCR = SCK;
udelay(1);
GPSR = SDA;
udelay(1);
GPDR &= ~SDA;
GPSR = SCK;
udelay(1);
if (GPLR & SDA)
printk(KERN_WARNING "No ACK from ADV7171\n");
udelay(1);
GPCR = SCK | SDA;
udelay(1);
GPDR |= SDA;
udelay(1);
}
static void adv7171_write(unsigned reg, unsigned val)
{
unsigned gpdr = GPDR;
unsigned gplr = GPLR;
ASSABET_BCR_frob(ASSABET_BCR_AUDIO_ON, ASSABET_BCR_AUDIO_ON);
udelay(100);
GPCR = SDA | SCK | MOD; /* clear L3 mode to ensure UDA1341 doesn't respond */
GPDR = (GPDR | SCK | MOD) & ~SDA;
udelay(10);
if (!(GPLR & SDA))
printk(KERN_WARNING "Something dragging SDA down?\n");
GPDR |= SDA;
adv7171_start();
adv7171_send(0x54);
adv7171_send(reg);
adv7171_send(val);
adv7171_stop();
/* Restore GPIO state for L3 bus */
GPSR = gplr & (SDA | SCK | MOD);
GPCR = (~gplr) & (SDA | SCK | MOD);
GPDR = gpdr;
}
static void adv7171_sleep(void)
{
/* Put the ADV7171 into sleep mode */
adv7171_write(0x04, 0x40);
}
static unsigned codec_nreset;
static void assabet_codec_reset(unsigned mask, int set)
{
unsigned long flags;
bool old;
local_irq_save(flags);
old = !codec_nreset;
if (set)
codec_nreset &= ~mask;
else
codec_nreset |= mask;
if (old != !codec_nreset) {
if (codec_nreset) {
ASSABET_BCR_set(ASSABET_BCR_NCODEC_RST);
adv7171_sleep();
} else {
ASSABET_BCR_clear(ASSABET_BCR_NCODEC_RST);
}
}
local_irq_restore(flags);
}
static void assabet_ucb1x00_reset(enum ucb1x00_reset state)
{
int set = state == UCB_RST_REMOVE || state == UCB_RST_SUSPEND ||
state == UCB_RST_PROBE_FAIL;
assabet_codec_reset(RST_UCB1X00, set);
}
void assabet_uda1341_reset(int set)
{
assabet_codec_reset(RST_UDA1341, set);
}
EXPORT_SYMBOL(assabet_uda1341_reset);
/*
* Assabet flash support code.
*/
#ifdef ASSABET_REV_4
/*
* Phase 4 Assabet has two 28F160B3 flash parts in bank 0:
*/
static struct mtd_partition assabet_partitions[] = {
{
.name = "bootloader",
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "bootloader params",
.size = 0x00020000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "jffs",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#else
/*
* Phase 5 Assabet has two 28F128J3A flash parts in bank 0:
*/
static struct mtd_partition assabet_partitions[] = {
{
.name = "bootloader",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "bootloader params",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "jffs",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
static struct flash_platform_data assabet_flash_data = {
.map_name = "cfi_probe",
.parts = assabet_partitions,
.nr_parts = ARRAY_SIZE(assabet_partitions),
};
static struct resource assabet_flash_resources[] = {
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
DEFINE_RES_MEM(SA1100_CS1_PHYS, SZ_32M),
};
static struct ucb1x00_plat_data assabet_ucb1x00_data = {
.reset = assabet_ucb1x00_reset,
.gpio_base = -1,
.can_wakeup = 1,
};
static struct mcp_plat_data assabet_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec_pdata = &assabet_ucb1x00_data,
};
static void assabet_lcd_set_visual(u32 visual)
{
u_int is_true_color = visual == FB_VISUAL_TRUECOLOR;
if (machine_is_assabet()) {
#if 1 // phase 4 or newer Assabet's
if (is_true_color)
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
#else
// older Assabet's
if (is_true_color)
ASSABET_BCR_clear(ASSABET_BCR_LCD_12RGB);
else
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
#endif
}
}
#ifndef ASSABET_PAL_VIDEO
static void assabet_lcd_backlight_power(int on)
{
if (on)
ASSABET_BCR_set(ASSABET_BCR_LIGHT_ON);
else
ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
}
/*
* Turn on/off the backlight. When turning the backlight on, we wait
* 500us after turning it on so we don't cause the supplies to droop
* when we enable the LCD controller (and cause a hard reset.)
*/
static void assabet_lcd_power(int on)
{
if (on) {
ASSABET_BCR_set(ASSABET_BCR_LCD_ON);
udelay(500);
} else
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
}
/*
* The assabet uses a sharp LQ039Q2DS54 LCD module. It is actually
* takes an RGB666 signal, but we provide it with an RGB565 signal
* instead (def_rgb_16).
*/
static struct sa1100fb_mach_info lq039q2ds54_info = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 61, .upper_margin = 3,
.right_margin = 9, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
.backlight_power = assabet_lcd_backlight_power,
.lcd_power = assabet_lcd_power,
.set_visual = assabet_lcd_set_visual,
};
#else
static void assabet_pal_backlight_power(int on)
{
ASSABET_BCR_clear(ASSABET_BCR_LIGHT_ON);
}
static void assabet_pal_power(int on)
{
ASSABET_BCR_clear(ASSABET_BCR_LCD_ON);
}
static struct sa1100fb_mach_info pal_info = {
.pixclock = 67797, .bpp = 16,
.xres = 640, .yres = 512,
.hsync_len = 64, .vsync_len = 6,
.left_margin = 125, .upper_margin = 70,
.right_margin = 115, .lower_margin = 36,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
.backlight_power = assabet_pal_backlight_power,
.lcd_power = assabet_pal_power,
.set_visual = assabet_lcd_set_visual,
};
#endif
#ifdef CONFIG_ASSABET_NEPONSET
static struct resource neponset_resources[] = {
DEFINE_RES_MEM(0x10000000, 0x08000000),
DEFINE_RES_MEM(0x18000000, 0x04000000),
DEFINE_RES_MEM(0x40000000, SZ_8K),
DEFINE_RES_IRQ(IRQ_GPIO25),
};
#endif
static struct gpiod_lookup_table assabet_cf_gpio_table = {
.dev_id = "sa11x0-pcmcia.1",
.table = {
GPIO_LOOKUP("gpio", 21, "ready", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio", 22, "detect", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio", 24, "bvd2", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio", 25, "bvd1", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("assabet", 1, "reset", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("assabet", 7, "bus-enable", GPIO_ACTIVE_LOW),
{ },
},
};
static struct regulator_consumer_supply assabet_cf_vcc_consumers[] = {
REGULATOR_SUPPLY("vcc", "sa11x0-pcmcia.1"),
};
static struct fixed_voltage_config assabet_cf_vcc_pdata __initdata = {
.supply_name = "cf-power",
.microvolts = 3300000,
};
static struct gpiod_lookup_table assabet_cf_vcc_gpio_table = {
.dev_id = "reg-fixed-voltage.0",
.table = {
GPIO_LOOKUP("assabet", 0, NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct gpiod_lookup_table assabet_leds_gpio_table = {
.dev_id = "leds-gpio",
.table = {
GPIO_LOOKUP("assabet", 13, NULL, GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 14, NULL, GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpio_led assabet_leds[] __initdata = {
{
.name = "assabet:red",
.default_trigger = "cpu0",
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
}, {
.name = "assabet:green",
.default_trigger = "heartbeat",
.default_state = LEDS_GPIO_DEFSTATE_KEEP,
},
};
static const struct gpio_led_platform_data assabet_leds_pdata __initconst = {
.num_leds = ARRAY_SIZE(assabet_leds),
.leds = assabet_leds,
};
static struct gpio_keys_button assabet_keys_buttons[] = {
{
.gpio = 0,
.irq = IRQ_GPIO0,
.desc = "gpio0",
.wakeup = 1,
.can_disable = 1,
.debounce_interval = 5,
}, {
.gpio = 1,
.irq = IRQ_GPIO1,
.desc = "gpio1",
.wakeup = 1,
.can_disable = 1,
.debounce_interval = 5,
},
};
static const struct gpio_keys_platform_data assabet_keys_pdata = {
.buttons = assabet_keys_buttons,
.nbuttons = ARRAY_SIZE(assabet_keys_buttons),
.rep = 0,
};
static struct gpiod_lookup_table assabet_uart1_gpio_table = {
.dev_id = "sa11x0-uart.1",
.table = {
GPIO_LOOKUP("assabet", 16, "dtr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 17, "rts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 25, "dcd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 26, "cts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 27, "dsr", GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpiod_lookup_table assabet_uart3_gpio_table = {
.dev_id = "sa11x0-uart.3",
.table = {
GPIO_LOOKUP("assabet", 28, "cts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 29, "dsr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 30, "dcd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("assabet", 31, "rng", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init assabet_init(void)
{
/*
* Ensure that the power supply is in "high power" mode.
*/
GPSR = GPIO_GPIO16;
GPDR |= GPIO_GPIO16;
/*
* Ensure that these pins are set as outputs and are driving
* logic 0. This ensures that we won't inadvertently toggle
* the WS latch in the CPLD, and we don't float causing
* excessive power drain. --rmk
*/
GPCR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
/*
* Also set GPIO27 as an output; this is used to clock UART3
* via the FPGA and as otherwise has no pullups or pulldowns,
* so stop it floating.
*/
GPCR = GPIO_GPIO27;
GPDR |= GPIO_GPIO27;
/*
* Set up registers for sleep mode.
*/
PWER = PWER_GPIO0;
PGSR = 0;
PCFR = 0;
PSDR = 0;
PPDR |= PPC_TXD3 | PPC_TXD1;
PPSR |= PPC_TXD3 | PPC_TXD1;
sa11x0_ppc_configure_mcp();
if (machine_has_neponset()) {
#ifndef CONFIG_ASSABET_NEPONSET
printk( "Warning: Neponset detected but full support "
"hasn't been configured in the kernel\n" );
#else
platform_device_register_simple("neponset", 0,
neponset_resources, ARRAY_SIZE(neponset_resources));
#endif
} else {
gpiod_add_lookup_table(&assabet_uart1_gpio_table);
gpiod_add_lookup_table(&assabet_uart3_gpio_table);
gpiod_add_lookup_table(&assabet_cf_vcc_gpio_table);
sa11x0_register_fixed_regulator(0, &assabet_cf_vcc_pdata,
assabet_cf_vcc_consumers,
ARRAY_SIZE(assabet_cf_vcc_consumers),
true);
}
platform_device_register_resndata(NULL, "gpio-keys", 0,
NULL, 0,
&assabet_keys_pdata,
sizeof(assabet_keys_pdata));
gpiod_add_lookup_table(&assabet_leds_gpio_table);
gpio_led_register_device(-1, &assabet_leds_pdata);
#ifndef ASSABET_PAL_VIDEO
sa11x0_register_lcd(&lq039q2ds54_info);
#else
sa11x0_register_lcd(&pal_video);
#endif
sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
ARRAY_SIZE(assabet_flash_resources));
sa11x0_register_mcp(&assabet_mcp_data);
if (!machine_has_neponset())
sa11x0_register_pcmcia(1, &assabet_cf_gpio_table);
}
/*
* On Assabet, we must probe for the Neponset board _before_
* paging_init() has occurred to actually determine the amount
* of RAM available. To do so, we map the appropriate IO section
* in the page table here in order to access GPIO registers.
*/
static void __init map_sa1100_gpio_regs( void )
{
unsigned long phys = __PREG(GPLR) & PMD_MASK;
unsigned long virt = (unsigned long)io_p2v(phys);
int prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO);
pmd_t *pmd;
pmd = pmd_off_k(virt);
*pmd = __pmd(phys | prot);
flush_pmd_entry(pmd);
}
/*
* Read System Configuration "Register"
* (taken from "Intel StrongARM SA-1110 Microprocessor Development Board
* User's Guide", section 4.4.1)
*
* This same scan is performed in arch/arm/boot/compressed/head-sa1100.S
* to set up the serial port for decompression status messages. We
* repeat it here because the kernel may not be loaded as a zImage, and
* also because it's a hassle to communicate the SCR value to the kernel
* from the decompressor.
*
* Note that IRQs are guaranteed to be disabled.
*/
static void __init get_assabet_scr(void)
{
unsigned long scr, i;
GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */
GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */
GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */
for(i = 100; i--; ) /* Read GPIO 9:2 */
scr = GPLR;
GPDR |= 0x3fc; /* restore correct pin direction */
scr &= 0x3fc; /* save as system configuration byte. */
SCR_value = scr;
}
static void __init
fixup_assabet(struct tag *tags, char **cmdline)
{
/* This must be done before any call to machine_has_neponset() */
map_sa1100_gpio_regs();
get_assabet_scr();
if (machine_has_neponset())
printk("Neponset expansion board detected\n");
}
static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
{
if (port->mapbase == _Ser1UTCR0) {
if (state)
ASSABET_BCR_clear(ASSABET_BCR_RS232EN);
else
ASSABET_BCR_set(ASSABET_BCR_RS232EN);
}
}
static struct sa1100_port_fns assabet_port_fns __initdata = {
.pm = assabet_uart_pm,
};
static struct map_desc assabet_io_desc[] __initdata = {
{ /* Board Control Register */
.virtual = 0xf1000000,
.pfn = __phys_to_pfn(0x12000000),
.length = 0x00100000,
.type = MT_DEVICE
}, { /* MQ200 */
.virtual = 0xf2800000,
.pfn = __phys_to_pfn(0x4b800000),
.length = 0x00800000,
.type = MT_DEVICE
}
};
static void __init assabet_map_io(void)
{
sa1100_map_io();
iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
/*
* Set SUS bit in SDCR0 so serial port 1 functions.
* Its called GPCLKR0 in my SA1110 manual.
*/
Ser1SDCR0 |= SDCR0_SUS;
MSC1 = (MSC1 & ~0xffff) |
MSC_NonBrst | MSC_32BitStMem |
MSC_RdAcc(2) | MSC_WrAcc(2) | MSC_Rec(0);
if (!machine_has_neponset())
sa1100_register_uart_fns(&assabet_port_fns);
/*
* When Neponset is attached, the first UART should be
* UART3. That's what Angel is doing and many documents
* are stating this.
*
* We do the Neponset mapping even if Neponset support
* isn't compiled in so the user will still get something on
* the expected physical serial port.
*
* We no longer do this; not all boot loaders support it,
* and UART3 appears to be somewhat unreliable with blob.
*/
sa1100_register_uart(0, 1);
sa1100_register_uart(2, 3);
}
static void __init assabet_init_irq(void)
{
u32 def_val;
sa1100_init_irq();
if (machine_has_neponset())
def_val = ASSABET_BCR_DB1111;
else
def_val = ASSABET_BCR_DB1110;
/*
* Angel sets this, but other bootloaders may not.
*
* This must precede any driver calls to BCR_set() or BCR_clear().
*/
assabet_init_gpio((void *)&ASSABET_BCR, def_val);
}
MACHINE_START(ASSABET, "Intel-Assabet")
.atag_offset = 0x100,
.fixup = fixup_assabet,
.map_io = assabet_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = assabet_init_irq,
.init_time = sa1100_timer_init,
.init_machine = assabet_init,
.init_late = sa11x0_init_late,
#ifdef CONFIG_SA1111
.dma_zone_size = SZ_1M,
#endif
.restart = sa11x0_restart,
MACHINE_END
+145
View File
@@ -0,0 +1,145 @@
// SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/arm/mach-sa1100/clock.c
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <mach/hardware.h>
#include <mach/generic.h>
static const char * const clk_tucr_parents[] = {
"clk32768", "clk3686400",
};
static DEFINE_SPINLOCK(tucr_lock);
static int clk_gpio27_enable(struct clk_hw *hw)
{
unsigned long flags;
/*
* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
* (SA-1110 Developer's Manual, section 9.1.2.1)
*/
local_irq_save(flags);
GAFR |= GPIO_32_768kHz;
GPDR |= GPIO_32_768kHz;
local_irq_restore(flags);
return 0;
}
static void clk_gpio27_disable(struct clk_hw *hw)
{
unsigned long flags;
local_irq_save(flags);
GPDR &= ~GPIO_32_768kHz;
GAFR &= ~GPIO_32_768kHz;
local_irq_restore(flags);
}
static const struct clk_ops clk_gpio27_ops = {
.enable = clk_gpio27_enable,
.disable = clk_gpio27_disable,
};
static const char * const clk_gpio27_parents[] = {
"tucr-mux",
};
static const struct clk_init_data clk_gpio27_init_data __initconst = {
.name = "gpio27",
.ops = &clk_gpio27_ops,
.parent_names = clk_gpio27_parents,
.num_parents = ARRAY_SIZE(clk_gpio27_parents),
};
/*
* Derived from the table 8-1 in the SA1110 manual, the MPLL appears to
* multiply its input rate by 4 x (4 + PPCR). This calculation gives
* the exact rate. The figures given in the table are the rates rounded
* to 100kHz. Stick with sa11x0_getspeed() for the time being.
*/
static unsigned long clk_mpll_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
return sa11x0_getspeed(0) * 1000;
}
static const struct clk_ops clk_mpll_ops = {
.recalc_rate = clk_mpll_recalc_rate,
};
static const char * const clk_mpll_parents[] = {
"clk3686400",
};
static const struct clk_init_data clk_mpll_init_data __initconst = {
.name = "mpll",
.ops = &clk_mpll_ops,
.parent_names = clk_mpll_parents,
.num_parents = ARRAY_SIZE(clk_mpll_parents),
.flags = CLK_GET_RATE_NOCACHE | CLK_IS_CRITICAL,
};
int __init sa11xx_clk_init(void)
{
struct clk_hw *hw;
int ret;
hw = clk_hw_register_fixed_rate(NULL, "clk32768", NULL, 0, 32768);
if (IS_ERR(hw))
return PTR_ERR(hw);
clk_hw_register_clkdev(hw, NULL, "sa1100-rtc");
hw = clk_hw_register_fixed_rate(NULL, "clk3686400", NULL, 0, 3686400);
if (IS_ERR(hw))
return PTR_ERR(hw);
clk_hw_register_clkdev(hw, "OSTIMER0", NULL);
hw = kzalloc_obj(*hw);
if (!hw)
return -ENOMEM;
hw->init = &clk_mpll_init_data;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(hw);
return ret;
}
clk_hw_register_clkdev(hw, NULL, "sa11x0-fb");
clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia");
clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.0");
clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.1");
clk_hw_register_clkdev(hw, NULL, "1800");
hw = clk_hw_register_mux(NULL, "tucr-mux", clk_tucr_parents,
ARRAY_SIZE(clk_tucr_parents), 0,
(void __iomem *)&TUCR, FShft(TUCR_TSEL),
FAlnMsk(TUCR_TSEL), 0, &tucr_lock);
clk_set_rate(hw->clk, 3686400);
hw = kzalloc_obj(*hw);
if (!hw)
return -ENOMEM;
hw->init = &clk_gpio27_init_data;
ret = clk_hw_register(NULL, hw);
if (ret) {
kfree(hw);
return ret;
}
clk_hw_register_clkdev(hw, NULL, "sa1111.0");
return 0;
}
+429
View File
@@ -0,0 +1,429 @@
/*
* linux/arch/arm/mach-sa1100/collie.c
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
* This file contains all Collie-specific tweaks.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* ChangeLog:
* 2006 Pavel Machek <pavel@ucw.cz>
* 03-06-2004 John Lenz <lenz@cs.wisc.edu>
* 06-04-2002 Chris Larson <kergoth@digitalnemesis.net>
* 04-16-2001 Lineo Japan,Inc. ...
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/platform_device.h>
#include <linux/mfd/ucb1x00.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/timer.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/power/gpio-charger.h>
#include <video/sa1100fb.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <mach/collie.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <asm/hardware/scoop.h>
#include <asm/mach/sharpsl_param.h>
#include <asm/hardware/locomo.h>
#include <linux/platform_data/mfd-mcp-sa11x0.h>
#include <mach/irqs.h>
#include "generic.h"
static struct resource collie_scoop_resources[] = {
[0] = DEFINE_RES_MEM(0x40800000, SZ_4K),
};
static struct scoop_config collie_scoop_setup = {
.io_dir = COLLIE_SCOOP_IO_DIR,
.io_out = COLLIE_SCOOP_IO_OUT,
.gpio_base = COLLIE_SCOOP_GPIO_BASE,
};
struct platform_device colliescoop_device = {
.name = "sharp-scoop",
.id = -1,
.dev = {
.platform_data = &collie_scoop_setup,
},
.num_resources = ARRAY_SIZE(collie_scoop_resources),
.resource = collie_scoop_resources,
};
static struct scoop_pcmcia_dev collie_pcmcia_scoop[] = {
{
.dev = &colliescoop_device.dev,
.irq = COLLIE_IRQ_GPIO_CF_IRQ,
.cd_irq = COLLIE_IRQ_GPIO_CF_CD,
.cd_irq_str = "PCMCIA0 CD",
},
};
static struct scoop_pcmcia_config collie_pcmcia_config = {
.devs = &collie_pcmcia_scoop[0],
.num_devs = 1,
};
static struct ucb1x00_plat_data collie_ucb1x00_data = {
.gpio_base = COLLIE_TC35143_GPIO_BASE,
};
static struct mcp_plat_data collie_mcp_data = {
.mccr0 = MCCR0_ADM | MCCR0_ExtClk,
.sclk_rate = 9216000,
.codec_pdata = &collie_ucb1x00_data,
};
/* Battery management GPIOs */
static struct gpiod_lookup_table collie_battery_gpiod_table = {
/* the MCP codec mcp0 has the ucb1x00 as attached device */
.dev_id = "ucb1x00",
.table = {
/* This is found on the main GPIO on the SA1100 */
GPIO_LOOKUP("gpio", COLLIE_GPIO_CO,
"main battery full", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio", COLLIE_GPIO_MAIN_BAT_LOW,
"main battery low", GPIO_ACTIVE_HIGH),
/*
* This is GPIO 0 on the Scoop expander, which is registered
* from common/scoop.c with this gpio chip label.
*/
GPIO_LOOKUP("sharp-scoop", 0,
"main charge on", GPIO_ACTIVE_HIGH),
{ },
},
};
/*
* Collie AC IN
*/
static struct gpiod_lookup_table collie_power_gpiod_table = {
.dev_id = "gpio-charger",
.table = {
GPIO_LOOKUP("gpio", COLLIE_GPIO_AC_IN,
NULL, GPIO_ACTIVE_HIGH),
{ },
},
};
static char *collie_ac_supplied_to[] = {
"main-battery",
"backup-battery",
};
static struct gpio_charger_platform_data collie_power_data = {
.name = "charger",
.type = POWER_SUPPLY_TYPE_MAINS,
.supplied_to = collie_ac_supplied_to,
.num_supplicants = ARRAY_SIZE(collie_ac_supplied_to),
};
static struct platform_device collie_power_device = {
.name = "gpio-charger",
.id = -1,
.dev.platform_data = &collie_power_data,
};
#ifdef CONFIG_SHARP_LOCOMO
/*
* low-level UART features.
*/
struct platform_device collie_locomo_device;
static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
{
if (mctrl & TIOCM_RTS)
locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
else
locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
if (mctrl & TIOCM_DTR)
locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
else
locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
}
static u_int collie_uart_get_mctrl(struct uart_port *port)
{
int ret = TIOCM_CD;
unsigned int r;
r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
if (r == -ENODEV)
return ret;
if (r & LOCOMO_GPIO_CTS)
ret |= TIOCM_CTS;
if (r & LOCOMO_GPIO_DSR)
ret |= TIOCM_DSR;
return ret;
}
static struct sa1100_port_fns collie_port_fns __initdata = {
.set_mctrl = collie_uart_set_mctrl,
.get_mctrl = collie_uart_get_mctrl,
};
static int collie_uart_probe(struct locomo_dev *dev)
{
return 0;
}
static struct locomo_driver collie_uart_driver = {
.drv = {
.name = "collie_uart",
},
.devid = LOCOMO_DEVID_UART,
.probe = collie_uart_probe,
};
static int __init collie_uart_init(void)
{
return locomo_driver_register(&collie_uart_driver);
}
device_initcall(collie_uart_init);
#endif
static struct resource locomo_resources[] = {
[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
[1] = DEFINE_RES_IRQ(IRQ_GPIO25),
};
static struct locomo_platform_data locomo_info = {
.irq_base = IRQ_BOARD_START,
};
struct platform_device collie_locomo_device = {
.name = "locomo",
.id = 0,
.dev = {
.platform_data = &locomo_info,
},
.num_resources = ARRAY_SIZE(locomo_resources),
.resource = locomo_resources,
};
static struct gpio_keys_button collie_gpio_keys[] = {
{
.type = EV_PWR,
.code = KEY_RESERVED,
.gpio = COLLIE_GPIO_ON_KEY,
.desc = "On key",
.wakeup = 1,
.active_low = 1,
},
{
.type = EV_PWR,
.code = KEY_WAKEUP,
.gpio = COLLIE_GPIO_WAKEUP,
.desc = "Sync",
.wakeup = 1,
.active_low = 1,
},
};
static struct gpio_keys_platform_data collie_gpio_keys_data = {
.buttons = collie_gpio_keys,
.nbuttons = ARRAY_SIZE(collie_gpio_keys),
};
static struct platform_device collie_gpio_keys_device = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &collie_gpio_keys_data,
},
};
static struct platform_device *devices[] __initdata = {
&collie_locomo_device,
&colliescoop_device,
&collie_power_device,
&collie_gpio_keys_device,
};
static struct mtd_partition collie_partitions[] = {
{
.name = "bootloader",
.offset = 0,
.size = 0x000C0000,
.mask_flags = MTD_WRITEABLE
}, {
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0x00100000,
}, {
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = 0x00e20000,
}, {
.name = "bootblock",
.offset = MTDPART_OFS_APPEND,
.size = 0x00020000,
.mask_flags = MTD_WRITEABLE
}
};
static int collie_flash_init(void)
{
int rc = gpio_request(COLLIE_GPIO_VPEN, "flash Vpp enable");
if (rc)
return rc;
rc = gpio_direction_output(COLLIE_GPIO_VPEN, 1);
if (rc)
gpio_free(COLLIE_GPIO_VPEN);
return rc;
}
static void collie_set_vpp(int vpp)
{
gpio_set_value(COLLIE_GPIO_VPEN, vpp);
}
static void collie_flash_exit(void)
{
gpio_free(COLLIE_GPIO_VPEN);
}
static struct flash_platform_data collie_flash_data = {
.map_name = "cfi_probe",
.init = collie_flash_init,
.set_vpp = collie_set_vpp,
.exit = collie_flash_exit,
.parts = collie_partitions,
.nr_parts = ARRAY_SIZE(collie_partitions),
};
static struct resource collie_flash_resources[] = {
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M),
};
static struct sa1100fb_mach_info collie_lcd_info = {
.pixclock = 171521, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 5, .vsync_len = 1,
.left_margin = 11, .upper_margin = 2,
.right_margin = 30, .lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
#ifdef CONFIG_BACKLIGHT_LOCOMO
.lcd_power = locomolcd_power
#endif
};
static void __init collie_init(void)
{
int ret = 0;
/* cpu initialize */
GAFR = GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK |
GPIO_MCP_CLK | GPIO_32_768kHz;
GPDR = GPIO_LDD8 | GPIO_LDD9 | GPIO_LDD10 | GPIO_LDD11 | GPIO_LDD12 |
GPIO_LDD13 | GPIO_LDD14 | GPIO_LDD15 | GPIO_SSP_TXD |
GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SDLC_SCLK |
_COLLIE_GPIO_UCB1x00_RESET | _COLLIE_GPIO_nMIC_ON |
_COLLIE_GPIO_nREMOCON_ON | GPIO_32_768kHz;
PPDR = PPC_LDD0 | PPC_LDD1 | PPC_LDD2 | PPC_LDD3 | PPC_LDD4 | PPC_LDD5 |
PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS |
PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PWER = 0;
PGSR = _COLLIE_GPIO_nREMOCON_ON;
PSDR = PPC_RXD1 | PPC_RXD2 | PPC_RXD3 | PPC_RXD4;
PCFR = PCFR_OPDE;
GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
sa11x0_ppc_configure_mcp();
platform_scoop_config = &collie_pcmcia_config;
gpiod_add_lookup_table(&collie_power_gpiod_table);
gpiod_add_lookup_table(&collie_battery_gpiod_table);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
if (ret) {
printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
}
sa11x0_register_lcd(&collie_lcd_info);
sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
ARRAY_SIZE(collie_flash_resources));
sa11x0_register_mcp(&collie_mcp_data);
sharpsl_save_param();
}
static struct map_desc collie_io_desc[] __initdata = {
{ /* 32M main flash (cs0) */
.virtual = 0xe8000000,
.pfn = __phys_to_pfn(0x00000000),
.length = 0x02000000,
.type = MT_DEVICE
}, { /* 32M boot flash (cs1) */
.virtual = 0xea000000,
.pfn = __phys_to_pfn(0x08000000),
.length = 0x02000000,
.type = MT_DEVICE
}
};
static void __init collie_map_io(void)
{
sa1100_map_io();
iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
#ifdef CONFIG_SHARP_LOCOMO
sa1100_register_uart_fns(&collie_port_fns);
#endif
sa1100_register_uart(0, 3);
sa1100_register_uart(1, 1);
}
MACHINE_START(COLLIE, "Sharp-Collie")
.map_io = collie_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_time = sa1100_timer_init,
.init_machine = collie_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
MACHINE_END
+470
View File
@@ -0,0 +1,470 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/generic.c
*
* Author: Nicolas Pitre
*
* Code common to all SA11x0 machines.
*/
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/irqchip/irq-sa11x0.h>
#include <video/sa1100fb.h>
#include <soc/sa1100/pwer.h>
#include <asm/div64.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
#include <asm/irq.h>
#include <asm/system_misc.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <mach/reset.h>
#include "generic.h"
#include <clocksource/pxa.h>
#define NR_FREQS 16
/*
* This table is setup for a 3.6864MHz Crystal.
*/
struct cpufreq_frequency_table sa11x0_freq_table[NR_FREQS+1] = {
{ .frequency = 59000, /* 59.0 MHz */},
{ .frequency = 73700, /* 73.7 MHz */},
{ .frequency = 88500, /* 88.5 MHz */},
{ .frequency = 103200, /* 103.2 MHz */},
{ .frequency = 118000, /* 118.0 MHz */},
{ .frequency = 132700, /* 132.7 MHz */},
{ .frequency = 147500, /* 147.5 MHz */},
{ .frequency = 162200, /* 162.2 MHz */},
{ .frequency = 176900, /* 176.9 MHz */},
{ .frequency = 191700, /* 191.7 MHz */},
{ .frequency = 206400, /* 206.4 MHz */},
{ .frequency = 221200, /* 221.2 MHz */},
{ .frequency = 235900, /* 235.9 MHz */},
{ .frequency = 250700, /* 250.7 MHz */},
{ .frequency = 265400, /* 265.4 MHz */},
{ .frequency = 280200, /* 280.2 MHz */},
{ .frequency = CPUFREQ_TABLE_END, },
};
unsigned int sa11x0_getspeed(unsigned int cpu)
{
if (cpu)
return 0;
return sa11x0_freq_table[PPCR & 0xf].frequency;
}
/*
* Default power-off for SA1100
*/
static void sa1100_power_off(void)
{
mdelay(100);
local_irq_disable();
/* disable internal oscillator, float CS lines */
PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
/* enable wake-up on GPIO0 (Assabet...) */
PWER = GFER = GRER = 1;
/*
* set scratchpad to zero, just in case it is used as a
* restart address by the bootloader.
*/
PSPR = 0;
/* enter sleep mode */
PMCR = PMCR_SF;
}
void sa11x0_restart(enum reboot_mode mode, const char *cmd)
{
clear_reset_status(RESET_STATUS_ALL);
if (mode == REBOOT_SOFT) {
/* Jump into ROM at address 0 */
soft_restart(0);
} else {
/* Use on-chip reset capability */
RSRR = RSRR_SWR;
}
}
static void sa11x0_register_device(struct platform_device *dev, void *data)
{
int err;
dev->dev.platform_data = data;
err = platform_device_register(dev);
if (err)
printk(KERN_ERR "Unable to register device %s: %d\n",
dev->name, err);
}
static struct resource sa11x0udc_resources[] = {
[0] = DEFINE_RES_MEM(__PREG(Ser0UDCCR), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser0UDC),
};
static u64 sa11x0udc_dma_mask = 0xffffffffUL;
static struct platform_device sa11x0udc_device = {
.name = "sa11x0-udc",
.id = -1,
.dev = {
.dma_mask = &sa11x0udc_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0udc_resources),
.resource = sa11x0udc_resources,
};
static struct resource sa11x0uart1_resources[] = {
[0] = DEFINE_RES_MEM(__PREG(Ser1UTCR0), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser1UART),
};
static struct platform_device sa11x0uart1_device = {
.name = "sa11x0-uart",
.id = 1,
.num_resources = ARRAY_SIZE(sa11x0uart1_resources),
.resource = sa11x0uart1_resources,
};
static struct resource sa11x0uart3_resources[] = {
[0] = DEFINE_RES_MEM(__PREG(Ser3UTCR0), SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser3UART),
};
static struct platform_device sa11x0uart3_device = {
.name = "sa11x0-uart",
.id = 3,
.num_resources = ARRAY_SIZE(sa11x0uart3_resources),
.resource = sa11x0uart3_resources,
};
static struct resource sa11x0mcp_resources[] = {
[0] = DEFINE_RES_MEM(__PREG(Ser4MCCR0), SZ_64K),
[1] = DEFINE_RES_MEM(__PREG(Ser4MCCR1), 4),
[2] = DEFINE_RES_IRQ(IRQ_Ser4MCP),
};
static u64 sa11x0mcp_dma_mask = 0xffffffffUL;
static struct platform_device sa11x0mcp_device = {
.name = "sa11x0-mcp",
.id = -1,
.dev = {
.dma_mask = &sa11x0mcp_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0mcp_resources),
.resource = sa11x0mcp_resources,
};
void __init sa11x0_ppc_configure_mcp(void)
{
/* Setup the PPC unit for the MCP */
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
}
void sa11x0_register_mcp(struct mcp_plat_data *data)
{
sa11x0_register_device(&sa11x0mcp_device, data);
}
static struct resource sa11x0ssp_resources[] = {
[0] = DEFINE_RES_MEM(0x80070000, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_Ser4SSP),
};
static u64 sa11x0ssp_dma_mask = 0xffffffffUL;
static struct platform_device sa11x0ssp_device = {
.name = "sa11x0-ssp",
.id = -1,
.dev = {
.dma_mask = &sa11x0ssp_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0ssp_resources),
.resource = sa11x0ssp_resources,
};
static struct resource sa11x0fb_resources[] = {
[0] = DEFINE_RES_MEM(0xb0100000, SZ_64K),
[1] = DEFINE_RES_IRQ(IRQ_LCD),
};
static struct platform_device sa11x0fb_device = {
.name = "sa11x0-fb",
.id = -1,
.dev = {
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0fb_resources),
.resource = sa11x0fb_resources,
};
void sa11x0_register_lcd(struct sa1100fb_mach_info *inf)
{
sa11x0_register_device(&sa11x0fb_device, inf);
}
void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *table)
{
if (table)
gpiod_add_lookup_table(table);
platform_device_register_simple("sa11x0-pcmcia", socket, NULL, 0);
}
static struct platform_device sa11x0mtd_device = {
.name = "sa1100-mtd",
.id = -1,
};
void sa11x0_register_mtd(struct flash_platform_data *flash,
struct resource *res, int nr)
{
flash->name = "sa1100";
sa11x0mtd_device.resource = res;
sa11x0mtd_device.num_resources = nr;
sa11x0_register_device(&sa11x0mtd_device, flash);
}
static struct resource sa1100_rtc_resources[] = {
DEFINE_RES_MEM(0x90010000, 0x40),
DEFINE_RES_IRQ_NAMED(IRQ_RTC1Hz, "rtc 1Hz"),
DEFINE_RES_IRQ_NAMED(IRQ_RTCAlrm, "rtc alarm"),
};
static struct platform_device sa11x0rtc_device = {
.name = "sa1100-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(sa1100_rtc_resources),
.resource = sa1100_rtc_resources,
};
static struct resource sa11x0dma_resources[] = {
DEFINE_RES_MEM(DMA_PHYS, DMA_SIZE),
DEFINE_RES_IRQ(IRQ_DMA0),
DEFINE_RES_IRQ(IRQ_DMA1),
DEFINE_RES_IRQ(IRQ_DMA2),
DEFINE_RES_IRQ(IRQ_DMA3),
DEFINE_RES_IRQ(IRQ_DMA4),
DEFINE_RES_IRQ(IRQ_DMA5),
};
static u64 sa11x0dma_dma_mask = DMA_BIT_MASK(32);
static struct platform_device sa11x0dma_device = {
.name = "sa11x0-dma",
.id = -1,
.dev = {
.dma_mask = &sa11x0dma_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(sa11x0dma_resources),
.resource = sa11x0dma_resources,
};
static struct platform_device *sa11x0_devices[] __initdata = {
&sa11x0udc_device,
&sa11x0uart1_device,
&sa11x0uart3_device,
&sa11x0ssp_device,
&sa11x0rtc_device,
&sa11x0dma_device,
};
static int __init sa1100_init(void)
{
struct resource wdt_res = DEFINE_RES_MEM(0x90000000, 0x20);
register_platform_power_off(sa1100_power_off);
regulator_has_full_constraints();
platform_device_register_simple("sa1100_wdt", -1, &wdt_res, 1);
return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices));
}
arch_initcall(sa1100_init);
void __init sa11x0_init_late(void)
{
sa11x0_pm_init();
}
int __init sa11x0_register_fixed_regulator(int n,
struct fixed_voltage_config *cfg,
struct regulator_consumer_supply *supplies, unsigned num_supplies,
bool uses_gpio)
{
struct regulator_init_data *id;
cfg->init_data = id = kzalloc_obj(*cfg->init_data);
if (!cfg->init_data)
return -ENOMEM;
if (!uses_gpio)
id->constraints.always_on = 1;
id->constraints.name = cfg->supply_name;
id->constraints.min_uV = cfg->microvolts;
id->constraints.max_uV = cfg->microvolts;
id->constraints.valid_modes_mask = REGULATOR_MODE_NORMAL;
id->constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
id->consumer_supplies = supplies;
id->num_consumer_supplies = num_supplies;
platform_device_register_resndata(NULL, "reg-fixed-voltage", n,
NULL, 0, cfg, sizeof(*cfg));
return 0;
}
/*
* Common I/O mapping:
*
* Typically, static virtual address mappings are as follow:
*
* 0xf0000000-0xf3ffffff: miscellaneous stuff (CPLDs, etc.)
* 0xf4000000-0xf4ffffff: SA-1111
* 0xf5000000-0xf5ffffff: reserved (used by cache flushing area)
* 0xf6000000-0xfffeffff: reserved (internal SA1100 IO defined above)
* 0xffff0000-0xffff0fff: SA1100 exception vectors
* 0xffff2000-0xffff2fff: Minicache copy_user_page area
*
* Below 0xe8000000 is reserved for vm allocation.
*
* The machine specific code must provide the extra mapping beside the
* default mapping provided here.
*/
static struct map_desc standard_io_desc[] __initdata = {
{ /* PCM */
.virtual = 0xf8000000,
.pfn = __phys_to_pfn(0x80000000),
.length = 0x00100000,
.type = MT_DEVICE
}, { /* SCM */
.virtual = 0xfa000000,
.pfn = __phys_to_pfn(0x90000000),
.length = 0x00100000,
.type = MT_DEVICE
}, { /* MER */
.virtual = 0xfc000000,
.pfn = __phys_to_pfn(0xa0000000),
.length = 0x00100000,
.type = MT_DEVICE
}, { /* LCD + DMA */
.virtual = 0xfe000000,
.pfn = __phys_to_pfn(0xb0000000),
.length = 0x00200000,
.type = MT_DEVICE
},
};
void __init sa1100_map_io(void)
{
iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
}
void __init sa1100_timer_init(void)
{
pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000));
}
static struct resource irq_resource =
DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
void __init sa1100_init_irq(void)
{
request_resource(&iomem_resource, &irq_resource);
sa11x0_init_irq_nodt(IRQ_GPIO0_SC, irq_resource.start);
sa1100_init_gpio();
sa11xx_clk_init();
}
/*
* Disable the memory bus request/grant signals on the SA1110 to
* ensure that we don't receive spurious memory requests. We set
* the MBGNT signal false to ensure the SA1111 doesn't own the
* SDRAM bus.
*/
void sa1110_mb_disable(void)
{
unsigned long flags;
local_irq_save(flags);
PGSR &= ~GPIO_MBGNT;
GPCR = GPIO_MBGNT;
GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
GAFR &= ~(GPIO_MBGNT | GPIO_MBREQ);
local_irq_restore(flags);
}
/*
* If the system is going to use the SA-1111 DMA engines, set up
* the memory bus request/grant pins.
*/
void sa1110_mb_enable(void)
{
unsigned long flags;
local_irq_save(flags);
PGSR &= ~GPIO_MBGNT;
GPCR = GPIO_MBGNT;
GPDR = (GPDR & ~GPIO_MBREQ) | GPIO_MBGNT;
GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
TUCR |= TUCR_MR;
local_irq_restore(flags);
}
int sa11x0_gpio_set_wake(unsigned int gpio, unsigned int on)
{
if (on)
PWER |= BIT(gpio);
else
PWER &= ~BIT(gpio);
return 0;
}
int sa11x0_sc_set_wake(unsigned int irq, unsigned int on)
{
if (BIT(irq) != IC_RTCAlrm)
return -EINVAL;
if (on)
PWER |= PWER_RTC;
else
PWER &= ~PWER_RTC;
return 0;
}
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* linux/arch/arm/mach-sa1100/generic.h
*
* Author: Nicolas Pitre
*/
#include <linux/cpufreq.h>
#include <linux/reboot.h>
extern void sa1100_timer_init(void);
extern void __init sa1100_map_io(void);
extern void __init sa1100_init_irq(void);
extern void __init sa1100_init_gpio(void);
extern void sa11x0_restart(enum reboot_mode, const char *);
extern void sa11x0_init_late(void);
#define SET_BANK(__nr,__start,__size) \
mi->bank[__nr].start = (__start), \
mi->bank[__nr].size = (__size)
extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void);
extern struct cpufreq_frequency_table sa11x0_freq_table[];
extern unsigned int sa11x0_getspeed(unsigned int cpu);
struct flash_platform_data;
struct resource;
void sa11x0_register_mtd(struct flash_platform_data *flash,
struct resource *res, int nr);
struct mcp_plat_data;
void sa11x0_ppc_configure_mcp(void);
void sa11x0_register_mcp(struct mcp_plat_data *data);
struct sa1100fb_mach_info;
void sa11x0_register_lcd(struct sa1100fb_mach_info *inf);
#ifdef CONFIG_PM
int sa11x0_pm_init(void);
#else
static inline int sa11x0_pm_init(void) { return 0; }
#endif
int sa11xx_clk_init(void);
struct gpiod_lookup_table;
void sa11x0_register_pcmcia(int socket, struct gpiod_lookup_table *);
struct fixed_voltage_config;
struct regulator_consumer_supply;
int sa11x0_register_fixed_regulator(int n, struct fixed_voltage_config *cfg,
struct regulator_consumer_supply *supplies, unsigned num_supplies,
bool uses_gpio);
+134
View File
@@ -0,0 +1,134 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for Compaq iPAQ H3600 handheld computer
*
* Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
* Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <video/sa1100fb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/h3xxx.h>
#include <mach/irqs.h>
#include "generic.h"
static bool h3600_lcd_request(void)
{
static bool h3600_lcd_ok;
int rc;
if (h3600_lcd_ok)
return true;
rc = gpio_request(H3XXX_EGPIO_LCD_ON, "LCD power");
if (rc)
goto out;
rc = gpio_direction_output(H3XXX_EGPIO_LCD_ON, 0);
if (rc)
goto out_free_on;
rc = gpio_request(H3600_EGPIO_LCD_PCI, "LCD control");
if (rc)
goto out_free_on;
rc = gpio_direction_output(H3600_EGPIO_LCD_PCI, 0);
if (rc)
goto out_free_pci;
rc = gpio_request(H3600_EGPIO_LCD_5V_ON, "LCD 5v");
if (rc)
goto out_free_pci;
rc = gpio_direction_output(H3600_EGPIO_LCD_5V_ON, 0);
if (rc)
goto out_free_5v_on;
rc = gpio_request(H3600_EGPIO_LVDD_ON, "LCD 9v/-6.5v");
if (rc)
goto out_free_5v_on;
rc = gpio_direction_output(H3600_EGPIO_LVDD_ON, 0);
if (rc)
goto out_free_lvdd_on;
goto out;
out_free_lvdd_on:
gpio_free(H3600_EGPIO_LVDD_ON);
out_free_5v_on:
gpio_free(H3600_EGPIO_LCD_5V_ON);
out_free_pci:
gpio_free(H3600_EGPIO_LCD_PCI);
out_free_on:
gpio_free(H3XXX_EGPIO_LCD_ON);
out:
if (rc)
pr_err("%s: can't request GPIOs\n", __func__);
else
h3600_lcd_ok = true;
return h3600_lcd_ok;
}
static void h3600_lcd_power(int enable)
{
if (!h3600_lcd_request())
return;
gpio_direction_output(H3XXX_EGPIO_LCD_ON, enable);
gpio_direction_output(H3600_EGPIO_LCD_PCI, enable);
gpio_direction_output(H3600_EGPIO_LCD_5V_ON, enable);
gpio_direction_output(H3600_EGPIO_LVDD_ON, enable);
}
static const struct sa1100fb_rgb h3600_rgb_16 = {
.red = { .offset = 12, .length = 4, },
.green = { .offset = 7, .length = 4, },
.blue = { .offset = 1, .length = 4, },
.transp = { .offset = 0, .length = 0, },
};
static struct sa1100fb_mach_info h3600_lcd_info = {
.pixclock = 174757, .bpp = 16,
.xres = 320, .yres = 240,
.hsync_len = 3, .vsync_len = 3,
.left_margin = 12, .upper_margin = 10,
.right_margin = 17, .lower_margin = 1,
.cmap_static = 1,
.lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
.rgb[RGB_16] = &h3600_rgb_16,
.lcd_power = h3600_lcd_power,
};
static void __init h3600_map_io(void)
{
h3xxx_map_io();
}
static void __init h3600_mach_init(void)
{
h3xxx_mach_init();
sa11x0_register_lcd(&h3600_lcd_info);
}
MACHINE_START(H3600, "Compaq iPAQ H3600")
.atag_offset = 0x100,
.map_io = h3600_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_time = sa1100_timer_init,
.init_machine = h3600_mach_init,
.init_late = sa11x0_init_late,
.restart = sa11x0_restart,
MACHINE_END
+288
View File
@@ -0,0 +1,288 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Support for Compaq iPAQ H3100 and H3600 handheld computers (common code)
*
* Copyright (c) 2000,1 Compaq Computer Corporation. (Author: Jamey Hicks)
* Copyright (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
*/
#include <linux/kernel.h>
#include <linux/gpio/machine.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/platform_data/gpio-htc-egpio.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/h3xxx.h>
#include <mach/irqs.h>
#include "generic.h"
/*
* H3xxx flash support
*/
static struct mtd_partition h3xxx_partitions[] = {
{
.name = "H3XXX boot firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
.name = "H3XXX rootfs",
.size = MTDPART_SIZ_FULL,
.offset = 0x00040000,
}
};
static void h3xxx_set_vpp(int vpp)
{
gpio_set_value(H3XXX_EGPIO_VPP_ON, vpp);
}
static int h3xxx_flash_init(void)
{
int err = gpio_request(H3XXX_EGPIO_VPP_ON, "Flash Vpp");
if (err) {
pr_err("%s: can't request H3XXX_EGPIO_VPP_ON\n", __func__);
return err;
}
err = gpio_direction_output(H3XXX_EGPIO_VPP_ON, 0);
if (err)
gpio_free(H3XXX_EGPIO_VPP_ON);
return err;
}
static void h3xxx_flash_exit(void)
{
gpio_free(H3XXX_EGPIO_VPP_ON);
}
static struct flash_platform_data h3xxx_flash_data = {
.map_name = "cfi_probe",
.set_vpp = h3xxx_set_vpp,
.init = h3xxx_flash_init,
.exit = h3xxx_flash_exit,
.parts = h3xxx_partitions,
.nr_parts = ARRAY_SIZE(h3xxx_partitions),
};
static struct resource h3xxx_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
/*
* H3xxx uart support
*/
static void h3xxx_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
{
if (port->mapbase == _Ser3UTCR0) {
if (!gpio_request(H3XXX_EGPIO_RS232_ON, "RS232 transceiver")) {
gpio_direction_output(H3XXX_EGPIO_RS232_ON, !state);
gpio_free(H3XXX_EGPIO_RS232_ON);
} else {
pr_err("%s: can't request H3XXX_EGPIO_RS232_ON\n",
__func__);
}
}
}
/*
* Enable/Disable wake up events for this serial port.
* Obviously, we only support this on the normal COM port.
*/
static int h3xxx_uart_set_wake(struct uart_port *port, u_int enable)
{
int err = -EINVAL;
if (port->mapbase == _Ser3UTCR0) {
if (enable)
PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
else
PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
err = 0;
}
return err;
}
static struct sa1100_port_fns h3xxx_port_fns __initdata = {
.pm = h3xxx_uart_pm,
.set_wake = h3xxx_uart_set_wake,
};
static struct gpiod_lookup_table h3xxx_uart3_gpio_table = {
.dev_id = "sa11x0-uart.3",
.table = {
GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_DCD, "dcd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_CTS, "cts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio", H3XXX_GPIO_COM_RTS, "rts", GPIO_ACTIVE_LOW),
{ },
},
};
/*
* EGPIO
*/
static struct resource egpio_resources[] = {
[0] = DEFINE_RES_MEM(H3600_EGPIO_PHYS, 0x4),
};
static struct htc_egpio_chip egpio_chips[] = {
[0] = {
.reg_start = 0,
.gpio_base = H3XXX_EGPIO_BASE,
.num_gpios = 16,
.direction = HTC_EGPIO_OUTPUT,
.initial_values = 0x0080, /* H3XXX_EGPIO_RS232_ON */
},
};
static struct htc_egpio_platform_data egpio_info = {
.reg_width = 16,
.bus_width = 16,
.chip = egpio_chips,
.num_chips = ARRAY_SIZE(egpio_chips),
};
static struct platform_device h3xxx_egpio = {
.name = "htc-egpio",
.id = -1,
.resource = egpio_resources,
.num_resources = ARRAY_SIZE(egpio_resources),
.dev = {
.platform_data = &egpio_info,
},
};
/*
* GPIO keys
*/
static struct gpio_keys_button h3xxx_button_table[] = {
{
.code = KEY_POWER,
.gpio = H3XXX_GPIO_PWR_BUTTON,
.desc = "Power Button",
.active_low = 1,
.type = EV_KEY,
.wakeup = 1,
}, {
.code = KEY_ENTER,
.gpio = H3XXX_GPIO_ACTION_BUTTON,
.active_low = 1,
.desc = "Action button",
.type = EV_KEY,
.wakeup = 0,
},
};
static struct gpio_keys_platform_data h3xxx_keys_data = {
.buttons = h3xxx_button_table,
.nbuttons = ARRAY_SIZE(h3xxx_button_table),
};
static struct platform_device h3xxx_keys = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &h3xxx_keys_data,
},
};
static struct resource h3xxx_micro_resources[] = {
DEFINE_RES_MEM(0x80010000, SZ_4K),
DEFINE_RES_MEM(0x80020000, SZ_4K),
DEFINE_RES_IRQ(IRQ_Ser1UART),
};
struct platform_device h3xxx_micro_asic = {
.name = "ipaq-h3xxx-micro",
.id = -1,
.resource = h3xxx_micro_resources,
.num_resources = ARRAY_SIZE(h3xxx_micro_resources),
};
static struct platform_device *h3xxx_devices[] = {
&h3xxx_egpio,
&h3xxx_keys,
&h3xxx_micro_asic,
};
static struct gpiod_lookup_table h3xxx_pcmcia_gpio_table = {
.dev_id = "sa11x0-pcmcia",
.table = {
GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_CD0,
"pcmcia0-detect", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_IRQ0,
"pcmcia0-ready", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_CD1,
"pcmcia1-detect", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio", H3XXX_GPIO_PCMCIA_IRQ1,
"pcmcia1-ready", GPIO_ACTIVE_HIGH),
{ },
},
};
void __init h3xxx_mach_init(void)
{
gpiod_add_lookup_table(&h3xxx_pcmcia_gpio_table);
gpiod_add_lookup_table(&h3xxx_uart3_gpio_table);
sa1100_register_uart_fns(&h3xxx_port_fns);
sa11x0_register_mtd(&h3xxx_flash_data, &h3xxx_flash_resource, 1);
platform_add_devices(h3xxx_devices, ARRAY_SIZE(h3xxx_devices));
}
static struct map_desc h3600_io_desc[] __initdata = {
{ /* static memory bank 2 CS#2 */
.virtual = H3600_BANK_2_VIRT,
.pfn = __phys_to_pfn(SA1100_CS2_PHYS),
.length = 0x02800000,
.type = MT_DEVICE
}, { /* static memory bank 4 CS#4 */
.virtual = H3600_BANK_4_VIRT,
.pfn = __phys_to_pfn(SA1100_CS4_PHYS),
.length = 0x00800000,
.type = MT_DEVICE
}, { /* EGPIO 0 CS#5 */
.virtual = H3600_EGPIO_VIRT,
.pfn = __phys_to_pfn(H3600_EGPIO_PHYS),
.length = 0x01000000,
.type = MT_DEVICE
}
};
/*
* Common map_io initialization
*/
void __init h3xxx_map_io(void)
{
sa1100_map_io();
iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
sa1100_register_uart(0, 3); /* Common serial port */
// sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
/* Ensure those pins are outputs and driving low */
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
/* Configure suspend conditions */
PGSR = 0;
PCFR = PCFR_OPDE;
PSDR = 0;
GPCR = 0x0fffffff; /* All outputs are set low by default */
GPDR = 0; /* Configure all GPIOs as input */
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,99 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/assabet.h
*
* Created 2000/06/05 by Nicolas Pitre <nico@fluxnic.net>
*
* This file contains the hardware specific definitions for Assabet
* Only include this file from SA1100-specific files.
*
* 2000/05/23 John Dorsey <john+@cs.cmu.edu>
* Definitions for Neponset added.
*/
#ifndef __ASM_ARCH_ASSABET_H
#define __ASM_ARCH_ASSABET_H
/* System Configuration Register flags */
#define ASSABET_SCR_SDRAM_LOW (1<<2) /* SDRAM size (low bit) */
#define ASSABET_SCR_SDRAM_HIGH (1<<3) /* SDRAM size (high bit) */
#define ASSABET_SCR_FLASH_LOW (1<<4) /* Flash size (low bit) */
#define ASSABET_SCR_FLASH_HIGH (1<<5) /* Flash size (high bit) */
#define ASSABET_SCR_GFX (1<<8) /* Graphics Accelerator (0 = present) */
#define ASSABET_SCR_SA1111 (1<<9) /* Neponset (0 = present) */
#define ASSABET_SCR_INIT -1
extern unsigned long SCR_value;
#ifdef CONFIG_ASSABET_NEPONSET
#define machine_has_neponset() ((SCR_value & ASSABET_SCR_SA1111) == 0)
#else
#define machine_has_neponset() (0)
#endif
/* Board Control Register */
#define ASSABET_BCR_BASE 0xf1000000
#define ASSABET_BCR (*(volatile unsigned int *)(ASSABET_BCR_BASE))
#define ASSABET_BCR_CF_PWR (1<<0) /* Compact Flash Power (1 = 3.3v, 0 = off) */
#define ASSABET_BCR_CF_RST (1<<1) /* Compact Flash Reset (1 = power up reset) */
#define ASSABET_BCR_NGFX_RST (1<<1) /* Graphics Accelerator Reset (0 = hold reset) */
#define ASSABET_BCR_NCODEC_RST (1<<2) /* 0 = Holds UCB1300, ADI7171, and UDA1341 in reset */
#define ASSABET_BCR_IRDA_FSEL (1<<3) /* IRDA Frequency select (0 = SIR, 1 = MIR/ FIR) */
#define ASSABET_BCR_IRDA_MD0 (1<<4) /* Range/Power select */
#define ASSABET_BCR_IRDA_MD1 (1<<5) /* Range/Power select */
#define ASSABET_BCR_STEREO_LB (1<<6) /* Stereo Loopback */
#define ASSABET_BCR_CF_BUS_OFF (1<<7) /* Compact Flash bus (0 = on, 1 = off (float)) */
#define ASSABET_BCR_AUDIO_ON (1<<8) /* Audio power on */
#define ASSABET_BCR_LIGHT_ON (1<<9) /* Backlight */
#define ASSABET_BCR_LCD_12RGB (1<<10) /* 0 = 16RGB, 1 = 12RGB */
#define ASSABET_BCR_LCD_ON (1<<11) /* LCD power on */
#define ASSABET_BCR_RS232EN (1<<12) /* RS232 transceiver enable */
#define ASSABET_BCR_LED_RED (1<<13) /* D9 (0 = on, 1 = off) */
#define ASSABET_BCR_LED_GREEN (1<<14) /* D8 (0 = on, 1 = off) */
#define ASSABET_BCR_VIB_ON (1<<15) /* Vibration motor (quiet alert) */
#define ASSABET_BCR_COM_DTR (1<<16) /* COMport Data Terminal Ready */
#define ASSABET_BCR_COM_RTS (1<<17) /* COMport Request To Send */
#define ASSABET_BCR_RAD_WU (1<<18) /* Radio wake up interrupt */
#define ASSABET_BCR_SMB_EN (1<<19) /* System management bus enable */
#define ASSABET_BCR_TV_IR_DEC (1<<20) /* TV IR Decode Enable (not implemented) */
#define ASSABET_BCR_QMUTE (1<<21) /* Quick Mute */
#define ASSABET_BCR_RAD_ON (1<<22) /* Radio Power On */
#define ASSABET_BCR_SPK_OFF (1<<23) /* 1 = Speaker amplifier power off */
#ifdef CONFIG_SA1100_ASSABET
extern void ASSABET_BCR_frob(unsigned int mask, unsigned int set);
#else
#define ASSABET_BCR_frob(x,y) do { } while (0)
#endif
extern void assabet_uda1341_reset(int set);
#define ASSABET_BCR_set(x) ASSABET_BCR_frob((x), (x))
#define ASSABET_BCR_clear(x) ASSABET_BCR_frob((x), 0)
#define ASSABET_BSR_BASE 0xf1000000
#define ASSABET_BSR (*(volatile unsigned int*)(ASSABET_BSR_BASE))
#define ASSABET_BSR_RS232_VALID (1 << 24)
#define ASSABET_BSR_COM_DCD (1 << 25)
#define ASSABET_BSR_COM_CTS (1 << 26)
#define ASSABET_BSR_COM_DSR (1 << 27)
#define ASSABET_BSR_RAD_CTS (1 << 28)
#define ASSABET_BSR_RAD_DSR (1 << 29)
#define ASSABET_BSR_RAD_DCD (1 << 30)
#define ASSABET_BSR_RAD_RI (1 << 31)
/* GPIOs (bitmasks) for which the generic definition doesn't say much */
#define ASSABET_GPIO_RADIO_IRQ GPIO_GPIO (14) /* Radio interrupt request */
#define ASSABET_GPIO_PS_MODE_SYNC GPIO_GPIO (16) /* Power supply mode/sync */
#define ASSABET_GPIO_STEREO_64FS_CLK GPIO_GPIO (19) /* SSP UDA1341 clock input */
#define ASSABET_GPIO_GFX_IRQ GPIO_GPIO (24) /* Graphics IRQ */
#define ASSABET_GPIO_BATT_LOW GPIO_GPIO (26) /* Low battery */
#define ASSABET_GPIO_RCLK GPIO_GPIO (26) /* CCLK/2 */
#endif
@@ -0,0 +1,113 @@
/*
* FILE bitfield.h
*
* Version 1.1
* Author Copyright (c) Marc A. Viredaz, 1998
* DEC Western Research Laboratory, Palo Alto, CA
* Date April 1998 (April 1997)
* System Advanced RISC Machine (ARM)
* Language C or ARM Assembly
* Purpose Definition of macros to operate on bit fields.
*/
#ifndef __BITFIELD_H
#define __BITFIELD_H
#ifndef __ASSEMBLY__
#define UData(Data) ((unsigned long) (Data))
#else
#define UData(Data) (Data)
#endif
/*
* MACRO: Fld
*
* Purpose
* The macro "Fld" encodes a bit field, given its size and its shift value
* with respect to bit 0.
*
* Note
* A more intuitive way to encode bit fields would have been to use their
* mask. However, extracting size and shift value information from a bit
* field's mask is cumbersome and might break the assembler (255-character
* line-size limit).
*
* Input
* Size Size of the bit field, in number of bits.
* Shft Shift value of the bit field with respect to bit 0.
*
* Output
* Fld Encoded bit field.
*/
#define Fld(Size, Shft) (((Size) << 16) + (Shft))
/*
* MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit
*
* Purpose
* The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return
* the size, shift value, mask, aligned mask, and first bit of a
* bit field.
*
* Input
* Field Encoded bit field (using the macro "Fld").
*
* Output
* FSize Size of the bit field, in number of bits.
* FShft Shift value of the bit field with respect to bit 0.
* FMsk Mask for the bit field.
* FAlnMsk Mask for the bit field, aligned on bit 0.
* F1stBit First bit of the bit field.
*/
#define FSize(Field) ((Field) >> 16)
#define FShft(Field) ((Field) & 0x0000FFFF)
#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
#define F1stBit(Field) (UData (1) << FShft (Field))
/*
* MACRO: FInsrt
*
* Purpose
* The macro "FInsrt" inserts a value into a bit field by shifting the
* former appropriately.
*
* Input
* Value Bit-field value.
* Field Encoded bit field (using the macro "Fld").
*
* Output
* FInsrt Bit-field value positioned appropriately.
*/
#define FInsrt(Value, Field) \
(UData (Value) << FShft (Field))
/*
* MACRO: FExtr
*
* Purpose
* The macro "FExtr" extracts the value of a bit field by masking and
* shifting it appropriately.
*
* Input
* Data Data containing the bit-field to be extracted.
* Field Encoded bit field (using the macro "Fld").
*
* Output
* FExtr Bit-field value.
*/
#define FExtr(Data, Field) \
((UData (Data) >> FShft (Field)) & FAlnMsk (Field))
#endif /* __BITFIELD_H */
@@ -0,0 +1,94 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/collie.h
*
* This file contains the hardware specific definitions for Collie
* Only include this file from SA1100-specific files.
*
* ChangeLog:
* 04-06-2001 Lineo Japan, Inc.
* 04-16-2001 SHARP Corporation
* 07-07-2002 Chris Larson <clarson@digi.com>
*
*/
#ifndef __ASM_ARCH_COLLIE_H
#define __ASM_ARCH_COLLIE_H
#include "hardware.h" /* Gives GPIO_MAX */
#define COLLIE_SCOOP_GPIO_BASE (GPIO_MAX + 1)
#define COLLIE_GPIO_CHARGE_ON (COLLIE_SCOOP_GPIO_BASE + 0)
#define COLLIE_SCP_DIAG_BOOT1 SCOOP_GPCR_PA12
#define COLLIE_SCP_DIAG_BOOT2 SCOOP_GPCR_PA13
#define COLLIE_SCP_MUTE_L SCOOP_GPCR_PA14
#define COLLIE_SCP_MUTE_R SCOOP_GPCR_PA15
#define COLLIE_SCP_5VON SCOOP_GPCR_PA16
#define COLLIE_SCP_AMP_ON SCOOP_GPCR_PA17
#define COLLIE_GPIO_VPEN (COLLIE_SCOOP_GPIO_BASE + 7)
#define COLLIE_SCP_LB_VOL_CHG SCOOP_GPCR_PA19
#define COLLIE_SCOOP_IO_DIR (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \
COLLIE_SCP_LB_VOL_CHG)
#define COLLIE_SCOOP_IO_OUT (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R)
/* GPIOs for gpiolib */
#define COLLIE_GPIO_ON_KEY (0)
#define COLLIE_GPIO_AC_IN (1)
#define COLLIE_GPIO_SDIO_INT (11)
#define COLLIE_GPIO_CF_IRQ (14)
#define COLLIE_GPIO_nREMOCON_INT (15)
#define COLLIE_GPIO_UCB1x00_RESET (16)
#define COLLIE_GPIO_nMIC_ON (17)
#define COLLIE_GPIO_nREMOCON_ON (18)
#define COLLIE_GPIO_CO (20)
#define COLLIE_GPIO_MCP_CLK (21)
#define COLLIE_GPIO_CF_CD (22)
#define COLLIE_GPIO_UCB1x00_IRQ (23)
#define COLLIE_GPIO_WAKEUP (24)
#define COLLIE_GPIO_GA_INT (25)
#define COLLIE_GPIO_MAIN_BAT_LOW (26)
/* GPIO definitions for direct register access */
#define _COLLIE_GPIO_ON_KEY GPIO_GPIO(0)
#define _COLLIE_GPIO_AC_IN GPIO_GPIO(1)
#define _COLLIE_GPIO_nREMOCON_INT GPIO_GPIO(15)
#define _COLLIE_GPIO_UCB1x00_RESET GPIO_GPIO(16)
#define _COLLIE_GPIO_nMIC_ON GPIO_GPIO(17)
#define _COLLIE_GPIO_nREMOCON_ON GPIO_GPIO(18)
#define _COLLIE_GPIO_CO GPIO_GPIO(20)
#define _COLLIE_GPIO_WAKEUP GPIO_GPIO(24)
/* Interrupts */
#define COLLIE_IRQ_GPIO_ON_KEY IRQ_GPIO0
#define COLLIE_IRQ_GPIO_AC_IN IRQ_GPIO1
#define COLLIE_IRQ_GPIO_SDIO_IRQ IRQ_GPIO11
#define COLLIE_IRQ_GPIO_CF_IRQ IRQ_GPIO14
#define COLLIE_IRQ_GPIO_nREMOCON_INT IRQ_GPIO15
#define COLLIE_IRQ_GPIO_CO IRQ_GPIO20
#define COLLIE_IRQ_GPIO_CF_CD IRQ_GPIO22
#define COLLIE_IRQ_GPIO_UCB1x00_IRQ IRQ_GPIO23
#define COLLIE_IRQ_GPIO_WAKEUP IRQ_GPIO24
#define COLLIE_IRQ_GPIO_GA_INT IRQ_GPIO25
#define COLLIE_IRQ_GPIO_MAIN_BAT_LOW IRQ_GPIO26
/* GPIO's on the TC35143AF (Toshiba Analog Frontend) */
#define COLLIE_TC35143_GPIO_BASE (GPIO_MAX + 13)
#define COLLIE_TC35143_GPIO_VERSION0 UCB_IO_0
#define COLLIE_TC35143_GPIO_TBL_CHK UCB_IO_1
#define COLLIE_TC35143_GPIO_VPEN_ON UCB_IO_2
#define COLLIE_GPIO_IR_ON (COLLIE_TC35143_GPIO_BASE + 3)
#define COLLIE_TC35143_GPIO_AMP_ON UCB_IO_4
#define COLLIE_TC35143_GPIO_VERSION1 UCB_IO_5
#define COLLIE_TC35143_GPIO_FS8KLPF UCB_IO_5
#define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6
#define COLLIE_GPIO_MBAT_ON (COLLIE_TC35143_GPIO_BASE + 7)
#define COLLIE_GPIO_BBAT_ON (COLLIE_TC35143_GPIO_BASE + 8)
#define COLLIE_GPIO_TMP_ON (COLLIE_TC35143_GPIO_BASE + 9)
#define COLLIE_TC35143_GPIO_IN (UCB_IO_0 | UCB_IO_2 | UCB_IO_5)
#define COLLIE_TC35143_GPIO_OUT (UCB_IO_1 | UCB_IO_3 | UCB_IO_4 \
| UCB_IO_6)
#endif
@@ -0,0 +1 @@
#include "../../generic.h"
@@ -0,0 +1,81 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Definitions for Compaq iPAQ H3100 and H3600 handheld computers
*
* (c) 2000 Compaq Computer Corporation. (Author: Jamey Hicks)
* (c) 2009 Dmitry Artamonow <mad_soft@inbox.ru>
*/
#ifndef _INCLUDE_H3XXX_H_
#define _INCLUDE_H3XXX_H_
#include "hardware.h" /* Gives GPIO_MAX */
/* Physical memory regions corresponding to chip selects */
#define H3600_EGPIO_PHYS (SA1100_CS5_PHYS + 0x01000000)
#define H3600_BANK_2_PHYS SA1100_CS2_PHYS
#define H3600_BANK_4_PHYS SA1100_CS4_PHYS
/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
#define H3600_EGPIO_VIRT 0xf0000000
#define H3600_BANK_2_VIRT 0xf1000000
#define H3600_BANK_4_VIRT 0xf3800000
/*
* gpiolib numbers for all iPAQs
*/
#define H3XXX_GPIO_PWR_BUTTON 0
#define H3XXX_GPIO_PCMCIA_CD1 10
#define H3XXX_GPIO_PCMCIA_IRQ1 11
#define H3XXX_GPIO_PCMCIA_CD0 17
#define H3XXX_GPIO_ACTION_BUTTON 18
#define H3XXX_GPIO_SYS_CLK 19
#define H3XXX_GPIO_PCMCIA_IRQ0 21
#define H3XXX_GPIO_COM_DCD 23
#define H3XXX_GPIO_OPTION 24
#define H3XXX_GPIO_COM_CTS 25
#define H3XXX_GPIO_COM_RTS 26
/* machine-specific gpios */
#define H3100_GPIO_BT_ON 2
#define H3100_GPIO_QMUTE 4
#define H3100_GPIO_LCD_3V_ON 5
#define H3100_GPIO_AUD_ON 6
#define H3100_GPIO_AUD_PWR_ON 7
#define H3100_GPIO_IR_ON 8
#define H3100_GPIO_IR_FSEL 9
#define H3600_GPIO_CLK_SET0 12 /* audio sample rate clock generator */
#define H3600_GPIO_CLK_SET1 13
#define H3600_GPIO_SOFT_RESET 20 /* also known as BATT_FAULT */
#define H3600_GPIO_OPT_LOCK 22
#define H3600_GPIO_OPT_DET 27
/* H3100 / 3600 EGPIO pins */
#define H3XXX_EGPIO_BASE (GPIO_MAX + 1)
#define H3XXX_EGPIO_VPP_ON (H3XXX_EGPIO_BASE + 0)
#define H3XXX_EGPIO_CARD_RESET (H3XXX_EGPIO_BASE + 1) /* reset the attached pcmcia/compactflash card. active high. */
#define H3XXX_EGPIO_OPT_RESET (H3XXX_EGPIO_BASE + 2) /* reset the attached option pack. active high. */
#define H3XXX_EGPIO_CODEC_NRESET (H3XXX_EGPIO_BASE + 3) /* reset the onboard UDA1341. active low. */
#define H3XXX_EGPIO_OPT_NVRAM_ON (H3XXX_EGPIO_BASE + 4) /* apply power to optionpack nvram, active high. */
#define H3XXX_EGPIO_OPT_ON (H3XXX_EGPIO_BASE + 5) /* full power to option pack. active high. */
#define H3XXX_EGPIO_LCD_ON (H3XXX_EGPIO_BASE + 6) /* enable 3.3V to LCD. active high. */
#define H3XXX_EGPIO_RS232_ON (H3XXX_EGPIO_BASE + 7) /* UART3 transceiver force on. Active high. */
/* H3600 only EGPIO pins */
#define H3600_EGPIO_LCD_PCI (H3XXX_EGPIO_BASE + 8) /* LCD control IC enable. active high. */
#define H3600_EGPIO_IR_ON (H3XXX_EGPIO_BASE + 9) /* apply power to IR module. active high. */
#define H3600_EGPIO_AUD_AMP_ON (H3XXX_EGPIO_BASE + 10) /* apply power to audio power amp. active high. */
#define H3600_EGPIO_AUD_PWR_ON (H3XXX_EGPIO_BASE + 11) /* apply power to reset of audio circuit. active high. */
#define H3600_EGPIO_QMUTE (H3XXX_EGPIO_BASE + 12) /* mute control for onboard UDA1341. active high. */
#define H3600_EGPIO_IR_FSEL (H3XXX_EGPIO_BASE + 13) /* IR speed select: 1->fast, 0->slow */
#define H3600_EGPIO_LCD_5V_ON (H3XXX_EGPIO_BASE + 14) /* enable 5V to LCD. active high. */
#define H3600_EGPIO_LVDD_ON (H3XXX_EGPIO_BASE + 15) /* enable 9V and -6.5V to LCD. */
void __init h3xxx_map_io(void);
void __init h3xxx_mach_init(void);
#endif /* _INCLUDE_H3XXX_H_ */
@@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/hardware.h
*
* Copyright (C) 1998 Nicolas Pitre <nico@fluxnic.net>
*
* This file contains the hardware definitions for SA1100 architecture
*
* 2000/05/23 John Dorsey <john+@cs.cmu.edu>
* Definitions for SA1111 added.
*/
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
#define UNCACHEABLE_ADDR 0xfa050000 /* ICIP */
/*
* SA1100 internal I/O mappings
*
* We have the following mapping:
* phys virt
* 80000000 f8000000
* 90000000 fa000000
* a0000000 fc000000
* b0000000 fe000000
*/
#define VIO_BASE 0xf8000000 /* virtual start of IO space */
#define VIO_SHIFT 3 /* x = IO space shrink power */
#define PIO_START 0x80000000 /* physical start of IO space */
#define io_p2v( x ) \
IOMEM( (((x)&0x00ffffff) | (((x)&0x30000000)>>VIO_SHIFT)) + VIO_BASE )
#define io_v2p( x ) \
( (((x)&0x00ffffff) | (((x)&(0x30000000>>VIO_SHIFT))<<VIO_SHIFT)) + PIO_START )
#define __MREG(x) IOMEM(io_p2v(x))
#ifndef __ASSEMBLY__
# define __REG(x) (*((volatile unsigned long __iomem *)io_p2v(x)))
# define __PREG(x) (io_v2p((unsigned long)&(x)))
#else
# define __REG(x) io_p2v(x)
# define __PREG(x) io_v2p(x)
#endif
#include "SA-1100.h"
#endif /* _ASM_ARCH_HARDWARE_H */
@@ -0,0 +1,101 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/irqs.h
*
* Copyright (C) 1996 Russell King
* Copyright (C) 1998 Deborah Wallach (updates for SA1100/Brutus).
* Copyright (C) 1999 Nicolas Pitre (full GPIO irq isolation)
*
* 2001/11/14 RMK Cleaned up and standardised a lot of the IRQs.
*/
#define IRQ_GPIO0_SC 1
#define IRQ_GPIO1_SC 2
#define IRQ_GPIO2_SC 3
#define IRQ_GPIO3_SC 4
#define IRQ_GPIO4_SC 5
#define IRQ_GPIO5_SC 6
#define IRQ_GPIO6_SC 7
#define IRQ_GPIO7_SC 8
#define IRQ_GPIO8_SC 9
#define IRQ_GPIO9_SC 10
#define IRQ_GPIO10_SC 11
#define IRQ_GPIO11_27 12
#define IRQ_LCD 13 /* LCD controller */
#define IRQ_Ser0UDC 14 /* Ser. port 0 UDC */
#define IRQ_Ser1SDLC 15 /* Ser. port 1 SDLC */
#define IRQ_Ser1UART 16 /* Ser. port 1 UART */
#define IRQ_Ser2ICP 17 /* Ser. port 2 ICP */
#define IRQ_Ser3UART 18 /* Ser. port 3 UART */
#define IRQ_Ser4MCP 19 /* Ser. port 4 MCP */
#define IRQ_Ser4SSP 20 /* Ser. port 4 SSP */
#define IRQ_DMA0 21 /* DMA controller channel 0 */
#define IRQ_DMA1 22 /* DMA controller channel 1 */
#define IRQ_DMA2 23 /* DMA controller channel 2 */
#define IRQ_DMA3 24 /* DMA controller channel 3 */
#define IRQ_DMA4 25 /* DMA controller channel 4 */
#define IRQ_DMA5 26 /* DMA controller channel 5 */
#define IRQ_OST0 27 /* OS Timer match 0 */
#define IRQ_OST1 28 /* OS Timer match 1 */
#define IRQ_OST2 29 /* OS Timer match 2 */
#define IRQ_OST3 30 /* OS Timer match 3 */
#define IRQ_RTC1Hz 31 /* RTC 1 Hz clock */
#define IRQ_RTCAlrm 32 /* RTC Alarm */
#define IRQ_GPIO0 33
#define IRQ_GPIO1 34
#define IRQ_GPIO2 35
#define IRQ_GPIO3 36
#define IRQ_GPIO4 37
#define IRQ_GPIO5 38
#define IRQ_GPIO6 39
#define IRQ_GPIO7 40
#define IRQ_GPIO8 41
#define IRQ_GPIO9 42
#define IRQ_GPIO10 43
#define IRQ_GPIO11 44
#define IRQ_GPIO12 45
#define IRQ_GPIO13 46
#define IRQ_GPIO14 47
#define IRQ_GPIO15 48
#define IRQ_GPIO16 49
#define IRQ_GPIO17 50
#define IRQ_GPIO18 51
#define IRQ_GPIO19 52
#define IRQ_GPIO20 53
#define IRQ_GPIO21 54
#define IRQ_GPIO22 55
#define IRQ_GPIO23 56
#define IRQ_GPIO24 57
#define IRQ_GPIO25 58
#define IRQ_GPIO26 59
#define IRQ_GPIO27 60
/*
* The next 16 interrupts are for board specific purposes. Since
* the kernel can only run on one machine at a time, we can re-use
* these. If you need more, increase IRQ_BOARD_END, but keep it
* within sensible limits. IRQs 61 to 76 are available.
*/
#define IRQ_BOARD_START 61
#define IRQ_BOARD_END 77
/*
* Figure out the MAX IRQ number.
*
* Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
* allocate their IRQs above NR_IRQS.
*
* LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
* to be included in the NR_IRQS calculation.
*/
#ifdef CONFIG_SHARP_LOCOMO
#define NR_IRQS_LOCOMO 4
#else
#define NR_IRQS_LOCOMO 0
#endif
#ifndef NR_IRQS
#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
#endif
#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* arch/arm/mach-sa1100/include/mach/jornada720.h
*
* SSP/MCU communication definitions for HP Jornada 710/720/728
*
* Copyright 2007,2008 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
* Copyright 2000 John Ankcorn <jca@lcs.mit.edu>
*/
/* HP Jornada 7xx microprocessor commands */
#define GETBATTERYDATA 0xc0
#define GETSCANKEYCODE 0x90
#define GETTOUCHSAMPLES 0xa0
#define GETCONTRAST 0xD0
#define SETCONTRAST 0xD1
#define GETBRIGHTNESS 0xD2
#define SETBRIGHTNESS 0xD3
#define CONTRASTOFF 0xD8
#define BRIGHTNESSOFF 0xD9
#define PWMOFF 0xDF
#define TXDUMMY 0x11
#define ERRORCODE 0x00
extern void jornada_ssp_start(void);
extern void jornada_ssp_end(void);
extern int jornada_ssp_inout(u8 byte);
extern int jornada_ssp_byte(u8 byte);
@@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/memory.h
*
* Copyright (C) 1999-2000 Nicolas Pitre <nico@fluxnic.net>
*/
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
#include <linux/sizes.h>
/*
* Because of the wide memory address space between physical RAM banks on the
* SA1100, it's much convenient to use Linux's SparseMEM support to implement
* our memory map representation. Assuming all memory nodes have equal access
* characteristics, we then have generic discontiguous memory support.
*
* The sparsemem banks are matched with the physical memory bank addresses
* which are incidentally the same as virtual addresses.
*
* node 0: 0xc0000000 - 0xc7ffffff
* node 1: 0xc8000000 - 0xcfffffff
* node 2: 0xd0000000 - 0xd7ffffff
* node 3: 0xd8000000 - 0xdfffffff
*/
#define MAX_PHYSMEM_BITS 32
#define SECTION_SIZE_BITS 27
/*
* Cache flushing area - SA1100 zero bank
*/
#define FLUSH_BASE_PHYS 0xe0000000
#define FLUSH_BASE 0xf5000000
#define FLUSH_BASE_MINICACHE 0xf5100000
#endif
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* MTD primitives for XIP support. Architecture specific functions
*
* Do not include this file directly. It's included from linux/mtd/xip.h
*
* Author: Nicolas Pitre
* Created: Nov 2, 2004
* Copyright: (C) 2004 MontaVista Software, Inc.
*/
#ifndef __ARCH_SA1100_MTD_XIP_H__
#define __ARCH_SA1100_MTD_XIP_H__
#include <mach/hardware.h>
#define xip_irqpending() (ICIP & ICMR)
/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
#define xip_currtime() readl_relaxed(OSCR)
#define xip_elapsed_since(x) (signed)((readl_relaxed(OSCR) - (x)) / 4)
#endif /* __ARCH_SA1100_MTD_XIP_H__ */
@@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/neponset.h
*
* Created 2000/06/05 by Nicolas Pitre <nico@fluxnic.net>
*
* This file contains the hardware specific definitions for Assabet
* Only include this file from SA1100-specific files.
*
* 2000/05/23 John Dorsey <john+@cs.cmu.edu>
* Definitions for Neponset added.
*/
#ifndef __ASM_ARCH_NEPONSET_H
#define __ASM_ARCH_NEPONSET_H
/*
* Neponset definitions:
*/
#define NCR_GP01_OFF (1<<0)
#define NCR_TP_PWR_EN (1<<1)
#define NCR_MS_PWR_EN (1<<2)
#define NCR_ENET_OSC_EN (1<<3)
#define NCR_SPI_KB_WK_UP (1<<4)
#define NCR_A0VPP (1<<5)
#define NCR_A1VPP (1<<6)
void neponset_ncr_frob(unsigned int, unsigned int);
#define neponset_ncr_set(v) neponset_ncr_frob(0, v)
#define neponset_ncr_clear(v) neponset_ncr_frob(v, 0)
#endif
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_ARCH_RESET_H
#define __ASM_ARCH_RESET_H
#include "hardware.h"
#define RESET_STATUS_HARDWARE (1 << 0) /* Hardware Reset */
#define RESET_STATUS_WATCHDOG (1 << 1) /* Watchdog Reset */
#define RESET_STATUS_LOWPOWER (1 << 2) /* Exit from Low Power/Sleep */
#define RESET_STATUS_GPIO (1 << 3) /* GPIO Reset */
#define RESET_STATUS_ALL (0xf)
static inline void clear_reset_status(unsigned int mask)
{
RCSR = mask;
}
#endif /* __ASM_ARCH_RESET_H */
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arch/arm/mach-sa1100/include/mach/uncompress.h
*
* (C) 1999 Nicolas Pitre <nico@fluxnic.net>
*
* Reorganised to be machine independent.
*/
#include "hardware.h"
#define IOMEM(x) (x)
/*
* The following code assumes the serial port has already been
* initialized by the bootloader. We search for the first enabled
* port in the most probable order. If you didn't setup a port in
* your bootloader then nothing will appear (which might be desired).
*/
#define UART(x) (*(volatile unsigned long *)(serial_port + (x)))
static inline void putc(int c)
{
unsigned long serial_port;
do {
serial_port = _Ser3UTCR0;
if (UART(UTCR3) & UTCR3_TXE) break;
serial_port = _Ser1UTCR0;
if (UART(UTCR3) & UTCR3_TXE) break;
serial_port = _Ser2UTCR0;
if (UART(UTCR3) & UTCR3_TXE) break;
return;
} while (0);
/* wait for space in the UART's transmitter */
while (!(UART(UTSR1) & UTSR1_TNF))
barrier();
/* send the character out. */
UART(UTDR) = c;
}
static inline void flush(void)
{
}
/*
* Nothing to do for these
*/
#define arch_decomp_setup()
@@ -0,0 +1,380 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/jornada720.c
*
* HP Jornada720 init code
*
* Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
* Copyright (C) 2005 Michael Gernoth <michael@gernoth.net>
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/gpio/machine.h>
#include <linux/platform_data/sa11x0-serial.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <video/s1d13xxxfb.h>
#include <asm/hardware/sa1111.h>
#include <asm/page.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include "generic.h"
/*
* HP Documentation referred in this file:
* http://www.jlime.com/downloads/development/docs/jornada7xx/jornada720.txt
*/
/* line 110 of HP's doc */
#define TUCR_VAL 0x20000400
/* memory space (line 52 of HP's doc) */
#define SA1111REGSTART 0x40000000
#define SA1111REGLEN 0x00002000
#define EPSONREGSTART 0x48000000
#define EPSONREGLEN 0x00100000
#define EPSONFBSTART 0x48200000
/* 512kB framebuffer */
#define EPSONFBLEN 512*1024
static struct s1d13xxxfb_regval s1d13xxxfb_initregs[] = {
/* line 344 of HP's doc */
{0x0001,0x00}, // Miscellaneous Register
{0x01FC,0x00}, // Display Mode Register
{0x0004,0x00}, // General IO Pins Configuration Register 0
{0x0005,0x00}, // General IO Pins Configuration Register 1
{0x0008,0x00}, // General IO Pins Control Register 0
{0x0009,0x00}, // General IO Pins Control Register 1
{0x0010,0x01}, // Memory Clock Configuration Register
{0x0014,0x11}, // LCD Pixel Clock Configuration Register
{0x0018,0x01}, // CRT/TV Pixel Clock Configuration Register
{0x001C,0x01}, // MediaPlug Clock Configuration Register
{0x001E,0x01}, // CPU To Memory Wait State Select Register
{0x0020,0x00}, // Memory Configuration Register
{0x0021,0x45}, // DRAM Refresh Rate Register
{0x002A,0x01}, // DRAM Timings Control Register 0
{0x002B,0x03}, // DRAM Timings Control Register 1
{0x0030,0x1c}, // Panel Type Register
{0x0031,0x00}, // MOD Rate Register
{0x0032,0x4F}, // LCD Horizontal Display Width Register
{0x0034,0x07}, // LCD Horizontal Non-Display Period Register
{0x0035,0x01}, // TFT FPLINE Start Position Register
{0x0036,0x0B}, // TFT FPLINE Pulse Width Register
{0x0038,0xEF}, // LCD Vertical Display Height Register 0
{0x0039,0x00}, // LCD Vertical Display Height Register 1
{0x003A,0x13}, // LCD Vertical Non-Display Period Register
{0x003B,0x0B}, // TFT FPFRAME Start Position Register
{0x003C,0x01}, // TFT FPFRAME Pulse Width Register
{0x0040,0x05}, // LCD Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
{0x0041,0x00}, // LCD Miscellaneous Register
{0x0042,0x00}, // LCD Display Start Address Register 0
{0x0043,0x00}, // LCD Display Start Address Register 1
{0x0044,0x00}, // LCD Display Start Address Register 2
{0x0046,0x80}, // LCD Memory Address Offset Register 0
{0x0047,0x02}, // LCD Memory Address Offset Register 1
{0x0048,0x00}, // LCD Pixel Panning Register
{0x004A,0x00}, // LCD Display FIFO High Threshold Control Register
{0x004B,0x00}, // LCD Display FIFO Low Threshold Control Register
{0x0050,0x4F}, // CRT/TV Horizontal Display Width Register
{0x0052,0x13}, // CRT/TV Horizontal Non-Display Period Register
{0x0053,0x01}, // CRT/TV HRTC Start Position Register
{0x0054,0x0B}, // CRT/TV HRTC Pulse Width Register
{0x0056,0xDF}, // CRT/TV Vertical Display Height Register 0
{0x0057,0x01}, // CRT/TV Vertical Display Height Register 1
{0x0058,0x2B}, // CRT/TV Vertical Non-Display Period Register
{0x0059,0x09}, // CRT/TV VRTC Start Position Register
{0x005A,0x01}, // CRT/TV VRTC Pulse Width Register
{0x005B,0x10}, // TV Output Control Register
{0x0060,0x03}, // CRT/TV Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
{0x0062,0x00}, // CRT/TV Display Start Address Register 0
{0x0063,0x00}, // CRT/TV Display Start Address Register 1
{0x0064,0x00}, // CRT/TV Display Start Address Register 2
{0x0066,0x40}, // CRT/TV Memory Address Offset Register 0
{0x0067,0x01}, // CRT/TV Memory Address Offset Register 1
{0x0068,0x00}, // CRT/TV Pixel Panning Register
{0x006A,0x00}, // CRT/TV Display FIFO High Threshold Control Register
{0x006B,0x00}, // CRT/TV Display FIFO Low Threshold Control Register
{0x0070,0x00}, // LCD Ink/Cursor Control Register
{0x0071,0x01}, // LCD Ink/Cursor Start Address Register
{0x0072,0x00}, // LCD Cursor X Position Register 0
{0x0073,0x00}, // LCD Cursor X Position Register 1
{0x0074,0x00}, // LCD Cursor Y Position Register 0
{0x0075,0x00}, // LCD Cursor Y Position Register 1
{0x0076,0x00}, // LCD Ink/Cursor Blue Color 0 Register
{0x0077,0x00}, // LCD Ink/Cursor Green Color 0 Register
{0x0078,0x00}, // LCD Ink/Cursor Red Color 0 Register
{0x007A,0x1F}, // LCD Ink/Cursor Blue Color 1 Register
{0x007B,0x3F}, // LCD Ink/Cursor Green Color 1 Register
{0x007C,0x1F}, // LCD Ink/Cursor Red Color 1 Register
{0x007E,0x00}, // LCD Ink/Cursor FIFO Threshold Register
{0x0080,0x00}, // CRT/TV Ink/Cursor Control Register
{0x0081,0x01}, // CRT/TV Ink/Cursor Start Address Register
{0x0082,0x00}, // CRT/TV Cursor X Position Register 0
{0x0083,0x00}, // CRT/TV Cursor X Position Register 1
{0x0084,0x00}, // CRT/TV Cursor Y Position Register 0
{0x0085,0x00}, // CRT/TV Cursor Y Position Register 1
{0x0086,0x00}, // CRT/TV Ink/Cursor Blue Color 0 Register
{0x0087,0x00}, // CRT/TV Ink/Cursor Green Color 0 Register
{0x0088,0x00}, // CRT/TV Ink/Cursor Red Color 0 Register
{0x008A,0x1F}, // CRT/TV Ink/Cursor Blue Color 1 Register
{0x008B,0x3F}, // CRT/TV Ink/Cursor Green Color 1 Register
{0x008C,0x1F}, // CRT/TV Ink/Cursor Red Color 1 Register
{0x008E,0x00}, // CRT/TV Ink/Cursor FIFO Threshold Register
{0x0100,0x00}, // BitBlt Control Register 0
{0x0101,0x00}, // BitBlt Control Register 1
{0x0102,0x00}, // BitBlt ROP Code/Color Expansion Register
{0x0103,0x00}, // BitBlt Operation Register
{0x0104,0x00}, // BitBlt Source Start Address Register 0
{0x0105,0x00}, // BitBlt Source Start Address Register 1
{0x0106,0x00}, // BitBlt Source Start Address Register 2
{0x0108,0x00}, // BitBlt Destination Start Address Register 0
{0x0109,0x00}, // BitBlt Destination Start Address Register 1
{0x010A,0x00}, // BitBlt Destination Start Address Register 2
{0x010C,0x00}, // BitBlt Memory Address Offset Register 0
{0x010D,0x00}, // BitBlt Memory Address Offset Register 1
{0x0110,0x00}, // BitBlt Width Register 0
{0x0111,0x00}, // BitBlt Width Register 1
{0x0112,0x00}, // BitBlt Height Register 0
{0x0113,0x00}, // BitBlt Height Register 1
{0x0114,0x00}, // BitBlt Background Color Register 0
{0x0115,0x00}, // BitBlt Background Color Register 1
{0x0118,0x00}, // BitBlt Foreground Color Register 0
{0x0119,0x00}, // BitBlt Foreground Color Register 1
{0x01E0,0x00}, // Look-Up Table Mode Register
{0x01E2,0x00}, // Look-Up Table Address Register
/* not sure, wouldn't like to mess with the driver */
{0x01E4,0x00}, // Look-Up Table Data Register
/* jornada doc says 0x00, but I trust the driver */
{0x01F0,0x10}, // Power Save Configuration Register
{0x01F1,0x00}, // Power Save Status Register
{0x01F4,0x00}, // CPU-to-Memory Access Watchdog Timer Register
{0x01FC,0x01}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
};
static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
.initregs = s1d13xxxfb_initregs,
.initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
.platform_init_video = NULL
};
static struct resource s1d13xxxfb_resources[] = {
[0] = DEFINE_RES_MEM(EPSONFBSTART, EPSONFBLEN),
[1] = DEFINE_RES_MEM(EPSONREGSTART, EPSONREGLEN),
};
static struct platform_device s1d13xxxfb_device = {
.name = S1D_DEVICENAME,
.id = 0,
.dev = {
.platform_data = &s1d13xxxfb_data,
},
.num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
.resource = s1d13xxxfb_resources,
};
static struct gpiod_lookup_table jornada_pcmcia_gpiod_table = {
.dev_id = "1800",
.table = {
GPIO_LOOKUP("sa1111", 0, "s0-power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 1, "s1-power", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 2, "s0-3v", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 3, "s1-3v", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct resource sa1111_resources[] = {
[0] = DEFINE_RES_MEM(SA1111REGSTART, SA1111REGLEN),
[1] = DEFINE_RES_IRQ(IRQ_GPIO1),
};
static struct sa1111_platform_data sa1111_info = {
.disable_devs = SA1111_DEVID_PS2_MSE,
};
static u64 sa1111_dmamask = 0xffffffffUL;
static struct platform_device sa1111_device = {
.name = "sa1111",
.id = 0,
.dev = {
.dma_mask = &sa1111_dmamask,
.coherent_dma_mask = 0xffffffff,
.platform_data = &sa1111_info,
},
.num_resources = ARRAY_SIZE(sa1111_resources),
.resource = sa1111_resources,
};
static struct platform_device jornada_ssp_device = {
.name = "jornada_ssp",
.id = -1,
};
static struct resource jornada_kbd_resources[] = {
DEFINE_RES_IRQ(IRQ_GPIO0),
};
static struct platform_device jornada_kbd_device = {
.name = "jornada720_kbd",
.id = -1,
.num_resources = ARRAY_SIZE(jornada_kbd_resources),
.resource = jornada_kbd_resources,
};
static struct gpiod_lookup_table jornada_ts_gpiod_table = {
.dev_id = "jornada_ts",
.table = {
GPIO_LOOKUP("gpio", 9, "penup", GPIO_ACTIVE_HIGH),
},
};
static struct platform_device jornada_ts_device = {
.name = "jornada_ts",
.id = -1,
};
static struct platform_device *devices[] __initdata = {
&sa1111_device,
&jornada_ssp_device,
&s1d13xxxfb_device,
&jornada_kbd_device,
&jornada_ts_device,
};
static int __init jornada720_init(void)
{
int ret = -ENODEV;
if (machine_is_jornada720()) {
/* we want to use gpio20 as input to drive the clock of our uart 3 */
GPDR |= GPIO_GPIO20; /* Clear gpio20 pin as input */
TUCR = TUCR_VAL;
GPSR = GPIO_GPIO20; /* start gpio20 pin */
udelay(1);
GPCR = GPIO_GPIO20; /* stop gpio20 */
udelay(1);
GPSR = GPIO_GPIO20; /* restart gpio20 */
udelay(20); /* give it some time to restart */
gpiod_add_lookup_table(&jornada_ts_gpiod_table);
gpiod_add_lookup_table(&jornada_pcmcia_gpiod_table);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
return ret;
}
arch_initcall(jornada720_init);
static struct map_desc jornada720_io_desc[] __initdata = {
{ /* Epson registers */
.virtual = 0xf0000000,
.pfn = __phys_to_pfn(EPSONREGSTART),
.length = EPSONREGLEN,
.type = MT_DEVICE
}, { /* Epson frame buffer */
.virtual = 0xf1000000,
.pfn = __phys_to_pfn(EPSONFBSTART),
.length = EPSONFBLEN,
.type = MT_DEVICE
}
};
static void __init jornada720_map_io(void)
{
sa1100_map_io();
iotable_init(jornada720_io_desc, ARRAY_SIZE(jornada720_io_desc));
sa1100_register_uart(0, 3);
sa1100_register_uart(1, 1);
}
static struct mtd_partition jornada720_partitions[] = {
{
.name = "JORNADA720 boot firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
.name = "JORNADA720 kernel",
.size = 0x000c0000,
.offset = 0x00040000,
}, {
.name = "JORNADA720 params",
.size = 0x00040000,
.offset = 0x00100000,
}, {
.name = "JORNADA720 initrd",
.size = 0x00100000,
.offset = 0x00140000,
}, {
.name = "JORNADA720 root cramfs",
.size = 0x00300000,
.offset = 0x00240000,
}, {
.name = "JORNADA720 usr cramfs",
.size = 0x00800000,
.offset = 0x00540000,
}, {
.name = "JORNADA720 usr local",
.size = 0, /* will expand to the end of the flash */
.offset = 0x00d00000,
}
};
static void jornada720_set_vpp(int vpp)
{
if (vpp)
/* enabling flash write (line 470 of HP's doc) */
PPSR |= PPC_LDD7;
else
/* disabling flash write (line 470 of HP's doc) */
PPSR &= ~PPC_LDD7;
PPDR |= PPC_LDD7;
}
static struct flash_platform_data jornada720_flash_data = {
.map_name = "cfi_probe",
.set_vpp = jornada720_set_vpp,
.parts = jornada720_partitions,
.nr_parts = ARRAY_SIZE(jornada720_partitions),
};
static struct resource jornada720_flash_resource =
DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
static void __init jornada720_mach_init(void)
{
sa11x0_register_mtd(&jornada720_flash_data, &jornada720_flash_resource, 1);
}
MACHINE_START(JORNADA720, "HP Jornada 720")
/* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
.atag_offset = 0x100,
.map_io = jornada720_map_io,
.nr_irqs = SA1100_NR_IRQS,
.init_irq = sa1100_init_irq,
.init_time = sa1100_timer_init,
.init_machine = jornada720_mach_init,
.init_late = sa11x0_init_late,
#ifdef CONFIG_SA1111
.dma_zone_size = SZ_1M,
#endif
.restart = sa11x0_restart,
MACHINE_END
@@ -0,0 +1,202 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* arch/arm/mac-sa1100/jornada720_ssp.c
*
* Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
* Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
*
* SSP driver for the HP Jornada 710/720/728
*/
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/jornada720.h>
#include <asm/hardware/ssp.h>
static DEFINE_SPINLOCK(jornada_ssp_lock);
static unsigned long jornada_ssp_flags;
/**
* jornada_ssp_reverse - reverses input byte
* @byte: input byte to reverse
*
* we need to reverse all data we receive from the mcu due to its physical location
* returns : 01110111 -> 11101110
*/
inline u8 jornada_ssp_reverse(u8 byte)
{
return
((0x80 & byte) >> 7) |
((0x40 & byte) >> 5) |
((0x20 & byte) >> 3) |
((0x10 & byte) >> 1) |
((0x08 & byte) << 1) |
((0x04 & byte) << 3) |
((0x02 & byte) << 5) |
((0x01 & byte) << 7);
};
EXPORT_SYMBOL(jornada_ssp_reverse);
/**
* jornada_ssp_byte - waits for ready ssp bus and sends byte
* @byte: input byte to transmit
*
* waits for fifo buffer to clear and then transmits, if it doesn't then we will
* timeout after <timeout> rounds. Needs mcu running before its called.
*
* returns : %mcu output on success
* : %-ETIMEDOUT on timeout
*/
int jornada_ssp_byte(u8 byte)
{
int timeout = 400000;
u16 ret;
while ((GPLR & GPIO_GPIO10)) {
if (!--timeout) {
printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
return -ETIMEDOUT;
}
cpu_relax();
}
ret = jornada_ssp_reverse(byte) << 8;
ssp_write_word(ret);
ssp_read_word(&ret);
return jornada_ssp_reverse(ret);
};
EXPORT_SYMBOL(jornada_ssp_byte);
/**
* jornada_ssp_inout - decide if input is command or trading byte
* @byte: input byte to send (may be %TXDUMMY)
*
* returns : (jornada_ssp_byte(byte)) on success
* : %-ETIMEDOUT on timeout failure
*/
int jornada_ssp_inout(u8 byte)
{
int ret, i;
/* true means command byte */
if (byte != TXDUMMY) {
ret = jornada_ssp_byte(byte);
/* Proper return to commands is TxDummy */
if (ret != TXDUMMY) {
for (i = 0; i < 256; i++)/* flushing bus */
if (jornada_ssp_byte(TXDUMMY) == -1)
break;
return -ETIMEDOUT;
}
} else /* Exchange TxDummy for data */
ret = jornada_ssp_byte(TXDUMMY);
return ret;
};
EXPORT_SYMBOL(jornada_ssp_inout);
/**
* jornada_ssp_start - enable mcu
*
*/
void jornada_ssp_start(void)
{
spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
GPCR = GPIO_GPIO25;
udelay(50);
return;
};
EXPORT_SYMBOL(jornada_ssp_start);
/**
* jornada_ssp_end - disable mcu and turn off lock
*
*/
void jornada_ssp_end(void)
{
GPSR = GPIO_GPIO25;
spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
return;
};
EXPORT_SYMBOL(jornada_ssp_end);
static int jornada_ssp_probe(struct platform_device *dev)
{
int ret;
GPSR = GPIO_GPIO25;
ret = ssp_init();
/* worked fine, lets not bother with anything else */
if (!ret) {
printk(KERN_INFO "SSP: device initialized with irq\n");
return ret;
}
printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n");
/* init of Serial 4 port */
Ser4MCCR0 = 0;
Ser4SSCR0 = 0x0387;
Ser4SSCR1 = 0x18;
/* clear out any left over data */
ssp_flush();
/* enable MCU */
jornada_ssp_start();
/* see if return value makes sense */
ret = jornada_ssp_inout(GETBRIGHTNESS);
/* seems like it worked, just feed it with TxDummy to get rid of data */
if (ret == TXDUMMY)
jornada_ssp_inout(TXDUMMY);
jornada_ssp_end();
/* failed, lets just kill everything */
if (ret == -ETIMEDOUT) {
printk(KERN_WARNING "SSP: attempts failed, bailing\n");
ssp_exit();
return -ENODEV;
}
/* all fine */
printk(KERN_INFO "SSP: device initialized\n");
return 0;
};
static void jornada_ssp_remove(struct platform_device *dev)
{
/* Note that this doesn't actually remove the driver, since theres nothing to remove
* It just makes sure everything is turned off */
GPSR = GPIO_GPIO25;
ssp_exit();
};
struct platform_driver jornadassp_driver = {
.probe = jornada_ssp_probe,
.remove = jornada_ssp_remove,
.driver = {
.name = "jornada_ssp",
},
};
static int __init jornada_ssp_init(void)
{
return platform_driver_register(&jornadassp_driver);
}
module_init(jornada_ssp_init);
+438
View File
@@ -0,0 +1,438 @@
// SPDX-License-Identifier: GPL-2.0
/*
* linux/arch/arm/mach-sa1100/neponset.c
*/
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/gpio-reg.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/smc91x.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
#include <asm/hardware/sa1111.h>
#include <linux/sizes.h>
#include <mach/hardware.h>
#include <mach/assabet.h>
#include <mach/neponset.h>
#include <mach/irqs.h>
#define NEP_IRQ_SMC91X 0
#define NEP_IRQ_USAR 1
#define NEP_IRQ_SA1111 2
#define NEP_IRQ_NR 3
#define WHOAMI 0x00
#define LEDS 0x10
#define SWPK 0x20
#define IRR 0x24
#define KP_Y_IN 0x80
#define KP_X_OUT 0x90
#define NCR_0 0xa0
#define MDM_CTL_0 0xb0
#define MDM_CTL_1 0xb4
#define AUD_CTL 0xc0
#define IRR_ETHERNET (1 << 0)
#define IRR_USAR (1 << 1)
#define IRR_SA1111 (1 << 2)
#define NCR_NGPIO 7
#define MDM_CTL0_NGPIO 4
#define MDM_CTL1_NGPIO 6
#define AUD_NGPIO 2
extern void sa1110_mb_disable(void);
#define to_neponset_gpio_chip(x) container_of(x, struct neponset_gpio_chip, gc)
static const char *neponset_ncr_names[] = {
"gp01_off", "tp_power", "ms_power", "enet_osc",
"spi_kb_wk_up", "a0vpp", "a1vpp"
};
static const char *neponset_mdmctl0_names[] = {
"rts3", "dtr3", "rts1", "dtr1",
};
static const char *neponset_mdmctl1_names[] = {
"cts3", "dsr3", "dcd3", "cts1", "dsr1", "dcd1"
};
static const char *neponset_aud_names[] = {
"sel_1341", "mute_1341",
};
struct neponset_drvdata {
void __iomem *base;
struct platform_device *sa1111;
struct platform_device *smc91x;
unsigned irq_base;
struct gpio_chip *gpio[4];
};
static struct gpiod_lookup_table neponset_uart1_gpio_table = {
.dev_id = "sa11x0-uart.1",
.table = {
GPIO_LOOKUP("neponset-mdm-ctl0", 2, "rts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl0", 3, "dtr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 3, "cts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 4, "dsr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 5, "dcd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpiod_lookup_table neponset_uart3_gpio_table = {
.dev_id = "sa11x0-uart.3",
.table = {
GPIO_LOOKUP("neponset-mdm-ctl0", 0, "rts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl0", 1, "dtr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 0, "cts", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 1, "dsr", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("neponset-mdm-ctl1", 2, "dcd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpiod_lookup_table neponset_pcmcia_table = {
.dev_id = "1800",
.table = {
GPIO_LOOKUP("sa1111", 1, "a0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 0, "a1vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("neponset-ncr", 5, "a0vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("neponset-ncr", 6, "a1vpp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 2, "b0vcc", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("sa1111", 3, "b1vcc", GPIO_ACTIVE_HIGH),
{ },
},
};
static struct neponset_drvdata *nep;
void neponset_ncr_frob(unsigned int mask, unsigned int val)
{
struct neponset_drvdata *n = nep;
unsigned long m = mask, v = val;
if (nep)
n->gpio[0]->set_multiple(n->gpio[0], &m, &v);
else
WARN(1, "nep unset\n");
}
EXPORT_SYMBOL(neponset_ncr_frob);
/*
* Install handler for Neponset IRQ. Note that we have to loop here
* since the ETHERNET and USAR IRQs are level based, and we need to
* ensure that the IRQ signal is deasserted before returning. This
* is rather unfortunate.
*/
static void neponset_irq_handler(struct irq_desc *desc)
{
struct neponset_drvdata *d = irq_desc_get_handler_data(desc);
unsigned int irr;
while (1) {
/*
* Acknowledge the parent IRQ.
*/
desc->irq_data.chip->irq_ack(&desc->irq_data);
/*
* Read the interrupt reason register. Let's have all
* active IRQ bits high. Note: there is a typo in the
* Neponset user's guide for the SA1111 IRR level.
*/
irr = readb_relaxed(d->base + IRR);
irr ^= IRR_ETHERNET | IRR_USAR;
if ((irr & (IRR_ETHERNET | IRR_USAR | IRR_SA1111)) == 0)
break;
/*
* Since there is no individual mask, we have to
* mask the parent IRQ. This is safe, since we'll
* recheck the register for any pending IRQs.
*/
if (irr & (IRR_ETHERNET | IRR_USAR)) {
desc->irq_data.chip->irq_mask(&desc->irq_data);
/*
* Ack the interrupt now to prevent re-entering
* this neponset handler. Again, this is safe
* since we'll check the IRR register prior to
* leaving.
*/
desc->irq_data.chip->irq_ack(&desc->irq_data);
if (irr & IRR_ETHERNET)
generic_handle_irq(d->irq_base + NEP_IRQ_SMC91X);
if (irr & IRR_USAR)
generic_handle_irq(d->irq_base + NEP_IRQ_USAR);
desc->irq_data.chip->irq_unmask(&desc->irq_data);
}
if (irr & IRR_SA1111)
generic_handle_irq(d->irq_base + NEP_IRQ_SA1111);
}
}
/* Yes, we really do not have any kind of masking or unmasking */
static void nochip_noop(struct irq_data *irq)
{
}
static struct irq_chip nochip = {
.name = "neponset",
.irq_ack = nochip_noop,
.irq_mask = nochip_noop,
.irq_unmask = nochip_noop,
};
static int neponset_init_gpio(struct gpio_chip **gcp,
struct device *dev, const char *label, void __iomem *reg,
unsigned num, bool in, const char *const * names)
{
struct gpio_chip *gc;
gc = gpio_reg_init(dev, reg, -1, num, label, in ? 0xffffffff : 0,
readl_relaxed(reg), names, NULL, NULL);
if (IS_ERR(gc))
return PTR_ERR(gc);
*gcp = gc;
return 0;
}
static struct sa1111_platform_data sa1111_info = {
.disable_devs = SA1111_DEVID_PS2_MSE,
};
static int neponset_probe(struct platform_device *dev)
{
struct neponset_drvdata *d;
struct resource *nep_res, *sa1111_res, *smc91x_res;
struct resource sa1111_resources[] = {
DEFINE_RES_MEM(0x40000000, SZ_8K),
{ .flags = IORESOURCE_IRQ },
};
struct platform_device_info sa1111_devinfo = {
.parent = &dev->dev,
.name = "sa1111",
.id = 0,
.res = sa1111_resources,
.num_res = ARRAY_SIZE(sa1111_resources),
.data = &sa1111_info,
.size_data = sizeof(sa1111_info),
.dma_mask = 0xffffffffUL,
};
struct resource smc91x_resources[] = {
DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS,
0x02000000, "smc91x-regs"),
DEFINE_RES_MEM_NAMED(SA1100_CS3_PHYS + 0x02000000,
0x02000000, "smc91x-attrib"),
{ .flags = IORESOURCE_IRQ },
};
struct smc91x_platdata smc91x_platdata = {
.flags = SMC91X_USE_8BIT | SMC91X_IO_SHIFT_2 | SMC91X_NOWAIT,
};
struct platform_device_info smc91x_devinfo = {
.parent = &dev->dev,
.name = "smc91x",
.id = 0,
.res = smc91x_resources,
.num_res = ARRAY_SIZE(smc91x_resources),
.data = &smc91x_platdata,
.size_data = sizeof(smc91x_platdata),
};
int ret, irq;
if (nep)
return -EBUSY;
irq = ret = platform_get_irq(dev, 0);
if (ret < 0)
goto err_alloc;
nep_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
smc91x_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
sa1111_res = platform_get_resource(dev, IORESOURCE_MEM, 2);
if (!nep_res || !smc91x_res || !sa1111_res) {
ret = -ENXIO;
goto err_alloc;
}
d = kzalloc_obj(*d);
if (!d) {
ret = -ENOMEM;
goto err_alloc;
}
d->base = ioremap(nep_res->start, SZ_4K);
if (!d->base) {
ret = -ENOMEM;
goto err_ioremap;
}
if (readb_relaxed(d->base + WHOAMI) != 0x11) {
dev_warn(&dev->dev, "Neponset board detected, but wrong ID: %02x\n",
readb_relaxed(d->base + WHOAMI));
ret = -ENODEV;
goto err_id;
}
ret = irq_alloc_descs(-1, IRQ_BOARD_START, NEP_IRQ_NR, -1);
if (ret <= 0) {
dev_err(&dev->dev, "unable to allocate %u irqs: %d\n",
NEP_IRQ_NR, ret);
if (ret == 0)
ret = -ENOMEM;
goto err_irq_alloc;
}
d->irq_base = ret;
irq_set_chip_and_handler(d->irq_base + NEP_IRQ_SMC91X, &nochip,
handle_simple_irq);
irq_clear_status_flags(d->irq_base + NEP_IRQ_SMC91X, IRQ_NOREQUEST | IRQ_NOPROBE);
irq_set_chip_and_handler(d->irq_base + NEP_IRQ_USAR, &nochip,
handle_simple_irq);
irq_clear_status_flags(d->irq_base + NEP_IRQ_USAR, IRQ_NOREQUEST | IRQ_NOPROBE);
irq_set_chip(d->irq_base + NEP_IRQ_SA1111, &nochip);
irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
irq_set_chained_handler_and_data(irq, neponset_irq_handler, d);
/* Disable GPIO 0/1 drivers so the buttons work on the Assabet */
writeb_relaxed(NCR_GP01_OFF, d->base + NCR_0);
neponset_init_gpio(&d->gpio[0], &dev->dev, "neponset-ncr",
d->base + NCR_0, NCR_NGPIO, false,
neponset_ncr_names);
neponset_init_gpio(&d->gpio[1], &dev->dev, "neponset-mdm-ctl0",
d->base + MDM_CTL_0, MDM_CTL0_NGPIO, false,
neponset_mdmctl0_names);
neponset_init_gpio(&d->gpio[2], &dev->dev, "neponset-mdm-ctl1",
d->base + MDM_CTL_1, MDM_CTL1_NGPIO, true,
neponset_mdmctl1_names);
neponset_init_gpio(&d->gpio[3], &dev->dev, "neponset-aud-ctl",
d->base + AUD_CTL, AUD_NGPIO, false,
neponset_aud_names);
gpiod_add_lookup_table(&neponset_uart1_gpio_table);
gpiod_add_lookup_table(&neponset_uart3_gpio_table);
gpiod_add_lookup_table(&neponset_pcmcia_table);
/*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?)
*/
#if 0
enable_irq_wake(irq);
#endif
dev_info(&dev->dev, "Neponset daughter board, providing IRQ%u-%u\n",
d->irq_base, d->irq_base + NEP_IRQ_NR - 1);
nep = d;
/* Ensure that the memory bus request/grant signals are setup */
sa1110_mb_disable();
sa1111_resources[0].parent = sa1111_res;
sa1111_resources[1].start = d->irq_base + NEP_IRQ_SA1111;
sa1111_resources[1].end = d->irq_base + NEP_IRQ_SA1111;
d->sa1111 = platform_device_register_full(&sa1111_devinfo);
smc91x_resources[0].parent = smc91x_res;
smc91x_resources[1].parent = smc91x_res;
smc91x_resources[2].start = d->irq_base + NEP_IRQ_SMC91X;
smc91x_resources[2].end = d->irq_base + NEP_IRQ_SMC91X;
d->smc91x = platform_device_register_full(&smc91x_devinfo);
platform_set_drvdata(dev, d);
return 0;
err_irq_alloc:
err_id:
iounmap(d->base);
err_ioremap:
kfree(d);
err_alloc:
return ret;
}
static void neponset_remove(struct platform_device *dev)
{
struct neponset_drvdata *d = platform_get_drvdata(dev);
int irq = platform_get_irq(dev, 0);
if (!IS_ERR(d->sa1111))
platform_device_unregister(d->sa1111);
if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x);
gpiod_remove_lookup_table(&neponset_pcmcia_table);
gpiod_remove_lookup_table(&neponset_uart3_gpio_table);
gpiod_remove_lookup_table(&neponset_uart1_gpio_table);
irq_set_chained_handler(irq, NULL);
irq_free_descs(d->irq_base, NEP_IRQ_NR);
nep = NULL;
iounmap(d->base);
kfree(d);
}
#ifdef CONFIG_PM_SLEEP
static int neponset_resume(struct device *dev)
{
struct neponset_drvdata *d = dev_get_drvdata(dev);
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(d->gpio); i++) {
ret = gpio_reg_resume(d->gpio[i]);
if (ret)
break;
}
return ret;
}
static const struct dev_pm_ops neponset_pm_ops = {
.resume_noirq = neponset_resume,
.restore_noirq = neponset_resume,
};
#define PM_OPS &neponset_pm_ops
#else
#define PM_OPS NULL
#endif
static struct platform_driver neponset_device_driver = {
.probe = neponset_probe,
.remove = neponset_remove,
.driver = {
.name = "neponset",
.pm = PM_OPS,
},
};
static int __init neponset_init(void)
{
return platform_driver_register(&neponset_device_driver);
}
subsys_initcall(neponset_init);
+128
View File
@@ -0,0 +1,128 @@
/*
* SA1100 Power Management Routines
*
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*
* History:
*
* 2001-02-06: Cliff Brake Initial code
*
* 2001-02-25: Sukjae Cho <sjcho@east.isi.edu> &
* Chester Kuo <chester@linux.org.tw>
* Save more value for the resume function! Support
* Bitsy/Assabet/Freebird board
*
* 2001-08-29: Nicolas Pitre <nico@fluxnic.net>
* Cleaned up, pushed platform dependent stuff
* in the platform specific files.
*
* 2002-05-27: Nicolas Pitre Killed sleep.h and the kmalloced save array.
* Storage is local on the stack now.
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/suspend.h>
#include <linux/errno.h>
#include <linux/time.h>
#include <mach/hardware.h>
#include <asm/page.h>
#include <asm/suspend.h>
#include <asm/mach/time.h>
#include "generic.h"
extern int sa1100_finish_suspend(unsigned long);
#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
/*
* List of global SA11x0 peripheral registers to preserve.
* More ones like CP and general purpose register values are preserved
* on the stack and then the stack pointer is stored last in sleep.S.
*/
enum { SLEEP_SAVE_GPDR, SLEEP_SAVE_GAFR,
SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
SLEEP_SAVE_Ser1SDCR0,
SLEEP_SAVE_COUNT
};
static int sa11x0_pm_enter(suspend_state_t state)
{
unsigned long gpio, sleep_save[SLEEP_SAVE_COUNT];
gpio = GPLR;
/* save vital registers */
SAVE(GPDR);
SAVE(GAFR);
SAVE(PPDR);
SAVE(PPSR);
SAVE(PPAR);
SAVE(PSDR);
SAVE(Ser1SDCR0);
/* Clear previous reset status */
RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
/* set resume return address */
PSPR = __pa_symbol(cpu_resume);
/* go zzz */
cpu_suspend(0, sa1100_finish_suspend);
/*
* Ensure not to come back here if it wasn't intended
*/
RCSR = RCSR_SMR;
PSPR = 0;
/*
* Ensure interrupt sources are disabled; we will re-init
* the interrupt subsystem via the device manager.
*/
ICLR = 0;
ICCR = 1;
ICMR = 0;
/* restore registers */
RESTORE(GPDR);
RESTORE(GAFR);
RESTORE(PPDR);
RESTORE(PPSR);
RESTORE(PPAR);
RESTORE(PSDR);
RESTORE(Ser1SDCR0);
GPSR = gpio;
GPCR = ~gpio;
/*
* Clear the peripheral sleep-hold bit.
*/
PSSR = PSSR_PH;
return 0;
}
static const struct platform_suspend_ops sa11x0_pm_ops = {
.enter = sa11x0_pm_enter,
.valid = suspend_valid_only_mem,
};
int __init sa11x0_pm_init(void)
{
suspend_set_ops(&sa11x0_pm_ops);
return 0;
}
+143
View File
@@ -0,0 +1,143 @@
/*
* SA11x0 Assembler Sleep/WakeUp Management Routines
*
* Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*
* History:
*
* 2001-02-06: Cliff Brake Initial code
*
* 2001-08-29: Nicolas Pitre Simplified.
*
* 2002-05-27: Nicolas Pitre Revisited, more cleanup and simplification.
* Storage is on the stack now.
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/hardware.h>
.text
/*
* sa1100_finish_suspend()
*
* Causes sa11x0 to enter sleep state
*
* Must be aligned to a cacheline.
*/
.balign 32
ENTRY(sa1100_finish_suspend)
@ disable clock switching
mcr p15, 0, r1, c15, c2, 2
ldr r6, =MDREFR
ldr r4, [r6]
orr r4, r4, #MDREFR_K1DB2
ldr r5, =PPCR
@ Pre-load __loop_udelay into the I-cache
mov r0, #1
bl __loop_udelay
mov r0, r0
@ The following must all exist in a single cache line to
@ avoid accessing memory until this sequence is complete,
@ otherwise we occasionally hang.
@ Adjust memory timing before lowering CPU clock
str r4, [r6]
@ delay 90us and set CPU PLL to lowest speed
@ fixes resume problem on high speed SA1110
mov r0, #90
bl __loop_udelay
mov r1, #0
str r1, [r5]
mov r0, #90
bl __loop_udelay
/*
* SA1110 SDRAM controller workaround. register values:
*
* r0 = &MSC0
* r1 = &MSC1
* r2 = &MSC2
* r3 = MSC0 value
* r4 = MSC1 value
* r5 = MSC2 value
* r6 = &MDREFR
* r7 = first MDREFR value
* r8 = second MDREFR value
* r9 = &MDCNFG
* r10 = MDCNFG value
* r11 = third MDREFR value
* r12 = &PMCR
* r13 = PMCR value (1)
*/
ldr r0, =MSC0
ldr r1, =MSC1
ldr r2, =MSC2
ldr r3, [r0]
bic r3, r3, #FMsk(MSC_RT)
bic r3, r3, #FMsk(MSC_RT)<<16
ldr r4, [r1]
bic r4, r4, #FMsk(MSC_RT)
bic r4, r4, #FMsk(MSC_RT)<<16
ldr r5, [r2]
bic r5, r5, #FMsk(MSC_RT)
bic r5, r5, #FMsk(MSC_RT)<<16
ldr r7, [r6]
bic r7, r7, #0x0000FF00
bic r7, r7, #0x000000F0
orr r8, r7, #MDREFR_SLFRSH
ldr r9, =MDCNFG
ldr r10, [r9]
bic r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
bic r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)
bic r11, r8, #MDREFR_SLFRSH
bic r11, r11, #MDREFR_E1PIN
ldr r12, =PMCR
mov r13, #PMCR_SF
b sa1110_sdram_controller_fix
.align 5
sa1110_sdram_controller_fix:
@ Step 1 clear RT field of all MSCx registers
str r3, [r0]
str r4, [r1]
str r5, [r2]
@ Step 2 clear DRI field in MDREFR
str r7, [r6]
@ Step 3 set SLFRSH bit in MDREFR
str r8, [r6]
@ Step 4 clear DE bis in MDCNFG
str r10, [r9]
@ Step 5 clear DRAM refresh control register
str r11, [r6]
@ Wow, now the hardware suspend request pins can be used, that makes them functional for
@ about 7 ns out of the entire time that the CPU is running!
@ Step 6 set force sleep bit in PMCR
str r13, [r12]
20: b 20b @ loop waiting for sleep
+240
View File
@@ -0,0 +1,240 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* linux/arch/arm/mach-sa1100/ssp.c
*
* Copyright (C) 2003 Russell King.
*
* Generic SSP driver. This provides the generic core for simple
* IO-based SSP applications.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/hardware/ssp.h>
#define TIMEOUT 100000
static irqreturn_t ssp_interrupt(int irq, void *dev_id)
{
unsigned int status = Ser4SSSR;
if (status & SSSR_ROR)
printk(KERN_WARNING "SSP: receiver overrun\n");
Ser4SSSR = SSSR_ROR;
return status ? IRQ_HANDLED : IRQ_NONE;
}
/**
* ssp_write_word - write a word to the SSP port
* @data: 16-bit, MSB justified data to write.
*
* Wait for a free entry in the SSP transmit FIFO, and write a data
* word to the SSP port. Wait for the SSP port to start sending
* the data.
*
* The caller is expected to perform the necessary locking.
*
* Returns:
* %-ETIMEDOUT timeout occurred
* 0 success
*/
int ssp_write_word(u16 data)
{
int timeout = TIMEOUT;
while (!(Ser4SSSR & SSSR_TNF)) {
if (!--timeout)
return -ETIMEDOUT;
cpu_relax();
}
Ser4SSDR = data;
timeout = TIMEOUT;
while (!(Ser4SSSR & SSSR_BSY)) {
if (!--timeout)
return -ETIMEDOUT;
cpu_relax();
}
return 0;
}
/**
* ssp_read_word - read a word from the SSP port
*
* Wait for a data word in the SSP receive FIFO, and return the
* received data. Data is LSB justified.
*
* Note: Currently, if data is not expected to be received, this
* function will wait for ever.
*
* The caller is expected to perform the necessary locking.
*
* Returns:
* %-ETIMEDOUT timeout occurred
* 16-bit data success
*/
int ssp_read_word(u16 *data)
{
int timeout = TIMEOUT;
while (!(Ser4SSSR & SSSR_RNE)) {
if (!--timeout)
return -ETIMEDOUT;
cpu_relax();
}
*data = (u16)Ser4SSDR;
return 0;
}
/**
* ssp_flush - flush the transmit and receive FIFOs
*
* Wait for the SSP to idle, and ensure that the receive FIFO
* is empty.
*
* The caller is expected to perform the necessary locking.
*
* Returns:
* %-ETIMEDOUT timeout occurred
* 0 success
*/
int ssp_flush(void)
{
int timeout = TIMEOUT * 2;
do {
while (Ser4SSSR & SSSR_RNE) {
if (!--timeout)
return -ETIMEDOUT;
(void) Ser4SSDR;
}
if (!--timeout)
return -ETIMEDOUT;
} while (Ser4SSSR & SSSR_BSY);
return 0;
}
/**
* ssp_enable - enable the SSP port
*
* Turn on the SSP port.
*/
void ssp_enable(void)
{
Ser4SSCR0 |= SSCR0_SSE;
}
/**
* ssp_disable - shut down the SSP port
*
* Turn off the SSP port, optionally powering it down.
*/
void ssp_disable(void)
{
Ser4SSCR0 &= ~SSCR0_SSE;
}
/**
* ssp_save_state - save the SSP configuration
* @ssp: pointer to structure to save SSP configuration
*
* Save the configured SSP state for suspend.
*/
void ssp_save_state(struct ssp_state *ssp)
{
ssp->cr0 = Ser4SSCR0;
ssp->cr1 = Ser4SSCR1;
Ser4SSCR0 &= ~SSCR0_SSE;
}
/**
* ssp_restore_state - restore a previously saved SSP configuration
* @ssp: pointer to configuration saved by ssp_save_state
*
* Restore the SSP configuration saved previously by ssp_save_state.
*/
void ssp_restore_state(struct ssp_state *ssp)
{
Ser4SSSR = SSSR_ROR;
Ser4SSCR0 = ssp->cr0 & ~SSCR0_SSE;
Ser4SSCR1 = ssp->cr1;
Ser4SSCR0 = ssp->cr0;
}
/**
* ssp_init - setup the SSP port
*
* initialise and claim resources for the SSP port.
*
* Returns:
* %-ENODEV if the SSP port is unavailable
* %-EBUSY if the resources are already in use
* %0 on success
*/
int ssp_init(void)
{
int ret;
if (!(PPAR & PPAR_SPR) && (Ser4MCCR0 & MCCR0_MCE))
return -ENODEV;
if (!request_mem_region(__PREG(Ser4SSCR0), 0x18, "SSP")) {
return -EBUSY;
}
Ser4SSSR = SSSR_ROR;
ret = request_irq(IRQ_Ser4SSP, ssp_interrupt, 0, "SSP", NULL);
if (ret)
goto out_region;
return 0;
out_region:
release_mem_region(__PREG(Ser4SSCR0), 0x18);
return ret;
}
/**
* ssp_exit - undo the effects of ssp_init
*
* release and free resources for the SSP port.
*/
void ssp_exit(void)
{
Ser4SSCR0 &= ~SSCR0_SSE;
free_irq(IRQ_Ser4SSP, NULL);
release_mem_region(__PREG(Ser4SSCR0), 0x18);
}
MODULE_AUTHOR("Russell King");
MODULE_DESCRIPTION("SA11x0 SSP PIO driver");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ssp_write_word);
EXPORT_SYMBOL(ssp_read_word);
EXPORT_SYMBOL(ssp_flush);
EXPORT_SYMBOL(ssp_enable);
EXPORT_SYMBOL(ssp_disable);
EXPORT_SYMBOL(ssp_save_state);
EXPORT_SYMBOL(ssp_restore_state);
EXPORT_SYMBOL(ssp_init);
EXPORT_SYMBOL(ssp_exit);