[ARM] pxa/zeus: make Viper pcmcia support more generic to support Zeus

The Arcom Zeus CF slot requires the same kind of support as the Viper.
To avoid code duplication, introduce a platform device that abstracts
the differences.

This also allows for the removal of the ugly export of viper_cf_rst().

Signed-off-by: Marc Zyngier <[email protected]>
Signed-off-by: Eric Miao <[email protected]>
This commit is contained in:
Marc Zyngier 2009-11-14 13:39:13 +01:00 • committed by Eric Miao
commit c2de1c3829
9 changed files with 155 additions and 40 deletions

View file

@ -208,7 +208,7 @@ config PCMCIA_PXA2XX
depends on ARM && ARCH_PXA && PCMCIA
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCH_VIPER || ARCH_PXA_ESERIES || MACH_STARGATE2)
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2)
select PCMCIA_SOC_COMMON
help
Say Y here to include support for the PXA2xx PCMCIA controller

View file

@ -67,7 +67,7 @@ pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock_cs.o
pxa2xx-obj-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o
pxa2xx-obj-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o
pxa2xx-obj-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x2xx_cs.o
pxa2xx-obj-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o
pxa2xx-obj-$(CONFIG_ARCOM_PCMCIA) += pxa2xx_viper.o
pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps4.o
pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o
pxa2xx-obj-$(CONFIG_MACH_PALMTC) += pxa2xx_palmtc.o

View file

@ -214,7 +214,8 @@ static void pxa2xx_configure_sockets(struct device *dev)
MECR |= MECR_CIT;
/* Set MECR:NOS (Number Of Sockets) */
if ((ops->first + ops->nr) > 1 || machine_is_viper())
if ((ops->first + ops->nr) > 1 ||
machine_is_viper() || machine_is_arcom_zeus())
MECR |= MECR_NOS;
else
MECR &= ~MECR_NOS;

View file

