^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) Device driver for the PCMCIA control functionality of StrongARM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) SA-1100 microprocessors.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) The contents of this file are subject to the Mozilla Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) License Version 1.1 (the "License"); you may not use this file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) except in compliance with the License. You may obtain a copy of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) the License at http://www.mozilla.org/MPL/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) Software distributed under the License is distributed on an "AS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) implied. See the License for the specific language governing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) rights and limitations under the License.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) The initial developer of the original code is John G. Dorsey
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) <john+@cs.cmu.edu>. Portions created by John G. Dorsey are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) Copyright (C) 1999 John G. Dorsey. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) Alternatively, the contents of this file may be used under the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) terms of the GNU Public License version 2 (the "GPL"), in which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) case the provisions of the GPL are applicable instead of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) above. If you wish to allow the use of your version of this file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) only under the terms of the GPL and not to allow others to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) your version of this file under the MPL, indicate your decision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) by deleting the provisions above and replace them with the notice
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) and other provisions required by the GPL. If you do not delete
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) the provisions above, a recipient may use your version of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) file under either the MPL or the GPL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/regulator/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <pcmcia/ss.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <asm/hardware/scoop.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include "sa1100_generic.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static const char *sa11x0_cf_gpio_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) [SOC_STAT_CD] = "detect",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) [SOC_STAT_BVD1] = "bvd1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) [SOC_STAT_BVD2] = "bvd2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) [SOC_STAT_RDY] = "ready",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int sa11x0_cf_hw_init(struct soc_pcmcia_socket *skt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct device *dev = skt->socket.dev.parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) skt->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (IS_ERR(skt->gpio_reset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return PTR_ERR(skt->gpio_reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) skt->gpio_bus_enable = devm_gpiod_get_optional(dev, "bus-enable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) GPIOD_OUT_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (IS_ERR(skt->gpio_bus_enable))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return PTR_ERR(skt->gpio_bus_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) skt->vcc.reg = devm_regulator_get_optional(dev, "vcc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (IS_ERR(skt->vcc.reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return PTR_ERR(skt->vcc.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!skt->vcc.reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) dev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "no Vcc regulator provided, ignoring Vcc controls\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) for (i = 0; i < ARRAY_SIZE(sa11x0_cf_gpio_names); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) skt->stat[i].name = sa11x0_cf_gpio_names[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) skt->stat[i].desc = devm_gpiod_get_optional(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) sa11x0_cf_gpio_names[i], GPIOD_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (IS_ERR(skt->stat[i].desc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return PTR_ERR(skt->stat[i].desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int sa11x0_cf_configure_socket(struct soc_pcmcia_socket *skt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) const socket_state_t *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return soc_pcmcia_regulator_set(skt, &skt->vcc, state->Vcc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static struct pcmcia_low_level sa11x0_cf_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) .hw_init = sa11x0_cf_hw_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) .socket_state = soc_common_cf_socket_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .configure_socket = sa11x0_cf_configure_socket,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) int __init pcmcia_collie_init(struct device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int (*sa11x0_pcmcia_legacy_hw_init[])(struct device *dev) = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) pcmcia_h3600_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #ifdef CONFIG_SA1100_SIMPAD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) pcmcia_simpad_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #ifdef CONFIG_SA1100_COLLIE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pcmcia_collie_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static int sa11x0_drv_pcmcia_legacy_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int i, ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * Initialise any "on-board" PCMCIA sockets.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_legacy_hw_init); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) ret = sa11x0_pcmcia_legacy_hw_init[i](&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int sa11x0_drv_pcmcia_legacy_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct skt_dev_info *sinfo = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) platform_set_drvdata(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) for (i = 0; i < sinfo->nskt; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) soc_pcmcia_remove_one(&sinfo->skt[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static int sa11x0_drv_pcmcia_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct soc_pcmcia_socket *skt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (pdev->id == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return sa11x0_drv_pcmcia_legacy_probe(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) skt = devm_kzalloc(dev, sizeof(*skt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!skt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) platform_set_drvdata(pdev, skt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) skt->nr = pdev->id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) skt->clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (IS_ERR(skt->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) return PTR_ERR(skt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) sa11xx_drv_pcmcia_ops(&sa11x0_cf_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) soc_pcmcia_init_one(skt, &sa11x0_cf_ops, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return sa11xx_drv_pcmcia_add_one(skt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) struct soc_pcmcia_socket *skt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (dev->id == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return sa11x0_drv_pcmcia_legacy_remove(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) skt = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) soc_pcmcia_remove_one(skt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static struct platform_driver sa11x0_pcmcia_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .name = "sa11x0-pcmcia",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .probe = sa11x0_drv_pcmcia_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) .remove = sa11x0_drv_pcmcia_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* sa11x0_pcmcia_init()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * ^^^^^^^^^^^^^^^^^^^^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * This routine performs low-level PCMCIA initialization and then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * registers this socket driver with Card Services.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) * Returns: 0 on success, -ve error code on failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) static int __init sa11x0_pcmcia_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return platform_driver_register(&sa11x0_pcmcia_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* sa11x0_pcmcia_exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * ^^^^^^^^^^^^^^^^^^^^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * Invokes the low-level kernel service to free IRQs associated with this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * socket controller and reset GPIO edge detection.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static void __exit sa11x0_pcmcia_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) platform_driver_unregister(&sa11x0_pcmcia_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) MODULE_LICENSE("Dual MPL/GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) fs_initcall(sa11x0_pcmcia_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) module_exit(sa11x0_pcmcia_exit);