Back to home page

OSCL-LXR

 
 

    


0001 /*======================================================================
0002 
0003     Device driver for the PCMCIA control functionality of StrongARM
0004     SA-1100 microprocessors.
0005 
0006     The contents of this file are subject to the Mozilla Public
0007     License Version 1.1 (the "License"); you may not use this file
0008     except in compliance with the License. You may obtain a copy of
0009     the License at http://www.mozilla.org/MPL/
0010 
0011     Software distributed under the License is distributed on an "AS
0012     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
0013     implied. See the License for the specific language governing
0014     rights and limitations under the License.
0015 
0016     The initial developer of the original code is John G. Dorsey
0017     <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
0018     Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
0019 
0020     Alternatively, the contents of this file may be used under the
0021     terms of the GNU Public License version 2 (the "GPL"), in which
0022     case the provisions of the GPL are applicable instead of the
0023     above.  If you wish to allow the use of your version of this file
0024     only under the terms of the GPL and not to allow others to use
0025     your version of this file under the MPL, indicate your decision
0026     by deleting the provisions above and replace them with the notice
0027     and other provisions required by the GPL.  If you do not delete
0028     the provisions above, a recipient may use your version of this
0029     file under either the MPL or the GPL.
0030     
0031 ======================================================================*/
0032 
0033 #include <linux/module.h>
0034 #include <linux/gpio/consumer.h>
0035 #include <linux/init.h>
0036 #include <linux/regulator/consumer.h>
0037 #include <linux/slab.h>
0038 #include <linux/platform_device.h>
0039 
0040 #include <pcmcia/ss.h>
0041 
0042 #include <asm/hardware/scoop.h>
0043 
0044 #include "sa1100_generic.h"
0045 
0046 static const char *sa11x0_cf_gpio_names[] = {
0047     [SOC_STAT_CD] = "detect",
0048     [SOC_STAT_BVD1] = "bvd1",
0049     [SOC_STAT_BVD2] = "bvd2",
0050     [SOC_STAT_RDY] = "ready",
0051 };
0052 
0053 static int sa11x0_cf_hw_init(struct soc_pcmcia_socket *skt)
0054 {
0055     struct device *dev = skt->socket.dev.parent;
0056     int i;
0057 
0058     skt->gpio_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
0059     if (IS_ERR(skt->gpio_reset))
0060         return PTR_ERR(skt->gpio_reset);
0061 
0062     skt->gpio_bus_enable = devm_gpiod_get_optional(dev, "bus-enable",
0063                                GPIOD_OUT_HIGH);
0064     if (IS_ERR(skt->gpio_bus_enable))
0065         return PTR_ERR(skt->gpio_bus_enable);
0066 
0067     skt->vcc.reg = devm_regulator_get_optional(dev, "vcc");
0068     if (IS_ERR(skt->vcc.reg))
0069         return PTR_ERR(skt->vcc.reg);
0070 
0071     if (!skt->vcc.reg)
0072         dev_warn(dev,
0073              "no Vcc regulator provided, ignoring Vcc controls\n");
0074 
0075     for (i = 0; i < ARRAY_SIZE(sa11x0_cf_gpio_names); i++) {
0076         skt->stat[i].name = sa11x0_cf_gpio_names[i];
0077         skt->stat[i].desc = devm_gpiod_get_optional(dev,
0078                     sa11x0_cf_gpio_names[i], GPIOD_IN);
0079         if (IS_ERR(skt->stat[i].desc))
0080             return PTR_ERR(skt->stat[i].desc);
0081     }
0082     return 0;
0083 }
0084 
0085 static int sa11x0_cf_configure_socket(struct soc_pcmcia_socket *skt,
0086     const socket_state_t *state)
0087 {
0088     return soc_pcmcia_regulator_set(skt, &skt->vcc, state->Vcc);
0089 }
0090 
0091 static struct pcmcia_low_level sa11x0_cf_ops = {
0092     .owner = THIS_MODULE,
0093     .hw_init = sa11x0_cf_hw_init,
0094     .socket_state = soc_common_cf_socket_state,
0095     .configure_socket = sa11x0_cf_configure_socket,
0096 };
0097 
0098 int __init pcmcia_collie_init(struct device *dev);
0099 
0100 static int (*sa11x0_pcmcia_legacy_hw_init[])(struct device *dev) = {
0101 #if defined(CONFIG_SA1100_H3100) || defined(CONFIG_SA1100_H3600)
0102     pcmcia_h3600_init,
0103 #endif
0104 #ifdef CONFIG_SA1100_SIMPAD
0105     pcmcia_simpad_init,
0106 #endif
0107 #ifdef CONFIG_SA1100_COLLIE
0108        pcmcia_collie_init,
0109 #endif
0110 };
0111 
0112 static int sa11x0_drv_pcmcia_legacy_probe(struct platform_device *dev)
0113 {
0114     int i, ret = -ENODEV;
0115 
0116     /*
0117      * Initialise any "on-board" PCMCIA sockets.
0118      */
0119     for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_legacy_hw_init); i++) {
0120         ret = sa11x0_pcmcia_legacy_hw_init[i](&dev->dev);
0121         if (ret == 0)
0122             break;
0123     }
0124 
0125     return ret;
0126 }
0127 
0128 static int sa11x0_drv_pcmcia_legacy_remove(struct platform_device *dev)
0129 {
0130     struct skt_dev_info *sinfo = platform_get_drvdata(dev);
0131     int i;
0132 
0133     platform_set_drvdata(dev, NULL);
0134 
0135     for (i = 0; i < sinfo->nskt; i++)
0136         soc_pcmcia_remove_one(&sinfo->skt[i]);
0137 
0138     return 0;
0139 }
0140 
0141 static int sa11x0_drv_pcmcia_probe(struct platform_device *pdev)
0142 {
0143     struct soc_pcmcia_socket *skt;
0144     struct device *dev = &pdev->dev;
0145 
0146     if (pdev->id == -1)
0147         return sa11x0_drv_pcmcia_legacy_probe(pdev);
0148 
0149     skt = devm_kzalloc(dev, sizeof(*skt), GFP_KERNEL);
0150     if (!skt)
0151         return -ENOMEM;
0152 
0153     platform_set_drvdata(pdev, skt);
0154 
0155     skt->nr = pdev->id;
0156     skt->clk = devm_clk_get(dev, NULL);
0157     if (IS_ERR(skt->clk))
0158         return PTR_ERR(skt->clk);
0159 
0160     sa11xx_drv_pcmcia_ops(&sa11x0_cf_ops);
0161     soc_pcmcia_init_one(skt, &sa11x0_cf_ops, dev);
0162 
0163     return sa11xx_drv_pcmcia_add_one(skt);
0164 }
0165 
0166 static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
0167 {
0168     struct soc_pcmcia_socket *skt;
0169 
0170     if (dev->id == -1)
0171         return sa11x0_drv_pcmcia_legacy_remove(dev);
0172 
0173     skt = platform_get_drvdata(dev);
0174 
0175     soc_pcmcia_remove_one(skt);
0176 
0177     return 0;
0178 }
0179 
0180 static struct platform_driver sa11x0_pcmcia_driver = {
0181     .driver = {
0182         .name       = "sa11x0-pcmcia",
0183     },
0184     .probe      = sa11x0_drv_pcmcia_probe,
0185     .remove     = sa11x0_drv_pcmcia_remove,
0186 };
0187 
0188 /* sa11x0_pcmcia_init()
0189  * ^^^^^^^^^^^^^^^^^^^^
0190  *
0191  * This routine performs low-level PCMCIA initialization and then
0192  * registers this socket driver with Card Services.
0193  *
0194  * Returns: 0 on success, -ve error code on failure
0195  */
0196 static int __init sa11x0_pcmcia_init(void)
0197 {
0198     return platform_driver_register(&sa11x0_pcmcia_driver);
0199 }
0200 
0201 /* sa11x0_pcmcia_exit()
0202  * ^^^^^^^^^^^^^^^^^^^^
0203  * Invokes the low-level kernel service to free IRQs associated with this
0204  * socket controller and reset GPIO edge detection.
0205  */
0206 static void __exit sa11x0_pcmcia_exit(void)
0207 {
0208     platform_driver_unregister(&sa11x0_pcmcia_driver);
0209 }
0210 
0211 MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
0212 MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller");
0213 MODULE_LICENSE("Dual MPL/GPL");
0214 
0215 fs_initcall(sa11x0_pcmcia_init);
0216 module_exit(sa11x0_pcmcia_exit);