From 1df15df24619fa571e23d283980b8aecd408ed60 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 15 Sep 2016 16:41:40 +0100 Subject: pcmcia: convert sa1100_h3600 to support dual-slot sleeve only --- drivers/pcmcia/Makefile | 4 +- drivers/pcmcia/l1110.c | 109 ++++++++++++++++++++++++++++++++++++++++++ drivers/pcmcia/l1110.h | 15 ++++++ drivers/pcmcia/sa1100_h3600.c | 97 ++++++++++++++----------------------- 4 files changed, 161 insertions(+), 64 deletions(-) create mode 100644 drivers/pcmcia/l1110.c create mode 100644 drivers/pcmcia/l1110.h diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 01779c5c45f3..3013ef03c4cf 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -45,8 +45,8 @@ sa1111_cs-$(CONFIG_ARCH_LUBBOCK) += sa1111_lubbock.o sa1100_cs-y += sa1100_generic.o sa1100_cs-$(CONFIG_SA1100_COLLIE) += pxa2xx_sharpsl.o -sa1100_cs-$(CONFIG_SA1100_H3100) += sa1100_h3600.o -sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-$(CONFIG_SA1100_H3100) += sa1100_h3600.o l1110.o +sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o l1110.o sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o pxa2xx_cm_x2xx_cs-y += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o diff --git a/drivers/pcmcia/l1110.c b/drivers/pcmcia/l1110.c new file mode 100644 index 000000000000..67507019d3db --- /dev/null +++ b/drivers/pcmcia/l1110.c @@ -0,0 +1,109 @@ +#include +#include + +#include "l1110.h" +#include "soc_common.h" + +enum { + PRS_S1 = BIT(0), + PRS_S2 = BIT(1), + PRS_S3 = BIT(2), + PRS_S4 = BIT(3), + PRS_BVD1 = BIT(4), + PRS_BVD2 = BIT(5), + PRS_VS1 = BIT(6), + PRS_VS2 = BIT(7), + PRS_RDY = BIT(8), + PRS_CD1 = BIT(9), + PRS_CD2 = BIT(10), + + PRC_S1 = PRS_S1, /* x1vcc - TPS2205 D2/D7 */ + PRC_S2 = PRS_S2, /* x0vcc - TPS2205 D3/D6 */ + PRC_S3 = PRS_S3, /* x0vpp - TPS2205 D1/D5 */ + PRC_S4 = PRS_S4, /* x1vpp - TPS2205 D0/D4 */ + PRC_RST = BIT(4), + PRC_APOE = BIT(5), /* auto power off enable */ + PRC_CFE = BIT(6), /* CF enable: A25:11 driven high */ + PRC_SOE = BIT(7), /* signal output enable */ + PRC_SSP = BIT(8), /* socket select polarity */ +}; + +struct l1110 { + void __iomem *reg; + u16 prc; +}; + +int l1110_init(struct device *dev, struct l1110 **ptr, resource_size_t base, + unsigned int ssp) +{ + struct l1110 *l; + + l = devm_kzalloc(dev, sizeof(*l), GFP_KERNEL); + if (!l) + return -ENOMEM; + + l->prc = PRC_APOE | (ssp ? PRC_SSP : 0); + l->reg = devm_ioremap(dev, base, 2); + if (!l->reg) + return -ENOMEM; + + *ptr = l; + + writew_relaxed(l->prc, l->reg); + + return 0; +} +EXPORT_SYMBOL_GPL(l1110_init); + +void l1110_socket_state(struct l1110 *l, struct pcmcia_state *state) +{ + u16 prs = readw_relaxed(l->reg); + + state->bvd1 = !!(prs & PRS_BVD1); + state->bvd2 = !!(prs & PRS_BVD2); + state->vs_3v = !(prs & PRS_VS1); + state->vs_Xv = !(prs & PRS_VS2); +} +EXPORT_SYMBOL_GPL(l1110_socket_state); + +int l1110_configure_socket(struct l1110 *l, const socket_state_t *state) +{ + u16 prc = l->prc; + + switch (state->Vcc) { + case 0: + break; + case 33: + prc |= PRC_S1; + break; + case 50: + prc |= PRC_S2; + break; + default: + return -EINVAL; + } + + if (state->Vpp) { + if (state->Vpp == 12) + prc |= PRC_S4; + else if (state->Vpp == state->Vcc) + prc |= PRC_S3; + else + return -EINVAL; + } + + if (state->flags & SS_RESET) + prc |= PRC_RST; + + if (state->flags & SS_OUTPUT_ENA) + prc |= PRC_SOE; + + writew_relaxed(prc, l->reg); + + return 0; +} +EXPORT_SYMBOL_GPL(l1110_configure_socket); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("LinkUp Systems L1110 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/l1110.h b/drivers/pcmcia/l1110.h new file mode 100644 index 000000000000..2e404f64836a --- /dev/null +++ b/drivers/pcmcia/l1110.h @@ -0,0 +1,15 @@ +#ifndef L1110_H +#define L1110_H + +#include +#include + +struct l1110; +struct pcmcia_state; + +int l1110_init(struct device *dev, struct l1110 **ptr, resource_size_t base, + unsigned int ssp); +void l1110_socket_state(struct l1110 *l, struct pcmcia_state *state); +int l1110_configure_socket(struct l1110 *l, const socket_state_t *state); + +#endif diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index a6d387d9ec4d..2e9265e59ae4 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -5,23 +5,23 @@ * PCMCIA implementation routines for H3600 * */ -#include #include #include -#include -#include -#include -#include -#include -#include #include -#include +#include "l1110.h" #include "sa1100_generic.h" -static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt) +struct ipaq_option_id { + u16 vendor; + u16 device; +}; + +static int l1110_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { + struct device *dev = skt->socket.dev.parent; + struct l1110 *l; int err; skt->stat[SOC_STAT_CD].name = skt->nr ? "pcmcia1-detect" : "pcmcia0-detect"; @@ -31,75 +31,48 @@ static int h3600_pcmcia_hw_init(struct soc_pcmcia_socket *skt) if (err) return err; - switch (skt->nr) { - case 0: - err = gpio_request(H3XXX_EGPIO_CARD_RESET, "PCMCIA CARD RESET"); - if (err) - goto err05; - err = gpio_direction_output(H3XXX_EGPIO_CARD_RESET, 0); - if (err) - goto err06; - break; - case 1: - break; - } - return 0; + err = l1110_init(dev, &l, skt->nr ? 0x19000000 : 0x1a000000, + skt->nr); + if (err) + return err; -err06: gpio_free(H3XXX_EGPIO_CARD_RESET); -err05: return err; -} + skt->socket.driver_data = l; -static void h3600_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) -{ - switch (skt->nr) { - case 0: - /* Disable CF bus: */ - gpio_free(H3XXX_EGPIO_CARD_RESET); - break; - case 1: - break; - } + return 0; } -static void -h3600_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) +static void l1110_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) { - state->bvd1 = 0; - state->bvd2 = 0; - state->vs_3v = 0; - state->vs_Xv = 0; + struct l1110 *l = skt->socket.driver_data; + + l1110_socket_state(l, state); } -static int -h3600_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) +static int l1110_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t *state) { - if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) { - printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", - state->Vcc / 10, state->Vcc % 10); - return -1; - } - - gpio_set_value(H3XXX_EGPIO_CARD_RESET, !!(state->flags & SS_RESET)); + struct l1110 *l = skt->socket.driver_data; - /* Silently ignore Vpp, output enable, speaker enable. */ - - return 0; + return l1110_configure_socket(l, state); } -struct pcmcia_low_level h3600_pcmcia_ops = { +static struct pcmcia_low_level l1110_pcmcia_ops = { .owner = THIS_MODULE, - .hw_init = h3600_pcmcia_hw_init, - .hw_shutdown = h3600_pcmcia_hw_shutdown, - .socket_state = h3600_pcmcia_socket_state, - .configure_socket = h3600_pcmcia_configure_socket, + .hw_init = l1110_pcmcia_hw_init, + .socket_state = l1110_pcmcia_socket_state, + .configure_socket = l1110_pcmcia_configure_socket, }; int pcmcia_h3600_init(struct device *dev) { - int ret = -ENODEV; + struct ipaq_option_id *id = dev->platform_data; + + if ((!machine_is_h3600() && !machine_is_h3100()) || !id) + return -ENODEV; - if (machine_is_h3600() || machine_is_h3100()) - ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); + if (id->vendor != 0x1125 || id->device != 0x0001) + return -ENODEV; - return ret; + return sa11xx_drv_pcmcia_probe(dev, &l1110_pcmcia_ops, 0, 2); } -- cgit