11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Driver for the media bay on the PowerBook 3400 and 2400. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1998 Paul Mackerras. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Various evolutions by Benjamin Herrenschmidt & Henry Worth 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 91da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 101da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 111da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds #include <linux/types.h> 141da177e4SLinus Torvalds #include <linux/errno.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/delay.h> 171da177e4SLinus Torvalds #include <linux/sched.h> 181da177e4SLinus Torvalds #include <linux/timer.h> 191da177e4SLinus Torvalds #include <linux/stddef.h> 201da177e4SLinus Torvalds #include <linux/init.h> 2133f6e794SPaul Mackerras #include <linux/kthread.h> 229a24729dSDaniel Walker #include <linux/mutex.h> 231da177e4SLinus Torvalds #include <asm/prom.h> 241da177e4SLinus Torvalds #include <asm/pgtable.h> 251da177e4SLinus Torvalds #include <asm/io.h> 261da177e4SLinus Torvalds #include <asm/machdep.h> 271da177e4SLinus Torvalds #include <asm/pmac_feature.h> 281da177e4SLinus Torvalds #include <asm/mediabay.h> 291da177e4SLinus Torvalds #include <asm/sections.h> 301da177e4SLinus Torvalds #include <asm/ohare.h> 311da177e4SLinus Torvalds #include <asm/heathrow.h> 321da177e4SLinus Torvalds #include <asm/keylargo.h> 331da177e4SLinus Torvalds #include <linux/adb.h> 341da177e4SLinus Torvalds #include <linux/pmu.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) 371da177e4SLinus Torvalds #define MB_FCR8(bay, r) (((volatile u8 __iomem *)((bay)->base)) + (r)) 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) 401da177e4SLinus Torvalds #define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) 411da177e4SLinus Torvalds #define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) 421da177e4SLinus Torvalds #define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) 431da177e4SLinus Torvalds #define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) 441da177e4SLinus Torvalds #define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds struct media_bay_info; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds struct mb_ops { 491da177e4SLinus Torvalds char* name; 501da177e4SLinus Torvalds void (*init)(struct media_bay_info *bay); 511da177e4SLinus Torvalds u8 (*content)(struct media_bay_info *bay); 521da177e4SLinus Torvalds void (*power)(struct media_bay_info *bay, int on_off); 531da177e4SLinus Torvalds int (*setup_bus)(struct media_bay_info *bay, u8 device_id); 541da177e4SLinus Torvalds void (*un_reset)(struct media_bay_info *bay); 551da177e4SLinus Torvalds void (*un_reset_ide)(struct media_bay_info *bay); 561da177e4SLinus Torvalds }; 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds struct media_bay_info { 591da177e4SLinus Torvalds u32 __iomem *base; 601da177e4SLinus Torvalds int content_id; 611da177e4SLinus Torvalds int state; 621da177e4SLinus Torvalds int last_value; 631da177e4SLinus Torvalds int value_count; 641da177e4SLinus Torvalds int timer; 651da177e4SLinus Torvalds struct macio_dev *mdev; 66519a6510SUwe Kleine-König const struct mb_ops* ops; 671da177e4SLinus Torvalds int index; 681da177e4SLinus Torvalds int cached_gpio; 691da177e4SLinus Torvalds int sleeping; 70d58b0c39SBenjamin Herrenschmidt int user_lock; 719a24729dSDaniel Walker struct mutex lock; 721da177e4SLinus Torvalds }; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #define MAX_BAYS 2 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds static struct media_bay_info media_bays[MAX_BAYS]; 77d58b0c39SBenjamin Herrenschmidt static int media_bay_count = 0; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * Wait that number of ms between each step in normal polling mode 811da177e4SLinus Torvalds */ 821da177e4SLinus Torvalds #define MB_POLL_DELAY 25 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* 851da177e4SLinus Torvalds * Consider the media-bay ID value stable if it is the same for 861da177e4SLinus Torvalds * this number of milliseconds 871da177e4SLinus Torvalds */ 881da177e4SLinus Torvalds #define MB_STABLE_DELAY 100 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* Wait after powering up the media bay this delay in ms 911da177e4SLinus Torvalds * timeout bumped for some powerbooks 921da177e4SLinus Torvalds */ 931da177e4SLinus Torvalds #define MB_POWER_DELAY 200 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* 961da177e4SLinus Torvalds * Hold the media-bay reset signal true for this many ticks 971da177e4SLinus Torvalds * after a device is inserted before releasing it. 981da177e4SLinus Torvalds */ 991da177e4SLinus Torvalds #define MB_RESET_DELAY 50 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* 1021da177e4SLinus Torvalds * Wait this long after the reset signal is released and before doing 1031da177e4SLinus Torvalds * further operations. After this delay, the IDE reset signal is released 1041da177e4SLinus Torvalds * too for an IDE device 1051da177e4SLinus Torvalds */ 1061da177e4SLinus Torvalds #define MB_SETUP_DELAY 100 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted 110d58b0c39SBenjamin Herrenschmidt * (or until the device is ready) before calling into the driver 1111da177e4SLinus Torvalds */ 1121da177e4SLinus Torvalds #define MB_IDE_WAIT 1000 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* 1151da177e4SLinus Torvalds * States of a media bay 1161da177e4SLinus Torvalds */ 1171da177e4SLinus Torvalds enum { 1181da177e4SLinus Torvalds mb_empty = 0, /* Idle */ 1191da177e4SLinus Torvalds mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */ 1201da177e4SLinus Torvalds mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */ 1211da177e4SLinus Torvalds mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */ 1221da177e4SLinus Torvalds mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */ 1231da177e4SLinus Torvalds mb_up, /* Media bay full */ 1241da177e4SLinus Torvalds mb_powering_down /* Powering down (avoid too fast down/up) */ 1251da177e4SLinus Torvalds }; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds #define MB_POWER_SOUND 0x08 1281da177e4SLinus Torvalds #define MB_POWER_FLOPPY 0x04 1291da177e4SLinus Torvalds #define MB_POWER_ATA 0x02 1301da177e4SLinus Torvalds #define MB_POWER_PCI 0x01 1311da177e4SLinus Torvalds #define MB_POWER_OFF 0x00 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds /* 1341da177e4SLinus Torvalds * Functions for polling content of media bay 1351da177e4SLinus Torvalds */ 1361da177e4SLinus Torvalds 137aacaf9bdSJon Loeliger static u8 1381da177e4SLinus Torvalds ohare_mb_content(struct media_bay_info *bay) 1391da177e4SLinus Torvalds { 1401da177e4SLinus Torvalds return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 143aacaf9bdSJon Loeliger static u8 1441da177e4SLinus Torvalds heathrow_mb_content(struct media_bay_info *bay) 1451da177e4SLinus Torvalds { 1461da177e4SLinus Torvalds return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 149aacaf9bdSJon Loeliger static u8 1501da177e4SLinus Torvalds keylargo_mb_content(struct media_bay_info *bay) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds int new_gpio; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; 1551da177e4SLinus Torvalds if (new_gpio) { 1561da177e4SLinus Torvalds bay->cached_gpio = new_gpio; 1571da177e4SLinus Torvalds return MB_NO; 1581da177e4SLinus Torvalds } else if (bay->cached_gpio != new_gpio) { 1591da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 1601da177e4SLinus Torvalds (void)MB_IN32(bay, KEYLARGO_MBCR); 1611da177e4SLinus Torvalds udelay(5); 1621da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 1631da177e4SLinus Torvalds (void)MB_IN32(bay, KEYLARGO_MBCR); 1641da177e4SLinus Torvalds udelay(5); 1651da177e4SLinus Torvalds bay->cached_gpio = new_gpio; 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds /* 1711da177e4SLinus Torvalds * Functions for powering up/down the bay, puts the bay device 1721da177e4SLinus Torvalds * into reset state as well 1731da177e4SLinus Torvalds */ 1741da177e4SLinus Torvalds 175aacaf9bdSJon Loeliger static void 1761da177e4SLinus Torvalds ohare_mb_power(struct media_bay_info* bay, int on_off) 1771da177e4SLinus Torvalds { 1781da177e4SLinus Torvalds if (on_off) { 1791da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 1801da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N); 1811da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N); 1821da177e4SLinus Torvalds } else { 1831da177e4SLinus Torvalds /* Disable all devices */ 1841da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK); 1851da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 1861da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 1871da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N); 1881da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 1891da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds MB_BIC(bay, OHARE_MBCR, 0x00000F00); 1921da177e4SLinus Torvalds } 1931da177e4SLinus Torvalds 194aacaf9bdSJon Loeliger static void 1951da177e4SLinus Torvalds heathrow_mb_power(struct media_bay_info* bay, int on_off) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds if (on_off) { 1981da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 1991da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 2001da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 2011da177e4SLinus Torvalds } else { 2021da177e4SLinus Torvalds /* Disable all devices */ 2031da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); 2041da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 2051da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 2061da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 2071da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 2081da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds 213aacaf9bdSJon Loeliger static void 2141da177e4SLinus Torvalds keylargo_mb_power(struct media_bay_info* bay, int on_off) 2151da177e4SLinus Torvalds { 2161da177e4SLinus Torvalds if (on_off) { 2171da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 2181da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 2191da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 2201da177e4SLinus Torvalds } else { 2211da177e4SLinus Torvalds /* Disable all devices */ 2221da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); 2231da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 2241da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 2251da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 2261da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 2271da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /* 2331da177e4SLinus Torvalds * Functions for configuring the media bay for a given type of device, 2341da177e4SLinus Torvalds * enable the related busses 2351da177e4SLinus Torvalds */ 2361da177e4SLinus Torvalds 237aacaf9bdSJon Loeliger static int 2381da177e4SLinus Torvalds ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 2391da177e4SLinus Torvalds { 2401da177e4SLinus Torvalds switch(device_id) { 2411da177e4SLinus Torvalds case MB_FD: 2421da177e4SLinus Torvalds case MB_FD1: 2431da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); 2441da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 2451da177e4SLinus Torvalds return 0; 2461da177e4SLinus Torvalds case MB_CD: 2471da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); 2481da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); 2491da177e4SLinus Torvalds return 0; 2501da177e4SLinus Torvalds case MB_PCI: 2511da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); 2521da177e4SLinus Torvalds return 0; 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds return -ENODEV; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 257aacaf9bdSJon Loeliger static int 2581da177e4SLinus Torvalds heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds switch(device_id) { 2611da177e4SLinus Torvalds case MB_FD: 2621da177e4SLinus Torvalds case MB_FD1: 2631da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); 2641da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 2651da177e4SLinus Torvalds return 0; 2661da177e4SLinus Torvalds case MB_CD: 2671da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 2681da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); 2691da177e4SLinus Torvalds return 0; 2701da177e4SLinus Torvalds case MB_PCI: 2711da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); 2721da177e4SLinus Torvalds return 0; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds return -ENODEV; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 277aacaf9bdSJon Loeliger static int 2781da177e4SLinus Torvalds keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds switch(device_id) { 2811da177e4SLinus Torvalds case MB_CD: 2821da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); 2831da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 2841da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 2851da177e4SLinus Torvalds return 0; 2861da177e4SLinus Torvalds case MB_PCI: 2871da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); 2881da177e4SLinus Torvalds return 0; 2891da177e4SLinus Torvalds case MB_SOUND: 2901da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); 2911da177e4SLinus Torvalds return 0; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds return -ENODEV; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds /* 2971da177e4SLinus Torvalds * Functions for tweaking resets 2981da177e4SLinus Torvalds */ 2991da177e4SLinus Torvalds 300aacaf9bdSJon Loeliger static void 3011da177e4SLinus Torvalds ohare_mb_un_reset(struct media_bay_info* bay) 3021da177e4SLinus Torvalds { 3031da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 306aacaf9bdSJon Loeliger static void keylargo_mb_init(struct media_bay_info *bay) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 311aacaf9bdSJon Loeliger static void heathrow_mb_un_reset(struct media_bay_info* bay) 3121da177e4SLinus Torvalds { 3131da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 3141da177e4SLinus Torvalds } 3151da177e4SLinus Torvalds 316aacaf9bdSJon Loeliger static void keylargo_mb_un_reset(struct media_bay_info* bay) 3171da177e4SLinus Torvalds { 3181da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 321aacaf9bdSJon Loeliger static void ohare_mb_un_reset_ide(struct media_bay_info* bay) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326aacaf9bdSJon Loeliger static void heathrow_mb_un_reset_ide(struct media_bay_info* bay) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 331aacaf9bdSJon Loeliger static void keylargo_mb_un_reset_ide(struct media_bay_info* bay) 3321da177e4SLinus Torvalds { 3331da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds 336aacaf9bdSJon Loeliger static inline void set_mb_power(struct media_bay_info* bay, int onoff) 3371da177e4SLinus Torvalds { 3381da177e4SLinus Torvalds /* Power up up and assert the bay reset line */ 3391da177e4SLinus Torvalds if (onoff) { 3401da177e4SLinus Torvalds bay->ops->power(bay, 1); 3411da177e4SLinus Torvalds bay->state = mb_powering_up; 342d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: powering up\n", bay->index); 3431da177e4SLinus Torvalds } else { 3441da177e4SLinus Torvalds /* Make sure everything is powered down & disabled */ 3451da177e4SLinus Torvalds bay->ops->power(bay, 0); 3461da177e4SLinus Torvalds bay->state = mb_powering_down; 347d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: powering down\n", bay->index); 3481da177e4SLinus Torvalds } 3491da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 3501da177e4SLinus Torvalds } 3511da177e4SLinus Torvalds 352aacaf9bdSJon Loeliger static void poll_media_bay(struct media_bay_info* bay) 3531da177e4SLinus Torvalds { 3541da177e4SLinus Torvalds int id = bay->ops->content(bay); 3551da177e4SLinus Torvalds 356d58b0c39SBenjamin Herrenschmidt static char *mb_content_types[] = { 357d58b0c39SBenjamin Herrenschmidt "a floppy drive", 358d58b0c39SBenjamin Herrenschmidt "a floppy drive", 359ec16f3dfSMasanari Iida "an unsupported audio device", 360d58b0c39SBenjamin Herrenschmidt "an ATA device", 361d58b0c39SBenjamin Herrenschmidt "an unsupported PCI device", 362d58b0c39SBenjamin Herrenschmidt "an unknown device", 363d58b0c39SBenjamin Herrenschmidt }; 364d58b0c39SBenjamin Herrenschmidt 365d58b0c39SBenjamin Herrenschmidt if (id != bay->last_value) { 366d58b0c39SBenjamin Herrenschmidt bay->last_value = id; 367d58b0c39SBenjamin Herrenschmidt bay->value_count = 0; 368d58b0c39SBenjamin Herrenschmidt return; 369d58b0c39SBenjamin Herrenschmidt } 370d58b0c39SBenjamin Herrenschmidt if (id == bay->content_id) 371d58b0c39SBenjamin Herrenschmidt return; 372d58b0c39SBenjamin Herrenschmidt 3731da177e4SLinus Torvalds bay->value_count += msecs_to_jiffies(MB_POLL_DELAY); 3741da177e4SLinus Torvalds if (bay->value_count >= msecs_to_jiffies(MB_STABLE_DELAY)) { 3751da177e4SLinus Torvalds /* If the device type changes without going thru 3761da177e4SLinus Torvalds * "MB_NO", we force a pass by "MB_NO" to make sure 3771da177e4SLinus Torvalds * things are properly reset 3781da177e4SLinus Torvalds */ 3791da177e4SLinus Torvalds if ((id != MB_NO) && (bay->content_id != MB_NO)) { 3801da177e4SLinus Torvalds id = MB_NO; 381d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: forcing MB_NO\n", bay->index); 3821da177e4SLinus Torvalds } 383d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: switching to %d\n", bay->index, id); 3841da177e4SLinus Torvalds set_mb_power(bay, id != MB_NO); 3851da177e4SLinus Torvalds bay->content_id = id; 386d58b0c39SBenjamin Herrenschmidt if (id >= MB_NO || id < 0) 387d58b0c39SBenjamin Herrenschmidt printk(KERN_INFO "mediabay%d: Bay is now empty\n", bay->index); 388d58b0c39SBenjamin Herrenschmidt else 389d58b0c39SBenjamin Herrenschmidt printk(KERN_INFO "mediabay%d: Bay contains %s\n", 390d58b0c39SBenjamin Herrenschmidt bay->index, mb_content_types[id]); 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 394d58b0c39SBenjamin Herrenschmidt int check_media_bay(struct macio_dev *baydev) 3951da177e4SLinus Torvalds { 396d58b0c39SBenjamin Herrenschmidt struct media_bay_info* bay; 397d58b0c39SBenjamin Herrenschmidt int id; 3981da177e4SLinus Torvalds 399d58b0c39SBenjamin Herrenschmidt if (baydev == NULL) 400d58b0c39SBenjamin Herrenschmidt return MB_NO; 4011da177e4SLinus Torvalds 402d58b0c39SBenjamin Herrenschmidt /* This returns an instant snapshot, not locking, sine 403d58b0c39SBenjamin Herrenschmidt * we may be called with the bay lock held. The resulting 404d58b0c39SBenjamin Herrenschmidt * fuzzyness of the result if called at the wrong time is 405d58b0c39SBenjamin Herrenschmidt * not actually a huge deal 406d58b0c39SBenjamin Herrenschmidt */ 407d58b0c39SBenjamin Herrenschmidt bay = macio_get_drvdata(baydev); 408d58b0c39SBenjamin Herrenschmidt if (bay == NULL) 409d58b0c39SBenjamin Herrenschmidt return MB_NO; 410d58b0c39SBenjamin Herrenschmidt id = bay->content_id; 411d58b0c39SBenjamin Herrenschmidt if (bay->state != mb_up) 412d58b0c39SBenjamin Herrenschmidt return MB_NO; 413d58b0c39SBenjamin Herrenschmidt if (id == MB_FD1) 414d58b0c39SBenjamin Herrenschmidt return MB_FD; 415d58b0c39SBenjamin Herrenschmidt return id; 416d58b0c39SBenjamin Herrenschmidt } 417d58b0c39SBenjamin Herrenschmidt EXPORT_SYMBOL_GPL(check_media_bay); 418d58b0c39SBenjamin Herrenschmidt 419d58b0c39SBenjamin Herrenschmidt void lock_media_bay(struct macio_dev *baydev) 4201da177e4SLinus Torvalds { 421d58b0c39SBenjamin Herrenschmidt struct media_bay_info* bay; 4221da177e4SLinus Torvalds 423d58b0c39SBenjamin Herrenschmidt if (baydev == NULL) 424d58b0c39SBenjamin Herrenschmidt return; 425d58b0c39SBenjamin Herrenschmidt bay = macio_get_drvdata(baydev); 426d58b0c39SBenjamin Herrenschmidt if (bay == NULL) 427d58b0c39SBenjamin Herrenschmidt return; 4289a24729dSDaniel Walker mutex_lock(&bay->lock); 429d58b0c39SBenjamin Herrenschmidt bay->user_lock = 1; 430d58b0c39SBenjamin Herrenschmidt } 431d58b0c39SBenjamin Herrenschmidt EXPORT_SYMBOL_GPL(lock_media_bay); 4321da177e4SLinus Torvalds 433d58b0c39SBenjamin Herrenschmidt void unlock_media_bay(struct macio_dev *baydev) 434d58b0c39SBenjamin Herrenschmidt { 435d58b0c39SBenjamin Herrenschmidt struct media_bay_info* bay; 4361da177e4SLinus Torvalds 437d58b0c39SBenjamin Herrenschmidt if (baydev == NULL) 438d58b0c39SBenjamin Herrenschmidt return; 439d58b0c39SBenjamin Herrenschmidt bay = macio_get_drvdata(baydev); 440d58b0c39SBenjamin Herrenschmidt if (bay == NULL) 441d58b0c39SBenjamin Herrenschmidt return; 442d58b0c39SBenjamin Herrenschmidt if (bay->user_lock) { 443d58b0c39SBenjamin Herrenschmidt bay->user_lock = 0; 4449a24729dSDaniel Walker mutex_unlock(&bay->lock); 445d58b0c39SBenjamin Herrenschmidt } 446d58b0c39SBenjamin Herrenschmidt } 447d58b0c39SBenjamin Herrenschmidt EXPORT_SYMBOL_GPL(unlock_media_bay); 448d58b0c39SBenjamin Herrenschmidt 449d58b0c39SBenjamin Herrenschmidt static int mb_broadcast_hotplug(struct device *dev, void *data) 450d58b0c39SBenjamin Herrenschmidt { 451d58b0c39SBenjamin Herrenschmidt struct media_bay_info* bay = data; 452d58b0c39SBenjamin Herrenschmidt struct macio_dev *mdev; 453d58b0c39SBenjamin Herrenschmidt struct macio_driver *drv; 454d58b0c39SBenjamin Herrenschmidt int state; 455d58b0c39SBenjamin Herrenschmidt 456d58b0c39SBenjamin Herrenschmidt if (dev->bus != &macio_bus_type) 457d58b0c39SBenjamin Herrenschmidt return 0; 458d58b0c39SBenjamin Herrenschmidt 459d58b0c39SBenjamin Herrenschmidt state = bay->state == mb_up ? bay->content_id : MB_NO; 460d58b0c39SBenjamin Herrenschmidt if (state == MB_FD1) 461d58b0c39SBenjamin Herrenschmidt state = MB_FD; 462d58b0c39SBenjamin Herrenschmidt mdev = to_macio_device(dev); 463d58b0c39SBenjamin Herrenschmidt drv = to_macio_driver(dev->driver); 464d58b0c39SBenjamin Herrenschmidt if (dev->driver && drv->mediabay_event) 465d58b0c39SBenjamin Herrenschmidt drv->mediabay_event(mdev, state); 4661da177e4SLinus Torvalds return 0; 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 469aacaf9bdSJon Loeliger static void media_bay_step(int i) 4701da177e4SLinus Torvalds { 4711da177e4SLinus Torvalds struct media_bay_info* bay = &media_bays[i]; 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds /* We don't poll when powering down */ 4741da177e4SLinus Torvalds if (bay->state != mb_powering_down) 4751da177e4SLinus Torvalds poll_media_bay(bay); 4761da177e4SLinus Torvalds 477d58b0c39SBenjamin Herrenschmidt /* If timer expired run state machine */ 478d58b0c39SBenjamin Herrenschmidt if (bay->timer != 0) { 4791da177e4SLinus Torvalds bay->timer -= msecs_to_jiffies(MB_POLL_DELAY); 4801da177e4SLinus Torvalds if (bay->timer > 0) 4811da177e4SLinus Torvalds return; 4821da177e4SLinus Torvalds bay->timer = 0; 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 4851da177e4SLinus Torvalds switch(bay->state) { 4861da177e4SLinus Torvalds case mb_powering_up: 4871da177e4SLinus Torvalds if (bay->ops->setup_bus(bay, bay->last_value) < 0) { 488d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: device not supported (kind:%d)\n", 489d58b0c39SBenjamin Herrenschmidt i, bay->content_id); 4901da177e4SLinus Torvalds set_mb_power(bay, 0); 4911da177e4SLinus Torvalds break; 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_RESET_DELAY); 4941da177e4SLinus Torvalds bay->state = mb_enabling_bay; 495d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); 4961da177e4SLinus Torvalds break; 4971da177e4SLinus Torvalds case mb_enabling_bay: 4981da177e4SLinus Torvalds bay->ops->un_reset(bay); 4991da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_SETUP_DELAY); 5001da177e4SLinus Torvalds bay->state = mb_resetting; 501d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: releasing bay reset (kind:%d)\n", 502d58b0c39SBenjamin Herrenschmidt i, bay->content_id); 5031da177e4SLinus Torvalds break; 5041da177e4SLinus Torvalds case mb_resetting: 5051da177e4SLinus Torvalds if (bay->content_id != MB_CD) { 506d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: bay is up (kind:%d)\n", i, 507d58b0c39SBenjamin Herrenschmidt bay->content_id); 5081da177e4SLinus Torvalds bay->state = mb_up; 509d58b0c39SBenjamin Herrenschmidt device_for_each_child(&bay->mdev->ofdev.dev, 510d58b0c39SBenjamin Herrenschmidt bay, mb_broadcast_hotplug); 5111da177e4SLinus Torvalds break; 5121da177e4SLinus Torvalds } 513d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: releasing ATA reset (kind:%d)\n", 514d58b0c39SBenjamin Herrenschmidt i, bay->content_id); 5151da177e4SLinus Torvalds bay->ops->un_reset_ide(bay); 5161da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_IDE_WAIT); 5171da177e4SLinus Torvalds bay->state = mb_ide_resetting; 5181da177e4SLinus Torvalds break; 519d58b0c39SBenjamin Herrenschmidt 5201da177e4SLinus Torvalds case mb_ide_resetting: 521d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id); 5221da177e4SLinus Torvalds bay->state = mb_up; 523d58b0c39SBenjamin Herrenschmidt device_for_each_child(&bay->mdev->ofdev.dev, 524d58b0c39SBenjamin Herrenschmidt bay, mb_broadcast_hotplug); 5251da177e4SLinus Torvalds break; 526d58b0c39SBenjamin Herrenschmidt 5271da177e4SLinus Torvalds case mb_powering_down: 5281da177e4SLinus Torvalds bay->state = mb_empty; 529d58b0c39SBenjamin Herrenschmidt device_for_each_child(&bay->mdev->ofdev.dev, 530d58b0c39SBenjamin Herrenschmidt bay, mb_broadcast_hotplug); 531d58b0c39SBenjamin Herrenschmidt pr_debug("mediabay%d: end of power down\n", i); 5321da177e4SLinus Torvalds break; 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* 5371da177e4SLinus Torvalds * This procedure runs as a kernel thread to poll the media bay 5381da177e4SLinus Torvalds * once each tick and register and unregister the IDE interface 5391da177e4SLinus Torvalds * with the IDE driver. It needs to be a thread because 5401da177e4SLinus Torvalds * ide_register can't be called from interrupt context. 5411da177e4SLinus Torvalds */ 542aacaf9bdSJon Loeliger static int media_bay_task(void *x) 5431da177e4SLinus Torvalds { 5441da177e4SLinus Torvalds int i; 5451da177e4SLinus Torvalds 54633f6e794SPaul Mackerras while (!kthread_should_stop()) { 5471da177e4SLinus Torvalds for (i = 0; i < media_bay_count; ++i) { 5489a24729dSDaniel Walker mutex_lock(&media_bays[i].lock); 5491da177e4SLinus Torvalds if (!media_bays[i].sleeping) 5501da177e4SLinus Torvalds media_bay_step(i); 5519a24729dSDaniel Walker mutex_unlock(&media_bays[i].lock); 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds msleep_interruptible(MB_POLL_DELAY); 5551da177e4SLinus Torvalds } 55633f6e794SPaul Mackerras return 0; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5595e655772SJeff Mahoney static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds struct media_bay_info* bay; 5621da177e4SLinus Torvalds u32 __iomem *regbase; 5631da177e4SLinus Torvalds struct device_node *ofnode; 564cc5d0189SBenjamin Herrenschmidt unsigned long base; 5651da177e4SLinus Torvalds int i; 5661da177e4SLinus Torvalds 56761c7a080SGrant Likely ofnode = mdev->ofdev.dev.of_node; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds if (macio_resource_count(mdev) < 1) 5701da177e4SLinus Torvalds return -ENODEV; 5711da177e4SLinus Torvalds if (macio_request_resources(mdev, "media-bay")) 5721da177e4SLinus Torvalds return -EBUSY; 5731da177e4SLinus Torvalds /* Media bay registers are located at the beginning of the 574cc5d0189SBenjamin Herrenschmidt * mac-io chip, for now, we trick and align down the first 575cc5d0189SBenjamin Herrenschmidt * resource passed in 5761da177e4SLinus Torvalds */ 577cc5d0189SBenjamin Herrenschmidt base = macio_resource_start(mdev, 0) & 0xffff0000u; 578cc5d0189SBenjamin Herrenschmidt regbase = (u32 __iomem *)ioremap(base, 0x100); 5791da177e4SLinus Torvalds if (regbase == NULL) { 5801da177e4SLinus Torvalds macio_release_resources(mdev); 5811da177e4SLinus Torvalds return -ENOMEM; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds i = media_bay_count++; 5851da177e4SLinus Torvalds bay = &media_bays[i]; 5861da177e4SLinus Torvalds bay->mdev = mdev; 5871da177e4SLinus Torvalds bay->base = regbase; 5881da177e4SLinus Torvalds bay->index = i; 5891da177e4SLinus Torvalds bay->ops = match->data; 5901da177e4SLinus Torvalds bay->sleeping = 0; 5919a24729dSDaniel Walker mutex_init(&bay->lock); 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* Init HW probing */ 5941da177e4SLinus Torvalds if (bay->ops->init) 5951da177e4SLinus Torvalds bay->ops->init(bay); 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", i, bay->ops->name); 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds /* Force an immediate detect */ 6001da177e4SLinus Torvalds set_mb_power(bay, 0); 6011da177e4SLinus Torvalds msleep(MB_POWER_DELAY); 6021da177e4SLinus Torvalds bay->content_id = MB_NO; 6031da177e4SLinus Torvalds bay->last_value = bay->ops->content(bay); 6041da177e4SLinus Torvalds bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 6051da177e4SLinus Torvalds bay->state = mb_empty; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* Mark us ready by filling our mdev data */ 6081da177e4SLinus Torvalds macio_set_drvdata(mdev, bay); 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds /* Startup kernel thread */ 6111da177e4SLinus Torvalds if (i == 0) 61233f6e794SPaul Mackerras kthread_run(media_bay_task, NULL, "media-bay"); 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds return 0; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds } 6171da177e4SLinus Torvalds 618aacaf9bdSJon Loeliger static int media_bay_suspend(struct macio_dev *mdev, pm_message_t state) 6191da177e4SLinus Torvalds { 6201da177e4SLinus Torvalds struct media_bay_info *bay = macio_get_drvdata(mdev); 6211da177e4SLinus Torvalds 6223a2d5b70SRafael J. Wysocki if (state.event != mdev->ofdev.dev.power.power_state.event 6233a2d5b70SRafael J. Wysocki && (state.event & PM_EVENT_SLEEP)) { 6249a24729dSDaniel Walker mutex_lock(&bay->lock); 6251da177e4SLinus Torvalds bay->sleeping = 1; 6261da177e4SLinus Torvalds set_mb_power(bay, 0); 6279a24729dSDaniel Walker mutex_unlock(&bay->lock); 6281da177e4SLinus Torvalds msleep(MB_POLL_DELAY); 6291da177e4SLinus Torvalds mdev->ofdev.dev.power.power_state = state; 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds return 0; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 634aacaf9bdSJon Loeliger static int media_bay_resume(struct macio_dev *mdev) 6351da177e4SLinus Torvalds { 6361da177e4SLinus Torvalds struct media_bay_info *bay = macio_get_drvdata(mdev); 6371da177e4SLinus Torvalds 638ca078baeSPavel Machek if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { 639829ca9a3SPavel Machek mdev->ofdev.dev.power.power_state = PMSG_ON; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds /* We re-enable the bay using it's previous content 6421da177e4SLinus Torvalds only if it did not change. Note those bozo timings, 6431da177e4SLinus Torvalds they seem to help the 3400 get it right. 6441da177e4SLinus Torvalds */ 6451da177e4SLinus Torvalds /* Force MB power to 0 */ 6469a24729dSDaniel Walker mutex_lock(&bay->lock); 6471da177e4SLinus Torvalds set_mb_power(bay, 0); 6481da177e4SLinus Torvalds msleep(MB_POWER_DELAY); 6491da177e4SLinus Torvalds if (bay->ops->content(bay) != bay->content_id) { 650d58b0c39SBenjamin Herrenschmidt printk("mediabay%d: Content changed during sleep...\n", bay->index); 6519a24729dSDaniel Walker mutex_unlock(&bay->lock); 6521da177e4SLinus Torvalds return 0; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds set_mb_power(bay, 1); 6551da177e4SLinus Torvalds bay->last_value = bay->content_id; 6561da177e4SLinus Torvalds bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 6571da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 6581da177e4SLinus Torvalds do { 6591da177e4SLinus Torvalds msleep(MB_POLL_DELAY); 6601da177e4SLinus Torvalds media_bay_step(bay->index); 6611da177e4SLinus Torvalds } while((bay->state != mb_empty) && 6621da177e4SLinus Torvalds (bay->state != mb_up)); 6631da177e4SLinus Torvalds bay->sleeping = 0; 6649a24729dSDaniel Walker mutex_unlock(&bay->lock); 6651da177e4SLinus Torvalds } 6661da177e4SLinus Torvalds return 0; 6671da177e4SLinus Torvalds } 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds /* Definitions of "ops" structures. 6711da177e4SLinus Torvalds */ 672*306e352aSArnd Bergmann static const struct mb_ops ohare_mb_ops = { 6731da177e4SLinus Torvalds .name = "Ohare", 6741da177e4SLinus Torvalds .content = ohare_mb_content, 6751da177e4SLinus Torvalds .power = ohare_mb_power, 6761da177e4SLinus Torvalds .setup_bus = ohare_mb_setup_bus, 6771da177e4SLinus Torvalds .un_reset = ohare_mb_un_reset, 6781da177e4SLinus Torvalds .un_reset_ide = ohare_mb_un_reset_ide, 6791da177e4SLinus Torvalds }; 6801da177e4SLinus Torvalds 681*306e352aSArnd Bergmann static const struct mb_ops heathrow_mb_ops = { 6821da177e4SLinus Torvalds .name = "Heathrow", 6831da177e4SLinus Torvalds .content = heathrow_mb_content, 6841da177e4SLinus Torvalds .power = heathrow_mb_power, 6851da177e4SLinus Torvalds .setup_bus = heathrow_mb_setup_bus, 6861da177e4SLinus Torvalds .un_reset = heathrow_mb_un_reset, 6871da177e4SLinus Torvalds .un_reset_ide = heathrow_mb_un_reset_ide, 6881da177e4SLinus Torvalds }; 6891da177e4SLinus Torvalds 690*306e352aSArnd Bergmann static const struct mb_ops keylargo_mb_ops = { 6911da177e4SLinus Torvalds .name = "KeyLargo", 6921da177e4SLinus Torvalds .init = keylargo_mb_init, 6931da177e4SLinus Torvalds .content = keylargo_mb_content, 6941da177e4SLinus Torvalds .power = keylargo_mb_power, 6951da177e4SLinus Torvalds .setup_bus = keylargo_mb_setup_bus, 6961da177e4SLinus Torvalds .un_reset = keylargo_mb_un_reset, 6971da177e4SLinus Torvalds .un_reset_ide = keylargo_mb_un_reset_ide, 6981da177e4SLinus Torvalds }; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds /* 7011da177e4SLinus Torvalds * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL 7021da177e4SLinus Torvalds * register is always set when there is something in the media bay. 7031da177e4SLinus Torvalds * This causes problems for the interrupt code if we attach an interrupt 7041da177e4SLinus Torvalds * handler to the media-bay interrupt, because it tends to go into 7051da177e4SLinus Torvalds * an infinite loop calling the media bay interrupt handler. 7061da177e4SLinus Torvalds * Therefore we do it all by polling the media bay once each tick. 7071da177e4SLinus Torvalds */ 7081da177e4SLinus Torvalds 7095e655772SJeff Mahoney static struct of_device_id media_bay_match[] = 7101da177e4SLinus Torvalds { 7111da177e4SLinus Torvalds { 7121da177e4SLinus Torvalds .name = "media-bay", 7131da177e4SLinus Torvalds .compatible = "keylargo-media-bay", 7141da177e4SLinus Torvalds .data = &keylargo_mb_ops, 7151da177e4SLinus Torvalds }, 7161da177e4SLinus Torvalds { 7171da177e4SLinus Torvalds .name = "media-bay", 7181da177e4SLinus Torvalds .compatible = "heathrow-media-bay", 7191da177e4SLinus Torvalds .data = &heathrow_mb_ops, 7201da177e4SLinus Torvalds }, 7211da177e4SLinus Torvalds { 7221da177e4SLinus Torvalds .name = "media-bay", 7231da177e4SLinus Torvalds .compatible = "ohare-media-bay", 7241da177e4SLinus Torvalds .data = &ohare_mb_ops, 7251da177e4SLinus Torvalds }, 7261da177e4SLinus Torvalds {}, 7271da177e4SLinus Torvalds }; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds static struct macio_driver media_bay_driver = 7301da177e4SLinus Torvalds { 731c2cdf6abSBenjamin Herrenschmidt .driver = { 7321da177e4SLinus Torvalds .name = "media-bay", 733c2cdf6abSBenjamin Herrenschmidt .of_match_table = media_bay_match, 734c2cdf6abSBenjamin Herrenschmidt }, 7351da177e4SLinus Torvalds .probe = media_bay_attach, 7361da177e4SLinus Torvalds .suspend = media_bay_suspend, 7371da177e4SLinus Torvalds .resume = media_bay_resume 7381da177e4SLinus Torvalds }; 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds static int __init media_bay_init(void) 7411da177e4SLinus Torvalds { 7421da177e4SLinus Torvalds int i; 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds for (i=0; i<MAX_BAYS; i++) { 7451da177e4SLinus Torvalds memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); 7461da177e4SLinus Torvalds media_bays[i].content_id = -1; 7471da177e4SLinus Torvalds } 748e8222502SBenjamin Herrenschmidt if (!machine_is(powermac)) 749e8222502SBenjamin Herrenschmidt return 0; 7501da177e4SLinus Torvalds 7511da177e4SLinus Torvalds macio_register_driver(&media_bay_driver); 7521da177e4SLinus Torvalds 7531da177e4SLinus Torvalds return 0; 7541da177e4SLinus Torvalds } 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds device_initcall(media_bay_init); 757