root/drivers/media/mmc/siano/smssdio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smssdio_sendrequest
  2. smssdio_interrupt
  3. smssdio_probe
  4. smssdio_remove
  5. smssdio_module_init
  6. smssdio_module_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  smssdio.c - Siano 1xxx SDIO interface driver
   4  *
   5  *  Copyright 2008 Pierre Ossman
   6  *
   7  * Based on code by Siano Mobile Silicon, Inc.,
   8  * Copyright (C) 2006-2008, Uri Shkolnik
   9  *
  10  * This hardware is a bit odd in that all transfers should be done
  11  * to/from the SMSSDIO_DATA register, yet the "increase address" bit
  12  * always needs to be set.
  13  *
  14  * Also, buffers from the card are always aligned to 128 byte
  15  * boundaries.
  16  */
  17 
  18 /*
  19  * General cleanup notes:
  20  *
  21  * - only typedefs should be name *_t
  22  *
  23  * - use ERR_PTR and friends for smscore_register_device()
  24  *
  25  * - smscore_getbuffer should zero fields
  26  *
  27  * Fix stop command
  28  */
  29 
  30 #include "smscoreapi.h"
  31 
  32 #include <linux/moduleparam.h>
  33 #include <linux/slab.h>
  34 #include <linux/firmware.h>
  35 #include <linux/delay.h>
  36 #include <linux/mmc/card.h>
  37 #include <linux/mmc/sdio_func.h>
  38 #include <linux/mmc/sdio_ids.h>
  39 #include <linux/module.h>
  40 
  41 #include "sms-cards.h"
  42 #include "smsendian.h"
  43 
  44 /* Registers */
  45 
  46 #define SMSSDIO_DATA            0x00
  47 #define SMSSDIO_INT             0x04
  48 #define SMSSDIO_BLOCK_SIZE      128
  49 
  50 static const struct sdio_device_id smssdio_ids[] = {
  51         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
  52          .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
  53         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
  54          .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
  55         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
  56          .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
  57         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
  58          .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
  59         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
  60          .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
  61         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x302),
  62         .driver_data = SMS1XXX_BOARD_SIANO_MING},
  63         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x500),
  64         .driver_data = SMS1XXX_BOARD_SIANO_PELE},
  65         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x600),
  66         .driver_data = SMS1XXX_BOARD_SIANO_RIO},
  67         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x700),
  68         .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160},
  69         {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x800),
  70         .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530},
  71         { /* end: all zeroes */ },
  72 };
  73 
  74 MODULE_DEVICE_TABLE(sdio, smssdio_ids);
  75 
  76 struct smssdio_device {
  77         struct sdio_func *func;
  78 
  79         struct smscore_device_t *coredev;
  80 
  81         struct smscore_buffer_t *split_cb;
  82 };
  83 
  84 /*******************************************************************/
  85 /* Siano core callbacks                                            */
  86 /*******************************************************************/
  87 
  88 static int smssdio_sendrequest(void *context, void *buffer, size_t size)
  89 {
  90         int ret = 0;
  91         struct smssdio_device *smsdev;
  92 
  93         smsdev = context;
  94 
  95         sdio_claim_host(smsdev->func);
  96 
  97         smsendian_handle_tx_message((struct sms_msg_data *) buffer);
  98         while (size >= smsdev->func->cur_blksize) {
  99                 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
 100                                         buffer, smsdev->func->cur_blksize);
 101                 if (ret)
 102                         goto out;
 103 
 104                 buffer += smsdev->func->cur_blksize;
 105                 size -= smsdev->func->cur_blksize;
 106         }
 107 
 108         if (size) {
 109                 ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA,
 110                                         buffer, size);
 111         }
 112 
 113 out:
 114         sdio_release_host(smsdev->func);
 115 
 116         return ret;
 117 }
 118 
 119 /*******************************************************************/
 120 /* SDIO callbacks                                                  */
 121 /*******************************************************************/
 122 
 123 static void smssdio_interrupt(struct sdio_func *func)
 124 {
 125         int ret;
 126 
 127         struct smssdio_device *smsdev;
 128         struct smscore_buffer_t *cb;
 129         struct sms_msg_hdr *hdr;
 130         size_t size;
 131 
 132         smsdev = sdio_get_drvdata(func);
 133 
 134         /*
 135          * The interrupt register has no defined meaning. It is just
 136          * a way of turning of the level triggered interrupt.
 137          */
 138         (void)sdio_readb(func, SMSSDIO_INT, &ret);
 139         if (ret) {
 140                 pr_err("Unable to read interrupt register!\n");
 141                 return;
 142         }
 143 
 144         if (smsdev->split_cb == NULL) {
 145                 cb = smscore_getbuffer(smsdev->coredev);
 146                 if (!cb) {
 147                         pr_err("Unable to allocate data buffer!\n");
 148                         return;
 149                 }
 150 
 151                 ret = sdio_memcpy_fromio(smsdev->func,
 152                                          cb->p,
 153                                          SMSSDIO_DATA,
 154                                          SMSSDIO_BLOCK_SIZE);
 155                 if (ret) {
 156                         pr_err("Error %d reading initial block!\n", ret);
 157                         return;
 158                 }
 159 
 160                 hdr = cb->p;
 161 
 162                 if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) {
 163                         smsdev->split_cb = cb;
 164                         return;
 165                 }
 166 
 167                 if (hdr->msg_length > smsdev->func->cur_blksize)
 168                         size = hdr->msg_length - smsdev->func->cur_blksize;
 169                 else
 170                         size = 0;
 171         } else {
 172                 cb = smsdev->split_cb;
 173                 hdr = cb->p;
 174 
 175                 size = hdr->msg_length - sizeof(struct sms_msg_hdr);
 176 
 177                 smsdev->split_cb = NULL;
 178         }
 179 
 180         if (size) {
 181                 void *buffer;
 182 
 183                 buffer = cb->p + (hdr->msg_length - size);
 184                 size = ALIGN(size, SMSSDIO_BLOCK_SIZE);
 185 
 186                 BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE);
 187 
 188                 /*
 189                  * First attempt to transfer all of it in one go...
 190                  */
 191                 ret = sdio_memcpy_fromio(smsdev->func,
 192                                          buffer,
 193                                          SMSSDIO_DATA,
 194                                          size);
 195                 if (ret && ret != -EINVAL) {
 196                         smscore_putbuffer(smsdev->coredev, cb);
 197                         pr_err("Error %d reading data from card!\n", ret);
 198                         return;
 199                 }
 200 
 201                 /*
 202                  * ..then fall back to one block at a time if that is
 203                  * not possible...
 204                  *
 205                  * (we have to do this manually because of the
 206                  * problem with the "increase address" bit)
 207                  */
 208                 if (ret == -EINVAL) {
 209                         while (size) {
 210                                 ret = sdio_memcpy_fromio(smsdev->func,
 211                                                   buffer, SMSSDIO_DATA,
 212                                                   smsdev->func->cur_blksize);
 213                                 if (ret) {
 214                                         smscore_putbuffer(smsdev->coredev, cb);
 215                                         pr_err("Error %d reading data from card!\n",
 216                                                ret);
 217                                         return;
 218                                 }
 219 
 220                                 buffer += smsdev->func->cur_blksize;
 221                                 if (size > smsdev->func->cur_blksize)
 222                                         size -= smsdev->func->cur_blksize;
 223                                 else
 224                                         size = 0;
 225                         }
 226                 }
 227         }
 228 
 229         cb->size = hdr->msg_length;
 230         cb->offset = 0;
 231 
 232         smsendian_handle_rx_message((struct sms_msg_data *) cb->p);
 233         smscore_onresponse(smsdev->coredev, cb);
 234 }
 235 
 236 static int smssdio_probe(struct sdio_func *func,
 237                          const struct sdio_device_id *id)
 238 {
 239         int ret;
 240 
 241         int board_id;
 242         struct smssdio_device *smsdev;
 243         struct smsdevice_params_t params;
 244 
 245         board_id = id->driver_data;
 246 
 247         smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
 248         if (!smsdev)
 249                 return -ENOMEM;
 250 
 251         smsdev->func = func;
 252 
 253         memset(&params, 0, sizeof(struct smsdevice_params_t));
 254 
 255         params.device = &func->dev;
 256         params.buffer_size = 0x5000;    /* ?? */
 257         params.num_buffers = 22;        /* ?? */
 258         params.context = smsdev;
 259 
 260         snprintf(params.devpath, sizeof(params.devpath),
 261                  "sdio\\%s", sdio_func_id(func));
 262 
 263         params.sendrequest_handler = smssdio_sendrequest;
 264 
 265         params.device_type = sms_get_board(board_id)->type;
 266 
 267         if (params.device_type != SMS_STELLAR)
 268                 params.flags |= SMS_DEVICE_FAMILY2;
 269         else {
 270                 /*
 271                  * FIXME: Stellar needs special handling...
 272                  */
 273                 ret = -ENODEV;
 274                 goto free;
 275         }
 276 
 277         ret = smscore_register_device(&params, &smsdev->coredev, GFP_DMA, NULL);
 278         if (ret < 0)
 279                 goto free;
 280 
 281         smscore_set_board_id(smsdev->coredev, board_id);
 282 
 283         sdio_claim_host(func);
 284 
 285         ret = sdio_enable_func(func);
 286         if (ret)
 287                 goto release;
 288 
 289         ret = sdio_set_block_size(func, SMSSDIO_BLOCK_SIZE);
 290         if (ret)
 291                 goto disable;
 292 
 293         ret = sdio_claim_irq(func, smssdio_interrupt);
 294         if (ret)
 295                 goto disable;
 296 
 297         sdio_set_drvdata(func, smsdev);
 298 
 299         sdio_release_host(func);
 300 
 301         ret = smscore_start_device(smsdev->coredev);
 302         if (ret < 0)
 303                 goto reclaim;
 304 
 305         return 0;
 306 
 307 reclaim:
 308         sdio_claim_host(func);
 309         sdio_release_irq(func);
 310 disable:
 311         sdio_disable_func(func);
 312 release:
 313         sdio_release_host(func);
 314         smscore_unregister_device(smsdev->coredev);
 315 free:
 316         kfree(smsdev);
 317 
 318         return ret;
 319 }
 320 
 321 static void smssdio_remove(struct sdio_func *func)
 322 {
 323         struct smssdio_device *smsdev;
 324 
 325         smsdev = sdio_get_drvdata(func);
 326 
 327         /* FIXME: racy! */
 328         if (smsdev->split_cb)
 329                 smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
 330 
 331         smscore_unregister_device(smsdev->coredev);
 332 
 333         sdio_claim_host(func);
 334         sdio_release_irq(func);
 335         sdio_disable_func(func);
 336         sdio_release_host(func);
 337 
 338         kfree(smsdev);
 339 }
 340 
 341 static struct sdio_driver smssdio_driver = {
 342         .name = "smssdio",
 343         .id_table = smssdio_ids,
 344         .probe = smssdio_probe,
 345         .remove = smssdio_remove,
 346 };
 347 
 348 /*******************************************************************/
 349 /* Module functions                                                */
 350 /*******************************************************************/
 351 
 352 static int __init smssdio_module_init(void)
 353 {
 354         int ret = 0;
 355 
 356         printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
 357         printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
 358 
 359         ret = sdio_register_driver(&smssdio_driver);
 360 
 361         return ret;
 362 }
 363 
 364 static void __exit smssdio_module_exit(void)
 365 {
 366         sdio_unregister_driver(&smssdio_driver);
 367 }
 368 
 369 module_init(smssdio_module_init);
 370 module_exit(smssdio_module_exit);
 371 
 372 MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
 373 MODULE_AUTHOR("Pierre Ossman");
 374 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */