#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
struct cpufreq_frequency_table sa11x0_freq_table[NR_FREQS+1] = {
{ .frequency = 59000, },
{ .frequency = 73700, },
{ .frequency = 88500, },
{ .frequency = 103200, },
{ .frequency = 118000, },
{ .frequency = 132700, },
{ .frequency = 147500, },
{ .frequency = 162200, },
{ .frequency = 176900, },
{ .frequency = 191700, },
{ .frequency = 206400, },
{ .frequency = 221200, },
{ .frequency = 235900, },
{ .frequency = 250700, },
{ .frequency = 265400, },
{ .frequency = 280200, },
{ .frequency = CPUFREQ_TABLE_END, },
};
unsigned int sa11x0_getspeed(unsigned int cpu)
{
if (cpu)
return 0;
return sa11x0_freq_table[PPCR & 0xf].frequency;
}
static void sa1100_power_off(void)
{
mdelay(100);
local_irq_disable();
PCFR = (PCFR_OPDE | PCFR_FP | PCFR_FS);
PWER = GFER = GRER = 1;
PSPR = 0;
PMCR = PMCR_SF;
}
void sa11x0_restart(enum reboot_mode mode, const char *cmd)
{
clear_reset_status(RESET_STATUS_ALL);
if (mode == REBOOT_SOFT) {
soft_restart(0);
} else {
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)
{
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;
}
static struct map_desc standard_io_desc[] __initdata = {
{
.virtual = 0xf8000000,
.pfn = __phys_to_pfn(0x80000000),
.length = 0x00100000,
.type = MT_DEVICE
}, {
.virtual = 0xfa000000,
.pfn = __phys_to_pfn(0x90000000),
.length = 0x00100000,
.type = MT_DEVICE
}, {
.virtual = 0xfc000000,
.pfn = __phys_to_pfn(0xa0000000),
.length = 0x00100000,
.type = MT_DEVICE
}, {
.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();
}
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);
}
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;
}