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 | a0fcdc0 | 2007-03-09 07:24:15 -0500 | [diff] [blame] | 27 | #define DRV_VERSION "0.1.0ac2" |
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 | |
| 255 | ata_std_dev_select(ap,device); |
| 256 | } |
| 257 | |
| 258 | static void |
| 259 | mpc52xx_ata_error_handler(struct ata_port *ap) |
| 260 | { |
| 261 | ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL, |
| 262 | ata_std_postreset); |
| 263 | } |
| 264 | |
| 265 | |
| 266 | |
| 267 | static struct scsi_host_template mpc52xx_ata_sht = { |
| 268 | .module = THIS_MODULE, |
| 269 | .name = DRV_NAME, |
| 270 | .ioctl = ata_scsi_ioctl, |
| 271 | .queuecommand = ata_scsi_queuecmd, |
| 272 | .can_queue = ATA_DEF_QUEUE, |
| 273 | .this_id = ATA_SHT_THIS_ID, |
| 274 | .sg_tablesize = LIBATA_MAX_PRD, |
| 275 | .max_sectors = ATA_MAX_SECTORS, |
| 276 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
| 277 | .emulated = ATA_SHT_EMULATED, |
| 278 | .use_clustering = ATA_SHT_USE_CLUSTERING, |
| 279 | .proc_name = DRV_NAME, |
| 280 | .dma_boundary = ATA_DMA_BOUNDARY, |
| 281 | .slave_configure = ata_scsi_slave_config, |
| 282 | .bios_param = ata_std_bios_param, |
| 283 | }; |
| 284 | |
| 285 | static struct ata_port_operations mpc52xx_ata_port_ops = { |
| 286 | .port_disable = ata_port_disable, |
| 287 | .set_piomode = mpc52xx_ata_set_piomode, |
| 288 | .dev_select = mpc52xx_ata_dev_select, |
| 289 | .tf_load = ata_tf_load, |
| 290 | .tf_read = ata_tf_read, |
| 291 | .check_status = ata_check_status, |
| 292 | .exec_command = ata_exec_command, |
| 293 | .freeze = ata_bmdma_freeze, |
| 294 | .thaw = ata_bmdma_thaw, |
| 295 | .error_handler = mpc52xx_ata_error_handler, |
Jeff Garzik | a0fcdc0 | 2007-03-09 07:24:15 -0500 | [diff] [blame] | 296 | .cable_detect = ata_cable_40wire, |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 297 | .qc_prep = ata_qc_prep, |
| 298 | .qc_issue = ata_qc_issue_prot, |
Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 299 | .data_xfer = ata_data_xfer, |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 300 | .irq_clear = ata_bmdma_irq_clear, |
Akira Iguchi | 246ce3b | 2007-01-26 16:27:58 +0900 | [diff] [blame] | 301 | .irq_on = ata_irq_on, |
| 302 | .irq_ack = ata_irq_ack, |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 303 | .port_start = ata_port_start, |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 304 | }; |
| 305 | |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 306 | static int __devinit |
| 307 | mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv) |
| 308 | { |
Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 309 | struct ata_host *host; |
| 310 | struct ata_port *ap; |
| 311 | struct ata_ioports *aio; |
| 312 | int rc; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 313 | |
Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 314 | host = ata_host_alloc(dev, 1); |
| 315 | if (!host) |
| 316 | return -ENOMEM; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 317 | |
Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 318 | ap = host->ports[0]; |
| 319 | ap->flags |= ATA_FLAG_SLAVE_POSS; |
| 320 | ap->pio_mask = 0x1f; /* Up to PIO4 */ |
| 321 | ap->mwdma_mask = 0x00; /* No MWDMA */ |
| 322 | ap->udma_mask = 0x00; /* No UDMA */ |
| 323 | ap->ops = &mpc52xx_ata_port_ops; |
| 324 | host->private_data = priv; |
| 325 | |
| 326 | aio = &ap->ioaddr; |
Al Viro | 89952d1 | 2007-03-14 09:17:59 +0000 | [diff] [blame] | 327 | aio->cmd_addr = NULL; /* Don't have a classic reg block */ |
Tejun Heo | 0d5ff56 | 2007-02-01 15:06:36 +0900 | [diff] [blame] | 328 | aio->altstatus_addr = &priv->ata_regs->tf_control; |
| 329 | aio->ctl_addr = &priv->ata_regs->tf_control; |
| 330 | aio->data_addr = &priv->ata_regs->tf_data; |
| 331 | aio->error_addr = &priv->ata_regs->tf_features; |
| 332 | aio->feature_addr = &priv->ata_regs->tf_features; |
| 333 | aio->nsect_addr = &priv->ata_regs->tf_sec_count; |
| 334 | aio->lbal_addr = &priv->ata_regs->tf_sec_num; |
| 335 | aio->lbam_addr = &priv->ata_regs->tf_cyl_low; |
| 336 | aio->lbah_addr = &priv->ata_regs->tf_cyl_high; |
| 337 | aio->device_addr = &priv->ata_regs->tf_dev_head; |
| 338 | aio->status_addr = &priv->ata_regs->tf_command; |
| 339 | aio->command_addr = &priv->ata_regs->tf_command; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 340 | |
Tejun Heo | 5d72882 | 2007-04-17 23:44:08 +0900 | [diff] [blame] | 341 | /* activate host */ |
| 342 | return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0, |
| 343 | &mpc52xx_ata_sht); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 344 | } |
| 345 | |
| 346 | static struct mpc52xx_ata_priv * |
| 347 | mpc52xx_ata_remove_one(struct device *dev) |
| 348 | { |
| 349 | struct ata_host *host = dev_get_drvdata(dev); |
| 350 | struct mpc52xx_ata_priv *priv = host->private_data; |
| 351 | |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 352 | ata_host_detach(host); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 353 | |
| 354 | return priv; |
| 355 | } |
| 356 | |
| 357 | |
| 358 | /* ======================================================================== */ |
| 359 | /* OF Platform driver */ |
| 360 | /* ======================================================================== */ |
| 361 | |
| 362 | static int __devinit |
| 363 | mpc52xx_ata_probe(struct of_device *op, const struct of_device_id *match) |
| 364 | { |
| 365 | unsigned int ipb_freq; |
| 366 | struct resource res_mem; |
| 367 | int ata_irq = NO_IRQ; |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 368 | struct mpc52xx_ata __iomem *ata_regs; |
| 369 | struct mpc52xx_ata_priv *priv; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 370 | int rv; |
| 371 | |
| 372 | /* Get ipb frequency */ |
| 373 | ipb_freq = mpc52xx_find_ipb_freq(op->node); |
| 374 | if (!ipb_freq) { |
| 375 | printk(KERN_ERR DRV_NAME ": " |
| 376 | "Unable to find IPB Bus frequency\n" ); |
| 377 | return -ENODEV; |
| 378 | } |
| 379 | |
| 380 | /* Get IRQ and register */ |
| 381 | rv = of_address_to_resource(op->node, 0, &res_mem); |
| 382 | if (rv) { |
| 383 | printk(KERN_ERR DRV_NAME ": " |
| 384 | "Error while parsing device node resource\n" ); |
| 385 | return rv; |
| 386 | } |
| 387 | |
| 388 | ata_irq = irq_of_parse_and_map(op->node, 0); |
| 389 | if (ata_irq == NO_IRQ) { |
| 390 | printk(KERN_ERR DRV_NAME ": " |
| 391 | "Error while mapping the irq\n"); |
| 392 | return -EINVAL; |
| 393 | } |
| 394 | |
| 395 | /* Request mem region */ |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 396 | if (!devm_request_mem_region(&op->dev, res_mem.start, |
| 397 | sizeof(struct mpc52xx_ata), DRV_NAME)) { |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 398 | printk(KERN_ERR DRV_NAME ": " |
| 399 | "Error while requesting mem region\n"); |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 400 | rv = -EBUSY; |
| 401 | goto err; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | /* Remap registers */ |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 405 | ata_regs = devm_ioremap(&op->dev, res_mem.start, |
| 406 | sizeof(struct mpc52xx_ata)); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 407 | if (!ata_regs) { |
| 408 | printk(KERN_ERR DRV_NAME ": " |
| 409 | "Error while mapping register set\n"); |
| 410 | rv = -ENOMEM; |
| 411 | goto err; |
| 412 | } |
| 413 | |
| 414 | /* Prepare our private structure */ |
Tejun Heo | 24dc5f3 | 2007-01-20 16:00:28 +0900 | [diff] [blame] | 415 | priv = devm_kzalloc(&op->dev, sizeof(struct mpc52xx_ata_priv), |
| 416 | GFP_ATOMIC); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 417 | if (!priv) { |
| 418 | printk(KERN_ERR DRV_NAME ": " |
| 419 | "Error while allocating private structure\n"); |
| 420 | rv = -ENOMEM; |
| 421 | goto err; |
| 422 | } |
| 423 | |
| 424 | priv->ipb_period = 1000000000 / (ipb_freq / 1000); |
| 425 | priv->ata_regs = ata_regs; |
| 426 | priv->ata_irq = ata_irq; |
| 427 | priv->csel = -1; |
| 428 | |
| 429 | /* Init the hw */ |
| 430 | rv = mpc52xx_ata_hw_init(priv); |
| 431 | if (rv) { |
| 432 | printk(KERN_ERR DRV_NAME ": Error during HW init\n"); |
| 433 | goto err; |
| 434 | } |
| 435 | |
| 436 | /* Register ourselves to libata */ |
| 437 | rv = mpc52xx_ata_init_one(&op->dev, priv); |
| 438 | if (rv) { |
| 439 | printk(KERN_ERR DRV_NAME ": " |
| 440 | "Error while registering to ATA layer\n"); |
| 441 | return rv; |
| 442 | } |
| 443 | |
| 444 | /* Done */ |
| 445 | return 0; |
| 446 | |
| 447 | /* Error path */ |
| 448 | err: |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 449 | irq_dispose_mapping(ata_irq); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 450 | return rv; |
| 451 | } |
| 452 | |
| 453 | static int |
| 454 | mpc52xx_ata_remove(struct of_device *op) |
| 455 | { |
| 456 | struct mpc52xx_ata_priv *priv; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 457 | |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 458 | priv = mpc52xx_ata_remove_one(&op->dev); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 459 | irq_dispose_mapping(priv->ata_irq); |
| 460 | |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 461 | return 0; |
| 462 | } |
| 463 | |
| 464 | |
| 465 | #ifdef CONFIG_PM |
| 466 | |
| 467 | static int |
| 468 | mpc52xx_ata_suspend(struct of_device *op, pm_message_t state) |
| 469 | { |
Domen Puncer | 35142dd | 2007-07-03 10:27:38 +0200 | [diff] [blame] | 470 | struct ata_host *host = dev_get_drvdata(&op->dev); |
| 471 | |
| 472 | return ata_host_suspend(host, state); |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 473 | } |
| 474 | |
| 475 | static int |
| 476 | mpc52xx_ata_resume(struct of_device *op) |
| 477 | { |
Domen Puncer | 35142dd | 2007-07-03 10:27:38 +0200 | [diff] [blame] | 478 | struct ata_host *host = dev_get_drvdata(&op->dev); |
| 479 | struct mpc52xx_ata_priv *priv = host->private_data; |
| 480 | int rv; |
| 481 | |
| 482 | rv = mpc52xx_ata_hw_init(priv); |
| 483 | if (rv) { |
| 484 | printk(KERN_ERR DRV_NAME ": Error during HW init\n"); |
| 485 | return rv; |
| 486 | } |
| 487 | |
| 488 | ata_host_resume(host); |
| 489 | |
| 490 | return 0; |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 491 | } |
| 492 | |
| 493 | #endif |
| 494 | |
| 495 | |
| 496 | static struct of_device_id mpc52xx_ata_of_match[] = { |
| 497 | { |
Grant Likely | e3aba81 | 2007-02-12 13:36:55 -0700 | [diff] [blame] | 498 | .type = "ata", |
| 499 | .compatible = "mpc5200-ata", |
Sylvain Munaut | 155d291 | 2006-12-08 00:14:16 +0100 | [diff] [blame] | 500 | }, |
| 501 | {}, |
| 502 | }; |
| 503 | |
| 504 | |
| 505 | static struct of_platform_driver mpc52xx_ata_of_platform_driver = { |
| 506 | .owner = THIS_MODULE, |
| 507 | .name = DRV_NAME, |
| 508 | .match_table = mpc52xx_ata_of_match, |
| 509 | .probe = mpc52xx_ata_probe, |
| 510 | .remove = mpc52xx_ata_remove, |
| 511 | #ifdef CONFIG_PM |
| 512 | .suspend = mpc52xx_ata_suspend, |
| 513 | .resume = mpc52xx_ata_resume, |
| 514 | #endif |
| 515 | .driver = { |
| 516 | .name = DRV_NAME, |
| 517 | .owner = THIS_MODULE, |
| 518 | }, |
| 519 | }; |
| 520 | |
| 521 | |
| 522 | /* ======================================================================== */ |
| 523 | /* Module */ |
| 524 | /* ======================================================================== */ |
| 525 | |
| 526 | static int __init |
| 527 | mpc52xx_ata_init(void) |
| 528 | { |
| 529 | printk(KERN_INFO "ata: MPC52xx IDE/ATA libata driver\n"); |
| 530 | return of_register_platform_driver(&mpc52xx_ata_of_platform_driver); |
| 531 | } |
| 532 | |
| 533 | static void __exit |
| 534 | mpc52xx_ata_exit(void) |
| 535 | { |
| 536 | of_unregister_platform_driver(&mpc52xx_ata_of_platform_driver); |
| 537 | } |
| 538 | |
| 539 | module_init(mpc52xx_ata_init); |
| 540 | module_exit(mpc52xx_ata_exit); |
| 541 | |
| 542 | MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); |
| 543 | MODULE_DESCRIPTION("Freescale MPC52xx IDE/ATA libata driver"); |
| 544 | MODULE_LICENSE("GPL"); |
| 545 | MODULE_DEVICE_TABLE(of, mpc52xx_ata_of_match); |
| 546 | MODULE_VERSION(DRV_VERSION); |
| 547 | |