]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/ata/pata_imx.c
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[karo-tx-linux.git] / drivers / ata / pata_imx.c
index 203e3092ed07142dc76887c0aec524970d3c8831..d4caa23f5a88dd6c828afa84e9dca809b423874f 100644 (file)
@@ -11,7 +11,6 @@
  *
  * TODO:
  * - dmaengine support
- * - check if timing stuff needed
  */
 
 #include <linux/ata.h>
 
 #define DRV_NAME "pata_imx"
 
+#define PATA_IMX_ATA_TIME_OFF          0x00
+#define PATA_IMX_ATA_TIME_ON           0x01
+#define PATA_IMX_ATA_TIME_1            0x02
+#define PATA_IMX_ATA_TIME_2W           0x03
+#define PATA_IMX_ATA_TIME_2R           0x04
+#define PATA_IMX_ATA_TIME_AX           0x05
+#define PATA_IMX_ATA_TIME_PIO_RDX      0x06
+#define PATA_IMX_ATA_TIME_4            0x07
+#define PATA_IMX_ATA_TIME_9            0x08
+
 #define PATA_IMX_ATA_CONTROL           0x24
 #define PATA_IMX_ATA_CTRL_FIFO_RST_B   (1<<7)
 #define PATA_IMX_ATA_CTRL_ATA_RST_B    (1<<6)
 #define PATA_IMX_DRIVE_DATA            0xA0
 #define PATA_IMX_DRIVE_CONTROL         0xD8
 
+static u32 pio_t4[] = { 30,  20,  15,  10,  10 };
+static u32 pio_t9[] = { 20,  15,  10,  10,  10 };
+static u32 pio_tA[] = { 35,  35,  35,  35,  35 };
+
 struct pata_imx_priv {
        struct clk *clk;
        /* timings/interrupt/control regs */
@@ -38,28 +51,49 @@ struct pata_imx_priv {
        u32 ata_ctl;
 };
 
-static int pata_imx_set_mode(struct ata_link *link, struct ata_device **unused)
+static void pata_imx_set_timing(struct ata_device *adev,
+                               struct pata_imx_priv *priv)
+{
+       struct ata_timing timing;
+       unsigned long clkrate;
+       u32 T, mode;
+
+       clkrate = clk_get_rate(priv->clk);
+
+       if (adev->pio_mode < XFER_PIO_0 || adev->pio_mode > XFER_PIO_4 ||
+           !clkrate)
+               return;
+
+       T = 1000000000 / clkrate;
+       ata_timing_compute(adev, adev->pio_mode, &timing, T * 1000, 0);
+
+       mode = adev->pio_mode - XFER_PIO_0;
+
+       writeb(3, priv->host_regs + PATA_IMX_ATA_TIME_OFF);
+       writeb(3, priv->host_regs + PATA_IMX_ATA_TIME_ON);
+       writeb(timing.setup, priv->host_regs + PATA_IMX_ATA_TIME_1);
+       writeb(timing.act8b, priv->host_regs + PATA_IMX_ATA_TIME_2W);
+       writeb(timing.act8b, priv->host_regs + PATA_IMX_ATA_TIME_2R);
+       writeb(1, priv->host_regs + PATA_IMX_ATA_TIME_PIO_RDX);
+
+       writeb(pio_t4[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_4);
+       writeb(pio_t9[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_9);
+       writeb(pio_tA[mode] / T + 1, priv->host_regs + PATA_IMX_ATA_TIME_AX);
+}
+
+static void pata_imx_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
-       struct ata_device *dev;
-       struct ata_port *ap = link->ap;
        struct pata_imx_priv *priv = ap->host->private_data;
        u32 val;
 
-       ata_for_each_dev(dev, link, ENABLED) {
-               dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
-               dev->xfer_shift = ATA_SHIFT_PIO;
-               dev->flags |= ATA_DFLAG_PIO;
+       pata_imx_set_timing(adev, priv);
 
-               val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
-               if (ata_pio_need_iordy(dev))
-                       val |= PATA_IMX_ATA_CTRL_IORDY_EN;
-               else
-                       val &= ~PATA_IMX_ATA_CTRL_IORDY_EN;
-               __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL);
-
-               ata_dev_info(dev, "configured for PIO\n");
-       }
-       return 0;
+       val = __raw_readl(priv->host_regs + PATA_IMX_ATA_CONTROL);
+       if (ata_pio_need_iordy(adev))
+               val |= PATA_IMX_ATA_CTRL_IORDY_EN;
+       else
+               val &= ~PATA_IMX_ATA_CTRL_IORDY_EN;
+       __raw_writel(val, priv->host_regs + PATA_IMX_ATA_CONTROL);
 }
 
 static struct scsi_host_template pata_imx_sht = {
@@ -70,7 +104,7 @@ static struct ata_port_operations pata_imx_port_ops = {
        .inherits               = &ata_sff_port_ops,
        .sff_data_xfer          = ata_sff_data_xfer_noirq,
        .cable_detect           = ata_cable_unknown,
-       .set_mode               = pata_imx_set_mode,
+       .set_piomode            = pata_imx_set_piomode,
 };
 
 static void pata_imx_setup_port(struct ata_ioports *ioaddr)
@@ -126,7 +160,7 @@ static int pata_imx_probe(struct platform_device *pdev)
        ap = host->ports[0];
 
        ap->ops = &pata_imx_port_ops;
-       ap->pio_mask = ATA_PIO0;
+       ap->pio_mask = ATA_PIO4;
        ap->flags |= ATA_FLAG_SLAVE_POSS;
 
        io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);