summaryrefslogtreecommitdiff
path: root/drivers/pcmcia/l1110.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia/l1110.c')
-rw-r--r--drivers/pcmcia/l1110.c109
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");