From 828da9d195850c169152b5aa5b0ef6a58886a46c Mon Sep 17 00:00:00 2001 From: Kai Svahn Date: Fri, 26 Jan 2007 12:39:48 -0800 Subject: [PATCH] ARM: OMAP: Merge board specific files from N800 tree This patch merges board specific files from N800 tree. Nokia has published the files at: http://repository.maemo.org/pool/maemo3.0/free/source/ kernel-source-rx-34_2.6.18.orig.tar.gz kernel-source-rx-34_2.6.18-osso29.diff.gz Signed-off-by: Kai Svahn Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/Kconfig | 11 +- arch/arm/mach-omap2/Makefile | 4 + arch/arm/mach-omap2/board-n800-audio.c | 366 +++++++++++++++++ arch/arm/mach-omap2/board-n800-bt.c | 42 ++ arch/arm/mach-omap2/board-n800-dsp.c | 156 +++++++ arch/arm/mach-omap2/board-n800-flash.c | 156 +++++++ arch/arm/mach-omap2/board-n800-mmc.c | 282 +++++++++++++ arch/arm/mach-omap2/board-n800-pm.c | 79 ++++ arch/arm/mach-omap2/board-n800-usb.c | 102 +++++ arch/arm/mach-omap2/board-n800.c | 515 ++++++++++++++++++++++++ include/asm-arm/arch-omap/board-nokia.h | 14 +- include/asm-arm/arch-omap/board.h | 24 +- include/asm-arm/arch-omap/onenand.h | 1 + 13 files changed, 1748 insertions(+), 4 deletions(-) create mode 100644 arch/arm/mach-omap2/board-n800-audio.c create mode 100644 arch/arm/mach-omap2/board-n800-bt.c create mode 100644 arch/arm/mach-omap2/board-n800-dsp.c create mode 100644 arch/arm/mach-omap2/board-n800-flash.c create mode 100644 arch/arm/mach-omap2/board-n800-mmc.c create mode 100644 arch/arm/mach-omap2/board-n800-pm.c create mode 100644 arch/arm/mach-omap2/board-n800-usb.c create mode 100644 arch/arm/mach-omap2/board-n800.c diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index c7507adb5fb..752dd6e7582 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -54,4 +54,13 @@ config MACH_OMAP_APOLLON config MACH_OMAP_2430SDP bool "OMAP 2430 SDP board" - depends on ARCH_OMAP2 && ARCH_OMAP24XX \ No newline at end of file + depends on ARCH_OMAP2 && ARCH_OMAP24XX + +config MACH_NOKIA_N800 + bool "Nokia N800" + depends on ARCH_OMAP24XX + +config MACH_OMAP2_TUSB6010 + bool + depends on ARCH_OMAP2 && ARCH_OMAP2420 + default y if MACH_NOKIA_N800 \ No newline at end of file diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index 036f4eee4b7..4cccb4c6e90 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -16,4 +16,8 @@ obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o +obj-$(CONFIG_MACH_NOKIA_N800) += board-n800.o board-n800-flash.o \ + board-n800-mmc.o board-n800-bt.o \ + board-n800-audio.o board-n800-usb.o \ + board-n800-dsp.o board-n800-pm.o diff --git a/arch/arm/mach-omap2/board-n800-audio.c b/arch/arm/mach-omap2/board-n800-audio.c new file mode 100644 index 00000000000..9033de58319 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-audio.c @@ -0,0 +1,366 @@ +/* + * linux/arch/arm/mach-omap2/board-n800-audio.c + * + * Copyright (C) 2006 Nokia Corporation + * Contact: Juha Yrjola + * Jarkko Nikula + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "../plat-omap/dsp/dsp_common.h" + +#if defined(CONFIG_SPI_TSC2301_AUDIO) && defined(CONFIG_SND_OMAP24XX_EAC) +#define AUDIO_ENABLED + +static struct clk *sys_clkout2; +static struct clk *func96m_clk; +static struct device *eac_device; +static struct device *tsc2301_device; + +static int enable_audio; +static int audio_ok; +static spinlock_t audio_lock; + +/* + * Leaving EAC and sys_clkout2 pins multiplexed to those subsystems results + * in about 2 mA extra current leak when audios are powered down. The + * workaround is to multiplex them to protected mode (with pull-ups enabled) + * whenever audio is not being used. + */ +static int eac_mux_disabled = 0; +static int clkout2_mux_disabled = 0; +static u32 saved_mux[2]; + +static void n800_enable_eac_mux(void) +{ + if (!eac_mux_disabled) + return; + __raw_writel(saved_mux[1], IO_ADDRESS(0x48000124)); + eac_mux_disabled = 0; +} + +static void n800_disable_eac_mux(void) +{ + if (eac_mux_disabled) { + WARN_ON(eac_mux_disabled); + return; + } + saved_mux[1] = __raw_readl(IO_ADDRESS(0x48000124)); + __raw_writel(0x1f1f1f1f, IO_ADDRESS(0x48000124)); + eac_mux_disabled = 1; +} + +static void n800_enable_clkout2_mux(void) +{ + if (!clkout2_mux_disabled) + return; + __raw_writel(saved_mux[0], IO_ADDRESS(0x480000e8)); + clkout2_mux_disabled = 0; +} + +static void n800_disable_clkout2_mux(void) +{ + u32 l; + + if (clkout2_mux_disabled) { + WARN_ON(clkout2_mux_disabled); + return; + } + saved_mux[0] = __raw_readl(IO_ADDRESS(0x480000e8)); + l = saved_mux[0] & ~0xff; + l |= 0x1f; + __raw_writel(l, IO_ADDRESS(0x480000e8)); + clkout2_mux_disabled = 1; +} + +static int n800_eac_enable_ext_clocks(struct device *dev) +{ + BUG_ON(tsc2301_device == NULL); + n800_enable_eac_mux(); + tsc2301_mixer_enable_mclk(tsc2301_device); + + return 0; +} + +static void n800_eac_disable_ext_clocks(struct device *dev) +{ + BUG_ON(tsc2301_device == NULL); + tsc2301_mixer_disable_mclk(tsc2301_device); + n800_disable_eac_mux(); +} + +static int n800_audio_set_power(void *pdata, int dac, int adc) +{ + BUG_ON(pdata != tsc2301_device); + tsc2301_mixer_set_power(tsc2301_device, dac, adc); + + return 0; +} + +static int n800_audio_register_controls(void *pdata, struct snd_card *card) +{ + BUG_ON(pdata != tsc2301_device); + return tsc2301_mixer_register_controls(tsc2301_device, card); +} + +static struct eac_codec n800_eac_codec = { + .mclk_src = EAC_MCLK_EXT_2x12288000, + .codec_mode = EAC_CODEC_I2S, + .codec_conf.i2s.polarity_changed_mode = 0, + .codec_conf.i2s.sync_delay_enable = 0, + .default_rate = 48000, + .set_power = n800_audio_set_power, + .register_controls = n800_audio_register_controls, + .short_name = "TSC2301", +}; + +static int n800_register_codec(void) +{ + int r, do_enable = 0; + unsigned long flags; + + n800_eac_codec.private_data = tsc2301_device; + r = eac_register_codec(eac_device, &n800_eac_codec); + if (r < 0) + return r; + spin_lock_irqsave(&audio_lock, flags); + audio_ok = 1; + if (enable_audio) + do_enable = 1; + spin_unlock_irqrestore(&audio_lock, flags); + if (do_enable) + eac_set_mode(eac_device, 1, 1); + return 0; +} + +static void n800_unregister_codec(void) +{ + audio_ok = 0; + eac_unregister_codec(eac_device); + eac_set_mode(eac_device, 0, 0); +} + +static int n800_eac_init(struct device *dev) +{ + int r; + + BUG_ON(eac_device != NULL); + eac_device = dev; + if (tsc2301_device != NULL) { + r = n800_register_codec(); + if (r < 0) + return r; + } + + return 0; +} + +static void n800_eac_cleanup(struct device *dev) +{ + eac_device = NULL; + if (tsc2301_device != NULL) + n800_unregister_codec(); +} + +static int n800_codec_get_clocks(struct device *dev) +{ + sys_clkout2 = clk_get(dev, "sys_clkout2"); + if (IS_ERR(sys_clkout2)) { + dev_err(dev, "Could not get sys_clkout2\n"); + return -ENODEV; + } + /* configure 12 MHz output on SYS_CLKOUT2. Therefore we must use + * 96 MHz as its parent in order to get 12 MHz */ + func96m_clk = clk_get(dev, "func_96m_ck"); + if (IS_ERR(func96m_clk)) { + dev_err(dev, "Could not get func 96M clock\n"); + clk_put(sys_clkout2); + return -ENODEV; + } + + clk_set_parent(sys_clkout2, func96m_clk); + clk_set_rate(sys_clkout2, 12000000); + + return 0; +} + +static void n800_codec_put_clocks(struct device *dev) +{ + clk_put(func96m_clk); + clk_put(sys_clkout2); +} + +static int n800_codec_enable_clock(struct device *dev) +{ + n800_enable_clkout2_mux(); + return clk_enable(sys_clkout2); +} + +static void n800_codec_disable_clock(struct device *dev) +{ + clk_disable(sys_clkout2); + n800_disable_clkout2_mux(); +} + +static int n800_codec_init(struct device *dev) +{ + int r; + + BUG_ON(tsc2301_device != NULL); + tsc2301_device = dev; + if ((r = n800_codec_get_clocks(dev)) < 0) + return r; + if (eac_device != NULL) { + r = n800_register_codec(); + if (r < 0) { + n800_codec_put_clocks(dev); + return r; + } + } + return 0; +} + +static void n800_codec_cleanup(struct device *dev) +{ + tsc2301_device = NULL; + if (eac_device != NULL) + n800_unregister_codec(); + n800_codec_put_clocks(dev); +} + +static struct eac_platform_data n800_eac_data = { + .init = n800_eac_init, + .cleanup = n800_eac_cleanup, + .enable_ext_clocks = n800_eac_enable_ext_clocks, + .disable_ext_clocks = n800_eac_disable_ext_clocks, +}; + +static const struct tsc2301_mixer_gpio n800_mixer_gpios[] = { + { + .name = "Headset Amplifier", + .gpio = 1, + .deactivate_on_pd = 1, + }, { + .name = "Speaker Amplifier", + .gpio = 2, + .def_enable = 1, + .deactivate_on_pd = 1, + }, { + .name = "Headset Mic Select", + .gpio = 3, + } +}; + +static struct platform_device retu_headset_device = { + .name = "retu-headset", + .id = -1, + .dev = { + .release = NULL, + }, +}; + +void __init n800_audio_init(struct tsc2301_platform_data *tc) +{ + spin_lock_init(&audio_lock); + + if (platform_device_register(&retu_headset_device) < 0) + return; + omap_init_eac(&n800_eac_data); + + tc->pll_pdc = 7; + tc->pll_a = 7; + tc->pll_n = 9; + tc->pll_output = 1; + tc->mclk_ratio = TSC2301_MCLK_256xFS; + tc->i2s_sample_rate = TSC2301_I2S_SR_48000; + tc->i2s_format = TSC2301_I2S_FORMAT0; + tc->power_down_blocks = TSC2301_REG_PD_MISC_MOPD; + tc->mixer_gpios = n800_mixer_gpios; + tc->n_mixer_gpios = ARRAY_SIZE(n800_mixer_gpios); + tc->codec_init = n800_codec_init; + tc->codec_cleanup = n800_codec_cleanup; + tc->enable_clock = n800_codec_enable_clock; + tc->disable_clock = n800_codec_disable_clock; +} + +#else + +void __init n800_audio_init(void) +{ +} + +#endif + +#ifdef CONFIG_OMAP_DSP + +int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage) +{ +#ifdef AUDIO_ENABLED + unsigned long flags; + int do_enable = 0; + + spin_lock_irqsave(&audio_lock, flags); + + pr_debug("DSP power up request (audio codec %sinitialized)\n", + audio_ok ? "" : "not "); + + if (enable_audio) + goto out; + enable_audio = 1; + if (audio_ok) + do_enable = 1; +out: + spin_unlock_irqrestore(&audio_lock, flags); + if (do_enable) + eac_set_mode(eac_device, 1, 1); +#endif + return 0; +} + +int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage) +{ +#ifdef AUDIO_ENABLED + unsigned long flags; + int do_disable = 0; + + spin_lock_irqsave(&audio_lock, flags); + + pr_debug("DSP power down request (audio codec %sinitialized)\n", + audio_ok ? "" : "not "); + + if (!enable_audio) + goto out; + enable_audio = 0; + if (audio_ok) + do_disable = 1; +out: + spin_unlock_irqrestore(&audio_lock, flags); + if (do_disable) + eac_set_mode(eac_device, 0, 0); +#endif + return 0; +} + +#endif /* CONFIG_OMAP_DSP */ diff --git a/arch/arm/mach-omap2/board-n800-bt.c b/arch/arm/mach-omap2/board-n800-bt.c new file mode 100644 index 00000000000..4ea19cca83f --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-bt.c @@ -0,0 +1,42 @@ +/* + * Nokia N800 platform-specific data for Bluetooth + * + * Copyright (C) 2005, 2006 Nokia Corporation + * Contact: Ville Tervo + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include +#include + +static struct platform_device n800_bt_device = { + .name = "hci_h4p", + .id = -1, + .num_resources = 0, +}; + +void __init n800_bt_init(void) +{ + const struct omap_bluetooth_config *bt_config; + + bt_config = (void *) omap_get_config(OMAP_TAG_NOKIA_BT, + struct omap_bluetooth_config); + n800_bt_device.dev.platform_data = (void *) bt_config; + if (platform_device_register(&n800_bt_device) < 0) + BUG(); +} + diff --git a/arch/arm/mach-omap2/board-n800-dsp.c b/arch/arm/mach-omap2/board-n800-dsp.c new file mode 100644 index 00000000000..cb570243dc5 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-dsp.c @@ -0,0 +1,156 @@ +/* + * linux/arch/arm/mach-omap2/board-n800-dsp.c + * + * Copyright (C) 2006 Nokia Corporation. + * + * Contact: Hiroshi DOYU + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../plat-omap/dsp/dsp_common.h" + +#if defined(CONFIG_OMAP_DSP) + +/* + * dsp peripheral device: AUDIO + */ +static struct dsp_kfunc_device n800_audio_device = { + .name = "audio", + .type = DSP_KFUNC_DEV_TYPE_AUDIO, + .enable = n800_audio_enable, + .disable = n800_audio_disable, +}; + +/* + * dsp peripheral device: TIMER + */ +static int dsp_timer_probe(struct dsp_kfunc_device *kdev) +{ + char clockname[20]; + + strcpy(clockname, kdev->name); + strcat(clockname, "_fck"); + + kdev->fck = clk_get(NULL, clockname); + if (IS_ERR(kdev->fck)) { + printk(KERN_ERR "couldn't acquire %s\n", clockname); + return PTR_ERR(kdev->fck); + } + pr_debug("%s probed successfully\n", clockname); + + strcpy(clockname, kdev->name); + strcat(clockname, "_ick"); + kdev->ick = clk_get(NULL, clockname); + if (IS_ERR(kdev->ick)) { + printk(KERN_ERR "couldn't acquire %s\n", clockname); + goto fail; + } + pr_debug("%s probed successfully\n", clockname); + + return 0; + fail: + clk_put(kdev->fck); + + return PTR_ERR(kdev->ick); +} + +static int dsp_timer_remove(struct dsp_kfunc_device *kdev) +{ + clk_put(kdev->ick); + clk_put(kdev->fck); + pr_debug("%s removed successfully\n", kdev->name); + return 0; +} + +static int dsp_timer_enable(struct dsp_kfunc_device *kdev, int stage) +{ + pr_debug("%s enabled(%d)\n", kdev->name, stage); + + mutex_lock(&kdev->lock); + + if (kdev->enabled) + goto out; + kdev->enabled = 1; + + clk_enable(kdev->fck); + clk_enable(kdev->ick); + out: + mutex_unlock(&kdev->lock); + + return 0; +} + +static int dsp_timer_disable(struct dsp_kfunc_device *kdev, int stage) +{ + pr_debug("%s disabled(%d)\n", kdev->name, stage); + + mutex_lock(&kdev->lock); + + if (kdev->enabled == 0) + goto out; + kdev->enabled = 0; + + clk_disable(kdev->ick); + clk_disable(kdev->fck); + out: + mutex_unlock(&kdev->lock); + + return 0; +} + +static struct dsp_kfunc_device n800_timer_device = { + .name = "gpt5", + .type = DSP_KFUNC_DEV_TYPE_COMMON, + .probe = dsp_timer_probe, + .remove = dsp_timer_remove, + .enable = dsp_timer_enable, + .disable = dsp_timer_disable, +}; + +static struct dsp_kfunc_device *n800_kfunc_dev[] = { + &n800_audio_device, + &n800_timer_device, +}; + +void __init n800_dsp_init(void) +{ + int i, ret; + struct dsp_kfunc_device **p = n800_kfunc_dev; + + for (i = 0; i < ARRAY_SIZE(n800_kfunc_dev); i++) { + ret = dsp_kfunc_device_register(p[i]); + if (ret) { + printk(KERN_ERR + "KFUNC device registration failed: %s\n", + p[i]->name); + } + } +} + +#else +void __init n800_dsp_init(void) { } +#endif /* CONFIG_OMAP_DSP */ diff --git a/arch/arm/mach-omap2/board-n800-flash.c b/arch/arm/mach-omap2/board-n800-flash.c new file mode 100644 index 00000000000..528ee52a377 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-flash.c @@ -0,0 +1,156 @@ +/* + * linux/arch/arm/mach-omap2/board-n800-flash.c + * + * Copyright (C) 2006 Nokia Corporation + * Author: Juha Yrjola + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct mtd_partition n800_partitions[8]; + +static int n800_onenand_setup(void __iomem *); + +static struct omap_onenand_platform_data n800_onenand_data = { + .cs = 0, + .gpio_irq = 26, + .parts = n800_partitions, + .nr_parts = 0, /* filled later */ + .onenand_setup = n800_onenand_setup, +}; + +static struct platform_device n800_onenand_device = { + .name = "omap2-onenand", + .id = -1, + .dev = { + .platform_data = &n800_onenand_data, + }, +}; + +static unsigned short omap2_onenand_readw(void __iomem *addr) +{ + return readw(addr); +} + +static void omap2_onenand_writew(unsigned short value, void __iomem *addr) +{ + writew(value, addr); +} + +static int omap2_onenand_set_sync_mode(int cs, void __iomem *onenand_base) +{ + const int min_gpmc_clk_period = 18; + struct gpmc_timings t; + int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency; + u32 reg; + + tick_ns = gpmc_round_ns_to_ticks(1); + div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period); + gpmc_clk_ns = div * tick_ns; + if (gpmc_clk_ns >= 24) + latency = 3; + else + latency = 4; + + /* Configure OneNAND for sync read */ + reg = omap2_onenand_readw(onenand_base + ONENAND_REG_SYS_CFG1); + reg &= ~((0x7 << ONENAND_SYS_CFG1_BRL_SHIFT) | (0x7 << 9)); + reg |= (latency << ONENAND_SYS_CFG1_BRL_SHIFT) | + ONENAND_SYS_CFG1_SYNC_READ | + ONENAND_SYS_CFG1_BL_16; + omap2_onenand_writew(reg, onenand_base + ONENAND_REG_SYS_CFG1); + + /* FIXME: Get timings from platform data */ + /* Set syncronous read timings */ + memset(&t, 0, sizeof(t)); + t.sync_clk = min_gpmc_clk_period; + t.cs_on = 0; + t.adv_on = gpmc_round_ns_to_ticks(7); + fclk_offset_ns = t.adv_on + gpmc_round_ns_to_ticks(7); + fclk_offset = fclk_offset_ns / gpmc_round_ns_to_ticks(1); + t.page_burst_access = gpmc_clk_ns; + + /* Read */ + t.adv_rd_off = fclk_offset_ns + gpmc_round_ns_to_ticks(7); + t.oe_on = t.adv_rd_off; + t.access = fclk_offset_ns + (latency + 1) * gpmc_clk_ns; + t.oe_off = t.access + gpmc_round_ns_to_ticks(1); + t.cs_rd_off = t.oe_off; + t.rd_cycle = t.cs_rd_off + gpmc_round_ns_to_ticks(17); + + /* Write */ + t.adv_wr_off = t.adv_on + gpmc_round_ns_to_ticks(12); + t.we_on = t.adv_wr_off + gpmc_round_ns_to_ticks(1); + t.we_off = t.we_on + gpmc_round_ns_to_ticks(40); + t.cs_wr_off = t.we_off + gpmc_round_ns_to_ticks(1); + t.wr_cycle = t.cs_wr_off + gpmc_round_ns_to_ticks(1); + + /* Configure GPMC for synchronous read */ + fclk_offset %= div; + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, + GPMC_CONFIG1_WRAPBURST_SUPP | + GPMC_CONFIG1_READMULTIPLE_SUPP | + GPMC_CONFIG1_READTYPE_SYNC | + GPMC_CONFIG1_CLKACTIVATIONTIME(fclk_offset) | + GPMC_CONFIG1_PAGE_LEN(2) | + GPMC_CONFIG1_WAIT_READ_MON | + GPMC_CONFIG1_WAIT_PIN_SEL(0) | + GPMC_CONFIG1_DEVICESIZE_16 | + GPMC_CONFIG1_DEVICETYPE_NOR | + GPMC_CONFIG1_MUXADDDATA); + + return gpmc_cs_set_timings(cs, &t); +} + +static int n800_onenand_setup(void __iomem *onenand_base) +{ + struct omap_onenand_platform_data *datap = &n800_onenand_data; + struct device *dev = &n800_onenand_device.dev; + + /* Set sync timings in GPMC */ + if (omap2_onenand_set_sync_mode(datap->cs, onenand_base) < 0) { + dev_err(dev, "Unable to set synchronous mode\n"); + return -EINVAL; + } + + return 0; +} + +void __init n800_flash_init(void) +{ + const struct omap_partition_config *part; + int i = 0; + + while ((part = omap_get_nr_config(OMAP_TAG_PARTITION, + struct omap_partition_config, i)) != NULL) { + struct mtd_partition *mpart; + + mpart = n800_partitions + i; + mpart->name = (char *) part->name; + mpart->size = part->size; + mpart->offset = part->offset; + mpart->mask_flags = part->mask_flags; + i++; + if (i == ARRAY_SIZE(n800_partitions)) { + printk(KERN_ERR "Too many partitions supplied\n"); + return; + } + } + n800_onenand_data.nr_parts = i; + if (platform_device_register(&n800_onenand_device) < 0) { + printk(KERN_ERR "Unable to register OneNAND device\n"); + return; + } +} diff --git a/arch/arm/mach-omap2/board-n800-mmc.c b/arch/arm/mach-omap2/board-n800-mmc.c new file mode 100644 index 00000000000..b0bdd97ea53 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-mmc.c @@ -0,0 +1,282 @@ +/* + * linux/arch/arm/mach-omap2/board-n800-mmc.c + * + * Copyright (C) 2006 Nokia Corporation + * Author: Juha Yrjola + * + * 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. + */ + +#include +#include +#include + +#ifdef CONFIG_MMC_OMAP + +static const int slot_switch_gpio = 96; +static const int slot1_wp_gpio = 23; +static const int slot2_wp_gpio = 8; +static int slot1_cover_closed; +static int slot2_cover_closed; +static struct device *mmc_device; + +/* + * VMMC --> slot 1 + * VDCDC3_APE, VMCS2_APE --> slot 2 + * GPIO96 --> Menelaus GPIO2 + */ + +static int n800_mmc_switch_slot(struct device *dev, int slot) +{ +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Choose slot %d\n", slot + 1); +#endif + if (slot == 0) + omap_set_gpio_dataout(slot_switch_gpio, 0); + else + omap_set_gpio_dataout(slot_switch_gpio, 1); + return 0; +} + +static int n800_mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + int mV; + +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1, + power_on ? "on" : "off", vdd); +#endif + if (slot == 0) { + if (!power_on) + return menelaus_set_vmmc(0); + switch (1 << vdd) { + case MMC_VDD_33_34: + case MMC_VDD_32_33: + case MMC_VDD_31_32: + mV = 3100; + break; + case MMC_VDD_30_31: + mV = 3000; + break; + case MMC_VDD_28_29: + mV = 2800; + break; + case MMC_VDD_18_19: + mV = 1850; + break; + default: + BUG(); + } + return menelaus_set_vmmc(mV); + } else { + if (!power_on) + return menelaus_set_vdcdc(3, 0); + switch (1 << vdd) { + case MMC_VDD_33_34: + case MMC_VDD_32_33: + mV = 3300; + break; + case MMC_VDD_30_31: + case MMC_VDD_29_30: + mV = 3000; + break; + case MMC_VDD_28_29: + case MMC_VDD_27_28: + mV = 2800; + break; + case MMC_VDD_24_25: + case MMC_VDD_23_24: + mV = 2400; + break; + case MMC_VDD_22_23: + case MMC_VDD_21_22: + mV = 2200; + break; + case MMC_VDD_20_21: + case MMC_VDD_19_20: + mV = 2000; + break; + case MMC_VDD_18_19: + case MMC_VDD_17_18: + mV = 1800; + break; + case MMC_VDD_150_155: + case MMC_VDD_145_150: + mV = 1500; + break; + default: + BUG(); + } + return menelaus_set_vdcdc(3, mV); + } + return 0; +} + +static int n800_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode) +{ + int r; + +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1, + bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull"); +#endif + BUG_ON(slot != 0 && slot != 1); + slot++; + switch (bus_mode) { + case MMC_BUSMODE_OPENDRAIN: + r = menelaus_set_mmc_opendrain(slot, 1); + break; + case MMC_BUSMODE_PUSHPULL: + r = menelaus_set_mmc_opendrain(slot, 0); + break; + default: + BUG(); + } + if (r != 0 && printk_ratelimit()) + dev_err(dev, "MMC: unable to set bus mode for slot %d\n", + slot); + return r; +} + +#if 0 +static int n800_mmc_get_ro(struct device *dev, int slot) +{ + int ro; + + slot++; + if (slot == 1) + ro = omap_get_gpio_datain(slot1_wp_gpio); + else + ro = omap_get_gpio_datain(slot2_wp_gpio); +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Get RO slot %d: %s\n", + slot, ro ? "read-only" : "read-write"); +#endif + return ro; +} +#endif + +static int n800_mmc_get_cover_state(struct device *dev, int slot) +{ + slot++; + BUG_ON(slot != 1 && slot != 2); + if (slot == 1) + return slot1_cover_closed; + else + return slot2_cover_closed; +} + +static void n800_mmc_callback(void *data, u8 card_mask) +{ + if (card_mask & (1 << 1)) + slot2_cover_closed = 0; + else + slot2_cover_closed = 1; + omap_mmc_notify_cover_event(mmc_device, 1, slot2_cover_closed); +} + +void n800_mmc_slot1_cover_handler(void *arg, int state) +{ + if (mmc_device == NULL) + return; + + slot1_cover_closed = state; + omap_mmc_notify_cover_event(mmc_device, 0, state); +} + +static int n800_mmc_late_init(struct device *dev) +{ + int r; + + mmc_device = dev; + + r = menelaus_set_slot_sel(1); + if (r < 0) + return r; + + r = menelaus_set_mmc_slot(1, 1, 0, 1); + if (r < 0) + return r; + r = menelaus_set_mmc_slot(2, 1, 0, 1); + if (r < 0) + return r; + + r = menelaus_get_slot_pin_states(); + if (r < 0) + return r; + + if (r & (1 << 1)) + slot2_cover_closed = 1; + else + slot2_cover_closed = 0; + + r = menelaus_register_mmc_callback(n800_mmc_callback, NULL); + + return r; +} + +static void n800_mmc_cleanup(struct device *dev) +{ + menelaus_unregister_mmc_callback(); +} + +static struct omap_mmc_platform_data n800_mmc_data = { + .enabled = 1, + .nr_slots = 2, + .wire4 = 1, + .switch_slot = n800_mmc_switch_slot, + .init = n800_mmc_late_init, + .cleanup = n800_mmc_cleanup, + .slots[0] = { + .set_power = n800_mmc_set_power, + .set_bus_mode = n800_mmc_set_bus_mode, + .get_ro = NULL, + .get_cover_state= n800_mmc_get_cover_state, + .ocr_mask = MMC_VDD_18_19 | MMC_VDD_28_29 | MMC_VDD_30_31 | + MMC_VDD_32_33 | MMC_VDD_33_34, + .name = "internal", + }, + .slots[1] = { + .set_power = n800_mmc_set_power, + .set_bus_mode = n800_mmc_set_bus_mode, + .get_ro = NULL, + .get_cover_state= n800_mmc_get_cover_state, + .ocr_mask = MMC_VDD_150_155 | MMC_VDD_145_150 | MMC_VDD_17_18 | + MMC_VDD_18_19 | MMC_VDD_19_20 | MMC_VDD_20_21 | + MMC_VDD_21_22 | MMC_VDD_22_23 | MMC_VDD_23_24 | + MMC_VDD_24_25 | MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | MMC_VDD_32_33 | + MMC_VDD_33_34, + .name = "external", + }, +}; + +void __init n800_mmc_init(void) +{ + omap_set_mmc_info(1, &n800_mmc_data); + if (omap_request_gpio(slot_switch_gpio) < 0) + BUG(); + omap_set_gpio_dataout(slot_switch_gpio, 0); + omap_set_gpio_direction(slot_switch_gpio, 0); + if (omap_request_gpio(slot1_wp_gpio) < 0) + BUG(); + if (omap_request_gpio(slot2_wp_gpio) < 0) + BUG(); + omap_set_gpio_direction(slot1_wp_gpio, 1); + omap_set_gpio_direction(slot2_wp_gpio, 1); +} + +#else + +void __init n800_mmc_init(void) +{ +} + +void n800_mmc_slot1_cover_handler(void *arg, int state) +{ +} + +#endif diff --git a/arch/arm/mach-omap2/board-n800-pm.c b/arch/arm/mach-omap2/board-n800-pm.c new file mode 100644 index 00000000000..33f3e4da3e4 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-pm.c @@ -0,0 +1,79 @@ +/* + * Nokia N800 PM code + * + * Copyright (C) 2006 Nokia Corporation + * Author: Amit Kucheria + * + * 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. + */ + +#include +#include +#include + +#ifdef CONFIG_MENELAUS + +static int n800_auto_sleep_regulators(void) +{ + u32 val; + int ret; + + val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \ + | EN_VAUX_SLEEP | EN_VIO_SLEEP \ + | EN_VMEM_SLEEP | EN_DC3_SLEEP \ + | EN_VC_SLEEP | EN_DC2_SLEEP; + + ret = menelaus_set_regulator_sleep(1, val); + if (ret < 0) { + printk(KERN_ERR "Could not set regulators to sleep on " + "menelaus: %u\n", ret); + return ret; + } + return 0; +} + +static int n800_auto_voltage_scale(void) +{ + int ret; + + ret = menelaus_set_vcore_hw(1400, 1050); + if (ret < 0) { + printk(KERN_ERR "Could not set VCORE voltage on " + "menelaus: %u\n", ret); + return ret; + } + return 0; +} + +static int n800_menelaus_init(struct device *dev) +{ + int ret; + + ret = n800_auto_voltage_scale(); + if (ret < 0) + return ret; + ret = n800_auto_sleep_regulators(); + if (ret < 0) + return ret; + return 0; +} + +static struct menelaus_platform_data n800_menelaus_platform_data = { + .late_init = n800_menelaus_init, +}; + +void __init n800_pm_init(void) +{ + menelaus_set_platform_data(&n800_menelaus_platform_data); +} + +#else + +void __init n800_pm_init(void) +{ +} + +#endif + diff --git a/arch/arm/mach-omap2/board-n800-usb.c b/arch/arm/mach-omap2/board-n800-usb.c new file mode 100644 index 00000000000..122ba5beff5 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800-usb.c @@ -0,0 +1,102 @@ +/* + * linux/arch/arm/mach-omap2/board-n800-usb.c + * + * Copyright (C) 2006 Nokia Corporation + * Author: Juha Yrjola + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TUSB_ASYNC_CS 1 +#define TUSB_SYNC_CS 4 +#define GPIO_TUSB_INT 58 +#define GPIO_TUSB_ENABLE 0 + +static int tusb_set_power(int state); + +#if defined(CONFIG_USB_MUSB_OTG) +# define BOARD_MODE MUSB_OTG +#elif defined(CONFIG_USB_MUSB_PERIPHERAL) +# define BOARD_MODE MUSB_PERIPHERAL +#else /* defined(CONFIG_USB_MUSB_HOST) */ +# define BOARD_MODE MUSB_HOST +#endif + +static struct musb_hdrc_platform_data tusb_data = { + .mode = BOARD_MODE, + .multipoint = 1, + .set_power = tusb_set_power, + .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */ +}; + +/* + * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and + * 1.5 V voltage regulators of PM companion chip. Companion chip will then + * provide then PGOOD signal to TUSB6010 which will release it from reset. + */ +static int tusb_set_power(int state) +{ + int i, retval = 0; + + if (state) { + omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 1); + msleep(1); + + /* Wait until TUSB6010 pulls INT pin down */ + i = 100; + while (i && omap_get_gpio_datain(GPIO_TUSB_INT)) { + msleep(1); + i--; + } + + if (!i) { + printk(KERN_ERR "tusb: powerup failed\n"); + retval = -ENODEV; + } + } else { + omap_set_gpio_dataout(GPIO_TUSB_ENABLE, 0); + msleep(10); + } + + return retval; +} + +void __init n800_usb_init(void) +{ + int ret = 0; + static char announce[] __initdata = KERN_INFO "TUSB 6010\n"; + + /* PM companion chip power control pin */ + ret = omap_request_gpio(GPIO_TUSB_ENABLE); + if (ret != 0) { + printk(KERN_ERR "Could not get TUSB power GPIO%i\n", + GPIO_TUSB_ENABLE); + return; + } + omap_set_gpio_direction(GPIO_TUSB_ENABLE, 0); + + tusb_set_power(0); + + ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2, + TUSB_ASYNC_CS, TUSB_SYNC_CS, + GPIO_TUSB_INT, 0x3f); + if (ret != 0) + goto err; + + printk(announce); + + return; + +err: + omap_free_gpio(GPIO_TUSB_ENABLE); +} diff --git a/arch/arm/mach-omap2/board-n800.c b/arch/arm/mach-omap2/board-n800.c new file mode 100644 index 00000000000..73ff6236112 --- /dev/null +++ b/arch/arm/mach-omap2/board-n800.c @@ -0,0 +1,515 @@ +/* + * linux/arch/arm/mach-omap2/board-n800.c + * + * Copyright (C) 2005 Nokia Corporation + * Author: Juha Yrjola + * + * Modified from mach-omap2/board-generic.c + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <../drivers/cbus/tahvo.h> + +#define N800_BLIZZARD_POWERDOWN_GPIO 15 +#define N800_STI_GPIO 62 +#define N800_CAM_SENSOR_RESET_GPIO 53 +#define N800_KEYB_IRQ_GPIO 109 + +static void __init nokia_n800_init_irq(void) +{ + omap2_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); + +#ifdef CONFIG_OMAP_STI + if (omap_request_gpio(N800_STI_GPIO) < 0) { + printk(KERN_ERR "Failed to request GPIO %d for STI\n", + N800_STI_GPIO); + return; + } + + omap_set_gpio_direction(N800_STI_GPIO, 0); + omap_set_gpio_dataout(N800_STI_GPIO, 0); +#endif +} + +#if defined(CONFIG_MENELAUS) && defined(CONFIG_SENSORS_TMP105) + +static int n800_tmp105_set_power(int enable) +{ + return menelaus_set_vaux(enable ? 2800 : 0); +} + +#else + +#define n800_tmp105_set_power NULL + +#endif + +static struct omap_uart_config n800_uart_config __initdata = { + .enabled_uarts = (1 << 0) | (1 << 2), +}; + +#include "../../../drivers/cbus/retu.h" + +static struct omap_fbmem_config n800_fbmem0_config __initdata = { + .size = 752 * 1024, +}; + +static struct omap_fbmem_config n800_fbmem1_config __initdata = { + .size = 752 * 1024, +}; + +static struct omap_fbmem_config n800_fbmem2_config __initdata = { + .size = 752 * 1024, +}; + +static struct omap_tmp105_config n800_tmp105_config __initdata = { + .tmp105_irq_pin = 125, + .set_power = n800_tmp105_set_power, +}; + +static void mipid_shutdown(struct mipid_platform_data *pdata) +{ + if (pdata->nreset_gpio != -1) { + pr_info("shutdown LCD\n"); + omap_set_gpio_dataout(pdata->nreset_gpio, 0); + msleep(120); + } +} + +static struct mipid_platform_data n800_mipid_platform_data = { + .shutdown = mipid_shutdown, +}; + +static void __init mipid_dev_init(void) +{ + const struct omap_lcd_config *conf; + + conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (conf != NULL) { + n800_mipid_platform_data.nreset_gpio = conf->nreset_gpio; + n800_mipid_platform_data.data_lines = conf->data_lines; + } +} + +static struct { + struct clk *sys_ck; +} blizzard; + +static int blizzard_get_clocks(void) +{ + blizzard.sys_ck = clk_get(0, "osc_ck"); + if (IS_ERR(blizzard.sys_ck)) { + printk(KERN_ERR "can't get Blizzard clock\n"); + return PTR_ERR(blizzard.sys_ck); + } + return 0; +} + +static unsigned long blizzard_get_clock_rate(struct device *dev) +{ + return clk_get_rate(blizzard.sys_ck); +} + +static void blizzard_enable_clocks(int enable) +{ + if (enable) + clk_enable(blizzard.sys_ck); + else + clk_disable(blizzard.sys_ck); +} + +static void blizzard_power_up(struct device *dev) +{ + /* Vcore to 1.475V */ + tahvo_set_clear_reg_bits(0x07, 0, 0xf); + msleep(10); + + blizzard_enable_clocks(1); + omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1); +} + +static void blizzard_power_down(struct device *dev) +{ + omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 0); + blizzard_enable_clocks(0); + + /* Vcore to 1.005V */ + tahvo_set_clear_reg_bits(0x07, 0xf, 0); +} + +static struct blizzard_platform_data n800_blizzard_data = { + .power_up = blizzard_power_up, + .power_down = blizzard_power_down, + .get_clock_rate = blizzard_get_clock_rate, + .te_connected = 1, +}; + +static void __init blizzard_dev_init(void) +{ + int r; + + r = omap_request_gpio(N800_BLIZZARD_POWERDOWN_GPIO); + if (r < 0) + return; + omap_set_gpio_direction(N800_BLIZZARD_POWERDOWN_GPIO, 0); + omap_set_gpio_dataout(N800_BLIZZARD_POWERDOWN_GPIO, 1); + + blizzard_get_clocks(); + omapfb_set_ctrl_platform_data(&n800_blizzard_data); +} + +#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_VIDEO_CAMERA_SENSOR_TCM825X) && \ + defined(CONFIG_MENELAUS) +#define SUPPORT_SENSOR +#endif + +#ifdef SUPPORT_SENSOR + +static int sensor_okay; + +/* + * VSIM1 --> CAM_IOVDD --> IOVDD (1.8 V) + */ +static int tcm825x_sensor_power_on(void *data) +{ + int ret; + + if (!sensor_okay) + return -ENODEV; + + /* Set VMEM to 1.5V and VIO to 2.5V */ + ret = menelaus_set_vmem(1500); + if (ret < 0) { + /* Try once more, it seems the sensor power up causes + * some problems on the I2C bus. */ + ret = menelaus_set_vmem(1500); + if (ret < 0) + return ret; + } + msleep(1); + + ret = menelaus_set_vio(2500); + if (ret < 0) + return ret; + + /* Set VSim1 on */ + retu_write_reg(RETU_REG_CTRL_SET, 0x0080); + msleep(100); + + omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 1); + msleep(1); + + return 0; +} + +static int tcm825x_sensor_power_off(void * data) +{ + int ret; + + omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0); + msleep(1); + + /* Set VSim1 off */ + retu_write_reg(RETU_REG_CTRL_CLR, 0x0080); + msleep(1); + + /* Set VIO_MODE to off */ + ret = menelaus_set_vio(0); + if (ret < 0) + return ret; + msleep(1); + + /* Set VMEM_MODE to off */ + ret = menelaus_set_vmem(0); + if (ret < 0) + return ret; + msleep(1); + + return 0; +} + +static struct omap_camera_sensor_config n800_sensor_config = { + .power_on = tcm825x_sensor_power_on, + .power_off = tcm825x_sensor_power_off, +}; + +static void __init n800_cam_init(void) +{ + int r; + + r = omap_request_gpio(N800_CAM_SENSOR_RESET_GPIO); + if (r < 0) + return; + + omap_set_gpio_dataout(N800_CAM_SENSOR_RESET_GPIO, 0); + omap_set_gpio_direction(N800_CAM_SENSOR_RESET_GPIO, 0); + + sensor_okay = 1; +} + +#else + +static inline void n800_cam_init(void) {} + +#endif + +static struct omap_board_config_kernel n800_config[] = { + { OMAP_TAG_UART, &n800_uart_config }, +#ifdef SUPPORT_SENSOR + { OMAP_TAG_CAMERA_SENSOR, &n800_sensor_config }, +#endif + { OMAP_TAG_FBMEM, &n800_fbmem0_config }, + { OMAP_TAG_FBMEM, &n800_fbmem1_config }, + { OMAP_TAG_FBMEM, &n800_fbmem2_config }, + { OMAP_TAG_TMP105, &n800_tmp105_config }, +}; + + +static int n800_get_keyb_irq_state(struct device *dev) +{ + return !omap_get_gpio_datain(N800_KEYB_IRQ_GPIO); +} + +static struct tsc2301_platform_data tsc2301_config = { + .reset_gpio = 118, + .dav_gpio = 103, + .pen_int_gpio = 106, + .keymap = { + -1, /* Event for bit 0 */ + KEY_UP, /* Event for bit 1 (up) */ + KEY_F5, /* Event for bit 2 (home) */ + -1, /* Event for bit 3 */ + KEY_LEFT, /* Event for bit 4 (left) */ + KEY_ENTER, /* Event for bit 5 (enter) */ + KEY_RIGHT, /* Event for bit 6 (right) */ + -1, /* Event for bit 7 */ + KEY_ESC, /* Event for bit 8 (cycle) */ + KEY_DOWN, /* Event for bit 9 (down) */ + KEY_F4, /* Event for bit 10 (menu) */ + -1, /* Event for bit 11 */ + KEY_F8, /* Event for bit 12 (Zoom-) */ + KEY_F6, /* Event for bit 13 (FS) */ + KEY_F7, /* Event for bit 14 (Zoom+) */ + -1, /* Event for bit 15 */ + }, + .kp_rep = 0, + .get_keyb_irq_state = n800_get_keyb_irq_state, +}; + +static void tsc2301_dev_init(void) +{ + int gpio = N800_KEYB_IRQ_GPIO; + + if (omap_request_gpio(gpio) < 0) { + printk(KERN_ERR "can't get KBIRQ GPIO\n"); + return; + } + omap_set_gpio_direction(gpio, 1); + tsc2301_config.keyb_int = OMAP_GPIO_IRQ(gpio); +} + +static struct omap2_mcspi_device_config tsc2301_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct omap2_mcspi_device_config mipid_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct omap2_mcspi_device_config cx3110x_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct spi_board_info n800_spi_board_info[] __initdata = { + [0] = { + .modalias = "lcd_mipid", + .bus_num = 1, + .chip_select = 1, + .max_speed_hz = 4000000, + .controller_data= &mipid_mcspi_config, + .platform_data = &n800_mipid_platform_data, + }, [1] = { + .modalias = "cx3110x", + .bus_num = 2, + .chip_select = 0, + .max_speed_hz = 48000000, + .controller_data= &cx3110x_mcspi_config, + }, [2] = { + .modalias = "tsc2301", + .bus_num = 1, + .chip_select = 0, + .max_speed_hz = 6000000, + .controller_data= &tsc2301_mcspi_config, + .platform_data = &tsc2301_config, + }, +}; + +#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM) + +void retu_keypad_led_set_power(struct omap_pwm_led_platform_data *self, + int on_off) +{ + if (on_off) { + retu_write_reg(RETU_REG_CTRL_SET, 1 << 6); + msleep(2); + retu_write_reg(RETU_REG_CTRL_SET, 1 << 3); + } else { + retu_write_reg(RETU_REG_CTRL_CLR, (1 << 6) | (1 << 3)); + } +} + +static struct omap_pwm_led_platform_data n800_keypad_led_data = { + .name = "keypad", + .intensity_timer = 10, + .blink_timer = 9, + .set_power = retu_keypad_led_set_power, +}; + +static struct platform_device n800_keypad_led_device = { + .name = "omap_pwm_led", + .id = -1, + .dev = { + .platform_data = &n800_keypad_led_data, + }, +}; +#endif + +#if defined(CONFIG_TOUCHSCREEN_TSC2301) +static void __init n800_ts_set_config(void) +{ + const struct omap_lcd_config *conf; + + conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config); + if (conf != NULL) { + if (strcmp(conf->panel_name, "lph8923") == 0) { + tsc2301_config.ts_x_plate_ohm = 180; + tsc2301_config.ts_hw_avg = 4; + tsc2301_config.ts_ignore_last = 1; + tsc2301_config.ts_max_pressure = 255; + tsc2301_config.ts_stab_time = 100; + } else if (strcmp(conf->panel_name, "ls041y3") == 0) { + tsc2301_config.ts_x_plate_ohm = 280; + tsc2301_config.ts_hw_avg = 16; + tsc2301_config.ts_touch_pressure= 215; + tsc2301_config.ts_max_pressure = 255; + tsc2301_config.ts_ignore_last = 1; + } else { + printk(KERN_ERR "Unknown panel type, set default " + "touchscreen configuration\n"); + tsc2301_config.ts_x_plate_ohm = 200; + tsc2301_config.ts_stab_time = 100; + } + } +} +#else +static inline void n800_ts_set_config(void) +{ +} +#endif + +static struct omap_gpio_switch n800_gpio_switches[] __initdata = { + { + .name = "bat_cover", + .gpio = -1, + .debounce_rising = 100, + .debounce_falling = 0, + .notify = n800_mmc_slot1_cover_handler, + .notify_data = NULL, + }, { + .name = "headphone", + .gpio = -1, + .debounce_rising = 200, + .debounce_falling = 200, + }, { + .name = "cam_act", + .gpio = -1, + .debounce_rising = 200, + .debounce_falling = 200, + }, { + .name = "cam_turn", + .gpio = -1, + .debounce_rising = 100, + .debounce_falling = 100, + }, +}; + +static struct platform_device *n800_devices[] __initdata = { +#if defined(CONFIG_CBUS_RETU) && defined(CONFIG_LEDS_OMAP_PWM) + &n800_keypad_led_device, +#endif +}; + +static void __init nokia_n800_init(void) +{ + platform_add_devices(n800_devices, ARRAY_SIZE(n800_devices)); + n800_flash_init(); + n800_mmc_init(); + n800_bt_init(); + n800_audio_init(&tsc2301_config); + n800_dsp_init(); + n800_usb_init(); + n800_cam_init(); + n800_ts_set_config(); + spi_register_board_info(n800_spi_board_info, + ARRAY_SIZE(n800_spi_board_info)); + omap_serial_init(); + mipid_dev_init(); + blizzard_dev_init(); + tsc2301_dev_init(); + omap_register_gpio_switches(n800_gpio_switches, + ARRAY_SIZE(n800_gpio_switches)); + n800_pm_init(); +} + +static void __init nokia_n800_map_io(void) +{ + omap_board_config = n800_config; + omap_board_config_size = ARRAY_SIZE(n800_config); + + omap2_map_common_io(); +} + +MACHINE_START(NOKIA_N800, "Nokia N800") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = nokia_n800_map_io, + .init_irq = nokia_n800_init_irq, + .init_machine = nokia_n800_init, + .timer = &omap_timer, +MACHINE_END diff --git a/include/asm-arm/arch-omap/board-nokia.h b/include/asm-arm/arch-omap/board-nokia.h index 72deea20349..010eb052e36 100644 --- a/include/asm-arm/arch-omap/board-nokia.h +++ b/include/asm-arm/arch-omap/board-nokia.h @@ -11,12 +11,24 @@ #include +struct tsc2301_platform_data; +struct dsp_kfunc_device; +extern void n800_bt_init(void); +extern void n800_dsp_init(void); +extern void n800_flash_init(void); +extern void n800_mmc_init(void); +extern void n800_pm_init(void); +extern void n800_usb_init(void); +extern void n800_audio_init(struct tsc2301_platform_data *); +extern int n800_audio_enable(struct dsp_kfunc_device *kdev, int stage); +extern int n800_audio_disable(struct dsp_kfunc_device *kdev, int stage); +extern void n800_mmc_slot1_cover_handler(void *arg, int state); + #define OMAP_TAG_NOKIA_BT 0x4e01 #define OMAP_TAG_WLAN_CX3110X 0x4e02 #define OMAP_TAG_CBUS 0x4e03 #define OMAP_TAG_EM_ASIC_BB5 0x4e04 - #define BT_CHIP_CSR 1 #define BT_CHIP_TI 2 diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h index 18442f85031..bbadf08a4d2 100644 --- a/include/asm-arm/arch-omap/board.h +++ b/include/asm-arm/arch-omap/board.h @@ -25,9 +25,12 @@ #define OMAP_TAG_FBMEM 0x4f08 #define OMAP_TAG_STI_CONSOLE 0x4f09 #define OMAP_TAG_CAMERA_SENSOR 0x4f0a +#define OMAP_TAG_PARTITION 0x4f0b +#define OMAP_TAG_TEA5761 0x4f10 +#define OMAP_TAG_TMP105 0x4f11 #define OMAP_TAG_BOOT_REASON 0x4f80 -#define OMAP_TAG_FLASH_PART 0x4f81 +#define OMAP_TAG_FLASH_PART_STR 0x4f81 #define OMAP_TAG_VERSION_STR 0x4f82 struct omap_clock_config { @@ -139,8 +142,25 @@ struct omap_uart_config { unsigned int enabled_uarts; }; +struct omap_tea5761_config { + u16 enable_gpio; +}; + +/* This cannot be passed from the bootloader */ +struct omap_tmp105_config { + u16 tmp105_irq_pin; + int (* set_power)(int enable); +}; + +struct omap_partition_config { + char name[16]; + unsigned int size; + unsigned int offset; + /* same as in include/linux/mtd/partitions.h */ + unsigned int mask_flags; +}; -struct omap_flash_part_config { +struct omap_flash_part_str_config { char part_table[0]; }; diff --git a/include/asm-arm/arch-omap/onenand.h b/include/asm-arm/arch-omap/onenand.h index b8a19beae12..3e8ab2f49c9 100644 --- a/include/asm-arm/arch-omap/onenand.h +++ b/include/asm-arm/arch-omap/onenand.h @@ -16,4 +16,5 @@ struct omap_onenand_platform_data { int gpio_irq; struct mtd_partition *parts; int nr_parts; + int (*onenand_setup)(void __iomem *); }; -- 2.41.0