diff options
Diffstat (limited to 'drivers/pcmcia/l1110.c')
-rw-r--r-- | drivers/pcmcia/l1110.c | 109 |
1 files changed, 109 insertions, 0 deletions
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 <linux/io.h> +#include <linux/module.h> + +#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 <rmk+kernel@armlinux.org.uk>"); +MODULE_DESCRIPTION("LinkUp Systems L1110 driver"); +MODULE_LICENSE("GPL"); |