@ -1,9 +1,8 @@
/*
* VIPER PCMCIA support
* Viper/Zeus PCMCIA support
* Copyright 2004 Arcom Control Systems
*
* Maintained by Marc Zyngier <maz@misterjones.org>
* <marc.zyngier@altran.com>
*
* Based on:
* iPAQ h2200 PCMCIA support
@ -26,37 +25,47 @@
#include <asm/irq.h>
#include <mach/viper.h>
#include <asm/mach-types.h>
#include <mach/arcom-pcmcia.h>
#include "soc_common.h"
#include "pxa2xx_base.h"
static struct platform_device *arcom_pcmcia_dev;
static struct pcmcia_irqs irqs[] = {
{ 0, gpio_to_irq(VIPER_CF_CD_GPIO), "PCMCIA_CD" }
{
.sock = 0,
.str = "PCMCIA_CD",
},
};
static inline struct arcom_pcmcia_pdata *viper_get_pdata(void)
{
return arcom_pcmcia_dev->dev.platform_data;
}
static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
{
struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
unsigned long flags;
skt->socket.pci_irq = gpio_to_irq(VIPER_CF_RDY_GPIO);
skt->socket.pci_irq = gpio_to_irq(pdata->rdy_gpio);
irqs[0].irq = gpio_to_irq(pdata->cd_gpio);
if (gpio_request(VIPER_CF_CD_GPIO, "CF detect"))
if (gpio_request(pdata->cd_gpio, "CF detect"))
goto err_request_cd;
if (gpio_request(VIPER_CF_RDY_GPIO, "CF ready"))
if (gpio_request(pdata->rdy_gpio, "CF ready"))
goto err_request_rdy;
if (gpio_request(VIPER_CF_POWER_GPIO, "CF power"))
if (gpio_request(pdata->pwr_gpio, "CF power"))
goto err_request_pwr;
local_irq_save(flags);
/* GPIO 82 is the CF power enable line. initially off */
if (gpio_direction_output(VIPER_CF_POWER_GPIO, 0) ||
gpio_direction_input(VIPER_CF_CD_GPIO) ||
gpio_direction_input(VIPER_CF_RDY_GPIO)) {
if (gpio_direction_output(pdata->pwr_gpio, 0) ||
gpio_direction_input(pdata->cd_gpio) ||
gpio_direction_input(pdata->rdy_gpio)) {
local_irq_restore(flags);
goto err_dir;
}
@ -66,13 +75,13 @@ static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
err_dir:
gpio_free(VIPER_CF_POWER_GPIO);
gpio_free(pdata->pwr_gpio);
err_request_pwr:
gpio_free(VIPER_CF_RDY_GPIO);
gpio_free(pdata->rdy_gpio);
err_request_rdy:
gpio_free(VIPER_CF_CD_GPIO);
gpio_free(pdata->cd_gpio);
err_request_cd:
printk(KERN_ERR "viper: Failed to setup PCMCIA GPIOs\n");
dev_err(&arcom_pcmcia_dev->dev, "Failed to setup PCMCIA GPIOs\n");
return -1;
}
@ -81,17 +90,21 @@ err_request_cd:
*/
static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
{
struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
gpio_free(VIPER_CF_POWER_GPIO);
gpio_free(VIPER_CF_RDY_GPIO);
gpio_free(VIPER_CF_CD_GPIO);
gpio_free(pdata->pwr_gpio);
gpio_free(pdata->rdy_gpio);
gpio_free(pdata->cd_gpio);
}
static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
struct pcmcia_state *state)
{
state->detect = gpio_get_value(VIPER_CF_CD_GPIO) ? 0 : 1;
state->ready = gpio_get_value(VIPER_CF_RDY_GPIO) ? 1 : 0;
struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
state->detect = !gpio_get_value(pdata->cd_gpio);
state->ready = !!gpio_get_value(pdata->rdy_gpio);
state->bvd1 = 1;
state->bvd2 = 1;
state->wrprot = 0;
@ -102,20 +115,21 @@ static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
const socket_state_t *state)
{
struct arcom_pcmcia_pdata *pdata = viper_get_pdata();
/* Silently ignore Vpp, output enable, speaker enable. */
viper_cf_rst(state->flags & SS_RESET);
pdata->reset(state->flags & SS_RESET);
/* Apply socket voltage */
switch (state->Vcc) {
case 0:
gpio_set_value(VIPER_CF_POWER_GPIO, 0);
gpio_set_value(pdata->pwr_gpio, 0);
break;
case 33:
gpio_set_value(VIPER_CF_POWER_GPIO, 1);
gpio_set_value(pdata->pwr_gpio, 1);
break;
default:
printk(KERN_ERR "%s: Unsupported Vcc:%d\n",
__func__, state->Vcc);
dev_err(&arcom_pcmcia_dev->dev, "Unsupported Vcc:%d\n", state->Vcc);
return -1;
}
@ -130,7 +144,7 @@ static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
{
}
static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
static struct pcmcia_low_level viper_pcmcia_ops = {
.owner = THIS_MODULE,
.hw_init = viper_pcmcia_hw_init,
.hw_shutdown = viper_pcmcia_hw_shutdown,
@ -143,17 +157,25 @@ static struct pcmcia_low_level viper_pcmcia_ops __initdata = {
static struct platform_device *viper_pcmcia_device;
static int __init viper_pcmcia_init(void)
static int viper_pcmcia_probe(struct platform_device *pdev)
{
int ret;
if (!machine_is_viper())
return -ENODEV;
/* I can't imagine more than one device, but you never know... */
if (arcom_pcmcia_dev)
return -EEXIST;
if (!pdev->dev.platform_data)
return -EINVAL;
viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
if (!viper_pcmcia_device)
return -ENOMEM;
arcom_pcmcia_dev = pdev;
viper_pcmcia_device->dev.parent = &pdev->dev;
ret = platform_device_add_data(viper_pcmcia_device,
&viper_pcmcia_ops,
sizeof(viper_pcmcia_ops));
@ -161,18 +183,49 @@ static int __init viper_pcmcia_init(void)
if (!ret)
ret = platform_device_add(viper_pcmcia_device);
if (ret)
if (ret) {
platform_device_put(viper_pcmcia_device);
arcom_pcmcia_dev = NULL;
}
return ret;
}
static void __exit viper_pcmcia_exit(void)
static int viper_pcmcia_remove(struct platform_device *pdev)
{
platform_device_unregister(viper_pcmcia_device);
arcom_pcmcia_dev = NULL;
return 0;
}
static struct platform_device_id viper_pcmcia_id_table[] = {
{ .name = "viper-pcmcia", },
{ .name = "zeus-pcmcia", },
{ },
};
static struct platform_driver viper_pcmcia_driver = {
.probe = viper_pcmcia_probe,
.remove = viper_pcmcia_remove,
.driver = {
.name = "arcom-pcmcia",
.owner = THIS_MODULE,
},
.id_table = viper_pcmcia_id_table,
};
static int __init viper_pcmcia_init(void)
{
return platform_driver_register(&viper_pcmcia_driver);
}
static void __exit viper_pcmcia_exit(void)
{
return platform_driver_unregister(&viper_pcmcia_driver);
}
module_init(viper_pcmcia_init);
module_exit(viper_pcmcia_exit);
MODULE_DEVICE_TABLE(platform, viper_pcmcia_id_table);
MODULE_LICENSE("GPL");