linux/drivers/scsi/jazz_esp.c
<<
>>
Prefs
   1/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.
   2 *
   3 * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
   4 */
   5
   6#include <linux/kernel.h>
   7#include <linux/types.h>
   8#include <linux/module.h>
   9#include <linux/init.h>
  10#include <linux/interrupt.h>
  11#include <linux/platform_device.h>
  12#include <linux/dma-mapping.h>
  13
  14#include <asm/irq.h>
  15#include <asm/io.h>
  16#include <asm/dma.h>
  17
  18#include <asm/jazz.h>
  19#include <asm/jazzdma.h>
  20
  21#include <scsi/scsi_host.h>
  22
  23#include "esp_scsi.h"
  24
  25#define DRV_MODULE_NAME         "jazz_esp"
  26#define PFX DRV_MODULE_NAME     ": "
  27#define DRV_VERSION             "1.000"
  28#define DRV_MODULE_RELDATE      "May 19, 2007"
  29
  30static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg)
  31{
  32        *(volatile u8 *)(esp->regs + reg) = val;
  33}
  34
  35static u8 jazz_esp_read8(struct esp *esp, unsigned long reg)
  36{
  37        return *(volatile u8 *)(esp->regs + reg);
  38}
  39
  40static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf,
  41                                      size_t sz, int dir)
  42{
  43        return dma_map_single(esp->dev, buf, sz, dir);
  44}
  45
  46static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg,
  47                                  int num_sg, int dir)
  48{
  49        return dma_map_sg(esp->dev, sg, num_sg, dir);
  50}
  51
  52static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr,
  53                                  size_t sz, int dir)
  54{
  55        dma_unmap_single(esp->dev, addr, sz, dir);
  56}
  57
  58static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
  59                              int num_sg, int dir)
  60{
  61        dma_unmap_sg(esp->dev, sg, num_sg, dir);
  62}
  63
  64static int jazz_esp_irq_pending(struct esp *esp)
  65{
  66        if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR)
  67                return 1;
  68        return 0;
  69}
  70
  71static void jazz_esp_reset_dma(struct esp *esp)
  72{
  73        vdma_disable ((int)esp->dma_regs);
  74}
  75
  76static void jazz_esp_dma_drain(struct esp *esp)
  77{
  78        /* nothing to do */
  79}
  80
  81static void jazz_esp_dma_invalidate(struct esp *esp)
  82{
  83        vdma_disable ((int)esp->dma_regs);
  84}
  85
  86static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
  87                                  u32 dma_count, int write, u8 cmd)
  88{
  89        BUG_ON(!(cmd & ESP_CMD_DMA));
  90
  91        jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
  92        jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
  93        vdma_disable ((int)esp->dma_regs);
  94        if (write)
  95                vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ);
  96        else
  97                vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE);
  98
  99        vdma_set_addr ((int)esp->dma_regs, addr);
 100        vdma_set_count ((int)esp->dma_regs, dma_count);
 101        vdma_enable ((int)esp->dma_regs);
 102
 103        scsi_esp_cmd(esp, cmd);
 104}
 105
 106static int jazz_esp_dma_error(struct esp *esp)
 107{
 108        u32 enable = vdma_get_enable((int)esp->dma_regs);
 109
 110        if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR))
 111                return 1;
 112
 113        return 0;
 114}
 115
 116static const struct esp_driver_ops jazz_esp_ops = {
 117        .esp_write8     =       jazz_esp_write8,
 118        .esp_read8      =       jazz_esp_read8,
 119        .map_single     =       jazz_esp_map_single,
 120        .map_sg         =       jazz_esp_map_sg,
 121        .unmap_single   =       jazz_esp_unmap_single,
 122        .unmap_sg       =       jazz_esp_unmap_sg,
 123        .irq_pending    =       jazz_esp_irq_pending,
 124        .reset_dma      =       jazz_esp_reset_dma,
 125        .dma_drain      =       jazz_esp_dma_drain,
 126        .dma_invalidate =       jazz_esp_dma_invalidate,
 127        .send_dma_cmd   =       jazz_esp_send_dma_cmd,
 128        .dma_error      =       jazz_esp_dma_error,
 129};
 130
 131static int __devinit esp_jazz_probe(struct platform_device *dev)
 132{
 133        struct scsi_host_template *tpnt = &scsi_esp_template;
 134        struct Scsi_Host *host;
 135        struct esp *esp;
 136        struct resource *res;
 137        int err;
 138
 139        host = scsi_host_alloc(tpnt, sizeof(struct esp));
 140
 141        err = -ENOMEM;
 142        if (!host)
 143                goto fail;
 144
 145        host->max_id = 8;
 146        esp = shost_priv(host);
 147
 148        esp->host = host;
 149        esp->dev = dev;
 150        esp->ops = &jazz_esp_ops;
 151
 152        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 153        if (!res)
 154                goto fail_unlink;
 155
 156        esp->regs = (void __iomem *)res->start;
 157        if (!esp->regs)
 158                goto fail_unlink;
 159
 160        res = platform_get_resource(dev, IORESOURCE_MEM, 1);
 161        if (!res)
 162                goto fail_unlink;
 163
 164        esp->dma_regs = (void __iomem *)res->start;
 165
 166        esp->command_block = dma_alloc_coherent(esp->dev, 16,
 167                                                &esp->command_block_dma,
 168                                                GFP_KERNEL);
 169        if (!esp->command_block)
 170                goto fail_unmap_regs;
 171
 172        host->irq = platform_get_irq(dev, 0);
 173        err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 174        if (err < 0)
 175                goto fail_unmap_command_block;
 176
 177        esp->scsi_id = 7;
 178        esp->host->this_id = esp->scsi_id;
 179        esp->scsi_id_mask = (1 << esp->scsi_id);
 180        esp->cfreq = 40000000;
 181
 182        dev_set_drvdata(&dev->dev, esp);
 183
 184        err = scsi_esp_register(esp, &dev->dev);
 185        if (err)
 186                goto fail_free_irq;
 187
 188        return 0;
 189
 190fail_free_irq:
 191        free_irq(host->irq, esp);
 192fail_unmap_command_block:
 193        dma_free_coherent(esp->dev, 16,
 194                          esp->command_block,
 195                          esp->command_block_dma);
 196fail_unmap_regs:
 197fail_unlink:
 198        scsi_host_put(host);
 199fail:
 200        return err;
 201}
 202
 203static int __devexit esp_jazz_remove(struct platform_device *dev)
 204{
 205        struct esp *esp = dev_get_drvdata(&dev->dev);
 206        unsigned int irq = esp->host->irq;
 207
 208        scsi_esp_unregister(esp);
 209
 210        free_irq(irq, esp);
 211        dma_free_coherent(esp->dev, 16,
 212                          esp->command_block,
 213                          esp->command_block_dma);
 214
 215        scsi_host_put(esp->host);
 216
 217        return 0;
 218}
 219
 220/* work with hotplug and coldplug */
 221MODULE_ALIAS("platform:jazz_esp");
 222
 223static struct platform_driver esp_jazz_driver = {
 224        .probe          = esp_jazz_probe,
 225        .remove         = __devexit_p(esp_jazz_remove),
 226        .driver = {
 227                .name   = "jazz_esp",
 228                .owner  = THIS_MODULE,
 229        },
 230};
 231
 232static int __init jazz_esp_init(void)
 233{
 234        return platform_driver_register(&esp_jazz_driver);
 235}
 236
 237static void __exit jazz_esp_exit(void)
 238{
 239        platform_driver_unregister(&esp_jazz_driver);
 240}
 241
 242MODULE_DESCRIPTION("JAZZ ESP SCSI driver");
 243MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)");
 244MODULE_LICENSE("GPL");
 245MODULE_VERSION(DRV_VERSION);
 246
 247module_init(jazz_esp_init);
 248module_exit(jazz_esp_exit);
 249