| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 1 | /* | 
 | 2 |  * drivers/ata/pata_mpc52xx.c | 
 | 3 |  * | 
 | 4 |  * libata driver for the Freescale MPC52xx on-chip IDE interface | 
 | 5 |  * | 
 | 6 |  * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> | 
 | 7 |  * Copyright (C) 2003 Mipsys - Benjamin Herrenschmidt | 
 | 8 |  * | 
 | 9 |  * This file is licensed under the terms of the GNU General Public License | 
 | 10 |  * version 2. This program is licensed "as is" without any warranty of any | 
 | 11 |  * kind, whether express or implied. | 
 | 12 |  */ | 
 | 13 |  | 
 | 14 | #include <linux/kernel.h> | 
 | 15 | #include <linux/module.h> | 
 | 16 | #include <linux/slab.h> | 
 | 17 | #include <linux/delay.h> | 
 | 18 | #include <linux/libata.h> | 
 | 19 |  | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 20 | #include <asm/types.h> | 
 | 21 | #include <asm/prom.h> | 
 | 22 | #include <asm/of_platform.h> | 
 | 23 | #include <asm/mpc52xx.h> | 
 | 24 |  | 
 | 25 |  | 
 | 26 | #define DRV_NAME	"mpc52xx_ata" | 
| Jeff Garzik | 2a3103c | 2007-08-31 04:54:06 -0400 | [diff] [blame] | 27 | #define DRV_VERSION	"0.1.2" | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 28 |  | 
 | 29 |  | 
 | 30 | /* Private structures used by the driver */ | 
 | 31 | struct mpc52xx_ata_timings { | 
 | 32 | 	u32	pio1; | 
 | 33 | 	u32	pio2; | 
 | 34 | }; | 
 | 35 |  | 
 | 36 | struct mpc52xx_ata_priv { | 
 | 37 | 	unsigned int			ipb_period; | 
 | 38 | 	struct mpc52xx_ata __iomem *	ata_regs; | 
 | 39 | 	int				ata_irq; | 
 | 40 | 	struct mpc52xx_ata_timings	timings[2]; | 
 | 41 | 	int				csel; | 
 | 42 | }; | 
 | 43 |  | 
 | 44 |  | 
 | 45 | /* ATAPI-4 PIO specs (in ns) */ | 
 | 46 | static const int ataspec_t0[5]    = {600, 383, 240, 180, 120}; | 
 | 47 | static const int ataspec_t1[5]    = { 70,  50,  30,  30,  25}; | 
 | 48 | static const int ataspec_t2_8[5]  = {290, 290, 290,  80,  70}; | 
 | 49 | static const int ataspec_t2_16[5] = {165, 125, 100,  80,  70}; | 
 | 50 | static const int ataspec_t2i[5]   = {  0,   0,   0,  70,  25}; | 
 | 51 | static const int ataspec_t4[5]    = { 30,  20,  15,  10,  10}; | 
 | 52 | static const int ataspec_ta[5]    = { 35,  35,  35,  35,  35}; | 
 | 53 |  | 
 | 54 | #define CALC_CLKCYC(c,v) ((((v)+(c)-1)/(c))) | 
 | 55 |  | 
 | 56 |  | 
 | 57 | /* Bit definitions inside the registers */ | 
 | 58 | #define MPC52xx_ATA_HOSTCONF_SMR	0x80000000UL /* State machine reset */ | 
 | 59 | #define MPC52xx_ATA_HOSTCONF_FR		0x40000000UL /* FIFO Reset */ | 
 | 60 | #define MPC52xx_ATA_HOSTCONF_IE		0x02000000UL /* Enable interrupt in PIO */ | 
 | 61 | #define MPC52xx_ATA_HOSTCONF_IORDY	0x01000000UL /* Drive supports IORDY protocol */ | 
 | 62 |  | 
 | 63 | #define MPC52xx_ATA_HOSTSTAT_TIP	0x80000000UL /* Transaction in progress */ | 
 | 64 | #define MPC52xx_ATA_HOSTSTAT_UREP	0x40000000UL /* UDMA Read Extended Pause */ | 
 | 65 | #define MPC52xx_ATA_HOSTSTAT_RERR	0x02000000UL /* Read Error */ | 
 | 66 | #define MPC52xx_ATA_HOSTSTAT_WERR	0x01000000UL /* Write Error */ | 
 | 67 |  | 
 | 68 | #define MPC52xx_ATA_FIFOSTAT_EMPTY	0x01 /* FIFO Empty */ | 
 | 69 |  | 
 | 70 | #define MPC52xx_ATA_DMAMODE_WRITE	0x01 /* Write DMA */ | 
 | 71 | #define MPC52xx_ATA_DMAMODE_READ	0x02 /* Read DMA */ | 
 | 72 | #define MPC52xx_ATA_DMAMODE_UDMA	0x04 /* UDMA enabled */ | 
 | 73 | #define MPC52xx_ATA_DMAMODE_IE		0x08 /* Enable drive interrupt to CPU in DMA mode */ | 
 | 74 | #define MPC52xx_ATA_DMAMODE_FE		0x10 /* FIFO Flush enable in Rx mode */ | 
 | 75 | #define MPC52xx_ATA_DMAMODE_FR		0x20 /* FIFO Reset */ | 
 | 76 | #define MPC52xx_ATA_DMAMODE_HUT		0x40 /* Host UDMA burst terminate */ | 
 | 77 |  | 
 | 78 |  | 
 | 79 | /* Structure of the hardware registers */ | 
 | 80 | struct mpc52xx_ata { | 
 | 81 |  | 
 | 82 | 	/* Host interface registers */ | 
 | 83 | 	u32 config;		/* ATA + 0x00 Host configuration */ | 
 | 84 | 	u32 host_status;	/* ATA + 0x04 Host controller status */ | 
 | 85 | 	u32 pio1;		/* ATA + 0x08 PIO Timing 1 */ | 
 | 86 | 	u32 pio2;		/* ATA + 0x0c PIO Timing 2 */ | 
 | 87 | 	u32 mdma1;		/* ATA + 0x10 MDMA Timing 1 */ | 
 | 88 | 	u32 mdma2;		/* ATA + 0x14 MDMA Timing 2 */ | 
 | 89 | 	u32 udma1;		/* ATA + 0x18 UDMA Timing 1 */ | 
 | 90 | 	u32 udma2;		/* ATA + 0x1c UDMA Timing 2 */ | 
 | 91 | 	u32 udma3;		/* ATA + 0x20 UDMA Timing 3 */ | 
 | 92 | 	u32 udma4;		/* ATA + 0x24 UDMA Timing 4 */ | 
 | 93 | 	u32 udma5;		/* ATA + 0x28 UDMA Timing 5 */ | 
 | 94 | 	u32 share_cnt;		/* ATA + 0x2c ATA share counter */ | 
 | 95 | 	u32 reserved0[3]; | 
 | 96 |  | 
 | 97 | 	/* FIFO registers */ | 
 | 98 | 	u32 fifo_data;		/* ATA + 0x3c */ | 
 | 99 | 	u8  fifo_status_frame;	/* ATA + 0x40 */ | 
 | 100 | 	u8  fifo_status;	/* ATA + 0x41 */ | 
 | 101 | 	u16 reserved7[1]; | 
 | 102 | 	u8  fifo_control;	/* ATA + 0x44 */ | 
 | 103 | 	u8  reserved8[5]; | 
 | 104 | 	u16 fifo_alarm;		/* ATA + 0x4a */ | 
 | 105 | 	u16 reserved9; | 
 | 106 | 	u16 fifo_rdp;		/* ATA + 0x4e */ | 
 | 107 | 	u16 reserved10; | 
 | 108 | 	u16 fifo_wrp;		/* ATA + 0x52 */ | 
 | 109 | 	u16 reserved11; | 
 | 110 | 	u16 fifo_lfrdp;		/* ATA + 0x56 */ | 
 | 111 | 	u16 reserved12; | 
 | 112 | 	u16 fifo_lfwrp;		/* ATA + 0x5a */ | 
 | 113 |  | 
 | 114 | 	/* Drive TaskFile registers */ | 
 | 115 | 	u8  tf_control;		/* ATA + 0x5c TASKFILE Control/Alt Status */ | 
 | 116 | 	u8  reserved13[3]; | 
 | 117 | 	u16 tf_data;		/* ATA + 0x60 TASKFILE Data */ | 
 | 118 | 	u16 reserved14; | 
 | 119 | 	u8  tf_features;	/* ATA + 0x64 TASKFILE Features/Error */ | 
 | 120 | 	u8  reserved15[3]; | 
 | 121 | 	u8  tf_sec_count;	/* ATA + 0x68 TASKFILE Sector Count */ | 
 | 122 | 	u8  reserved16[3]; | 
 | 123 | 	u8  tf_sec_num;		/* ATA + 0x6c TASKFILE Sector Number */ | 
 | 124 | 	u8  reserved17[3]; | 
 | 125 | 	u8  tf_cyl_low;		/* ATA + 0x70 TASKFILE Cylinder Low */ | 
 | 126 | 	u8  reserved18[3]; | 
 | 127 | 	u8  tf_cyl_high;	/* ATA + 0x74 TASKFILE Cylinder High */ | 
 | 128 | 	u8  reserved19[3]; | 
 | 129 | 	u8  tf_dev_head;	/* ATA + 0x78 TASKFILE Device/Head */ | 
 | 130 | 	u8  reserved20[3]; | 
 | 131 | 	u8  tf_command;		/* ATA + 0x7c TASKFILE Command/Status */ | 
 | 132 | 	u8  dma_mode;		/* ATA + 0x7d ATA Host DMA Mode configuration */ | 
 | 133 | 	u8  reserved21[2]; | 
 | 134 | }; | 
 | 135 |  | 
 | 136 |  | 
 | 137 | /* ======================================================================== */ | 
 | 138 | /* Aux fns                                                                  */ | 
 | 139 | /* ======================================================================== */ | 
 | 140 |  | 
 | 141 |  | 
 | 142 | /* MPC52xx low level hw control */ | 
 | 143 |  | 
 | 144 | static int | 
 | 145 | mpc52xx_ata_compute_pio_timings(struct mpc52xx_ata_priv *priv, int dev, int pio) | 
 | 146 | { | 
 | 147 | 	struct mpc52xx_ata_timings *timing = &priv->timings[dev]; | 
 | 148 | 	unsigned int ipb_period = priv->ipb_period; | 
 | 149 | 	unsigned int t0, t1, t2_8, t2_16, t2i, t4, ta; | 
 | 150 |  | 
 | 151 | 	if ((pio<0) || (pio>4)) | 
 | 152 | 		return -EINVAL; | 
 | 153 |  | 
 | 154 | 	t0	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t0[pio]); | 
 | 155 | 	t1	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t1[pio]); | 
 | 156 | 	t2_8	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_8[pio]); | 
 | 157 | 	t2_16	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2_16[pio]); | 
 | 158 | 	t2i	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t2i[pio]); | 
 | 159 | 	t4	= CALC_CLKCYC(ipb_period, 1000 * ataspec_t4[pio]); | 
 | 160 | 	ta	= CALC_CLKCYC(ipb_period, 1000 * ataspec_ta[pio]); | 
 | 161 |  | 
 | 162 | 	timing->pio1 = (t0 << 24) | (t2_8 << 16) | (t2_16 << 8) | (t2i); | 
 | 163 | 	timing->pio2 = (t4 << 24) | (t1 << 16) | (ta << 8); | 
 | 164 |  | 
 | 165 | 	return 0; | 
 | 166 | } | 
 | 167 |  | 
 | 168 | static void | 
 | 169 | mpc52xx_ata_apply_timings(struct mpc52xx_ata_priv *priv, int device) | 
 | 170 | { | 
 | 171 | 	struct mpc52xx_ata __iomem *regs = priv->ata_regs; | 
 | 172 | 	struct mpc52xx_ata_timings *timing = &priv->timings[device]; | 
 | 173 |  | 
 | 174 | 	out_be32(®s->pio1,  timing->pio1); | 
 | 175 | 	out_be32(®s->pio2,  timing->pio2); | 
 | 176 | 	out_be32(®s->mdma1, 0); | 
 | 177 | 	out_be32(®s->mdma2, 0); | 
 | 178 | 	out_be32(®s->udma1, 0); | 
 | 179 | 	out_be32(®s->udma2, 0); | 
 | 180 | 	out_be32(®s->udma3, 0); | 
 | 181 | 	out_be32(®s->udma4, 0); | 
 | 182 | 	out_be32(®s->udma5, 0); | 
 | 183 |  | 
 | 184 | 	priv->csel = device; | 
 | 185 | } | 
 | 186 |  | 
 | 187 | static int | 
 | 188 | mpc52xx_ata_hw_init(struct mpc52xx_ata_priv *priv) | 
 | 189 | { | 
 | 190 | 	struct mpc52xx_ata __iomem *regs = priv->ata_regs; | 
 | 191 | 	int tslot; | 
 | 192 |  | 
 | 193 | 	/* Clear share_cnt (all sample code do this ...) */ | 
 | 194 | 	out_be32(®s->share_cnt, 0); | 
 | 195 |  | 
 | 196 | 	/* Configure and reset host */ | 
 | 197 | 	out_be32(®s->config, | 
 | 198 | 			MPC52xx_ATA_HOSTCONF_IE | | 
 | 199 | 			MPC52xx_ATA_HOSTCONF_IORDY | | 
 | 200 | 			MPC52xx_ATA_HOSTCONF_SMR | | 
 | 201 | 			MPC52xx_ATA_HOSTCONF_FR); | 
 | 202 |  | 
 | 203 | 	udelay(10); | 
 | 204 |  | 
 | 205 | 	out_be32(®s->config, | 
 | 206 | 			MPC52xx_ATA_HOSTCONF_IE | | 
 | 207 | 			MPC52xx_ATA_HOSTCONF_IORDY); | 
 | 208 |  | 
 | 209 | 	/* Set the time slot to 1us */ | 
 | 210 | 	tslot = CALC_CLKCYC(priv->ipb_period, 1000000); | 
 | 211 | 	out_be32(®s->share_cnt, tslot << 16 ); | 
 | 212 |  | 
 | 213 | 	/* Init timings to PIO0 */ | 
 | 214 | 	memset(priv->timings, 0x00, 2*sizeof(struct mpc52xx_ata_timings)); | 
 | 215 |  | 
 | 216 | 	mpc52xx_ata_compute_pio_timings(priv, 0, 0); | 
 | 217 | 	mpc52xx_ata_compute_pio_timings(priv, 1, 0); | 
 | 218 |  | 
 | 219 | 	mpc52xx_ata_apply_timings(priv, 0); | 
 | 220 |  | 
 | 221 | 	return 0; | 
 | 222 | } | 
 | 223 |  | 
 | 224 |  | 
 | 225 | /* ======================================================================== */ | 
 | 226 | /* libata driver                                                            */ | 
 | 227 | /* ======================================================================== */ | 
 | 228 |  | 
 | 229 | static void | 
 | 230 | mpc52xx_ata_set_piomode(struct ata_port *ap, struct ata_device *adev) | 
 | 231 | { | 
 | 232 | 	struct mpc52xx_ata_priv *priv = ap->host->private_data; | 
 | 233 | 	int pio, rv; | 
 | 234 |  | 
 | 235 | 	pio = adev->pio_mode - XFER_PIO_0; | 
 | 236 |  | 
 | 237 | 	rv = mpc52xx_ata_compute_pio_timings(priv, adev->devno, pio); | 
 | 238 |  | 
 | 239 | 	if (rv) { | 
 | 240 | 		printk(KERN_ERR DRV_NAME | 
 | 241 | 			": Trying to select invalid PIO mode %d\n", pio); | 
 | 242 | 		return; | 
 | 243 | 	} | 
 | 244 |  | 
 | 245 | 	mpc52xx_ata_apply_timings(priv, adev->devno); | 
 | 246 | } | 
 | 247 | static void | 
 | 248 | mpc52xx_ata_dev_select(struct ata_port *ap, unsigned int device) | 
 | 249 | { | 
 | 250 | 	struct mpc52xx_ata_priv *priv = ap->host->private_data; | 
 | 251 |  | 
 | 252 | 	if (device != priv->csel) | 
 | 253 | 		mpc52xx_ata_apply_timings(priv, device); | 
 | 254 |  | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 255 | 	ata_sff_dev_select(ap,device); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 256 | } | 
 | 257 |  | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 258 | static struct scsi_host_template mpc52xx_ata_sht = { | 
| Tejun Heo | 68d1d07 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 259 | 	ATA_PIO_SHT(DRV_NAME), | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 260 | }; | 
 | 261 |  | 
 | 262 | static struct ata_port_operations mpc52xx_ata_port_ops = { | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 263 | 	.inherits		= &ata_sff_port_ops, | 
| Tejun Heo | 5682ed3 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 264 | 	.sff_dev_select		= mpc52xx_ata_dev_select, | 
| Jeff Garzik | a0fcdc0 | 2007-03-09 07:24:15 -0500 | [diff] [blame] | 265 | 	.cable_detect		= ata_cable_40wire, | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 266 | 	.set_piomode		= mpc52xx_ata_set_piomode, | 
| Tejun Heo | 029cfd6 | 2008-03-25 12:22:49 +0900 | [diff] [blame] | 267 | 	.post_internal_cmd	= ATA_OP_NULL, | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 268 | }; | 
 | 269 |  | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 270 | static int __devinit | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 271 | mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv, | 
 | 272 | 		     unsigned long raw_ata_regs) | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 273 | { | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 274 | 	struct ata_host *host; | 
 | 275 | 	struct ata_port *ap; | 
 | 276 | 	struct ata_ioports *aio; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 277 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 278 | 	host = ata_host_alloc(dev, 1); | 
 | 279 | 	if (!host) | 
 | 280 | 		return -ENOMEM; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 281 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 282 | 	ap = host->ports[0]; | 
 | 283 | 	ap->flags		|= ATA_FLAG_SLAVE_POSS; | 
 | 284 | 	ap->pio_mask		= 0x1f;	/* Up to PIO4 */ | 
 | 285 | 	ap->mwdma_mask		= 0x00;	/* No MWDMA   */ | 
 | 286 | 	ap->udma_mask		= 0x00;	/* No UDMA    */ | 
 | 287 | 	ap->ops			= &mpc52xx_ata_port_ops; | 
 | 288 | 	host->private_data	= priv; | 
 | 289 |  | 
 | 290 | 	aio = &ap->ioaddr; | 
| Al Viro | 89952d1 | 2007-03-14 09:17:59 +0000 | [diff] [blame] | 291 | 	aio->cmd_addr		= NULL;	/* Don't have a classic reg block */ | 
| Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 292 | 	aio->altstatus_addr	= &priv->ata_regs->tf_control; | 
 | 293 | 	aio->ctl_addr		= &priv->ata_regs->tf_control; | 
 | 294 | 	aio->data_addr		= &priv->ata_regs->tf_data; | 
 | 295 | 	aio->error_addr		= &priv->ata_regs->tf_features; | 
 | 296 | 	aio->feature_addr	= &priv->ata_regs->tf_features; | 
 | 297 | 	aio->nsect_addr		= &priv->ata_regs->tf_sec_count; | 
 | 298 | 	aio->lbal_addr		= &priv->ata_regs->tf_sec_num; | 
 | 299 | 	aio->lbam_addr		= &priv->ata_regs->tf_cyl_low; | 
 | 300 | 	aio->lbah_addr		= &priv->ata_regs->tf_cyl_high; | 
 | 301 | 	aio->device_addr	= &priv->ata_regs->tf_dev_head; | 
 | 302 | 	aio->status_addr	= &priv->ata_regs->tf_command; | 
 | 303 | 	aio->command_addr	= &priv->ata_regs->tf_command; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 304 |  | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 305 | 	ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs); | 
 | 306 |  | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 307 | 	/* activate host */ | 
