linux/arch/arm/mach-pxa/em-x270.c
Linus Torvalds 6b5a12dbca ARM: SoC multiplatform code changes for v4.5
This branch is the culmination of 5 years of effort to bring the ARMv6
 and ARMv7 platforms together such that they can all be enabled and
 boot the same kernel. It has been a tremendous amount of cleanup and
 refactoring by a huge number of people, and creation of several new
 (and major) subsystems to better abstract out all the platform details
 in an appropriate manner.
 
 The bulk of this branch is a large patchset from Arnd that brings several
 of the more minor and older platforms we have closer to multiplatform
 support.  Among these are MMP, S3C64xx, Orion5x, mv78xx0 and realview
 Much of this is moving around header files from old mach directories,
 but there are also some cleanup patches of debug_ll (lowlevel debug
 per-platform options) and other parts.
 
 Linus Walleij also has some patchs to clean up the older ARM Realview
 platforms by finally introducing DT support, and Rob Herring has some
 for ARM Versatile which is now DT-only. Both of these platforms are
 now multiplatform.
 
 Finally, a couple of patches from Russell for Dove PMU, and a fix from
 Valentin Rothberg for Exynos ADC, which were rebased on top of the
 series to avoid conflicts.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIUAwUAVqAGcmCrR//JCVInAQLDog/4x9F0PHGmZhexGfFOpi2Od63Jjx55izRU
 zRXqRjjFjambOrZuOx8lEGDy/qzqKbsDU8D1P4IUugkDr2bLSXv+NTLZL1kNBIdm
 YOlJhw/BmzLYqauOHmBzGhtv1FDUk3rqbgTsP5tTWj5LpSkwjmqui3HBZpi+f3Rr
 YOn+NeQSARiw+51D0b106a9RFshQXRGgn5m3xFjLWhJqshb2z2Ew5cogX/zdwrrM
 ss1BFomxsvgk6S+snN6v7cEX2iXe3r89qNR5jEW5BgNpQGFsAUeXPr9zzH07L/Qq
 O7XLw9jt5MX/X5372zVHPb57WoflLbF9cFaaDUZV3eTqt3lC67BTxOtYIdC2i90k
 E5GYlsy88CRwT2EO+ok/6UTryph+hVv7JqHfbKfnISrbraMCK36DtDTpBIpZ9uYF
 rRB7ncJZUWBcyoe+qvitSl+2KV54iB1ez2RXsketxM98dDZsfB2M2ImFou1F/Pgg
 ALvpifPubi/uDe7xNUsSuaT6/3jAomBuNsxnkYJ3NeiH/+duZbOYGkzK/LlcjZyc
 UrA0IpLfwIFsBNzwfpZPZ1lkEu8Y1YZZ+Hv9k65q1wMuBDgrFI5zUeYrPZi4pN9T
 Yo1xP9FstVLDouJrpGZo12VIIxR1UBeGqfRI/BZ58LEF3PRq/g2OVFsdQia5gZKr
 ddiJKSL1Vw==
 =z1AW
 -----END PGP SIGNATURE-----

Merge tag 'armsoc-multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc

Pull ARM SoC multiplatform code updates from Arnd Bergmann:
 "This branch is the culmination of 5 years of effort to bring the ARMv6
  and ARMv7 platforms together such that they can all be enabled and
  boot the same kernel.  It has been a tremendous amount of cleanup and
  refactoring by a huge number of people, and creation of several new
  (and major) subsystems to better abstract out all the platform details
  in an appropriate manner.

  The bulk of this branch is a large patchset from Arnd that brings
  several of the more minor and older platforms we have closer to
  multiplatform support.  Among these are MMP, S3C64xx, Orion5x, mv78xx0
  and realview Much of this is moving around header files from old mach
  directories, but there are also some cleanup patches of debug_ll
  (lowlevel debug per-platform options) and other parts.

  Linus Walleij also has some patchs to clean up the older ARM Realview
  platforms by finally introducing DT support, and Rob Herring has some
  for ARM Versatile which is now DT-only.  Both of these platforms are
  now multiplatform.

  Finally, a couple of patches from Russell for Dove PMU, and a fix from
  Valentin Rothberg for Exynos ADC, which were rebased on top of the
  series to avoid conflicts"

* tag 'armsoc-multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (75 commits)
  ARM: realview: don't select SMP_ON_UP for UP builds
  ARM: s3c: simplify s3c_irqwake_{e,}intallow definition
  ARM: s3c64xx: fix pm-debug compilation
  iio: exynos-adc: fix irqf_oneshot.cocci warnings
  ARM: realview: build realview-dt SMP support only when used
  ARM: realview: select apropriate targets
  ARM: realview: clean up header files
  ARM: realview: make all header files local
  ARM: no longer make CPU targets visible separately
  ARM: integrator: use explicit core module options
  ARM: realview: enable multiplatform
  ARM: make default platform work for NOMMU
  ARM: debug-ll: move DEBUG_LL_UART_EFM32 to correct Kconfig location
  ARM: defconfig: use correct debug_ll settings
  ARM: versatile: convert to multi-platform
  ARM: versatile: merge mach code into a single file
  ARM: versatile: switch to DT only booting and remove legacy code
  ARM: versatile: add DT based PCI detection
  ARM: pxa: mark ezx structures as __maybe_unused
  ARM: pxa: mark raumfeld init functions as __maybe_unused
  ...
2016-01-20 18:03:56 -08:00

1334 lines
30 KiB
C

