aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-s3c6410/mach-om-3d7k.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c6410/mach-om-3d7k.c')
-rw-r--r--arch/arm/mach-s3c6410/mach-om-3d7k.c1069
1 files changed, 1069 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c6410/mach-om-3d7k.c b/arch/arm/mach-s3c6410/mach-om-3d7k.c
new file mode 100644
index 00000000000..6afd12e487d
--- /dev/null
+++ b/arch/arm/mach-s3c6410/mach-om-3d7k.c
@@ -0,0 +1,1069 @@
+/* linux/arch/arm/mach-s3c6410/mach-om-3d7k.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Andy Green <andy@openmoko.org>
+ *
+ * based on mach_smdk6410.c which is
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/lis302dl.h>
+#include <linux/lp5521.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/l1k002.h>
+#include <linux/pcap7200.h>
+#include <linux/bq27000_battery.h>
+#include <linux/hdq.h>
+
+#include <video/platform_lcd.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <asm/hardware/vic.h>
+#include <asm/hardware/tzic-sp890.h>
+#include <mach/map.h>
+#include <mach/regs-fb.h>
+#include <mach/spi-gpio.h>
+
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/fiq.h>
+
+#include <plat/regs-serial.h>
+#include <plat/regs-timer.h>
+#include <plat/regs-gpio.h>
+#include <plat/iic.h>
+#include <plat/fb.h>
+#include <plat/gpio-cfg.h>
+#include <plat/pm.h>
+#include <plat/pwm.h>
+
+#include <plat/s3c6410.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/tzic-sp890.h>
+
+/* #include <plat/udc.h> */
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/om-3d7k.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/mbc.h>
+#include <linux/mfd/pcf50633/adc.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/mfd/pcf50633/pmic.h>
+
+#include <plat/regs-usb-hs-otg.h>
+
+extern struct platform_device s3c_device_usbgadget;
+
+/* -------------------------------------------------------------------------------
+ * OM_3D7K FIQ related
+ *
+ * Calls into vibrator and hdq and based on the return values
+ * determines if we the FIQ source be kept alive
+ */
+
+#define DIVISOR_FROM_US(x) ((x) * 23)
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+#define FIQ_DIVISOR_HDQ DIVISOR_FROM_US(20)
+extern int hdq_fiq_handler(void);
+#endif
+
+/* Global data related to our fiq source */
+static u32 om_3d7k_fiq_ack_mask;
+static u32 om_3d7k_fiq_mod_mask;
+static struct s3c2410_pwm om_3d7k_fiq_pwm_timer;
+static u16 om_3d7k_fiq_timer_index;
+static int om_3d7k_fiq_irq;
+
+/* Convinience defines */
+#define S3C6410_INTMSK (S3C_VA_VIC0 + VIC_INT_ENABLE)
+#define S3C6410_INTMOD (S3C_VA_VIC0 + VIC_INT_SELECT)
+
+
+
+static void om_3d7k_fiq_handler(void)
+{
+ u16 divisor = 0xffff;
+
+ /* Vibrator servicing */
+
+ /* disable further timer interrupts if nobody has any work
+ * or adjust rate according to who still has work
+ *
+ * CAUTION: it means forground code must disable FIQ around
+ * its own non-atomic S3C2410_INTMSK changes... not common
+ * thankfully and taken care of by the fiq-basis patch
+ */
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+ if (hdq_fiq_handler())
+ divisor = FIQ_DIVISOR_HDQ;
+#endif
+
+ if (divisor == 0xffff) /* mask the fiq irq source */
+ __raw_writel((__raw_readl(S3C64XX_TINT_CSTAT) & 0x1f) & ~(1 << 3),
+ S3C64XX_TINT_CSTAT);
+ else /* still working, maybe at a different rate */
+ __raw_writel(divisor, S3C2410_TCNTB(om_3d7k_fiq_timer_index));
+
+ __raw_writel((__raw_readl(S3C64XX_TINT_CSTAT) & 0x1f ) | 1 << 8 , S3C64XX_TINT_CSTAT);
+
+}
+
+static void om_3d7k_fiq_kick(void)
+{
+ unsigned long flags;
+ u32 tcon;
+
+ /* we have to take care about FIQ because this modification is
+ * non-atomic, FIQ could come in after the read and before the
+ * writeback and its changes to the register would be lost
+ * (platform INTMSK mod code is taken care of already)
+ */
+ local_save_flags(flags);
+ local_fiq_disable();
+ /* allow FIQs to resume */
+ __raw_writel((__raw_readl(S3C64XX_TINT_CSTAT) & 0x1f)| 1 << 3,
+ S3C64XX_TINT_CSTAT);
+
+ tcon = __raw_readl(S3C2410_TCON) & ~S3C2410_TCON_T3START;
+ /* fake the timer to a count of 1 */
+ __raw_writel(1, S3C2410_TCNTB(om_3d7k_fiq_timer_index));
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD, S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3MANUALUPD | S3C2410_TCON_T3START,
+ S3C2410_TCON);
+ __raw_writel(tcon | S3C2410_TCON_T3START, S3C2410_TCON);
+ local_irq_restore(flags);
+}
+
+static int om_3d7k_fiq_enable(void)
+{
+ int irq_index_fiq = IRQ_TIMER3_VIC;
+ int rc = 0;
+
+ local_fiq_disable();
+
+ om_3d7k_fiq_irq = irq_index_fiq;
+ om_3d7k_fiq_ack_mask = 1 << 3;
+ om_3d7k_fiq_mod_mask = 1 << 27;
+ om_3d7k_fiq_timer_index = 3;
+
+ /* set up the timer to operate as a pwm device */
+
+ rc = s3c2410_pwm_init(&om_3d7k_fiq_pwm_timer);
+ if (rc)
+ goto bail;
+
+ om_3d7k_fiq_pwm_timer.timerid = PWM0 + om_3d7k_fiq_timer_index;
+ om_3d7k_fiq_pwm_timer.prescaler = ((6 - 1) / 2);
+ om_3d7k_fiq_pwm_timer.divider = S3C64XX_TCFG1_MUX_DIV2 << S3C2410_TCFG1_SHIFT(3);
+ /* default rate == ~32us */
+ om_3d7k_fiq_pwm_timer.counter = om_3d7k_fiq_pwm_timer.comparer = 3000;
+
+ rc = s3c2410_pwm_enable(&om_3d7k_fiq_pwm_timer);
+ if (rc)
+ goto bail;
+
+ /* let our selected interrupt be a magic FIQ interrupt */
+ __raw_writel(om_3d7k_fiq_mod_mask, S3C6410_INTMSK + 4);
+ __raw_writel(om_3d7k_fiq_mod_mask, S3C6410_INTMOD);
+ __raw_writel(om_3d7k_fiq_mod_mask, S3C6410_INTMSK);
+
+ __raw_writel(SP890_TZIC_UNLOCK_MAGIC, S3C64XX_VA_TZIC0_LOCK);
+ __raw_writel(om_3d7k_fiq_mod_mask, S3C64XX_VA_TZIC0_FIQENABLE);
+ __raw_writel(om_3d7k_fiq_mod_mask, S3C64XX_VA_TZIC0_INTSELECT);
+
+ s3c2410_pwm_start(&om_3d7k_fiq_pwm_timer);
+
+ /* it's ready to go as soon as we unmask the source in S3C2410_INTMSK */
+ local_fiq_enable();
+
+ set_fiq_c_handler(om_3d7k_fiq_handler);
+
+ if (rc < 0)
+ goto bail;
+
+ return 0;
+bail:
+ printk(KERN_ERR "Count not initialize FIQ for OM_3D7K %d \n", rc);
+ return rc;
+}
+
+static void om_3d7k_fiq_disable(void)
+{
+ __raw_writel(0, S3C6410_INTMOD);
+ local_fiq_disable();
+ om_3d7k_fiq_irq = 0; /* no active source interrupt now either */
+
+}
+/* -------------------- /OM_3D7K FIQ Handler ------------------------------------- */
+
+#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg om_3d7k_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [3] = {
+ .hwport = 3,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+};
+
+
+/*
+ * Situation is that Linux SPI can't work in an interrupt context, so we
+ * implement our own bitbang here. Arbitration is needed because not only
+ * can this interrupt happen at any time even if foreground wants to use
+ * the bitbang API from Linux, but multiple motion sensors can be on the
+ * same SPI bus, and multiple interrupts can happen.
+ *
+ * Foreground / interrupt arbitration is okay because the interrupts are
+ * disabled around all the foreground SPI code.
+ *
+ * Interrupt / Interrupt arbitration is evidently needed, otherwise we
+ * lose edge-triggered service after a while due to the two sensors sharing
+ * the SPI bus having irqs at the same time eventually.
+ *
+ * Servicing is typ 75 - 100us at 400MHz.
+ */
+
+/* #define DEBUG_SPEW_MS */
+#define MG_PER_SAMPLE 18
+
+struct lis302dl_platform_data lis302_pdata;
+
+/*
+ * generic SPI RX and TX bitbang
+ * only call with interrupts off!
+ */
+
+static void __3d7k_lis302dl_bitbang(struct lis302dl_info *lis, u8 *tx,
+ int tx_bytes, u8 *rx, int rx_bytes)
+{
+ struct lis302dl_platform_data *pdata = lis->pdata;
+ int n;
+ u8 shifter = 0;
+
+ gpio_direction_output(pdata->pin_chip_select, 1);
+ gpio_direction_output(pdata->pin_clk, 1);
+ gpio_direction_output(pdata->pin_chip_select, 0);
+
+ /* send the register index, r/w and autoinc bits */
+ for (n = 0; n < (tx_bytes << 3); n++) {
+ if (!(n & 7))
+ shifter = ~tx[n >> 3];
+ gpio_direction_output(pdata->pin_clk, 0);
+ gpio_direction_output(pdata->pin_mosi, !(shifter & 0x80));
+ gpio_direction_output(pdata->pin_clk, 1);
+ shifter <<= 1;
+ }
+
+ for (n = 0; n < (rx_bytes << 3); n++) { /* 8 bits each */
+ gpio_direction_output(pdata->pin_clk, 0);
+ shifter <<= 1;
+ if (gpio_direction_input(pdata->pin_miso))
+ shifter |= 1;
+ if ((n & 7) == 7)
+ rx[n >> 3] = shifter;
+ gpio_direction_output(pdata->pin_clk, 1);
+ }
+ gpio_direction_output(pdata->pin_chip_select, 1);
+}
+
+
+static int om_3d7k_lis302dl_bitbang_read_reg(struct lis302dl_info *lis, u8 reg)
+{
+ u8 data = 0xc0 | reg; /* read, autoincrement */
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ __3d7k_lis302dl_bitbang(lis, &data, 1, &data, 1);
+
+ local_irq_restore(flags);
+
+ return data;
+}
+
+static void om_3d7k_lis302dl_bitbang_write_reg(struct lis302dl_info *lis, u8 reg,
+ u8 val)
+{
+ u8 data[2] = { 0x00 | reg, val }; /* write, no autoincrement */
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ __3d7k_lis302dl_bitbang(lis, &data[0], 2, NULL, 0);
+
+ local_irq_restore(flags);
+
+}
+
+
+void om_3d7k_lis302dl_suspend_io(struct lis302dl_info *lis, int resume)
+{
+ struct lis302dl_platform_data *pdata = lis->pdata;
+
+ if (!resume) {
+ /*
+ * we don't want to power them with a high level
+ * because GSENSOR_3V3 is not up during suspend
+ */
+ gpio_direction_output(pdata->pin_chip_select, 0);
+ gpio_direction_output(pdata->pin_clk, 0);
+ gpio_direction_output(pdata->pin_mosi, 0);
+ s3c_gpio_setpull(pdata->pin_miso, S3C_GPIO_PULL_DOWN);
+
+ return;
+ }
+
+ /* back to normal */
+ gpio_direction_output(pdata->pin_chip_select, 1);
+ gpio_direction_output(pdata->pin_clk, 1);
+ s3c_gpio_setpull(pdata->pin_miso, S3C_GPIO_PULL_NONE);
+
+ s3c_gpio_cfgpin(pdata->pin_chip_select, S3C_GPIO_SFN(1));
+ s3c_gpio_cfgpin(pdata->pin_clk, S3C_GPIO_SFN(1));
+ s3c_gpio_cfgpin(pdata->pin_mosi, S3C_GPIO_SFN(1));
+ s3c_gpio_cfgpin(pdata->pin_miso, S3C_GPIO_SFN(0));
+
+}
+#if 0
+struct lis302dl_platform_data lis302_pdata = {
+ .name = "lis302",
+ .pin_chip_select= S3C64XX_GPC(3), /* NC */
+ .pin_clk = OM_3D7K_GPIO_ACCEL_CLK,
+ .pin_mosi = OM_3D7K_GPIO_ACCEL_MOSI,
+ .pin_miso = OM_3D7K_GPIO_ACCEL_MISO,
+ .interrupt = OM_3D7K_IRQ_GSENSOR_1,
+ .open_drain = 0,
+ .lis302dl_bitbang = __3d7k_lis302dl_bitbang,
+ .lis302dl_bitbang_reg_read = om_3d7k_lis302dl_bitbang_read_reg,
+ .lis302dl_bitbang_reg_write = om_3d7k_lis302dl_bitbang_write_reg,
+ .lis302dl_suspend_io = om_3d7k_lis302dl_suspend_io,
+};
+
+static struct platform_device s3c_device_spi_acc1 = {
+ .name = "lis302dl",
+ .id = 1,
+ .dev = {
+ .platform_data = &lis302_pdata,
+ },
+};
+
+#endif
+
+/* framebuffer and LCD setup. */
+
+/* GPF15 = LCD backlight control
+ * GPF13 => Panel power
+ * GPN5 = LCD nRESET signal
+ * PWM_TOUT1 => backlight brightness
+ */
+
+static void om_3d7k_lcd_power_set(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+
+}
+
+static struct plat_lcd_data om_3d7k_lcd_power_data = {
+ .set_power = om_3d7k_lcd_power_set,
+};
+
+static struct platform_device om_3d7k_lcd_powerdev = {
+ .name = "platform-lcd",
+ .dev.parent = &s3c_device_fb.dev,
+ .dev.platform_data = &om_3d7k_lcd_power_data,
+};
+
+static struct s3c_fb_pd_win om_3d7k_fb_win0 = {
+ /* this is to ensure we use win0 */
+ .win_mode = {
+ .pixclock = 40816,
+ .left_margin = 8,
+ .right_margin = 16,
+ .upper_margin = 2,
+ .lower_margin = 16,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .xres = 480,
+ .yres = 640,
+ },
+ .max_bpp = 32,
+ .default_bpp = 16,
+};
+
+static void om_3d7k_fb_gpio_setup(void)
+{
+ unsigned int gpio;
+
+ /* GPI0, GPI1, GPI8 are for hardware version contrl.
+ * They should be set as input in order to prevent
+ * current leaking
+ */
+ for (gpio = S3C64XX_GPI(2); gpio <= S3C64XX_GPI(15); gpio++) {
+ if (gpio != S3C64XX_GPI(8)) {
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+ }
+ }
+
+ for (gpio = S3C64XX_GPJ(0); gpio <= S3C64XX_GPJ(11); gpio++) {
+ s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2));
+ s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE);
+ }
+}
+
+static struct s3c_fb_platdata om_3d7k_lcd_pdata __initdata = {
+ .setup_gpio = om_3d7k_fb_gpio_setup,
+ .win[0] = &om_3d7k_fb_win0,
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+ .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+};
+
+
+struct map_desc om_3d7k_6410_iodesc[] = {};
+
+static struct resource om_3d7k_button_resources[] = {
+ [0] = {
+ .start = 0,
+ .end = 0,
+ },
+ [1] = {
+ .start = OM_3D7K_GPIO_HOLD,
+ .end = OM_3D7K_GPIO_HOLD,
+ },
+ [2] = {
+ .start = OM_3D7K_GPIO_JACK_INSERT,
+ .end = OM_3D7K_GPIO_JACK_INSERT,
+ },
+ [3] = {
+ .start = OM_3D7K_GPIO_KEY_PLUS,
+ .end = OM_3D7K_GPIO_KEY_PLUS,
+ },
+ [4] = {
+ .start = OM_3D7K_GPIO_KEY_MINUS,
+ .end = OM_3D7K_GPIO_KEY_MINUS,
+ },
+};
+
+static struct platform_device om_3d7k_button_dev = {
+ .name = "neo1973-button",
+ .num_resources = ARRAY_SIZE(om_3d7k_button_resources),
+ .resource = om_3d7k_button_resources,
+};
+
+
+/********************** PMU ***************************/
+/*
+ * OM_3D7K PMU Mapping info
+ *
+ * name maxcurr default Nom consumers
+ *
+ * AUTO 1100mA ON 3.3V 3.3V Main 3.3V rail
+ * DOWN1 500mA ON 1.2V 1.2V CPU VddARM, VddINT, VddMPLL, VddOTGI
+ * DOWN2 500mA ON 1.8V 1.8V CPU VddAlive via LDO, Memories, WLAN
+ * LED 25mA OFF 18V Backlight
+ * HCLDO 200mA OFF 2.8V Camera 2V8
+ * LDO1 50mA ON 3.3V 3.3V Accel
+ * LDO2 50mA OFF 1.5V Camera 1V5
+ * LDO3 50mA OFF 3.3V CODEC 3.3V
+ * LDO4 150mA ON 2.8V 2.7V uSD power
+ * LDO5 150mA OFF 3.0V GPS 3V
+ * LDO6 50mA ON 3.0V 3.0V LCM 3V
+ *
+ */
+
+
+/* PMU driver info */
+
+
+static struct regulator_consumer_supply ldo4_consumers[] = {
+ {
+ .dev = &s3c_device_hsmmc0.dev,
+ .supply = "SD_3V",
+ },
+};
+
+static struct platform_device om_3d7k_features_dev = {
+ .name = "om-3d7k",
+};
+
+static struct regulator_consumer_supply ldo5_consumers[] = {
+ {
+ .dev = &om_3d7k_features_dev.dev,
+ .supply = "RF_3V",
+ },
+};
+
+
+static void om_3d7k_pmu_event_callback(struct pcf50633 *pcf, int irq)
+{
+#if 0
+ if (irq == PCF50633_IRQ_USBINS) {
+ schedule_delayed_work(&om_3d7k_charger_work,
+ GTA02_CHARGER_CONFIGURE_TIMEOUT);
+ return;
+ } else if (irq == PCF50633_IRQ_USBREM) {
+ cancel_delayed_work_sync(&om_3d7k_charger_work);
+ pcf50633_mbc_usb_curlim_set(pcf, 0);
+ om_3d7k_usb_vbus_draw = 0;
+ }
+
+ bq27000_charging_state_change(&bq27000_battery_device);
+#endif
+}
+
+static void om_3d7k_pcf50633_attach_child_devices(struct pcf50633 *pcf);
+static void om_3d7k_pmu_regulator_registered(struct pcf50633 *pcf, int id);
+
+/* Global reference */
+struct pcf50633 *om_3d7k_pcf;
+
+struct pcf50633_platform_data om_3d7k_pcf_pdata = {
+
+ .resumers = {
+ [0] = PCF50633_INT1_USBINS |
+ PCF50633_INT1_USBREM |
+ PCF50633_INT1_ALARM,
+ [1] = PCF50633_INT2_ONKEYF,
+ [2] = PCF50633_INT3_ONKEY1S
+ },
+ .chg_ref_current_ma = 1000,
+ .reg_init_data = {
+ /* OM_3D7K: Main 3.3V rail */
+ [PCF50633_REGULATOR_AUTO] = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: CPU core power */
+ [PCF50633_REGULATOR_DOWN1] = {
+ .constraints = {
+ .min_uV = 900000,
+ .max_uV = 1200000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: Memories */
+ [PCF50633_REGULATOR_DOWN2] = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: Camera 2V8 */
+ [PCF50633_REGULATOR_HCLDO] = {
+ .constraints = {
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ },
+ .num_consumer_supplies = 0,
+/* .consumer_supplies = hcldo_consumers, */
+ },
+
+ /* OM_3D7K: Accel 3V3 */
+ [PCF50633_REGULATOR_LDO1] = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: Camera 1V5 */
+ [PCF50633_REGULATOR_LDO2] = {
+ .constraints = {
+ .min_uV = 1500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: Codec 3.3V */
+ [PCF50633_REGULATOR_LDO3] = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .always_on = 1,
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* OM_3D7K: uSD Power */
+ [PCF50633_REGULATOR_LDO4] = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = ldo4_consumers,
+ },
+ /* OM_3D7K: GPS 3V */
+ [PCF50633_REGULATOR_LDO5] = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = ldo5_consumers,
+ },
+ /* OM_3D7K: LCM 3V */
+ [PCF50633_REGULATOR_LDO6] = {
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3000000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+ /* power for memories in suspend */
+ [PCF50633_REGULATOR_MEMLDO] = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .state_mem = {
+ .enabled = 1,
+ },
+ },
+ .num_consumer_supplies = 0,
+ },
+
+ },
+ .probe_done = om_3d7k_pcf50633_attach_child_devices,
+ .regulator_registered = om_3d7k_pmu_regulator_registered,
+ .mbc_event_callback = om_3d7k_pmu_event_callback,
+};
+
+/* BQ27000 Battery */
+static int om_3d7k_get_charger_online_status(void)
+{
+ struct pcf50633 *pcf = om_3d7k_pcf;
+
+ return pcf50633_mbc_get_status(pcf) & PCF50633_MBC_USB_ONLINE;
+}
+
+static int om_3d7k_get_charger_active_status(void)
+{
+ struct pcf50633 *pcf = om_3d7k_pcf;
+
+ return pcf50633_mbc_get_status(pcf) & PCF50633_MBC_USB_ACTIVE;
+}
+
+
+struct bq27000_platform_data bq27000_pdata = {
+ .name = "battery",
+ .rsense_mohms = 20,
+ .hdq_read = hdq_read,
+ .hdq_write = hdq_write,
+ .hdq_initialized = hdq_initialized,
+ .get_charger_online_status = om_3d7k_get_charger_online_status,
+ .get_charger_active_status = om_3d7k_get_charger_active_status
+};
+
+struct platform_device bq27000_battery_device = {
+ .name = "bq27000-battery",
+ .dev = {
+ .platform_data = &bq27000_pdata,
+ },
+};
+
+#ifdef CONFIG_HDQ_GPIO_BITBANG
+/* HDQ */
+
+static void om_3d7k_hdq_attach_child_devices(struct device *parent_device)
+{
+ bq27000_battery_device.dev.parent = parent_device;
+ platform_device_register(&bq27000_battery_device);
+}
+
+static void om_3d7k_hdq_gpio_direction_out(void)
+{
+ unsigned long con;
+ void __iomem *regcon = S3C64XX_GPH_BASE;
+
+ con = __raw_readl(regcon);
+ con &= ~(0xf << 28);
+ con |= 0x01 << 28;
+ __raw_writel(con, regcon);
+
+ /* Set pull-up enabled */
+ con = __raw_readl(regcon + 0x0c);
+ con |= 3 << 14;
+ __raw_writel(con, regcon + 0x0c);
+}
+
+static void om_3d7k_hdq_gpio_direction_in(void)
+{
+ unsigned long con;
+ void __iomem *regcon = S3C64XX_GPH_BASE;
+
+ con = __raw_readl(regcon);
+ con &= ~(0xf << 28);
+ __raw_writel(con, regcon);
+}
+
+static void om_3d7k_hdq_gpio_set_value(int val)
+{
+ u32 dat;
+ void __iomem *base = S3C64XX_GPH_BASE;
+
+ dat = __raw_readl(base + 0x08);
+ if (val)
+ dat |= 1 << 7;
+ else
+ dat &= ~(1 << 7);
+
+ __raw_writel(dat, base + 0x08);
+}
+
+static int om_3d7k_hdq_gpio_get_value(void)
+{
+ u32 dat;
+ void *base = S3C64XX_GPH_BASE;
+
+ dat = __raw_readl(base + 0x08);
+
+ return dat & (1 << 7);
+}
+
+static struct resource om_3d7k_hdq_resources[] = {
+ [0] = {
+ .start = S3C64XX_GPH(7),
+ .end = S3C64XX_GPH(7),
+ },
+};
+
+struct hdq_platform_data om_3d7k_hdq_platform_data = {
+ .attach_child_devices = om_3d7k_hdq_attach_child_devices,
+ .gpio_dir_out = om_3d7k_hdq_gpio_direction_out,
+ .gpio_dir_in = om_3d7k_hdq_gpio_direction_in,
+ .gpio_set = om_3d7k_hdq_gpio_set_value,
+ .gpio_get = om_3d7k_hdq_gpio_get_value,
+
+ .enable_fiq = om_3d7k_fiq_enable,
+ .disable_fiq = om_3d7k_fiq_disable,
+ .kick_fiq = om_3d7k_fiq_kick,
+
+};
+
+struct platform_device om_3d7k_hdq_device = {
+ .name = "hdq",
+ .num_resources = 1,
+ .resource = om_3d7k_hdq_resources,
+ .dev = {
+ .platform_data = &om_3d7k_hdq_platform_data,
+ },
+};
+#endif
+
+static void om_3d7k_lp5521_chip_enable(int level)
+{
+ gpio_direction_output(OM_3D7K_GPIO_LED_EN, level);
+ mdelay(500);
+}
+
+static struct lp5521_platform_data om_3d7k_lp5521_pdata = {
+ .ext_enable = om_3d7k_lp5521_chip_enable,
+};
+
+static void om_3d7k_pcap7200_reset(void)
+{
+ gpio_direction_output(OM_3D7K_GPIO_TP_RESET, 1);
+ udelay(10);
+ gpio_direction_output(OM_3D7K_GPIO_TP_RESET, 0);
+}
+
+static struct pcap7200_platform_data om_3d7k_pcap7200_pdata = {
+ .mode = MULTI_TOUCH,
+ .reset = om_3d7k_pcap7200_reset,
+};
+
+static struct i2c_board_info om_3d7k_i2c_devs[] __initdata = {
+ {
+ I2C_BOARD_INFO("pcf50633", 0x73),
+ .irq = OM_3D7K_IRQ_PMU,
+ .platform_data = &om_3d7k_pcf_pdata,
+ },
+ {
+ I2C_BOARD_INFO("pcap7200", 0x0a),
+ .irq = OM_3D7K_IRQ_TOUCH,
+ .platform_data = &om_3d7k_pcap7200_pdata,
+ },
+ {
+ I2C_BOARD_INFO("lp5521", 0x32),
+ .irq = OM_3D7K_IRQ_LED,
+ .platform_data = &om_3d7k_lp5521_pdata,
+ },
+ {
+ I2C_BOARD_INFO("wm8753", 0x1a),
+ },
+};
+
+struct platform_device s3c24xx_pwm_device = {
+ .name = "s3c24xx_pwm",
+ .num_resources = 0,
+};
+
+struct platform_device om_3d7k_device_spi_lcm;
+
+static struct platform_device *om_3d7k_devices[] __initdata = {
+ &s3c_device_fb,
+ &s3c_device_i2c0,
+ &om_3d7k_device_spi_lcm,
+ &s3c_device_usbgadget,
+ &s3c24xx_pwm_device,
+};
+
+
+static void om_3d7k_pmu_regulator_registered(struct pcf50633 *pcf, int id)
+{
+ struct platform_device *regulator, *pdev;
+
+ regulator = pcf->regulator_pdev[id];
+
+ switch(id) {
+ case PCF50633_REGULATOR_LDO4:
+ pdev = &s3c_device_hsmmc0; /* uSD card */
+ break;
+ case PCF50633_REGULATOR_LDO5: /* GPS regulator */
+ pdev = &om_3d7k_features_dev;
+ break;
+ case PCF50633_REGULATOR_LDO6:
+ pdev = &om_3d7k_lcd_powerdev;
+ break;
+ default:
+ return;
+ }
+
+ pdev->dev.parent = &regulator->dev;
+ platform_device_register(pdev);
+}
+
+static struct platform_device *om_3d7k_devices_pmu_children[] = {
+ &om_3d7k_button_dev,
+// &s3c_device_spi_acc1, /* relies on PMU reg for power */
+};
+
+/* this is called when pc50633 is probed, unfortunately quite late in the
+ * day since it is an I2C bus device. Here we can belatedly define some
+ * platform devices with the advantage that we can mark the pcf50633 as the
+ * parent. This makes them get suspended and resumed with their parent
+ * the pcf50633 still around.
+ */
+
+static void om_3d7k_pcf50633_attach_child_devices(struct pcf50633 *pcf)
+{
+ int n;
+
+ om_3d7k_pcf = pcf;
+
+ for (n = 0; n < ARRAY_SIZE(om_3d7k_devices_pmu_children); n++)
+ om_3d7k_devices_pmu_children[n]->dev.parent = pcf->dev;
+
+ platform_add_devices(om_3d7k_devices_pmu_children,
+ ARRAY_SIZE(om_3d7k_devices_pmu_children));
+
+ /* Switch on backlight. Qi does not do it for us */
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0x00);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDDIM, 0x01);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDENA, 0x01);
+ pcf50633_reg_write(pcf, PCF50633_REG_LEDOUT, 0x3f);
+
+}
+
+static void om_3d7k_l1k002_pwronoff(int level)
+{
+ gpio_direction_output(OM_3D7K_GPIO_LCM_SD, 1);
+ udelay(15);
+
+ gpio_direction_output(OM_3D7K_GPIO_LCM_RESET, !!level);
+
+ if (level){
+ udelay(15);
+ gpio_direction_output(OM_3D7K_GPIO_LCM_SD, 0);
+ }
+}
+
+const struct l1k002_platform_data om_3d7k_l1k002_pdata = {
+ .pwr_onoff = om_3d7k_l1k002_pwronoff,
+};
+
+static struct spi_board_info om_3d7k_spi_board_info[] = {
+ {
+ .modalias = "l1k002",
+ .platform_data = &om_3d7k_l1k002_pdata,
+ /* controller_data */
+ /* irq */
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 1,
+ /* chip_select */
+ },
+};
+
+static void spi_gpio_cs(struct s3c64xx_spigpio_info *spi, int csidx, int cs)
+{
+ switch (cs) {
+ case BITBANG_CS_ACTIVE:
+ gpio_direction_output(OM_3D7K_GPIO_LCM_CS, 0);
+ break;
+ case BITBANG_CS_INACTIVE:
+ gpio_direction_output(OM_3D7K_GPIO_LCM_CS, 1);
+ break;
+ }
+}
+
+static struct s3c64xx_spigpio_info spi_gpio_cfg = {
+ .pin_clk = OM_3D7K_GPIO_LCM_CLK,
+ .pin_mosi = OM_3D7K_GPIO_LCM_MOSI,
+ /* no pinout to MISO */
+ .chip_select = &spi_gpio_cs,
+ .num_chipselect = 1,
+ .bus_num = 1,
+};
+
+struct platform_device om_3d7k_device_spi_lcm = {
+ .name = "spi_s3c64xx_gpio",
+ .id = 1,
+ .dev = {
+ .platform_data = &spi_gpio_cfg,
+ },
+};
+
+
+
+
+
+
+
+extern void s3c64xx_init_io(struct map_desc *, int);
+
+struct s3c_plat_otg_data s3c_hs_otg_plat_data = {
+ .phyclk = 0
+};
+
+
+static void __init om_3d7k_map_io(void)
+{
+ s3c64xx_init_io(om_3d7k_6410_iodesc, ARRAY_SIZE(om_3d7k_6410_iodesc));
+ s3c24xx_init_clocks(12000000);
+ s3c24xx_init_uarts(om_3d7k_uartcfgs, ARRAY_SIZE(om_3d7k_uartcfgs));
+}
+
+static void __init om_3d7k_machine_init(void)
+{
+ s3c_pm_init();
+
+ s3c_device_usbgadget.dev.platform_data = &s3c_hs_otg_plat_data;
+
+ s3c_i2c0_set_platdata(NULL);
+ s3c_fb_set_platdata(&om_3d7k_lcd_pdata);
+
+ i2c_register_board_info(0, om_3d7k_i2c_devs,
+ ARRAY_SIZE(om_3d7k_i2c_devs));
+
+ spi_register_board_info(om_3d7k_spi_board_info,
+ ARRAY_SIZE(om_3d7k_spi_board_info));
+
+ platform_add_devices(om_3d7k_devices, ARRAY_SIZE(om_3d7k_devices));
+
+ /* Register the HDQ and vibrator as children of pwm device */
+ om_3d7k_hdq_device.dev.parent = &s3c24xx_pwm_device.dev;
+ platform_device_register(&om_3d7k_hdq_device);
+}
+
+MACHINE_START(OM_3D7K, "OM-3D7K")
+ /* Maintainer: Andy Green <andy@openmoko.com> */
+ .phys_io = S3C_PA_UART & 0xfff00000,
+ .io_pg_offst = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C64XX_PA_SDRAM + 0x100,
+
+ .init_irq = s3c6410_init_irq,
+ .map_io = om_3d7k_map_io,
+ .init_machine = om_3d7k_machine_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
+