^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * drivers/ata/pata_palmld.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Driver for IDE channel in Palm LifeDrive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on research of:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Alex Osborne <ato@meshy.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Rewrite for mainline:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Marek Vasut <marek.vasut@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Rewritten version based on pata_ixp4xx_cf.c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * ixp4xx PATA/Compact Flash driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Copyright (C) 2006-07 Tower Technologies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Author: Alessandro Zummo <a.zummo@towertech.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/libata.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <scsi/scsi_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <mach/palmld.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define DRV_NAME "pata_palmld"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct palmld_pata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct ata_host *host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct gpio_desc *power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct gpio_desc *reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static struct scsi_host_template palmld_sht = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) ATA_PIO_SHT(DRV_NAME),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) static struct ata_port_operations palmld_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .inherits = &ata_sff_port_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .sff_data_xfer = ata_sff_data_xfer32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) .cable_detect = ata_cable_40wire,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int palmld_pata_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct palmld_pata *lda;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct ata_port *ap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) void __iomem *mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) lda = devm_kzalloc(dev, sizeof(*lda), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (!lda)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) /* allocate host */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) lda->host = ata_host_alloc(dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!lda->host)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) /* remap drive's physical memory address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) mem = devm_ioremap(dev, PALMLD_IDE_PHYS, 0x1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!mem)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* request and activate power and reset GPIOs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) lda->power = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (IS_ERR(lda->power))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return PTR_ERR(lda->power);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) lda->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (IS_ERR(lda->reset)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) gpiod_set_value(lda->power, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return PTR_ERR(lda->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) /* Assert reset to reset the drive */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) gpiod_set_value(lda->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) msleep(30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) gpiod_set_value(lda->reset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) msleep(30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* setup the ata port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) ap = lda->host->ports[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ap->ops = &palmld_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ap->pio_mask = ATA_PIO4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ap->flags |= ATA_FLAG_PIO_POLLING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* memory mapping voodoo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ap->ioaddr.cmd_addr = mem + 0x10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ap->ioaddr.altstatus_addr = mem + 0xe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ap->ioaddr.ctl_addr = mem + 0xe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* start the port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) ata_sff_std_ports(&ap->ioaddr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* activate host */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ret = ata_host_activate(lda->host, 0, NULL, IRQF_TRIGGER_RISING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) &palmld_sht);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* power down on failure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) gpiod_set_value(lda->power, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) platform_set_drvdata(pdev, lda);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static int palmld_pata_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct palmld_pata *lda = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ata_platform_remove_one(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* power down the HDD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) gpiod_set_value(lda->power, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static struct platform_driver palmld_pata_platform_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .name = DRV_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .probe = palmld_pata_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .remove = palmld_pata_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) module_platform_driver(palmld_pata_platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) MODULE_DESCRIPTION("PalmLD PATA driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) MODULE_ALIAS("platform:" DRV_NAME);