/*
* Support for CompuLab EM-X270 platform
*
* Copyright (C) 2007, 2008 CompuLab, Ltd.
* Author: Mike Rapoport <mike@compulab.co.il>
*
* 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/irq.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/dm9000.h>
#include <linux/rtc-v3020.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/mfd/da903x.h>
#include <linux/regulator/machine.h>
#include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h>
#include <linux/spi/libertas_spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/power_supply.h>
#include <linux/apm-emulation.h>
#include <linux/i2c.h>
#include <linux/platform_data/pca953x.h>
#include <linux/i2c/pxa-i2c.h>
#include <linux/regulator/userspace-consumer.h>
#include <media/soc_camera.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include "pxa27x.h"
#include "pxa27x-udc.h"
#include <mach/audio.h>
#include <linux/platform_data/video-pxafb.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/keypad-pxa27x.h>
#include <linux/platform_data/media/camera-pxa.h>
#include "generic.h"
#include "devices.h"
/* EM-X270 specific GPIOs */
#define GPIO13_MMC_CD (13)
#define GPIO95_MMC_WP (95)
#define GPIO56_NAND_RB (56)
#define GPIO93_CAM_RESET (93)
#define GPIO16_USB_HUB_RESET (16)
/* eXeda specific GPIOs */
#define GPIO114_MMC_CD (114)
#define GPIO20_NAND_RB (20)
#define GPIO38_SD_PWEN (38)
#define GPIO37_WLAN_RST (37)
#define GPIO95_TOUCHPAD_INT (95)
#define GPIO130_CAM_RESET (130)
#define GPIO10_USB_HUB_RESET (10)
/* common GPIOs */
#define GPIO11_NAND_CS (11)
#define GPIO41_ETHIRQ (41)
#define EM_X270_ETHIRQ PXA_GPIO_TO_IRQ(GPIO41_ETHIRQ)
#define GPIO115_WLAN_PWEN (115)
#define GPIO19_WLAN_STRAP (19)
#define GPIO9_USB_VBUS_EN (9)
static int mmc_cd;
static int nand_rb;
static int dm9000_flags;
static int cam_reset;
static int usb_hub_reset;
static unsigned long common_pin_config[] = {
/* AC'97 */
GPIO28_AC97_BITCLK,
GPIO29_AC97_SDATA_IN_0,
GPIO30_AC97_SDATA_OUT,
GPIO31_AC97_SYNC,
GPIO98_AC97_SYSCLK,
GPIO113_AC97_nRESET,
/* BTUART */
GPIO42_BTUART_RXD,
GPIO43_BTUART_TXD,
GPIO44_BTUART_CTS,
GPIO45_BTUART_RTS,
/* STUART */
GPIO46_STUART_RXD,
GPIO47_STUART_TXD,
/* MCI controller */
GPIO32_MMC_CLK,
GPIO112_MMC_CMD,
GPIO92_MMC_DAT_0,
GPIO109_MMC_DAT_1,
GPIO110_MMC_DAT_2,
GPIO111_MMC_DAT_3,
/* LCD */
GPIOxx_LCD_TFT_16BPP,
/* QCI */
GPIO84_CIF_FV,
GPIO25_CIF_LV,
GPIO53_CIF_MCLK,
GPIO54_CIF_PCLK,
GPIO81_CIF_DD_0,
GPIO55_CIF_DD_1,
GPIO51_CIF_DD_2,
GPIO50_CIF_DD_3,
GPIO52_CIF_DD_4,
GPIO48_CIF_DD_5,
GPIO17_CIF_DD_6,
GPIO12_CIF_DD_7,
/* I2C */
GPIO117_I2C_SCL,
GPIO118_I2C_SDA,
/* Keypad */
GPIO100_KP_MKIN_0 | WAKEUP_ON_LEVEL_HIGH,
GPIO101_KP_MKIN_1 | WAKEUP_ON_LEVEL_HIGH,
GPIO102_KP_MKIN_2 | WAKEUP_ON_LEVEL_HIGH,
GPIO34_KP_MKIN_3 | WAKEUP_ON_LEVEL_HIGH,
GPIO39_KP_MKIN_4 | WAKEUP_ON_LEVEL_HIGH,
GPIO99_KP_MKIN_5 | WAKEUP_ON_LEVEL_HIGH,
GPIO91_KP_MKIN_6 | WAKEUP_ON_LEVEL_HIGH,
GPIO36_KP_MKIN_7 | WAKEUP_ON_LEVEL_HIGH,
GPIO103_KP_MKOUT_0,
GPIO104_KP_MKOUT_1,
GPIO105_KP_MKOUT_2,
GPIO106_KP_MKOUT_3,
GPIO107_KP_MKOUT_4,
GPIO108_KP_MKOUT_5,
GPIO96_KP_MKOUT_6,
GPIO22_KP_MKOUT_7,
/* SSP1 */
GPIO26_SSP1_RXD,
GPIO23_SSP1_SCLK,
GPIO24_SSP1_SFRM,
GPIO57_SSP1_TXD,
/* SSP2 */
GPIO19_GPIO, /* SSP2 clock is used as GPIO for Libertas pin-strap */
GPIO14_GPIO,
GPIO89_SSP2_TXD,
GPIO88_SSP2_RXD,
/* SDRAM and local bus */
GPIO15_nCS_1,
GPIO78_nCS_2,
GPIO79_nCS_3,
GPIO80_nCS_4,
GPIO49_nPWE,
GPIO18_RDY,
/* GPIO */
GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH, /* sleep/resume button */
/* power controls */
GPIO20_GPIO | MFP_LPM_DRIVE_LOW, /* GPRS_PWEN */
GPIO115_GPIO | MFP_LPM_DRIVE_LOW, /* WLAN_PWEN */
/* NAND controls */
GPIO11_GPIO | MFP_LPM_DRIVE_HIGH, /* NAND CE# */
/* interrupts */
GPIO41_GPIO, /* DM9000 interrupt */
};
static unsigned long em_x270_pin_config[] = {
GPIO13_GPIO, /* MMC card detect */
GPIO16_GPIO, /* USB hub reset */
GPIO56_GPIO, /* NAND Ready/Busy */
GPIO93_GPIO | MFP_LPM_DRIVE_LOW, /* Camera reset */
GPIO95_GPIO, /* MMC Write protect */
};
static unsigned long exeda_pin_config[] = {
GPIO10_GPIO, /* USB hub reset */
GPIO20_GPIO, /* NAND Ready/Busy */
GPIO38_GPIO | MFP_LPM_DRIVE_LOW, /* SD slot power */
GPIO95_GPIO, /* touchpad IRQ */
GPIO114_GPIO, /* MMC card detect */
};
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
static struct resource em_x270_dm9000_resource[] = {
[0] = {
.start = PXA_CS2_PHYS,
.end = PXA_CS2_PHYS + 3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = PXA_CS2_PHYS + 8,
.end = PXA_CS2_PHYS + 8 + 0x3f,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = EM_X270_ETHIRQ,
.end = EM_X270_ETHIRQ,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct dm9000_plat_data em_x270_dm9000_platdata = {
.flags = DM9000_PLATF_NO_EEPROM,
};
static struct platform_device em_x270_dm9000 = {
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(em_x270_dm9000_resource),
.resource = em_x270_dm9000_resource,
.dev = {
.platform_data = &em_x270_dm9000_platdata,
}
};
static void __init em_x270_init_dm9000(void)
{
em_x270_dm9000_platdata.flags |= dm9000_flags;
platform_device_register(&em_x270_dm9000);
}
#else
static inline void em_x270_init_dm9000(void) {}
#endif
/* V3020 RTC */
#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE)
static struct resource em_x270_v3020_resource[] = {
[0] = {
.start = PXA_CS4_PHYS,
.end = PXA_CS4_PHYS + 3,
.flags = IORESOURCE_MEM,
},
};
static struct v3020_platform_data em_x270_v3020_platdata = {
.leftshift = 0,
};
static struct platform_device em_x270_rtc = {
.name = "v3020",
.num_resources = ARRAY_SIZE(em_x270_v3020_resource),
.resource = em_x270_v3020_resource,
.id = -1,
.dev = {
.platform_data = &em_x270_v3020_platdata,
}
};
static void __init em_x270_init_rtc(void)
{
platform_device_register(&em_x270_rtc);
}
#else
static inline void em_x270_init_rtc(void) {}
#endif
/* NAND flash */
#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
static inline void nand_cs_on(void)
{
gpio_set_value(GPIO11_NAND_CS, 0);
}
static void nand_cs_off(void)
{
dsb();
gpio_set_value(GPIO11_NAND_CS, 1);
}
/* hardware specific access to control-lines */
static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
unsigned int ctrl)
{
struct nand_chip *this = mtd_to_nand(mtd);
unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
dsb();
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_ALE)
nandaddr |= (1 << 3);
else
nandaddr &= ~(1 << 3);
if (ctrl & NAND_CLE)
nandaddr |= (1 << 2);
else
nandaddr &= ~(1 << 2);
if (ctrl & NAND_NCE)
nand_cs_on();
else
nand_cs_off();
}
dsb();
this->IO_ADDR_W = (void __iomem *)nandaddr;
if (dat != NAND_CMD_NONE)
writel(dat, this->IO_ADDR_W);
dsb();
}
/* read device ready pin */
static int em_x270_nand_device_ready(struct mtd_info *mtd)
{
dsb();
return gpio_get_value(nand_rb);
}
static struct mtd_partition em_x270_partition_info[] = {
[0] = {
.name = "em_x270-0",
.offset = 0,
.size = SZ_4M,
},
[1] = {
.name = "em_x270-1",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL
},
};
struct platform_nand_data em_x270_nand_platdata = {
.chip = {
.nr_chips = 1,
.chip_offset = 0,
.nr_partitions = ARRAY_SIZE(em_x270_partition_info),
.partitions = em_x270_partition_info,
.chip_delay = 20,
},
.ctrl = {
.hwcontrol = 0,
.dev_ready = em_x270_nand_device_ready,
.select_chip = 0,
.cmd_ctrl = em_x270_nand_cmd_ctl,
},
};
static struct resource em_x270_nand_resource[] = {
[0] = {
.start = PXA_CS1_PHYS,
.end = PXA_CS1_PHYS + 12,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device em_x270_nand = {
.name = "gen_nand",
.num_resources = ARRAY_SIZE(em_x270_nand_resource),
.resource = em_x270_nand_resource,
.id = -1,
.dev = {
.platform_data = &em_x270_nand_platdata,
}
};
static void __init em_x270_init_nand(void)
{
int err;
err = gpio_request(GPIO11_NAND_CS, "NAND CS");
if (err) {
pr_warn("EM-X270: failed to request NAND CS gpio\n");
return;
}
gpio_direction_output(GPIO11_NAND_CS, 1);
err = gpio_request(nand_rb, "NAND R/B");
if (err) {
pr_warn("EM-X270: failed to request NAND R/B gpio\n");
gpio_free(GPIO11_NAND_CS);
return;
}
gpio_direction_input(nand_rb);
platform_device_register(&em_x270_nand);
}
#else
static inline void em_x270_init_nand(void) {}
#endif
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
static struct mtd_partition em_x270_nor_parts[] = {
{
.name = "Bootloader",
.offset = 0x00000000,
.size = 0x00050000,
.mask_flags = MTD_WRITEABLE /* force read-only */
}, {
.name = "Environment",
.offset = 0x00050000,
.size = 0x00010000,
}, {
.name = "Reserved",
.offset = 0x00060000,
.size = 0x00050000,
.mask_flags = MTD_WRITEABLE /* force read-only */
}, {
.name = "Splashscreen",
.offset = 0x000b0000,
.size = 0x00050000,
}
};
static struct physmap_flash_data em_x270_nor_data[] = {
[0] = {
.width = 2,
.parts = em_x270_nor_parts,
.nr_parts = ARRAY_SIZE(em_x270_nor_parts),
},
};
static struct resource em_x270_nor_flash_resource = {
.start = PXA_CS0_PHYS,
.end = PXA_CS0_PHYS + SZ_1M - 1,
.flags = IORESOURCE_MEM,
};
static struct platform_device em_x270_physmap_flash = {
.name = "physmap-flash",
.id = 0,
.num_resources = 1,
.resource = &em_x270_nor_flash_resource,
.dev = {
.platform_data = &em_x270_nor_data,
},
};
static void __init em_x270_init_nor(void)
{
platform_device_register(&em_x270_physmap_flash);
}
#else
static inline void em_x270_init_nor(void) {}
#endif
/* PXA27x OHCI controller setup */
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static struct regulator *em_x270_usb_ldo;
static int em_x270_usb_hub_init(void)
{
int err;
em_x270_usb_ldo = regulator_get(NULL, "vcc usb");
if (IS_ERR(em_x270_usb_ldo))
return PTR_ERR(em_x270_usb_ldo);
err = gpio_request(GPIO9_USB_VBUS_EN, "vbus en");
if (err)
goto err_free_usb_ldo;
err = gpio_request(usb_hub_reset, "hub rst");
if (err)
goto err_free_vbus_gpio;
/* USB Hub power-on and reset */
gpio_direction_output(usb_hub_reset, 1);
gpio_direction_output(GPIO9_USB_VBUS_EN, 0);
err = regulator_enable(em_x270_usb_ldo);
if (err)
goto err_free_rst_gpio;
gpio_set_value(usb_hub_reset, 0);
gpio_set_value(usb_hub_reset, 1);
regulator_disable(em_x270_usb_ldo);
err = regulator_enable(em_x270_usb_ldo);
if (err)
goto err_free_rst_gpio;
gpio_set_value(usb_hub_reset, 0);
gpio_set_value(GPIO9_USB_VBUS_EN, 1);
return 0;
err_free_rst_gpio:
gpio_free(usb_hub_reset);
err_free_vbus_gpio:
gpio_free(GPIO9_USB_VBUS_EN);
err_free_usb_ldo:
regulator_put(em_x270_usb_ldo);
return err;
}
static int em_x270_ohci_init(struct device *dev)
{
int err;
/* we don't want to entirely disable USB if the HUB init failed */
err = em_x270_usb_hub_init();
if (err)
pr_err("USB Hub initialization failed: %d\n", err);
/* enable port 2 transiever */
UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
return 0;
}
static void em_x270_ohci_exit(struct device *dev)
{
gpio_free(usb_hub_reset);
gpio_free(GPIO9_USB_VBUS_EN);
if (!IS_ERR(em_x270_usb_ldo)) {
if (regulator_is_enabled(em_x270_usb_ldo))
regulator_disable(em_x270_usb_ldo);
regulator_put(em_x270_usb_ldo);
}
}
static struct pxaohci_platform_data em_x270_ohci_platform_data = {
.port_mode = PMM_PERPORT_MODE,
.flags = ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
.init = em_x270_ohci_init,
.exit = em_x270_ohci_exit,
};
static void __init em_x270_init_ohci(void)
{
pxa_set_ohci_info(&em_x270_ohci_platform_data);
}
#else
static inline void em_x270_init_ohci(void) {}
#endif
/* MCI controller setup */
#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
static struct regulator *em_x270_sdio_ldo;
static int em_x270_mci_init(struct device *dev,
irq_handler_t em_x270_detect_int,
void *data)
{
int err;
em_x270_sdio_ldo = regulator_get(dev, "vcc sdio");
if (IS_ERR(em_x270_sdio_ldo)) {
dev_err(dev, "can't request SDIO power supply: %ld\n",
PTR_ERR(em_x270_sdio_ldo));
return PTR_ERR(em_x270_sdio_ldo);
}
err = request_irq(gpio_to_irq(mmc_cd), em_x270_detect_int,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"MMC card detect", data);
if (err) {
dev_err(dev, "can't request MMC card detect IRQ: %d\n", err);
goto err_irq;
}
if (machine_is_em_x270()) {
err = gpio_request(GPIO95_MMC_WP, "MMC WP");
if (err) {
dev_err(dev, "can't request MMC write protect: %d\n",
err);
goto err_gpio_wp;
}
gpio_direction_input(GPIO95_MMC_WP);
} else {
err = gpio_request(GPIO38_SD_PWEN, "sdio power");
if (err) {
dev_err(dev, "can't request MMC power control : %d\n",
err);
goto err_gpio_wp;
}
gpio_direction_output(GPIO38_SD_PWEN, 1);
}
return 0;
err_gpio_wp:
free_irq(gpio_to_irq(mmc_cd), data);
err_irq:
regulator_put(em_x270_sdio_ldo);
return err;
}
static int em_x270_mci_setpower(struct device *dev, unsigned int vdd)
{
struct pxamci_platform_data* p_d = dev->platform_data;
if ((1 << vdd) & p_d->ocr_mask) {
int vdd_uV = (2000 + (vdd - __ffs(MMC_VDD_20_21)) * 100) * 1000;
regulator_set_voltage(em_x270_sdio_ldo, vdd_uV, vdd_uV);
return regulator_enable(em_x270_sdio_ldo);
} else {
regulator_disable(em_x270_sdio_ldo);
}
return 0;
}
static void em_x270_mci_exit(struct device *dev, void *data)
{
free_irq(gpio_to_irq(mmc_cd), data);
regulator_put(em_x270_sdio_ldo);
if (machine_is_em_x270())
gpio_free(GPIO95_MMC_WP);
else
gpio_free(GPIO38_SD_PWEN);
}
static int em_x270_mci_get_ro(struct device *dev)
{
return gpio_get_value(GPIO95_MMC_WP);
}
static struct pxamci_platform_data em_x270_mci_platform_data = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23|
MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27|
MMC_VDD_27_28|MMC_VDD_28_29|MMC_VDD_29_30|
MMC_VDD_30_31|MMC_VDD_31_32,
.init = em_x270_mci_init,
.setpower = em_x270_mci_setpower,
.exit = em_x270_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void __init em_x270_init_mmc(void)
{
if (machine_is_em_x270())
em_x270_mci_platform_data.get_ro = em_x270_mci_get_ro;
pxa_set_mci_info(&em_x270_mci_platform_data);
}
#else
static inline void em_x270_init_mmc(void) {}
#endif
/* LCD */
#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
static struct pxafb_mode_info em_x270_lcd_modes[] = {
[0] = {
.pixclock = 38250,
.bpp = 16,
.xres = 480,
.yres = 640,
.hsync_len = 8,
.vsync_len = 2,
.left_margin = 8,
.upper_margin = 2,
.right_margin = 24,
.lower_margin = 4,
.sync = 0,
},
[1] = {
.pixclock = 153800,
.bpp = 16,
.xres = 240,
.yres = 320,
.hsync_len = 8,
.vsync_len = 2,
.left_margin = 8,
.upper_margin = 2,
.right_margin = 88,
.lower_margin = 2,
.sync = 0,
},
};
static struct pxafb_mach_info em_x270_lcd = {
.modes = em_x270_lcd_modes,
.num_modes = 2,
.lcd_conn = LCD_COLOR_TFT_16BPP,
};
static void __init em_x270_init_lcd(void)
{
pxa_set_fb_info(NULL, &em_x270_lcd);
}
#else
static inline void em_x270_init_lcd(void) {}
#endif
#if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
static struct pxa2xx_spi_master em_x270_spi_info = {
.num_chipselect = 1,
};
static struct pxa2xx_spi_chip em_x270_tdo24m_chip = {
.rx_threshold = 1,
.tx_threshold = 1,
.gpio_cs = -1,
};
static struct tdo24m_platform_data em_x270_tdo24m_pdata = {
.model = TDO35S,
};
static struct pxa2xx_spi_master em_x270_spi_2_info = {
.num_chipselect = 1,
.enable_dma = 1,
};
static struct pxa2xx_spi_chip em_x270_libertas_chip = {
.rx_threshold = 1,
.tx_threshold = 1,
.timeout = 1000,
.gpio_cs = 14,
};
static unsigned long em_x270_libertas_pin_config[] = {
/* SSP2 */
GPIO19_SSP2_SCLK,
GPIO14_GPIO,
GPIO89_SSP2_TXD,
GPIO88_SSP2_RXD,
};
static int em_x270_libertas_setup(struct spi_device *spi)
{
int err = gpio_request(GPIO115_WLAN_PWEN, "WLAN PWEN");
if (err)
return err;
err = gpio_request(GPIO19_WLAN_STRAP, "WLAN STRAP");
if (err)
goto err_free_pwen;
if (machine_is_exeda()) {
err = gpio_request(GPIO37_WLAN_RST, "WLAN RST");
if (err)
goto err_free_strap;
gpio_direction_output(GPIO37_WLAN_RST, 1);
msleep(100);
}
gpio_direction_output(GPIO19_WLAN_STRAP, 1);
msleep(100);
pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_libertas_pin_config));
gpio_direction_output(GPIO115_WLAN_PWEN, 0);
msleep(100);
gpio_set_value(GPIO115_WLAN_PWEN, 1);
msleep(100);
spi->bits_per_word = 16;
spi_setup(spi);
return 0;
err_free_strap:
gpio_free(GPIO19_WLAN_STRAP);
err_free_pwen:
gpio_free(GPIO115_WLAN_PWEN);
return err;
}
static int em_x270_libertas_teardown(struct spi_device *spi)
{
gpio_set_value(GPIO115_WLAN_PWEN, 0);
gpio_free(GPIO115_WLAN_PWEN);
gpio_free(GPIO19_WLAN_STRAP);
if (machine_is_exeda()) {
gpio_set_value(GPIO37_WLAN_RST, 0);
gpio_free(GPIO37_WLAN_RST);
}
return 0;
}
struct libertas_spi_platform_data em_x270_libertas_pdata = {
.use_dummy_writes = 1,
.setup = em_x270_libertas_setup,
.teardown = em_x270_libertas_teardown,
};
static struct spi_board_info em_x270_spi_devices[] __initdata = {
{
.modalias = "tdo24m",
.max_speed_hz = 1000000,
.bus_num = 1,
.chip_select = 0,
.controller_data = &em_x270_tdo24m_chip,
.platform_data = &em_x270_tdo24m_pdata,
},
{
.modalias = "libertas_spi",
.max_speed_hz = 13000000,
.bus_num = 2,
.irq = PXA_GPIO_TO_IRQ(116),
.chip_select = 0,
.controller_data = &em_x270_libertas_chip,
.platform_data = &em_x270_libertas_pdata,
},
};
static void __init em_x270_init_spi(void)
{
pxa2xx_set_spi_info(1, &em_x270_spi_info);
pxa2xx_set_spi_info(2, &em_x270_spi_2_info);
spi_register_board_info(ARRAY_AND_SIZE(em_x270_spi_devices));
}
#else
static inline void em_x270_init_spi(void) {}
#endif
#if defined(CONFIG_SND_PXA2XX_LIB_AC97)
static pxa2xx_audio_ops_t em_x270_ac97_info = {
.reset_gpio = 113,
};
static void __init em_x270_init_ac97(void)
{
pxa_set_ac97_info(&em_x270_ac97_info);
}
#else
static inline void em_x270_init_ac97(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static const unsigned int em_x270_module_matrix_keys[] = {
KEY(0, 0, KEY_A), KEY(1, 0, KEY_UP), KEY(2, 1, KEY_B),
KEY(0, 2, KEY_LEFT), KEY(1, 1, KEY_ENTER), KEY(2, 0, KEY_RIGHT),
KEY(0, 1, KEY_C), KEY(1, 2, KEY_DOWN), KEY(2, 2, KEY_D),
};
static struct matrix_keymap_data em_x270_matrix_keymap_data = {
.keymap = em_x270_module_matrix_keys,
.keymap_size = ARRAY_SIZE(em_x270_module_matrix_keys),
};
struct pxa27x_keypad_platform_data em_x270_module_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 3,
.matrix_key_cols = 3,
.matrix_keymap_data = &em_x270_matrix_keymap_data,
};
static const unsigned int em_x270_exeda_matrix_keys[] = {
KEY(0, 0, KEY_RIGHTSHIFT), KEY(0, 1, KEY_RIGHTCTRL),
KEY(0, 2, KEY_RIGHTALT), KEY(0, 3, KEY_SPACE),
KEY(0, 4, KEY_LEFTALT), KEY(0, 5, KEY_LEFTCTRL),
KEY(0, 6, KEY_ENTER), KEY(0, 7, KEY_SLASH),
KEY(1, 0, KEY_DOT), KEY(1, 1, KEY_M),
KEY(1, 2, KEY_N), KEY(1, 3, KEY_B),
KEY(1, 4, KEY_V), KEY(1, 5, KEY_C),
KEY(1, 6, KEY_X), KEY(1, 7, KEY_Z),
KEY(2, 0, KEY_LEFTSHIFT), KEY(2, 1, KEY_SEMICOLON),
KEY(2, 2, KEY_L), KEY(2, 3, KEY_K),
KEY(2, 4, KEY_J), KEY(2, 5, KEY_H),
KEY(2, 6, KEY_G), KEY(2, 7, KEY_F),
KEY(3, 0, KEY_D), KEY(3, 1, KEY_S),
KEY(3, 2, KEY_A), KEY(3, 3, KEY_TAB),
KEY(3, 4, KEY_BACKSPACE), KEY(3, 5, KEY_P),
KEY(3, 6, KEY_O), KEY(3, 7, KEY_I),
KEY(4, 0, KEY_U), KEY(4, 1, KEY_Y),
KEY(4, 2, KEY_T), KEY(4, 3, KEY_R),
KEY(4, 4, KEY_E), KEY(4, 5, KEY_W),
KEY(4, 6, KEY_Q), KEY(4, 7, KEY_MINUS),
KEY(5, 0, KEY_0), KEY(5, 1, KEY_9),
KEY(5, 2, KEY_8), KEY(5, 3, KEY_7),
KEY(5, 4, KEY_6), KEY(5, 5, KEY_5),
KEY(5, 6, KEY_4), KEY(5, 7, KEY_3),
KEY(6, 0, KEY_2), KEY(6, 1, KEY_1),
KEY(6, 2, KEY_ENTER), KEY(6, 3, KEY_END),
KEY(6, 4, KEY_DOWN), KEY(6, 5, KEY_UP),
KEY(6, 6, KEY_MENU), KEY(6, 7, KEY_F1),
KEY(7, 0, KEY_LEFT), KEY(7, 1, KEY_RIGHT),
KEY(7, 2, KEY_BACK), KEY(7, 3, KEY_HOME),
KEY(7, 4, 0), KEY(7, 5, 0),
KEY(7, 6, 0), KEY(7, 7, 0),
};
static struct matrix_keymap_data em_x270_exeda_matrix_keymap_data = {
.keymap = em_x270_exeda_matrix_keys,
.keymap_size = ARRAY_SIZE(em_x270_exeda_matrix_keys),
};
struct pxa27x_keypad_platform_data em_x270_exeda_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 8,
.matrix_key_cols = 8,
.matrix_keymap_data = &em_x270_exeda_matrix_keymap_data,
};
static void __init em_x270_init_keypad(void)
{
if (machine_is_em_x270())
pxa_set_keypad_info(&em_x270_module_keypad_info);
else
pxa_set_keypad_info(&em_x270_exeda_keypad_info);
}
#else
static inline void em_x270_init_keypad(void) {}
#endif
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
static struct gpio_keys_button gpio_keys_button[] = {
[0] = {
.desc = "sleep/wakeup",
.code = KEY_SUSPEND,
.type = EV_PWR,
.gpio = 1,
.wakeup = 1,
},
};
static struct gpio_keys_platform_data em_x270_gpio_keys_data = {
.buttons = gpio_keys_button,
.nbuttons = 1,
};
static struct platform_device em_x270_gpio_keys = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &em_x270_gpio_keys_data,
},
};
static void __init em_x270_init_gpio_keys(void)
{
platform_device_register(&em_x270_gpio_keys);
}
#else
static inline void em_x270_init_gpio_keys(void) {}
#endif
/* Quick Capture Interface and sensor setup */
#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
static struct regulator *em_x270_camera_ldo;
static int em_x270_sensor_init(void)
{
int ret;
ret = gpio_request(cam_reset, "camera reset");
if (ret)
return ret;
gpio_direction_output(cam_reset, 0);
em_x270_camera_ldo = regulator_get(NULL, "vcc cam");
if (em_x270_camera_ldo == NULL) {
gpio_free(cam_reset);
return -ENODEV;
}
ret = regulator_enable(em_x270_camera_ldo);
if (ret) {
regulator_put(em_x270_camera_ldo);
gpio_free(cam_reset);
return ret;
}
gpio_set_value(cam_reset, 1);
return 0;
}
struct pxacamera_platform_data em_x270_camera_platform_data = {
.flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 |
PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN,
.mclk_10khz = 2600,
};
static int em_x270_sensor_power(struct device *dev, int on)
{
int ret;
int is_on = regulator_is_enabled(em_x270_camera_ldo);
if (on == is_on)
return 0;
gpio_set_value(cam_reset, !on);
if (on)
ret = regulator_enable(em_x270_camera_ldo);
else
ret = regulator_disable(em_x270_camera_ldo);
if (ret)
return ret;
gpio_set_value(cam_reset, on);
return 0;
}
static struct i2c_board_info em_x270_i2c_cam_info[] = {
{
I2C_BOARD_INFO("mt9m111", 0x48),
},
};
static struct soc_camera_link iclink = {
.bus_id = 0,
.power = em_x270_sensor_power,
.board_info = &em_x270_i2c_cam_info[0],
.i2c_adapter_id = 0,
};
static struct platform_device em_x270_camera = {
.name = "soc-camera-pdrv",
.id = -1,
.dev = {
.platform_data = &iclink,
},
};
static void __init em_x270_init_camera(void)
{
if (em_x270_sensor_init() == 0) {
pxa_set_camera_info(&em_x270_camera_platform_data);
platform_device_register(&em_x270_camera);
}
}
#else
static inline void em_x270_init_camera(void) {}
#endif
static struct regulator_bulk_data em_x270_gps_consumer_supply = {
.supply = "vcc gps",
};
static struct regulator_userspace_consumer_data em_x270_gps_consumer_data = {
.name = "vcc gps",
.num_supplies = 1,
.supplies = &em_x270_gps_consumer_supply,
};
static struct platform_device em_x270_gps_userspace_consumer = {
.name = "reg-userspace-consumer",
.id = 0,
.dev = {
.platform_data = &em_x270_gps_consumer_data,
},
};
static struct regulator_bulk_data em_x270_gprs_consumer_supply = {
.supply = "vcc gprs",
};
static struct regulator_userspace_consumer_data em_x270_gprs_consumer_data = {
.name = "vcc gprs",
.num_supplies = 1,
.supplies = &em_x270_gprs_consumer_supply
};
static struct platform_device em_x270_gprs_userspace_consumer = {
.name = "reg-userspace-consumer",
.id = 1,
.dev = {
.platform_data = &em_x270_gprs_consumer_data,
}
};
static struct platform_device *em_x270_userspace_consumers[] = {
&em_x270_gps_userspace_consumer,
&em_x270_gprs_userspace_consumer,
};
static void __init em_x270_userspace_consumers_init(void)
{
platform_add_devices(ARRAY_AND_SIZE(em_x270_userspace_consumers));
}
/* DA9030 related initializations */
#define REGULATOR_CONSUMER(_name, _dev_name, _supply) \
static struct regulator_consumer_supply _name##_consumers[] = { \
REGULATOR_SUPPLY(_supply, _dev_name), \
}
REGULATOR_CONSUMER(ldo3, "reg-userspace-consumer.0", "vcc gps");
REGULATOR_CONSUMER(ldo5, NULL, "vcc cam");
REGULATOR_CONSUMER(ldo10, "pxa2xx-mci", "vcc sdio");
REGULATOR_CONSUMER(ldo12, NULL, "vcc usb");
REGULATOR_CONSUMER(ldo19, "reg-userspace-consumer.1", "vcc gprs");
REGULATOR_CONSUMER(buck2, NULL, "vcc_core");
#define REGULATOR_INIT(_ldo, _min_uV, _max_uV, _ops_mask) \
static struct regulator_init_data _ldo##_data = { \
.constraints = { \
.min_uV = _min_uV, \
.max_uV = _max_uV, \
.state_mem = { \
.enabled = 0, \
}, \
.valid_ops_mask = _ops_mask, \
.apply_uV = 1, \
}, \
.num_consumer_supplies = ARRAY_SIZE(_ldo##_consumers), \
.consumer_supplies = _ldo##_consumers, \
};
REGULATOR_INIT(ldo3, 3200000, 3200000, REGULATOR_CHANGE_STATUS);
REGULATOR_INIT(ldo5, 3000000, 3000000, REGULATOR_CHANGE_STATUS);
REGULATOR_INIT(ldo10, 2000000, 3200000,
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE);
REGULATOR_INIT(ldo12, 3000000, 3000000, REGULATOR_CHANGE_STATUS);
REGULATOR_INIT(ldo19, 3200000, 3200000, REGULATOR_CHANGE_STATUS);
REGULATOR_INIT(buck2, 1000000, 1650000, REGULATOR_CHANGE_VOLTAGE);
struct led_info em_x270_led_info = {
.name = "em-x270:orange",
.default_trigger = "battery-charging-or-full",
};
struct power_supply_info em_x270_psy_info = {
.name = "battery",
.technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
.voltage_max_design = 4200000,
.voltage_min_design = 3000000,
.use_for_apm = 1,
};
static void em_x270_battery_low(void)
{
#if defined(CONFIG_APM_EMULATION)
apm_queue_event(APM_LOW_BATTERY);
#endif
}
static void em_x270_battery_critical(void)
{
#if defined(CONFIG_APM_EMULATION)
apm_queue_event(APM_CRITICAL_SUSPEND);
#endif
}
struct da9030_battery_info em_x270_batterty_info = {
.battery_info = &em_x270_psy_info,
.charge_milliamp = 1000,
.charge_millivolt = 4200,
.vbat_low = 3600,
.vbat_crit = 3400,
.vbat_charge_start = 4100,
.vbat_charge_stop = 4200,
.vbat_charge_restart = 4000,
.vcharge_min = 3200,
.vcharge_max = 5500,
.tbat_low = 197,
.tbat_high = 78,
.tbat_restart = 100,
.batmon_interval = 0,
.battery_low = em_x270_battery_low,
.battery_critical = em_x270_battery_critical,
};
#define DA9030_SUBDEV(_name, _id, _pdata) \
{ \
.name = "da903x-" #_name, \
.id = DA9030_ID_##_id, \
.platform_data = _pdata, \
}
#define DA9030_LDO(num) DA9030_SUBDEV(regulator, LDO##num, &ldo##num##_data)
struct da903x_subdev_info em_x270_da9030_subdevs[] = {
DA9030_LDO(3),
DA9030_LDO(5),
DA9030_LDO(10),
DA9030_LDO(12),
DA9030_LDO(19),
DA9030_SUBDEV(regulator, BUCK2, &buck2_data),
DA9030_SUBDEV(led, LED_PC, &em_x270_led_info),
DA9030_SUBDEV(backlight, WLED, &em_x270_led_info),
DA9030_SUBDEV(battery, BAT, &em_x270_batterty_info),
};
static struct da903x_platform_data em_x270_da9030_info = {
.num_subdevs = ARRAY_SIZE(em_x270_da9030_subdevs),
.subdevs = em_x270_da9030_subdevs,
};
static struct i2c_board_info em_x270_i2c_pmic_info = {
I2C_BOARD_INFO("da9030", 0x49),
.irq = PXA_GPIO_TO_IRQ(0),
.platform_data = &em_x270_da9030_info,
};
static struct i2c_pxa_platform_data em_x270_pwr_i2c_info = {
.use_pio = 1,
};
static void __init em_x270_init_da9030(void)
{
pxa27x_set_i2c_power_info(&em_x270_pwr_i2c_info);
i2c_register_board_info(1, &em_x270_i2c_pmic_info, 1);
}
static struct pca953x_platform_data exeda_gpio_ext_pdata = {
.gpio_base = 128,
};
static struct i2c_board_info exeda_i2c_info[] = {
{
I2C_BOARD_INFO("pca9555", 0x21),
.platform_data = &exeda_gpio_ext_pdata,
},
};
static struct i2c_pxa_platform_data em_x270_i2c_info = {
.fast_mode = 1,
};
static void __init em_x270_init_i2c(void)
{
pxa_set_i2c_info(&em_x270_i2c_info);
if (machine_is_exeda())
i2c_register_board_info(0, ARRAY_AND_SIZE(exeda_i2c_info));
}
static void __init em_x270_module_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(em_x270_pin_config));
mmc_cd = GPIO13_MMC_CD;
nand_rb = GPIO56_NAND_RB;
dm9000_flags = DM9000_PLATF_32BITONLY;
cam_reset = GPIO93_CAM_RESET;
usb_hub_reset = GPIO16_USB_HUB_RESET;
}
static void __init em_x270_exeda_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(exeda_pin_config));
mmc_cd = GPIO114_MMC_CD;
nand_rb = GPIO20_NAND_RB;
dm9000_flags = DM9000_PLATF_16BITONLY;
cam_reset = GPIO130_CAM_RESET;
usb_hub_reset = GPIO10_USB_HUB_RESET;
}
static void __init em_x270_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(common_pin_config));
pxa_set_ffuart_info(NULL);
pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL);
#ifdef CONFIG_PM
pxa27x_set_pwrmode(PWRMODE_DEEPSLEEP);
#endif
if (machine_is_em_x270())
em_x270_module_init();
else if (machine_is_exeda())
em_x270_exeda_init();
else
panic("Unsupported machine: %d\n", machine_arch_type);
em_x270_init_da9030();
em_x270_init_dm9000();
em_x270_init_rtc();
em_x270_init_nand();
em_x270_init_nor();
em_x270_init_lcd();
em_x270_init_mmc();
em_x270_init_ohci();
em_x270_init_keypad();
em_x270_init_gpio_keys();
em_x270_init_ac97();
em_x270_init_spi();
em_x270_init_i2c();
em_x270_init_camera();
em_x270_userspace_consumers_init();
regulator_has_full_constraints();
}
MACHINE_START(EM_X270, "Compulab EM-X270")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_time = pxa_timer_init,
.init_machine = em_x270_init,
.restart = pxa_restart,
MACHINE_END
MACHINE_START(EXEDA, "Compulab eXeda")
.atag_offset = 0x100,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = pxa27x_init_irq,
.handle_irq = pxa27x_handle_irq,
.init_time = pxa_timer_init,
.init_machine = em_x270_init,
.restart = pxa_restart,
MACHINE_END