Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  smssdio.c - Siano 1xxx SDIO interface driver
0004  *
0005  *  Copyright 2008 Pierre Ossman
0006  *
0007  * Based on code by Siano Mobile Silicon, Inc.,
0008  * Copyright (C) 2006-2008, Uri Shkolnik
0009  *
0010  * This hardware is a bit odd in that all transfers should be done
0011  * to/from the SMSSDIO_DATA register, yet the "increase address" bit
0012  * always needs to be set.
0013  *
0014  * Also, buffers from the card are always aligned to 128 byte
0015  * boundaries.
0016  */
0017 
0018 /*
0019  * General cleanup notes:
0020  *
0021  * - only typedefs should be name *_t
0022  *
0023  * - use ERR_PTR and friends for smscore_register_device()
0024  *
0025  * - smscore_getbuffer should zero fields
0026  *
0027  * Fix stop command
0028  */
0029 
0030 #include "smscoreapi.h"
0031 
0032 #include <linux/moduleparam.h>
0033 #include <linux/slab.h>
0034 #include <linux/firmware.h>
0035 #include <linux/delay.h>
0036 #include <linux/mmc/card.h>
0037 #include <linux/mmc/sdio_func.h>
0038 #include <linux/mmc/sdio_ids.h>
0039 #include <linux/module.h>
0040 
0041 #include "sms-cards.h"
0042 #include "smsendian.h"
0043 
0044 /* Registers */
0045 
0046 #define SMSSDIO_DATA        0x00
0047 #define SMSSDIO_INT     0x04
0048 #define SMSSDIO_BLOCK_SIZE  128
0049 
0050 static const struct sdio_device_id smssdio_ids[] = {
0051     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
0052      .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
0053     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
0054      .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
0055     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
0056      .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
0057     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
0058      .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
0059     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
0060      .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
0061     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_MING),
0062     .driver_data = SMS1XXX_BOARD_SIANO_MING},
0063     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_PELE),
0064     .driver_data = SMS1XXX_BOARD_SIANO_PELE},
0065     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_RIO),
0066     .driver_data = SMS1XXX_BOARD_SIANO_RIO},
0067     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_2160),
0068     .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160},
0069     {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_DENVER_1530),
0070     .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530},
0071     { /* end: all zeroes */ },
0072 };
0073 
0074 MODULE_DEVICE_TABLE(sdio, smssdio_ids);
0075 
0076 struct smssdio_device {
0077     struct sdio_func *func;
0078 
0079     struct smscore_device_t *coredev;
0080 
0081     struct smscore_buffer_t *split_cb;
0082 };
0083 
0084 /*******************************************************************/
0085 /* Siano core callbacks                                            */
0086 /*******************************************************************/
0087 
0088 static int smssdio_sendrequest(void *context, void *buffer, size_t size)
0089 {
0090     int ret = 0;
0091     struct smssdio_device *smsdev;
0092 
0093     smsdev = context;
0094 
0095     sdio_claim_host(smsdev->func);
0096 
0097     smsendian_handle_tx_message((struct sms_msg_data *) buffer);
0098     while (size >= smsdev->func->cur_blksize) {
0099         ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
0100                     buffer, smsdev->func->cur_blksize);
0101         if (ret)
0102             goto out;
0103 
0104         buffer += smsdev->func->cur_blksize;
0105         size -= smsdev->func->cur_blksize;
0106     }
0107 
0108     if (size) {
0109         ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
0110                     buffer, size);
0111     }
0112 
0113 out:
0114     sdio_release_host(smsdev->func);
0115 
0116     return ret;
0117 }
0118 
0119 /*******************************************************************/
0120 /* SDIO callbacks                                                  */
0121 /*******************************************************************/
0122 
0123 static void smssdio_interrupt(struct sdio_func *func)
0124 {
0125     int ret;
0126 
0127     struct smssdio_device *smsdev;
0128     struct smscore_buffer_t *cb;
0129     struct sms_msg_hdr *hdr;
0130     size_t size;
0131 
0132     smsdev = sdio_get_drvdata(func);
0133 
0134     /*
0135      * The interrupt register has no defined meaning. It is just
0136      * a way of turning of the level triggered interrupt.
0137      */
0138     (void)sdio_readb(func, SMSSDIO_INT, &ret);
0139     if (ret) {
0140         pr_err("Unable to read interrupt register!\n");
0141         return;
0142     }
0143 
0144     if (smsdev->split_cb == NULL) {
0145         cb = smscore_getbuffer(smsdev->coredev);
0146         if (!cb) {
0147             pr_err("Unable to allocate data buffer!\n");
0148             return;
0149         }
0150 
0151         ret = sdio_memcpy_fromio(smsdev->func,
0152                      cb->p,
0153                      SMSSDIO_DATA,
0154                      SMSSDIO_BLOCK_SIZE);
0155         if (ret) {
0156             pr_err("Error %d reading initial block!\n", ret);
0157             return;
0158         }
0159 
0160         hdr = cb->p;
0161 
0162         if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
0163             smsdev->split_cb = cb;
0164             return;
0165         }
0166 
0167         if (hdr->msg_length > smsdev->func->cur_blksize)
0168             size = hdr->msg_length - smsdev->func->cur_blksize;
0169         else
0170             size = 0;
0171     } else {
0172         cb = smsdev->split_cb;
0173         hdr = cb->p;
0174 
0175         size = hdr->msg_length - sizeof(struct sms_msg_hdr);
0176 
0177         smsdev->split_cb = NULL;
0178     }
0179 
0180     if (size) {
0181         void *buffer;
0182 
0183         buffer = cb->p + (hdr->msg_length - size);
0184         size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
0185 
0186         BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
0187 
0188         /*
0189          * First attempt to transfer all of it in one go...
0190          */
0191         ret = sdio_memcpy_fromio(smsdev->func,
0192                      buffer,
0193                      SMSSDIO_DATA,
0194                      size);
0195         if (ret && ret != -EINVAL) {
0196             smscore_putbuffer(smsdev->coredev, cb);
0197             pr_err("Error %d reading data from card!\n", ret);
0198             return;
0199         }
0200 
0201         /*
0202          * ..then fall back to one block at a time if that is
0203          * not possible...
0204          *
0205          * (we have to do this manually because of the
0206          * problem with the "increase address" bit)
0207          */
0208         if (ret == -EINVAL) {
0209             while (size) {
0210                 ret = sdio_memcpy_fromio(smsdev->func,
0211                           buffer, SMSSDIO_DATA,
0212                           smsdev->func->cur_blksize);
0213                 if (ret) {
0214                     smscore_putbuffer(smsdev->coredev, cb);
0215                     pr_err("Error %d reading data from card!\n",
0216                            ret);
0217                     return;
0218                 }
0219 
0220                 buffer += smsdev->func->cur_blksize;
0221                 if (size > smsdev->func->cur_blksize)
0222                     size -= smsdev->func->cur_blksize;
0223                 else
0224                     size = 0;
0225             }
0226         }
0227     }
0228 
0229     cb->size = hdr->msg_length;
0230     cb->offset = 0;
0231 
0232     smsendian_handle_rx_message((struct sms_msg_data *) cb->p);
0233     smscore_onresponse(smsdev->coredev, cb);
0234 }
0235 
0236 static int smssdio_probe(struct sdio_func *func,
0237              const struct sdio_device_id *id)
0238 {
0239     int ret;
0240 
0241     int board_id;
0242     struct smssdio_device *smsdev;
0243     struct smsdevice_params_t params;
0244 
0245     board_id = id->driver_data;
0246 
0247     smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
0248     if (!smsdev)
0249         return -ENOMEM;
0250 
0251     smsdev->func = func;
0252 
0253     memset(&params, 0, sizeof(struct smsdevice_params_t));
0254 
0255     params.device = &func->dev;
0256     params.buffer_size = 0x5000;    /* ?? */
0257     params.num_buffers = 22;    /* ?? */
0258     params.context = smsdev;
0259 
0260     snprintf(params.devpath, sizeof(params.devpath),
0261          "sdio\\%s", sdio_func_id(func));
0262 
0263     params.sendrequest_handler = smssdio_sendrequest;
0264 
0265     params.device_type = sms_get_board(board_id)->type;
0266 
0267     if (params.device_type != SMS_STELLAR)
0268         params.flags |= SMS_DEVICE_FAMILY2;
0269     else {
0270         /*
0271          * FIXME: Stellar needs special handling...
0272          */
0273         ret = -ENODEV;
0274         goto free;
0275     }
0276 
0277     ret = smscore_register_device(&params, &smsdev->coredev, GFP_DMA, NULL);
0278     if (ret < 0)
0279         goto free;
0280 
0281     smscore_set_board_id(smsdev->coredev, board_id);
0282 
0283     sdio_claim_host(func);
0284 
0285     ret = sdio_enable_func(func);
0286     if (ret)
0287         goto release;
0288 
0289     ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
0290     if (ret)
0291         goto disable;
0292 
0293     ret = sdio_claim_irq(func, smssdio_interrupt);
0294     if (ret)
0295         goto disable;
0296 
0297     sdio_set_drvdata(func, smsdev);
0298 
0299     sdio_release_host(func);
0300 
0301     ret = smscore_start_device(smsdev->coredev);
0302     if (ret < 0)
0303         goto reclaim;
0304 
0305     return 0;
0306 
0307 reclaim:
0308     sdio_claim_host(func);
0309     sdio_release_irq(func);
0310 disable:
0311     sdio_disable_func(func);
0312 release:
0313     sdio_release_host(func);
0314     smscore_unregister_device(smsdev->coredev);
0315 free:
0316     kfree(smsdev);
0317 
0318     return ret;
0319 }
0320 
0321 static void smssdio_remove(struct sdio_func *func)
0322 {
0323     struct smssdio_device *smsdev;
0324 
0325     smsdev = sdio_get_drvdata(func);
0326 
0327     /* FIXME: racy! */
0328     if (smsdev->split_cb)
0329         smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
0330 
0331     smscore_unregister_device(smsdev->coredev);
0332 
0333     sdio_claim_host(func);
0334     sdio_release_irq(func);
0335     sdio_disable_func(func);
0336     sdio_release_host(func);
0337 
0338     kfree(smsdev);
0339 }
0340 
0341 static struct sdio_driver smssdio_driver = {
0342     .name = "smssdio",
0343     .id_table = smssdio_ids,
0344     .probe = smssdio_probe,
0345     .remove = smssdio_remove,
0346 };
0347 
0348 /*******************************************************************/
0349 /* Module functions                                                */
0350 /*******************************************************************/
0351 
0352 static int __init smssdio_module_init(void)
0353 {
0354     int ret = 0;
0355 
0356     printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
0357     printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
0358 
0359     ret = sdio_register_driver(&smssdio_driver);
0360 
0361     return ret;
0362 }
0363 
0364 static void __exit smssdio_module_exit(void)
0365 {
0366     sdio_unregister_driver(&smssdio_driver);
0367 }
0368 
0369 module_init(smssdio_module_init);
0370 module_exit(smssdio_module_exit);
0371 
0372 MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
0373 MODULE_AUTHOR("Pierre Ossman");
0374 MODULE_LICENSE("GPL");