| Tejun Heo | 9363c38 | 2008-04-07 22:47:16 +0900 | [diff] [blame] | 308 | 	return ata_host_activate(host, priv->ata_irq, ata_sff_interrupt, 0, | 
| Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 309 | 				 &mpc52xx_ata_sht); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 310 | } | 
 | 311 |  | 
 | 312 | static struct mpc52xx_ata_priv * | 
 | 313 | mpc52xx_ata_remove_one(struct device *dev) | 
 | 314 | { | 
 | 315 | 	struct ata_host *host = dev_get_drvdata(dev); | 
 | 316 | 	struct mpc52xx_ata_priv *priv = host->private_data; | 
 | 317 |  | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 318 | 	ata_host_detach(host); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 319 |  | 
 | 320 | 	return priv; | 
 | 321 | } | 
 | 322 |  | 
 | 323 |  | 
 | 324 | /* ======================================================================== */ | 
 | 325 | /* OF Platform driver                                                       */ | 
 | 326 | /* ======================================================================== */ | 
 | 327 |  | 
 | 328 | static int __devinit | 
 | 329 | mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) | 
 | 330 | { | 
 | 331 | 	unsigned int ipb_freq; | 
 | 332 | 	struct resource res_mem; | 
| Alan Cox | 0eaea36 | 2008-01-19 15:48:59 +0000 | [diff] [blame] | 333 | 	int ata_irq; | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 334 | 	struct mpc52xx_ata __iomem *ata_regs; | 
 | 335 | 	struct mpc52xx_ata_priv *priv; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 336 | 	int rv; | 
 | 337 |  | 
 | 338 | 	/* Get ipb frequency */ | 
 | 339 | 	ipb_freq = mpc52xx_find_ipb_freq(op->node); | 
 | 340 | 	if (!ipb_freq) { | 
 | 341 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 342 | 			"Unable to find IPB Bus frequency\n" ); | 
 | 343 | 		return -ENODEV; | 
 | 344 | 	} | 
 | 345 |  | 
 | 346 | 	/* Get IRQ and register */ | 
 | 347 | 	rv = of_address_to_resource(op->node, 0, &res_mem); | 
 | 348 | 	if (rv) { | 
 | 349 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 350 | 			"Error while parsing device node resource\n" ); | 
 | 351 | 		return rv; | 
 | 352 | 	} | 
 | 353 |  | 
 | 354 | 	ata_irq = irq_of_parse_and_map(op->node, 0); | 
 | 355 | 	if (ata_irq == NO_IRQ) { | 
 | 356 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 357 | 			"Error while mapping the irq\n"); | 
 | 358 | 		return -EINVAL; | 
 | 359 | 	} | 
 | 360 |  | 
 | 361 | 	/* Request mem region */ | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 362 | 	if (!devm_request_mem_region(&op->dev, res_mem.start, | 
 | 363 | 				     sizeof(struct mpc52xx_ata), DRV_NAME)) { | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 364 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 365 | 			"Error while requesting mem region\n"); | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 366 | 		rv = -EBUSY; | 
 | 367 | 		goto err; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 368 | 	} | 
 | 369 |  | 
 | 370 | 	/* Remap registers */ | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 371 | 	ata_regs = devm_ioremap(&op->dev, res_mem.start, | 
 | 372 | 				sizeof(struct mpc52xx_ata)); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 373 | 	if (!ata_regs) { | 
 | 374 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 375 | 			"Error while mapping register set\n"); | 
 | 376 | 		rv = -ENOMEM; | 
 | 377 | 		goto err; | 
 | 378 | 	} | 
 | 379 |  | 
 | 380 | 	/* Prepare our private structure */ | 
| Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 381 | 	priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv), | 
 | 382 | 			    GFP_ATOMIC); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 383 | 	if (!priv) { | 
 | 384 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 385 | 			"Error while allocating private structure\n"); | 
 | 386 | 		rv = -ENOMEM; | 
 | 387 | 		goto err; | 
 | 388 | 	} | 
 | 389 |  | 
 | 390 | 	priv->ipb_period = 1000000000 / (ipb_freq / 1000); | 
 | 391 | 	priv->ata_regs = ata_regs; | 
 | 392 | 	priv->ata_irq = ata_irq; | 
 | 393 | 	priv->csel = -1; | 
 | 394 |  | 
 | 395 | 	/* Init the hw */ | 
 | 396 | 	rv = mpc52xx_ata_hw_init(priv); | 
 | 397 | 	if (rv) { | 
 | 398 | 		printk(KERN_ERR DRV_NAME ": Error during HW init\n"); | 
 | 399 | 		goto err; | 
 | 400 | 	} | 
 | 401 |  | 
 | 402 | 	/* Register ourselves to libata */ | 
| Tejun Heo | cbcdd87 | 2007-08-18 13:14:55 +0900 | [diff] [blame] | 403 | 	rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 404 | 	if (rv) { | 
 | 405 | 		printk(KERN_ERR DRV_NAME ": " | 
 | 406 | 			"Error while registering to ATA layer\n"); | 
 | 407 | 		return rv; | 
 | 408 | 	} | 
 | 409 |  | 
 | 410 | 	/* Done */ | 
 | 411 | 	return 0; | 
 | 412 |  | 
 | 413 | 	/* Error path */ | 
 | 414 | err: | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 415 | 	irq_dispose_mapping(ata_irq); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 416 | 	return rv; | 
 | 417 | } | 
 | 418 |  | 
 | 419 | static int | 
 | 420 | mpc52xx_ata_remove(struct of_device *op) | 
 | 421 | { | 
 | 422 | 	struct mpc52xx_ata_priv *priv; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 423 |  | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 424 | 	priv = mpc52xx_ata_remove_one(&op->dev); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 425 | 	irq_dispose_mapping(priv->ata_irq); | 
 | 426 |  | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 427 | 	return 0; | 
 | 428 | } | 
 | 429 |  | 
 | 430 |  | 
 | 431 | #ifdef CONFIG_PM | 
 | 432 |  | 
 | 433 | static int | 
 | 434 | mpc52xx_ata_suspend(struct of_device *op, pm_message_t state) | 
 | 435 | { | 
| Domen Puncer | 35142dd | 2007-07-03 10:27:38 +0200 | [diff] [blame] | 436 | 	struct ata_host *host = dev_get_drvdata(&op->dev); | 
 | 437 |  | 
 | 438 | 	return ata_host_suspend(host, state); | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 439 | } | 
 | 440 |  | 
 | 441 | static int | 
 | 442 | mpc52xx_ata_resume(struct of_device *op) | 
 | 443 | { | 
| Domen Puncer | 35142dd | 2007-07-03 10:27:38 +0200 | [diff] [blame] | 444 | 	struct ata_host *host = dev_get_drvdata(&op->dev); | 
 | 445 | 	struct mpc52xx_ata_priv *priv = host->private_data; | 
 | 446 | 	int rv; | 
 | 447 |  | 
 | 448 | 	rv = mpc52xx_ata_hw_init(priv); | 
 | 449 | 	if (rv) { | 
 | 450 | 		printk(KERN_ERR DRV_NAME ": Error during HW init\n"); | 
 | 451 | 		return rv; | 
 | 452 | 	} | 
 | 453 |  | 
 | 454 | 	ata_host_resume(host); | 
 | 455 |  | 
 | 456 | 	return 0; | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 457 | } | 
 | 458 |  | 
 | 459 | #endif | 
 | 460 |  | 
 | 461 |  | 
 | 462 | static struct of_device_id mpc52xx_ata_of_match[] = { | 
| Grant Likely | 66ffbe4 | 2008-01-24 22:25:31 -0700 | [diff] [blame] | 463 | 	{ .compatible = "fsl,mpc5200-ata", }, | 
 | 464 | 	{ .compatible = "mpc5200-ata", }, | 
| Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 465 | 	{}, | 
 | 466 | }; | 
 | 467 |  | 
 | 468 |  | 
 | 469 | static struct of_platform_driver mpc52xx_ata_of_platform_driver = { | 
 | 470 | 	.owner		= THIS_MODULE, | 
 | 471 | 	.name		= DRV_NAME, | 
 | 472 | 	.match_table	= mpc52xx_ata_of_match, | 
 | 473 | 	.probe		= mpc52xx_ata_probe, | 
 | 474 | 	.remove		= mpc52xx_ata_remove, | 
 | 475 | #ifdef CONFIG_PM | 
 | 476 | 	.suspend	= mpc52xx_ata_suspend, | 
 | 477 | 	.resume		= mpc52xx_ata_resume, | 
 | 478 | #endif | 
 | 479 | 	.driver		= { | 
 | 480 | 		.name	= DRV_NAME, | 
 | 481 | 		.owner	= THIS_MODULE, | 
 | 482 | 	}, | 
 | 483 | }; | 
 | 484 |  | 
 | 485 |  | 
 | 486 | /* ======================================================================== */ | 
 | 487 | /* Module                                                                   */ | 
 | 488 | /* ======================================================================== */ | 
 | 489 |  | 
 | 490 | static int __init | 
 | 491 | mpc52xx_ata_init(void) | 
 | 492 | { | 
 | 493 | 	printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n"); | 
 | 494 | 	return of_register_platform_driver(&mpc52xx_ata_of_platform_driver); | 
 | 495 | } | 
 | 496 |  | 
 | 497 | static void __exit | 
 | 498 | mpc52xx_ata_exit(void) | 
 | 499 | { | 
 | 500 | 	of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver); | 
 | 501 | } | 
 | 502 |  | 
 | 503 | module_init(mpc52xx_ata_init); | 
 | 504 | module_exit(mpc52xx_ata_exit); | 
 | 505 |  | 
 | 506 | MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); | 
 | 507 | MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); | 
 | 508 | MODULE_LICENSE("GPL"); | 
 | 509 | MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); | 
 | 510 | MODULE_VERSION(DRV_VERSION); | 
 | 511 |  |