summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2016-09-15 16:41:40 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2020-10-12 21:56:14 +0100
commit1df15df24619fa571e23d283980b8aecd408ed60 (patch)
tree528d2f5affeec04ffe50e4173cc7dc4325c07eac
parentb8ed2eca34fc3d57d2eadbc31c12a521fe08e221 (diff)
pcmcia: convert sa1100_h3600 to support dual-slot sleeve only
-rw-r--r--drivers/pcmcia/Makefile4
-rw-r--r--drivers/pcmcia/l1110.c109
-rw-r--r--drivers/pcmcia/l1110.h15
-rw-r--r--drivers/pcmcia/sa1100_h3600.c97
4 files changed, 161 insertions, 64 deletions
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 <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");
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 <linux/types.h>
+#include <pcmcia/ss.h>
+
+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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <mach/h3xxx.h>
+#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);
}