1*a16efc1cSKars de Jong /* 2*a16efc1cSKars de Jong * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux. 3*a16efc1cSKars de Jong * Amiga Technologies A4000T SCSI controller. 4*a16efc1cSKars de Jong * 5*a16efc1cSKars de Jong * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk> 6*a16efc1cSKars de Jong * plus modifications of the 53c7xx.c driver to support the Amiga. 7*a16efc1cSKars de Jong * 8*a16efc1cSKars de Jong * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org> 9*a16efc1cSKars de Jong */ 10*a16efc1cSKars de Jong 11*a16efc1cSKars de Jong #include <linux/module.h> 12*a16efc1cSKars de Jong #include <linux/platform_device.h> 13*a16efc1cSKars de Jong #include <linux/init.h> 14*a16efc1cSKars de Jong #include <linux/interrupt.h> 15*a16efc1cSKars de Jong #include <asm/amigaints.h> 16*a16efc1cSKars de Jong #include <scsi/scsi_host.h> 17*a16efc1cSKars de Jong #include <scsi/scsi_transport_spi.h> 18*a16efc1cSKars de Jong 19*a16efc1cSKars de Jong #include "53c700.h" 20*a16efc1cSKars de Jong 21*a16efc1cSKars de Jong MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>"); 22*a16efc1cSKars de Jong MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver"); 23*a16efc1cSKars de Jong MODULE_LICENSE("GPL"); 24*a16efc1cSKars de Jong 25*a16efc1cSKars de Jong 26*a16efc1cSKars de Jong static struct scsi_host_template a4000t_scsi_driver_template = { 27*a16efc1cSKars de Jong .name = "A4000T builtin SCSI", 28*a16efc1cSKars de Jong .proc_name = "A4000t", 29*a16efc1cSKars de Jong .this_id = 7, 30*a16efc1cSKars de Jong .module = THIS_MODULE, 31*a16efc1cSKars de Jong }; 32*a16efc1cSKars de Jong 33*a16efc1cSKars de Jong static struct platform_device *a4000t_scsi_device; 34*a16efc1cSKars de Jong 35*a16efc1cSKars de Jong #define A4000T_SCSI_ADDR 0xdd0040 36*a16efc1cSKars de Jong 37*a16efc1cSKars de Jong static int __devinit a4000t_probe(struct device *dev) 38*a16efc1cSKars de Jong { 39*a16efc1cSKars de Jong struct Scsi_Host * host = NULL; 40*a16efc1cSKars de Jong struct NCR_700_Host_Parameters *hostdata; 41*a16efc1cSKars de Jong 42*a16efc1cSKars de Jong if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI))) 43*a16efc1cSKars de Jong goto out; 44*a16efc1cSKars de Jong 45*a16efc1cSKars de Jong if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000, 46*a16efc1cSKars de Jong "A4000T builtin SCSI")) 47*a16efc1cSKars de Jong goto out; 48*a16efc1cSKars de Jong 49*a16efc1cSKars de Jong hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); 50*a16efc1cSKars de Jong if (hostdata == NULL) { 51*a16efc1cSKars de Jong printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n"); 52*a16efc1cSKars de Jong goto out_release; 53*a16efc1cSKars de Jong } 54*a16efc1cSKars de Jong memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters)); 55*a16efc1cSKars de Jong 56*a16efc1cSKars de Jong /* Fill in the required pieces of hostdata */ 57*a16efc1cSKars de Jong hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR); 58*a16efc1cSKars de Jong hostdata->clock = 50; 59*a16efc1cSKars de Jong hostdata->chip710 = 1; 60*a16efc1cSKars de Jong hostdata->dmode_extra = DMODE_FC2; 61*a16efc1cSKars de Jong hostdata->dcntl_extra = EA_710; 62*a16efc1cSKars de Jong 63*a16efc1cSKars de Jong /* and register the chip */ 64*a16efc1cSKars de Jong host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, dev); 65*a16efc1cSKars de Jong if (!host) { 66*a16efc1cSKars de Jong printk(KERN_ERR "a4000t-scsi: No host detected; " 67*a16efc1cSKars de Jong "board configuration problem?\n"); 68*a16efc1cSKars de Jong goto out_free; 69*a16efc1cSKars de Jong } 70*a16efc1cSKars de Jong 71*a16efc1cSKars de Jong host->this_id = 7; 72*a16efc1cSKars de Jong host->base = A4000T_SCSI_ADDR; 73*a16efc1cSKars de Jong host->irq = IRQ_AMIGA_PORTS; 74*a16efc1cSKars de Jong 75*a16efc1cSKars de Jong if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi", 76*a16efc1cSKars de Jong host)) { 77*a16efc1cSKars de Jong printk(KERN_ERR "a4000t-scsi: request_irq failed\n"); 78*a16efc1cSKars de Jong goto out_put_host; 79*a16efc1cSKars de Jong } 80*a16efc1cSKars de Jong 81*a16efc1cSKars de Jong scsi_scan_host(host); 82*a16efc1cSKars de Jong 83*a16efc1cSKars de Jong return 0; 84*a16efc1cSKars de Jong 85*a16efc1cSKars de Jong out_put_host: 86*a16efc1cSKars de Jong scsi_host_put(host); 87*a16efc1cSKars de Jong out_free: 88*a16efc1cSKars de Jong kfree(hostdata); 89*a16efc1cSKars de Jong out_release: 90*a16efc1cSKars de Jong release_mem_region(A4000T_SCSI_ADDR, 0x1000); 91*a16efc1cSKars de Jong out: 92*a16efc1cSKars de Jong return -ENODEV; 93*a16efc1cSKars de Jong } 94*a16efc1cSKars de Jong 95*a16efc1cSKars de Jong static __devexit int a4000t_device_remove(struct device *dev) 96*a16efc1cSKars de Jong { 97*a16efc1cSKars de Jong struct Scsi_Host *host = dev_to_shost(dev); 98*a16efc1cSKars de Jong struct NCR_700_Host_Parameters *hostdata = shost_priv(host); 99*a16efc1cSKars de Jong 100*a16efc1cSKars de Jong scsi_remove_host(host); 101*a16efc1cSKars de Jong 102*a16efc1cSKars de Jong NCR_700_release(host); 103*a16efc1cSKars de Jong kfree(hostdata); 104*a16efc1cSKars de Jong free_irq(host->irq, host); 105*a16efc1cSKars de Jong release_mem_region(A4000T_SCSI_ADDR, 0x1000); 106*a16efc1cSKars de Jong 107*a16efc1cSKars de Jong return 0; 108*a16efc1cSKars de Jong } 109*a16efc1cSKars de Jong 110*a16efc1cSKars de Jong static struct device_driver a4000t_scsi_driver = { 111*a16efc1cSKars de Jong .name = "a4000t-scsi", 112*a16efc1cSKars de Jong .bus = &platform_bus_type, 113*a16efc1cSKars de Jong .probe = a4000t_probe, 114*a16efc1cSKars de Jong .remove = __devexit_p(a4000t_device_remove), 115*a16efc1cSKars de Jong }; 116*a16efc1cSKars de Jong 117*a16efc1cSKars de Jong static int __init a4000t_scsi_init(void) 118*a16efc1cSKars de Jong { 119*a16efc1cSKars de Jong int err; 120*a16efc1cSKars de Jong 121*a16efc1cSKars de Jong err = driver_register(&a4000t_scsi_driver); 122*a16efc1cSKars de Jong if (err) 123*a16efc1cSKars de Jong return err; 124*a16efc1cSKars de Jong 125*a16efc1cSKars de Jong a4000t_scsi_device = platform_device_register_simple("a4000t-scsi", 126*a16efc1cSKars de Jong -1, NULL, 0); 127*a16efc1cSKars de Jong if (IS_ERR(a4000t_scsi_device)) { 128*a16efc1cSKars de Jong driver_unregister(&a4000t_scsi_driver); 129*a16efc1cSKars de Jong return PTR_ERR(a4000t_scsi_device); 130*a16efc1cSKars de Jong } 131*a16efc1cSKars de Jong 132*a16efc1cSKars de Jong return err; 133*a16efc1cSKars de Jong } 134*a16efc1cSKars de Jong 135*a16efc1cSKars de Jong static void __exit a4000t_scsi_exit(void) 136*a16efc1cSKars de Jong { 137*a16efc1cSKars de Jong platform_device_unregister(a4000t_scsi_device); 138*a16efc1cSKars de Jong driver_unregister(&a4000t_scsi_driver); 139*a16efc1cSKars de Jong } 140*a16efc1cSKars de Jong 141*a16efc1cSKars de Jong module_init(a4000t_scsi_init); 142*a16efc1cSKars de Jong module_exit(a4000t_scsi_exit); 143