[PATCH v3] libata: pata_samsung_cf: Add Samsung PATA controller driver
Kukjin Kim
kgene.kim at samsung.com
Fri Jun 11 03:41:31 EDT 2010
Ben Dooks wrote:
>
> On Thu, Jun 10, 2010 at 04:50:41PM +0900, Kukjin Kim wrote:
> > From: Abhilash Kesavan <a.kesavan at samsung.com>
> >
> > Adds support for the Samsung PATA controller. This driver is based on the
> > Libata subsystem and references the earlier patches sent for IDE
subsystem.
> >
Thanks for your review. :-)
> > Signed-off-by: Abhilash Kesavan <a.kesavan at samsung.com>
> > Signed-off-by: Kukjin Kim <kgene.kim at samsung.com>
>
> a few more comments, you may or may not want to fix before first
> submission.
>
> > ---
> >
> > Changes since v2:
> > - Changed the DRV_NAME to pata_samsung_cf
> > - Used msleep instead of mdelay
> >
> > drivers/ata/Makefile | 1 +
> > drivers/ata/pata_samsung_cf.c | 608
> +++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 618 insertions(+), 0 deletions(-)
> > create mode 100644 drivers/ata/pata_samsung_cf.c
> >
> > diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
> > index aa85a98..1b5facf 100644
> > --- a/drivers/ata/Kconfig
> > +++ b/drivers/ata/Kconfig
> > @@ -796,6 +796,15 @@ config PATA_RZ1000
> >
> > If unsure, say N.
> >
> > +config PATA_SAMSUNG_CF
> > + tristate "Samsung SoC PATA support"
> > + depends on SAMSUNG_DEV_IDE
> > + help
> > + This option enables basic support for Samsung's S3C/S5P board
> > + PATA controllers via the new ATA layer
> > +
> > + If unsure, say N.
> > +
> > config PATA_WINBOND_VLB
> > tristate "Winbond W83759A VLB PATA support (Experimental)"
> > depends on ISA && EXPERIMENTAL
> > diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
> > index 7ef89d7..9576776 100644
> > --- a/drivers/ata/Makefile
> > +++ b/drivers/ata/Makefile
> > @@ -87,6 +87,7 @@ obj-$(CONFIG_PATA_OF_PLATFORM) +=
> pata_of_platform.o
> > obj-$(CONFIG_PATA_QDI) += pata_qdi.o
> > obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
> > obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
> > +obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
> > obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o
> >
> > # Should be last but two libata driver
> > diff --git a/drivers/ata/pata_samsung_cf.c
b/drivers/ata/pata_samsung_cf.c
> > new file mode 100644
> > index 0000000..fef5515
> > --- /dev/null
> > +++ b/drivers/ata/pata_samsung_cf.c
> > @@ -0,0 +1,608 @@
> > +/* linux/drivers/ata/pata_samsung_cf.c
> > + *
> > + * Copyright (c) 2010 Samsung Electronics Co., Ltd.
> > + * http://www.samsung.com
> > + *
> > + * PATA driver for Samsung SoCs.
> > + * Supports CF Interface in True IDE mode. Currently only PIO mode has
been
> > + * implemented; UDMA support has to be added.
> > + *
> > + * Based on:
> > + * PATA driver for AT91SAM9260 Static Memory Controller
> > + * PATA driver for Toshiba SCC controller
> > + *
> > + * This program is free software; you can redistribute it and/or modify
it
> > + * under the terms of the GNU General Public License version 2
> > + * as published by the Free Software Foundation.
> > +*/
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/init.h>
> > +#include <linux/clk.h>
> > +#include <linux/libata.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +
> > +#include <plat/ata.h>
> > +#include <plat/regs-ata.h>
> > +
> > +#define DRV_NAME "pata_samsung_cf"
> > +#define DRV_VERSION "0.1"
> > +
> > +enum s3c_cpu_type {
> > + TYPE_S3C64XX,
> > + TYPE_S5PC100,
> > + TYPE_S5PV210,
> > +};
> > +
> > +/*
> > + * struct s3c_ide_info - S3C PATA instance.
> > + * @clk: The clock resource for this controller.
> > + * @ide_addr: The area mapped for the hardware registers.
> > + * @sfr_addr: The area mapped for the special function registers.
> > + * @irq: The IRQ number we are using.
> > + * @cpu_type: The exact type of this controller.
> > + * @fifo_status_reg: The ATA_FIFO_STATUS register offset.
> > + */
> > +struct s3c_ide_info {
> > + struct clk *clk;
> > + void __iomem *ide_addr;
> > + void __iomem *sfr_addr;
> > + unsigned int irq;
> > + enum s3c_cpu_type cpu_type;
> > + unsigned int fifo_status_reg;
> > +};
> > +
> > +static void pata_s3c_set_endian(void *s3c_ide_regbase, u8 mode)
> > +{
> should be void __iomem.
>
OK.
> > +static void pata_s3c_set_piomode(struct ata_port *ap, struct ata_device
*adev)
> > +{
> > + int mode = adev->pio_mode - XFER_PIO_0;
> > + struct s3c_ide_info *info = ap->host->private_data;
> > + ulong ata_cfg = readl(info->ide_addr + S3C_ATA_CFG);
> > + ulong piotime;
> > +
> > + /* Calculates timing parameters for PIO mode */
> > + piotime = pata_s3c_setup_timing(info, adev);
> > +
> > + /* Enables IORDY if mode requires it */
> > + if (ata_pio_need_iordy(adev))
> > + ata_cfg |= S3C_ATA_CFG_IORDYEN;
> > + else
> > + ata_cfg &= ~S3C_ATA_CFG_IORDYEN;
> > +
> > + /* Host controller supports upto PIO4 only */
> > + if (mode >= 0 && mode <= 4) {
>
> if this code was to stay in, it would have been better to either
> WARN_ON() or print some form of error messagee instead of just silently
> ignoring it... also, you should have probably set the minumum acceptable
> ATA mode to ensure any further actions would not cause problems with
> trying to run the b us too fast.
>
Will remove the code..will set up the timing parameters using
ata_timing_compute and the initial timing will be for PIO0 in case of
failure.
> > +/*
> > + * Waits until the IDE controller is able to perform next read/write
> > + * operation to the disk. Needed for 64XX series boards only.
> > + */
>
> if it is needed only for s3c64xx series, why don't we bail if the
> info->type != 64xx?
>
This is called via pata_s3c_port_ops for 64xx else goes to pata_s5p_port_ops.
> > +static int wait_for_host_ready(struct s3c_ide_info *info)
> > +{
> > + ulong timeout;
> > +
> > + /* wait for maximum of 20 msec */
> > + timeout = jiffies + msecs_to_jiffies(20);
> > + while (time_before(jiffies, timeout)) {
> > + if ((readl(info->ide_addr + info->fifo_status_reg) >> 28) ==
0)
>
> would be neater to have
> void __iomem *fifo_reg = info->ide_addr + info->fifo_status_reg
> ...
>
> while(...) {
> if (readl(fifo_reg) >> 28) == 0)
> ...
>
OK.
> > + return 0;
> > + }
> > + return -EBUSY;
> > +}
>
> [snip]
>
> > +/*
> > + * pata_s3c_data_xfer - Transfer data by PIO
> > + */
> > +unsigned int pata_s3c_data_xfer(struct ata_device *dev, unsigned char
*buf,
> > + unsigned int buflen, int rw)
> > +{
> > + struct ata_port *ap = dev->link->ap;
> > + struct s3c_ide_info *info = ap->host->private_data;
> > + void __iomem *data_addr = ap->ioaddr.data_addr;
> > + unsigned int words = buflen >> 1, i;
> > + u16 *data_ptr = (u16 *)buf;
>
> note, is there any chance of being passed a number of bytes? if so
> should we at least WARN_ON(buflen & 1) and return an error?
>
Will add a WARN_ON.
> > + if (rw == READ)
> > + for (i = 0; i < words; i++, data_ptr++) {
> > + wait_for_host_ready(info);
> > + *data_ptr = readw(data_addr);
> > + wait_for_host_ready(info);
> > + *data_ptr = readw(info->ide_addr
> > + + S3C_ATA_PIO_RDATA);
> > + }
Will add a description for read/write accesses.
> > + else
> > + for (i = 0; i < words; i++, data_ptr++) {
> > + wait_for_host_ready(info);
> > + writel(*data_ptr, data_addr);
> > + }
> > +
> > + return words << 1;
> > +}
> > +
> > +/*
> > + * pata_s3c_dev_select - Select device on ATA bus
> > + */
> > +static void pata_s3c_dev_select(struct ata_port *ap, unsigned int
device)
> > +{
> > + u8 tmp;
> > +
> > + if (device == 0)
> > + tmp = ATA_DEVICE_OBS;
> > + else
> > + tmp = ATA_DEVICE_OBS | ATA_DEV1;
>
> you could have done
> u8 tmp = ATA_DEVICE_OBS;
>
> if (device != 0)
> tmp |= ATA_DEV1
>
> > + ata_outb(ap->host, tmp, ap->ioaddr.device_addr);
> > + ata_sff_pause(ap);
> > +}
> > +
>
> [snip]
>
> > +static void pata_s3c_enable(void *s3c_ide_regbase, u8 state)
> state would be better as a bool or a natural int.
OK.
> > +{
> > + u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL);
> > + temp = state ? (temp | 1) : (temp & ~1);
> > + writel(temp, s3c_ide_regbase + S3C_ATA_CTRL);
> > +}
> > +
> > +static irqreturn_t pata_s3c_irq(int irq, void *dev_instance)
> > +{
> > + struct ata_host *host = dev_instance;
> > + struct s3c_ide_info *info = host->private_data;
> > + u32 reg;
> > +
> > + reg = readl(info->ide_addr + S3C_ATA_IRQ);
> > + writel(reg, info->ide_addr + S3C_ATA_IRQ);
>
> no decoding of the interrupt cause?
>
Others interrupts are for udma, mdma and EBI (we are using direct mode) and
so I let them be.
> > + return ata_sff_interrupt(irq, dev_instance);
> > +}
>
> > +static int __devexit pata_s3c_remove(struct platform_device *pdev)
> > +{
> > + struct ata_host *host = platform_get_drvdata(pdev);
> > + struct s3c_ide_info *info;
> > + struct resource *res;
>
> > +
> > + if (!host)
> > + return 0;
>
> don't think this check is really necessary.
>
OK.
> > + info = host->private_data;
> > +
> > + ata_host_detach(host);
> > +
> > + clk_disable(info->clk);
> > + clk_put(info->clk);
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + release_mem_region(res->start, resource_size(res));
> > + kfree(info);
> > +
> > + return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int pata_s3c_suspend(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ata_host *host = platform_get_drvdata(pdev);
> > + pm_message_t state = PMSG_SUSPEND;
> > +
> > + if (host)
> > + return ata_host_suspend(host, state);
>
> again, don't think you'l lget called here if you didn't sucessfully bind.
>
OK.
> > + else
> > + return 0;
> > +}
> > +
> > +static int pata_s3c_resume(struct device *dev)
> > +{
> > + struct platform_device *pdev = to_platform_device(dev);
> > + struct ata_host *host = platform_get_drvdata(pdev);
> > + struct s3c_ide_platdata *pdata = pdev->dev.platform_data;
> > + struct s3c_ide_info *info;
> > +
> > + info = host->private_data;
> > +
> > + if (host) {
> > + pata_s3c_hwinit(info, pdata);
> > + ata_host_resume(host);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dev_pm_ops pata_s3c_pm_ops = {
> > + .suspend = pata_s3c_suspend,
> > + .resume = pata_s3c_resume,
> > +};
>
> --
Thanks.
Best regards,
Kgene.
--
Kukjin Kim <kgene.kim at samsung.com>, Senior Engineer,
SW Solution Development Team, Samsung Electronics Co., Ltd.
More information about the linux-arm-kernel
mailing list