xref: /openbmc/linux/drivers/macintosh/mediabay.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * Driver for the media bay on the PowerBook 3400 and 2400.
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * Copyright (C) 1998 Paul Mackerras.
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  * Various evolutions by Benjamin Herrenschmidt & Henry Worth
7*1da177e4SLinus Torvalds  *
8*1da177e4SLinus Torvalds  *  This program is free software; you can redistribute it and/or
9*1da177e4SLinus Torvalds  *  modify it under the terms of the GNU General Public License
10*1da177e4SLinus Torvalds  *  as published by the Free Software Foundation; either version
11*1da177e4SLinus Torvalds  *  2 of the License, or (at your option) any later version.
12*1da177e4SLinus Torvalds  */
13*1da177e4SLinus Torvalds #include <linux/config.h>
14*1da177e4SLinus Torvalds #include <linux/types.h>
15*1da177e4SLinus Torvalds #include <linux/errno.h>
16*1da177e4SLinus Torvalds #include <linux/kernel.h>
17*1da177e4SLinus Torvalds #include <linux/delay.h>
18*1da177e4SLinus Torvalds #include <linux/sched.h>
19*1da177e4SLinus Torvalds #include <linux/timer.h>
20*1da177e4SLinus Torvalds #include <linux/hdreg.h>
21*1da177e4SLinus Torvalds #include <linux/stddef.h>
22*1da177e4SLinus Torvalds #include <linux/init.h>
23*1da177e4SLinus Torvalds #include <linux/ide.h>
24*1da177e4SLinus Torvalds #include <asm/prom.h>
25*1da177e4SLinus Torvalds #include <asm/pgtable.h>
26*1da177e4SLinus Torvalds #include <asm/io.h>
27*1da177e4SLinus Torvalds #include <asm/machdep.h>
28*1da177e4SLinus Torvalds #include <asm/pmac_feature.h>
29*1da177e4SLinus Torvalds #include <asm/mediabay.h>
30*1da177e4SLinus Torvalds #include <asm/sections.h>
31*1da177e4SLinus Torvalds #include <asm/ohare.h>
32*1da177e4SLinus Torvalds #include <asm/heathrow.h>
33*1da177e4SLinus Torvalds #include <asm/keylargo.h>
34*1da177e4SLinus Torvalds #include <linux/adb.h>
35*1da177e4SLinus Torvalds #include <linux/pmu.h>
36*1da177e4SLinus Torvalds 
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds #define MB_DEBUG
39*1da177e4SLinus Torvalds #define MB_IGNORE_SIGNALS
40*1da177e4SLinus Torvalds 
41*1da177e4SLinus Torvalds #ifdef MB_DEBUG
42*1da177e4SLinus Torvalds #define MBDBG(fmt, arg...)	printk(KERN_INFO fmt , ## arg)
43*1da177e4SLinus Torvalds #else
44*1da177e4SLinus Torvalds #define MBDBG(fmt, arg...)	do { } while (0)
45*1da177e4SLinus Torvalds #endif
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds #define MB_FCR32(bay, r)	((bay)->base + ((r) >> 2))
48*1da177e4SLinus Torvalds #define MB_FCR8(bay, r)		(((volatile u8 __iomem *)((bay)->base)) + (r))
49*1da177e4SLinus Torvalds 
50*1da177e4SLinus Torvalds #define MB_IN32(bay,r)		(in_le32(MB_FCR32(bay,r)))
51*1da177e4SLinus Torvalds #define MB_OUT32(bay,r,v)	(out_le32(MB_FCR32(bay,r), (v)))
52*1da177e4SLinus Torvalds #define MB_BIS(bay,r,v)		(MB_OUT32((bay), (r), MB_IN32((bay), r) | (v)))
53*1da177e4SLinus Torvalds #define MB_BIC(bay,r,v)		(MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v)))
54*1da177e4SLinus Torvalds #define MB_IN8(bay,r)		(in_8(MB_FCR8(bay,r)))
55*1da177e4SLinus Torvalds #define MB_OUT8(bay,r,v)	(out_8(MB_FCR8(bay,r), (v)))
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds struct media_bay_info;
58*1da177e4SLinus Torvalds 
59*1da177e4SLinus Torvalds struct mb_ops {
60*1da177e4SLinus Torvalds 	char*	name;
61*1da177e4SLinus Torvalds 	void	(*init)(struct media_bay_info *bay);
62*1da177e4SLinus Torvalds 	u8	(*content)(struct media_bay_info *bay);
63*1da177e4SLinus Torvalds 	void	(*power)(struct media_bay_info *bay, int on_off);
64*1da177e4SLinus Torvalds 	int	(*setup_bus)(struct media_bay_info *bay, u8 device_id);
65*1da177e4SLinus Torvalds 	void	(*un_reset)(struct media_bay_info *bay);
66*1da177e4SLinus Torvalds 	void	(*un_reset_ide)(struct media_bay_info *bay);
67*1da177e4SLinus Torvalds };
68*1da177e4SLinus Torvalds 
69*1da177e4SLinus Torvalds struct media_bay_info {
70*1da177e4SLinus Torvalds 	u32 __iomem			*base;
71*1da177e4SLinus Torvalds 	int				content_id;
72*1da177e4SLinus Torvalds 	int				state;
73*1da177e4SLinus Torvalds 	int				last_value;
74*1da177e4SLinus Torvalds 	int				value_count;
75*1da177e4SLinus Torvalds 	int				timer;
76*1da177e4SLinus Torvalds 	struct macio_dev		*mdev;
77*1da177e4SLinus Torvalds 	struct mb_ops*			ops;
78*1da177e4SLinus Torvalds 	int				index;
79*1da177e4SLinus Torvalds 	int				cached_gpio;
80*1da177e4SLinus Torvalds 	int				sleeping;
81*1da177e4SLinus Torvalds 	struct semaphore		lock;
82*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
83*1da177e4SLinus Torvalds 	void __iomem			*cd_base;
84*1da177e4SLinus Torvalds 	int 				cd_index;
85*1da177e4SLinus Torvalds 	int				cd_irq;
86*1da177e4SLinus Torvalds 	int				cd_retry;
87*1da177e4SLinus Torvalds #endif
88*1da177e4SLinus Torvalds };
89*1da177e4SLinus Torvalds 
90*1da177e4SLinus Torvalds #define MAX_BAYS	2
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds static struct media_bay_info media_bays[MAX_BAYS];
93*1da177e4SLinus Torvalds int media_bay_count = 0;
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
96*1da177e4SLinus Torvalds /* check the busy bit in the media-bay ide interface
97*1da177e4SLinus Torvalds    (assumes the media-bay contains an ide device) */
98*1da177e4SLinus Torvalds #define MB_IDE_READY(i)	((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0)
99*1da177e4SLinus Torvalds #endif
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds /*
102*1da177e4SLinus Torvalds  * Wait that number of ms between each step in normal polling mode
103*1da177e4SLinus Torvalds  */
104*1da177e4SLinus Torvalds #define MB_POLL_DELAY	25
105*1da177e4SLinus Torvalds 
106*1da177e4SLinus Torvalds /*
107*1da177e4SLinus Torvalds  * Consider the media-bay ID value stable if it is the same for
108*1da177e4SLinus Torvalds  * this number of milliseconds
109*1da177e4SLinus Torvalds  */
110*1da177e4SLinus Torvalds #define MB_STABLE_DELAY	100
111*1da177e4SLinus Torvalds 
112*1da177e4SLinus Torvalds /* Wait after powering up the media bay this delay in ms
113*1da177e4SLinus Torvalds  * timeout bumped for some powerbooks
114*1da177e4SLinus Torvalds  */
115*1da177e4SLinus Torvalds #define MB_POWER_DELAY	200
116*1da177e4SLinus Torvalds 
117*1da177e4SLinus Torvalds /*
118*1da177e4SLinus Torvalds  * Hold the media-bay reset signal true for this many ticks
119*1da177e4SLinus Torvalds  * after a device is inserted before releasing it.
120*1da177e4SLinus Torvalds  */
121*1da177e4SLinus Torvalds #define MB_RESET_DELAY	50
122*1da177e4SLinus Torvalds 
123*1da177e4SLinus Torvalds /*
124*1da177e4SLinus Torvalds  * Wait this long after the reset signal is released and before doing
125*1da177e4SLinus Torvalds  * further operations. After this delay, the IDE reset signal is released
126*1da177e4SLinus Torvalds  * too for an IDE device
127*1da177e4SLinus Torvalds  */
128*1da177e4SLinus Torvalds #define MB_SETUP_DELAY	100
129*1da177e4SLinus Torvalds 
130*1da177e4SLinus Torvalds /*
131*1da177e4SLinus Torvalds  * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted
132*1da177e4SLinus Torvalds  * (or until the device is ready) before waiting for busy bit to disappear
133*1da177e4SLinus Torvalds  */
134*1da177e4SLinus Torvalds #define MB_IDE_WAIT	1000
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds /*
137*1da177e4SLinus Torvalds  * Timeout waiting for busy bit of an IDE device to go down
138*1da177e4SLinus Torvalds  */
139*1da177e4SLinus Torvalds #define MB_IDE_TIMEOUT	5000
140*1da177e4SLinus Torvalds 
141*1da177e4SLinus Torvalds /*
142*1da177e4SLinus Torvalds  * Max retries of the full power up/down sequence for an IDE device
143*1da177e4SLinus Torvalds  */
144*1da177e4SLinus Torvalds #define MAX_CD_RETRIES	3
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds /*
147*1da177e4SLinus Torvalds  * States of a media bay
148*1da177e4SLinus Torvalds  */
149*1da177e4SLinus Torvalds enum {
150*1da177e4SLinus Torvalds 	mb_empty = 0,		/* Idle */
151*1da177e4SLinus Torvalds 	mb_powering_up,		/* power bit set, waiting MB_POWER_DELAY */
152*1da177e4SLinus Torvalds 	mb_enabling_bay,	/* enable bits set, waiting MB_RESET_DELAY */
153*1da177e4SLinus Torvalds 	mb_resetting,		/* reset bit unset, waiting MB_SETUP_DELAY */
154*1da177e4SLinus Torvalds 	mb_ide_resetting,	/* IDE reset bit unser, waiting MB_IDE_WAIT */
155*1da177e4SLinus Torvalds 	mb_ide_waiting,		/* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */
156*1da177e4SLinus Torvalds 	mb_up,			/* Media bay full */
157*1da177e4SLinus Torvalds 	mb_powering_down	/* Powering down (avoid too fast down/up) */
158*1da177e4SLinus Torvalds };
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds #define MB_POWER_SOUND		0x08
161*1da177e4SLinus Torvalds #define MB_POWER_FLOPPY		0x04
162*1da177e4SLinus Torvalds #define MB_POWER_ATA		0x02
163*1da177e4SLinus Torvalds #define MB_POWER_PCI		0x01
164*1da177e4SLinus Torvalds #define MB_POWER_OFF		0x00
165*1da177e4SLinus Torvalds 
166*1da177e4SLinus Torvalds /*
167*1da177e4SLinus Torvalds  * Functions for polling content of media bay
168*1da177e4SLinus Torvalds  */
169*1da177e4SLinus Torvalds 
170*1da177e4SLinus Torvalds static u8 __pmac
171*1da177e4SLinus Torvalds ohare_mb_content(struct media_bay_info *bay)
172*1da177e4SLinus Torvalds {
173*1da177e4SLinus Torvalds 	return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7;
174*1da177e4SLinus Torvalds }
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds static u8 __pmac
177*1da177e4SLinus Torvalds heathrow_mb_content(struct media_bay_info *bay)
178*1da177e4SLinus Torvalds {
179*1da177e4SLinus Torvalds 	return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7;
180*1da177e4SLinus Torvalds }
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds static u8 __pmac
183*1da177e4SLinus Torvalds keylargo_mb_content(struct media_bay_info *bay)
184*1da177e4SLinus Torvalds {
185*1da177e4SLinus Torvalds 	int new_gpio;
186*1da177e4SLinus Torvalds 
187*1da177e4SLinus Torvalds 	new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA;
188*1da177e4SLinus Torvalds 	if (new_gpio) {
189*1da177e4SLinus Torvalds 		bay->cached_gpio = new_gpio;
190*1da177e4SLinus Torvalds 		return MB_NO;
191*1da177e4SLinus Torvalds 	} else if (bay->cached_gpio != new_gpio) {
192*1da177e4SLinus Torvalds 		MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE);
193*1da177e4SLinus Torvalds 		(void)MB_IN32(bay, KEYLARGO_MBCR);
194*1da177e4SLinus Torvalds 		udelay(5);
195*1da177e4SLinus Torvalds 		MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F);
196*1da177e4SLinus Torvalds 		(void)MB_IN32(bay, KEYLARGO_MBCR);
197*1da177e4SLinus Torvalds 		udelay(5);
198*1da177e4SLinus Torvalds 		bay->cached_gpio = new_gpio;
199*1da177e4SLinus Torvalds 	}
200*1da177e4SLinus Torvalds 	return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7;
201*1da177e4SLinus Torvalds }
202*1da177e4SLinus Torvalds 
203*1da177e4SLinus Torvalds /*
204*1da177e4SLinus Torvalds  * Functions for powering up/down the bay, puts the bay device
205*1da177e4SLinus Torvalds  * into reset state as well
206*1da177e4SLinus Torvalds  */
207*1da177e4SLinus Torvalds 
208*1da177e4SLinus Torvalds static void __pmac
209*1da177e4SLinus Torvalds ohare_mb_power(struct media_bay_info* bay, int on_off)
210*1da177e4SLinus Torvalds {
211*1da177e4SLinus Torvalds 	if (on_off) {
212*1da177e4SLinus Torvalds 		/* Power up device, assert it's reset line */
213*1da177e4SLinus Torvalds 		MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N);
214*1da177e4SLinus Torvalds 		MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N);
215*1da177e4SLinus Torvalds 	} else {
216*1da177e4SLinus Torvalds 		/* Disable all devices */
217*1da177e4SLinus Torvalds 		MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK);
218*1da177e4SLinus Torvalds 		MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE);
219*1da177e4SLinus Torvalds 		/* Cut power from bay, release reset line */
220*1da177e4SLinus Torvalds 		MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N);
221*1da177e4SLinus Torvalds 		MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N);
222*1da177e4SLinus Torvalds 		MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);
223*1da177e4SLinus Torvalds 	}
224*1da177e4SLinus Torvalds 	MB_BIC(bay, OHARE_MBCR, 0x00000F00);
225*1da177e4SLinus Torvalds }
226*1da177e4SLinus Torvalds 
227*1da177e4SLinus Torvalds static void __pmac
228*1da177e4SLinus Torvalds heathrow_mb_power(struct media_bay_info* bay, int on_off)
229*1da177e4SLinus Torvalds {
230*1da177e4SLinus Torvalds 	if (on_off) {
231*1da177e4SLinus Torvalds 		/* Power up device, assert it's reset line */
232*1da177e4SLinus Torvalds 		MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
233*1da177e4SLinus Torvalds 		MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N);
234*1da177e4SLinus Torvalds 	} else {
235*1da177e4SLinus Torvalds 		/* Disable all devices */
236*1da177e4SLinus Torvalds 		MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK);
237*1da177e4SLinus Torvalds 		MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE);
238*1da177e4SLinus Torvalds 		/* Cut power from bay, release reset line */
239*1da177e4SLinus Torvalds 		MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N);
240*1da177e4SLinus Torvalds 		MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
241*1da177e4SLinus Torvalds 		MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
242*1da177e4SLinus Torvalds 	}
243*1da177e4SLinus Torvalds 	MB_BIC(bay, HEATHROW_MBCR, 0x00000F00);
244*1da177e4SLinus Torvalds }
245*1da177e4SLinus Torvalds 
246*1da177e4SLinus Torvalds static void __pmac
247*1da177e4SLinus Torvalds keylargo_mb_power(struct media_bay_info* bay, int on_off)
248*1da177e4SLinus Torvalds {
249*1da177e4SLinus Torvalds 	if (on_off) {
250*1da177e4SLinus Torvalds 		/* Power up device, assert it's reset line */
251*1da177e4SLinus Torvalds             	MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
252*1da177e4SLinus Torvalds             	MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER);
253*1da177e4SLinus Torvalds 	} else {
254*1da177e4SLinus Torvalds 		/* Disable all devices */
255*1da177e4SLinus Torvalds 		MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);
256*1da177e4SLinus Torvalds 		MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE);
257*1da177e4SLinus Torvalds 		/* Cut power from bay, release reset line */
258*1da177e4SLinus Torvalds 		MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER);
259*1da177e4SLinus Torvalds 		MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
260*1da177e4SLinus Torvalds 		MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
261*1da177e4SLinus Torvalds 	}
262*1da177e4SLinus Torvalds 	MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F);
263*1da177e4SLinus Torvalds }
264*1da177e4SLinus Torvalds 
265*1da177e4SLinus Torvalds /*
266*1da177e4SLinus Torvalds  * Functions for configuring the media bay for a given type of device,
267*1da177e4SLinus Torvalds  * enable the related busses
268*1da177e4SLinus Torvalds  */
269*1da177e4SLinus Torvalds 
270*1da177e4SLinus Torvalds static int __pmac
271*1da177e4SLinus Torvalds ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
272*1da177e4SLinus Torvalds {
273*1da177e4SLinus Torvalds 	switch(device_id) {
274*1da177e4SLinus Torvalds 		case MB_FD:
275*1da177e4SLinus Torvalds 		case MB_FD1:
276*1da177e4SLinus Torvalds 			MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE);
277*1da177e4SLinus Torvalds 			MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE);
278*1da177e4SLinus Torvalds 			return 0;
279*1da177e4SLinus Torvalds 		case MB_CD:
280*1da177e4SLinus Torvalds 			MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N);
281*1da177e4SLinus Torvalds 			MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE);
282*1da177e4SLinus Torvalds 			return 0;
283*1da177e4SLinus Torvalds 		case MB_PCI:
284*1da177e4SLinus Torvalds 			MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE);
285*1da177e4SLinus Torvalds 			return 0;
286*1da177e4SLinus Torvalds 	}
287*1da177e4SLinus Torvalds 	return -ENODEV;
288*1da177e4SLinus Torvalds }
289*1da177e4SLinus Torvalds 
290*1da177e4SLinus Torvalds static int __pmac
291*1da177e4SLinus Torvalds heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
292*1da177e4SLinus Torvalds {
293*1da177e4SLinus Torvalds 	switch(device_id) {
294*1da177e4SLinus Torvalds 		case MB_FD:
295*1da177e4SLinus Torvalds 		case MB_FD1:
296*1da177e4SLinus Torvalds 			MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE);
297*1da177e4SLinus Torvalds 			MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE);
298*1da177e4SLinus Torvalds 			return 0;
299*1da177e4SLinus Torvalds 		case MB_CD:
300*1da177e4SLinus Torvalds 			MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
301*1da177e4SLinus Torvalds 			MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE);
302*1da177e4SLinus Torvalds 			return 0;
303*1da177e4SLinus Torvalds 		case MB_PCI:
304*1da177e4SLinus Torvalds 			MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE);
305*1da177e4SLinus Torvalds 			return 0;
306*1da177e4SLinus Torvalds 	}
307*1da177e4SLinus Torvalds 	return -ENODEV;
308*1da177e4SLinus Torvalds }
309*1da177e4SLinus Torvalds 
310*1da177e4SLinus Torvalds static int __pmac
311*1da177e4SLinus Torvalds keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id)
312*1da177e4SLinus Torvalds {
313*1da177e4SLinus Torvalds 	switch(device_id) {
314*1da177e4SLinus Torvalds 		case MB_CD:
315*1da177e4SLinus Torvalds 			MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);
316*1da177e4SLinus Torvalds 			MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
317*1da177e4SLinus Torvalds 			MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE);
318*1da177e4SLinus Torvalds 			return 0;
319*1da177e4SLinus Torvalds 		case MB_PCI:
320*1da177e4SLinus Torvalds 			MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE);
321*1da177e4SLinus Torvalds 			return 0;
322*1da177e4SLinus Torvalds 		case MB_SOUND:
323*1da177e4SLinus Torvalds 			MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE);
324*1da177e4SLinus Torvalds 			return 0;
325*1da177e4SLinus Torvalds 	}
326*1da177e4SLinus Torvalds 	return -ENODEV;
327*1da177e4SLinus Torvalds }
328*1da177e4SLinus Torvalds 
329*1da177e4SLinus Torvalds /*
330*1da177e4SLinus Torvalds  * Functions for tweaking resets
331*1da177e4SLinus Torvalds  */
332*1da177e4SLinus Torvalds 
333*1da177e4SLinus Torvalds static void __pmac
334*1da177e4SLinus Torvalds ohare_mb_un_reset(struct media_bay_info* bay)
335*1da177e4SLinus Torvalds {
336*1da177e4SLinus Torvalds 	MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N);
337*1da177e4SLinus Torvalds }
338*1da177e4SLinus Torvalds 
339*1da177e4SLinus Torvalds static void __pmac keylargo_mb_init(struct media_bay_info *bay)
340*1da177e4SLinus Torvalds {
341*1da177e4SLinus Torvalds 	MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE);
342*1da177e4SLinus Torvalds }
343*1da177e4SLinus Torvalds 
344*1da177e4SLinus Torvalds static void __pmac heathrow_mb_un_reset(struct media_bay_info* bay)
345*1da177e4SLinus Torvalds {
346*1da177e4SLinus Torvalds 	MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N);
347*1da177e4SLinus Torvalds }
348*1da177e4SLinus Torvalds 
349*1da177e4SLinus Torvalds static void __pmac keylargo_mb_un_reset(struct media_bay_info* bay)
350*1da177e4SLinus Torvalds {
351*1da177e4SLinus Torvalds 	MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET);
352*1da177e4SLinus Torvalds }
353*1da177e4SLinus Torvalds 
354*1da177e4SLinus Torvalds static void __pmac ohare_mb_un_reset_ide(struct media_bay_info* bay)
355*1da177e4SLinus Torvalds {
356*1da177e4SLinus Torvalds 	MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N);
357*1da177e4SLinus Torvalds }
358*1da177e4SLinus Torvalds 
359*1da177e4SLinus Torvalds static void __pmac heathrow_mb_un_reset_ide(struct media_bay_info* bay)
360*1da177e4SLinus Torvalds {
361*1da177e4SLinus Torvalds 	MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N);
362*1da177e4SLinus Torvalds }
363*1da177e4SLinus Torvalds 
364*1da177e4SLinus Torvalds static void __pmac keylargo_mb_un_reset_ide(struct media_bay_info* bay)
365*1da177e4SLinus Torvalds {
366*1da177e4SLinus Torvalds 	MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N);
367*1da177e4SLinus Torvalds }
368*1da177e4SLinus Torvalds 
369*1da177e4SLinus Torvalds static inline void __pmac set_mb_power(struct media_bay_info* bay, int onoff)
370*1da177e4SLinus Torvalds {
371*1da177e4SLinus Torvalds 	/* Power up up and assert the bay reset line */
372*1da177e4SLinus Torvalds 	if (onoff) {
373*1da177e4SLinus Torvalds 		bay->ops->power(bay, 1);
374*1da177e4SLinus Torvalds 		bay->state = mb_powering_up;
375*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: powering up\n", bay->index);
376*1da177e4SLinus Torvalds 	} else {
377*1da177e4SLinus Torvalds 		/* Make sure everything is powered down & disabled */
378*1da177e4SLinus Torvalds 		bay->ops->power(bay, 0);
379*1da177e4SLinus Torvalds 		bay->state = mb_powering_down;
380*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: powering down\n", bay->index);
381*1da177e4SLinus Torvalds 	}
382*1da177e4SLinus Torvalds 	bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
383*1da177e4SLinus Torvalds }
384*1da177e4SLinus Torvalds 
385*1da177e4SLinus Torvalds static void __pmac poll_media_bay(struct media_bay_info* bay)
386*1da177e4SLinus Torvalds {
387*1da177e4SLinus Torvalds 	int id = bay->ops->content(bay);
388*1da177e4SLinus Torvalds 
389*1da177e4SLinus Torvalds 	if (id == bay->last_value) {
390*1da177e4SLinus Torvalds 		if (id != bay->content_id) {
391*1da177e4SLinus Torvalds 			bay->value_count += msecs_to_jiffies(MB_POLL_DELAY);
392*1da177e4SLinus Torvalds 			if (bay->value_count >= msecs_to_jiffies(MB_STABLE_DELAY)) {
393*1da177e4SLinus Torvalds 				/* If the device type changes without going thru
394*1da177e4SLinus Torvalds 				 * "MB_NO", we force a pass by "MB_NO" to make sure
395*1da177e4SLinus Torvalds 				 * things are properly reset
396*1da177e4SLinus Torvalds 				 */
397*1da177e4SLinus Torvalds 				if ((id != MB_NO) && (bay->content_id != MB_NO)) {
398*1da177e4SLinus Torvalds 					id = MB_NO;
399*1da177e4SLinus Torvalds 					MBDBG("mediabay%d: forcing MB_NO\n", bay->index);
400*1da177e4SLinus Torvalds 				}
401*1da177e4SLinus Torvalds 				MBDBG("mediabay%d: switching to %d\n", bay->index, id);
402*1da177e4SLinus Torvalds 				set_mb_power(bay, id != MB_NO);
403*1da177e4SLinus Torvalds 				bay->content_id = id;
404*1da177e4SLinus Torvalds 				if (id == MB_NO) {
405*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
406*1da177e4SLinus Torvalds 					bay->cd_retry = 0;
407*1da177e4SLinus Torvalds #endif
408*1da177e4SLinus Torvalds 					printk(KERN_INFO "media bay %d is empty\n", bay->index);
409*1da177e4SLinus Torvalds 				}
410*1da177e4SLinus Torvalds 			}
411*1da177e4SLinus Torvalds 		}
412*1da177e4SLinus Torvalds 	} else {
413*1da177e4SLinus Torvalds 		bay->last_value = id;
414*1da177e4SLinus Torvalds 		bay->value_count = 0;
415*1da177e4SLinus Torvalds 	}
416*1da177e4SLinus Torvalds }
417*1da177e4SLinus Torvalds 
418*1da177e4SLinus Torvalds int __pmac check_media_bay(struct device_node *which_bay, int what)
419*1da177e4SLinus Torvalds {
420*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
421*1da177e4SLinus Torvalds 	int	i;
422*1da177e4SLinus Torvalds 
423*1da177e4SLinus Torvalds 	for (i=0; i<media_bay_count; i++)
424*1da177e4SLinus Torvalds 		if (media_bays[i].mdev && which_bay == media_bays[i].mdev->ofdev.node) {
425*1da177e4SLinus Torvalds 			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
426*1da177e4SLinus Torvalds 				return 0;
427*1da177e4SLinus Torvalds 			media_bays[i].cd_index = -1;
428*1da177e4SLinus Torvalds 			return -EINVAL;
429*1da177e4SLinus Torvalds 		}
430*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */
431*1da177e4SLinus Torvalds 	return -ENODEV;
432*1da177e4SLinus Torvalds }
433*1da177e4SLinus Torvalds EXPORT_SYMBOL(check_media_bay);
434*1da177e4SLinus Torvalds 
435*1da177e4SLinus Torvalds int __pmac check_media_bay_by_base(unsigned long base, int what)
436*1da177e4SLinus Torvalds {
437*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
438*1da177e4SLinus Torvalds 	int	i;
439*1da177e4SLinus Torvalds 
440*1da177e4SLinus Torvalds 	for (i=0; i<media_bay_count; i++)
441*1da177e4SLinus Torvalds 		if (media_bays[i].mdev && base == (unsigned long) media_bays[i].cd_base) {
442*1da177e4SLinus Torvalds 			if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up)
443*1da177e4SLinus Torvalds 				return 0;
444*1da177e4SLinus Torvalds 			media_bays[i].cd_index = -1;
445*1da177e4SLinus Torvalds 			return -EINVAL;
446*1da177e4SLinus Torvalds 		}
447*1da177e4SLinus Torvalds #endif
448*1da177e4SLinus Torvalds 
449*1da177e4SLinus Torvalds 	return -ENODEV;
450*1da177e4SLinus Torvalds }
451*1da177e4SLinus Torvalds 
452*1da177e4SLinus Torvalds int __pmac media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base,
453*1da177e4SLinus Torvalds 	int irq, int index)
454*1da177e4SLinus Torvalds {
455*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
456*1da177e4SLinus Torvalds 	int	i;
457*1da177e4SLinus Torvalds 
458*1da177e4SLinus Torvalds 	for (i=0; i<media_bay_count; i++) {
459*1da177e4SLinus Torvalds 		struct media_bay_info* bay = &media_bays[i];
460*1da177e4SLinus Torvalds 
461*1da177e4SLinus Torvalds 		if (bay->mdev && which_bay == bay->mdev->ofdev.node) {
462*1da177e4SLinus Torvalds 			int timeout = 5000;
463*1da177e4SLinus Torvalds 
464*1da177e4SLinus Torvalds 			down(&bay->lock);
465*1da177e4SLinus Torvalds 
466*1da177e4SLinus Torvalds  			bay->cd_base	= (void __iomem *) base;
467*1da177e4SLinus Torvalds 			bay->cd_irq	= irq;
468*1da177e4SLinus Torvalds 
469*1da177e4SLinus Torvalds 			if ((MB_CD != bay->content_id) || bay->state != mb_up) {
470*1da177e4SLinus Torvalds 				up(&bay->lock);
471*1da177e4SLinus Torvalds 				return 0;
472*1da177e4SLinus Torvalds 			}
473*1da177e4SLinus Torvalds 			printk(KERN_DEBUG "Registered ide%d for media bay %d\n", index, i);
474*1da177e4SLinus Torvalds 			do {
475*1da177e4SLinus Torvalds 				if (MB_IDE_READY(i)) {
476*1da177e4SLinus Torvalds 					bay->cd_index	= index;
477*1da177e4SLinus Torvalds 					up(&bay->lock);
478*1da177e4SLinus Torvalds 					return 0;
479*1da177e4SLinus Torvalds 				}
480*1da177e4SLinus Torvalds 				mdelay(1);
481*1da177e4SLinus Torvalds 			} while(--timeout);
482*1da177e4SLinus Torvalds 			printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i);
483*1da177e4SLinus Torvalds 			up(&bay->lock);
484*1da177e4SLinus Torvalds 			return -ENODEV;
485*1da177e4SLinus Torvalds 		}
486*1da177e4SLinus Torvalds 	}
487*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */
488*1da177e4SLinus Torvalds 
489*1da177e4SLinus Torvalds 	return -ENODEV;
490*1da177e4SLinus Torvalds }
491*1da177e4SLinus Torvalds 
492*1da177e4SLinus Torvalds static void __pmac media_bay_step(int i)
493*1da177e4SLinus Torvalds {
494*1da177e4SLinus Torvalds 	struct media_bay_info* bay = &media_bays[i];
495*1da177e4SLinus Torvalds 
496*1da177e4SLinus Torvalds 	/* We don't poll when powering down */
497*1da177e4SLinus Torvalds 	if (bay->state != mb_powering_down)
498*1da177e4SLinus Torvalds 	    poll_media_bay(bay);
499*1da177e4SLinus Torvalds 
500*1da177e4SLinus Torvalds 	/* If timer expired or polling IDE busy, run state machine */
501*1da177e4SLinus Torvalds 	if ((bay->state != mb_ide_waiting) && (bay->timer != 0)) {
502*1da177e4SLinus Torvalds 		bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);
503*1da177e4SLinus Torvalds 		if (bay->timer > 0)
504*1da177e4SLinus Torvalds 			return;
505*1da177e4SLinus Torvalds 		bay->timer = 0;
506*1da177e4SLinus Torvalds 	}
507*1da177e4SLinus Torvalds 
508*1da177e4SLinus Torvalds 	switch(bay->state) {
509*1da177e4SLinus Torvalds 	case mb_powering_up:
510*1da177e4SLinus Torvalds 	    	if (bay->ops->setup_bus(bay, bay->last_value) < 0) {
511*1da177e4SLinus Torvalds 			MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id);
512*1da177e4SLinus Torvalds 	    		set_mb_power(bay, 0);
513*1da177e4SLinus Torvalds 	    		break;
514*1da177e4SLinus Torvalds 	    	}
515*1da177e4SLinus Torvalds 	    	bay->timer = msecs_to_jiffies(MB_RESET_DELAY);
516*1da177e4SLinus Torvalds 	    	bay->state = mb_enabling_bay;
517*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id);
518*1da177e4SLinus Torvalds 		break;
519*1da177e4SLinus Torvalds 	case mb_enabling_bay:
520*1da177e4SLinus Torvalds 		bay->ops->un_reset(bay);
521*1da177e4SLinus Torvalds 	    	bay->timer = msecs_to_jiffies(MB_SETUP_DELAY);
522*1da177e4SLinus Torvalds 	    	bay->state = mb_resetting;
523*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id);
524*1da177e4SLinus Torvalds 	    	break;
525*1da177e4SLinus Torvalds 
526*1da177e4SLinus Torvalds 	case mb_resetting:
527*1da177e4SLinus Torvalds 		if (bay->content_id != MB_CD) {
528*1da177e4SLinus Torvalds 			MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id);
529*1da177e4SLinus Torvalds 			bay->state = mb_up;
530*1da177e4SLinus Torvalds 			break;
531*1da177e4SLinus Torvalds 	    	}
532*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
533*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id);
534*1da177e4SLinus Torvalds 		bay->ops->un_reset_ide(bay);
535*1da177e4SLinus Torvalds 	    	bay->timer = msecs_to_jiffies(MB_IDE_WAIT);
536*1da177e4SLinus Torvalds 	    	bay->state = mb_ide_resetting;
537*1da177e4SLinus Torvalds #else
538*1da177e4SLinus Torvalds 		printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i);
539*1da177e4SLinus Torvalds 		set_mb_power(bay, 0);
540*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */
541*1da177e4SLinus Torvalds 	    	break;
542*1da177e4SLinus Torvalds 
543*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
544*1da177e4SLinus Torvalds 	case mb_ide_resetting:
545*1da177e4SLinus Torvalds 	    	bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT);
546*1da177e4SLinus Torvalds 	    	bay->state = mb_ide_waiting;
547*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id);
548*1da177e4SLinus Torvalds 	    	break;
549*1da177e4SLinus Torvalds 
550*1da177e4SLinus Torvalds 	case mb_ide_waiting:
551*1da177e4SLinus Torvalds 		if (bay->cd_base == NULL) {
552*1da177e4SLinus Torvalds 			bay->timer = 0;
553*1da177e4SLinus Torvalds 			bay->state = mb_up;
554*1da177e4SLinus Torvalds 			MBDBG("mediabay%d: up before IDE init\n", i);
555*1da177e4SLinus Torvalds 			break;
556*1da177e4SLinus Torvalds 		} else if (MB_IDE_READY(i)) {
557*1da177e4SLinus Torvalds 			bay->timer = 0;
558*1da177e4SLinus Torvalds 			bay->state = mb_up;
559*1da177e4SLinus Torvalds 			if (bay->cd_index < 0) {
560*1da177e4SLinus Torvalds 				hw_regs_t hw;
561*1da177e4SLinus Torvalds 
562*1da177e4SLinus Torvalds 				printk("mediabay %d, registering IDE...\n", i);
563*1da177e4SLinus Torvalds 				pmu_suspend();
564*1da177e4SLinus Torvalds 				ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL);
565*1da177e4SLinus Torvalds 				hw.irq = bay->cd_irq;
566*1da177e4SLinus Torvalds 				hw.chipset = ide_pmac;
567*1da177e4SLinus Torvalds 				bay->cd_index = ide_register_hw(&hw, NULL);
568*1da177e4SLinus Torvalds 				pmu_resume();
569*1da177e4SLinus Torvalds 			}
570*1da177e4SLinus Torvalds 			if (bay->cd_index == -1) {
571*1da177e4SLinus Torvalds 				/* We eventually do a retry */
572*1da177e4SLinus Torvalds 				bay->cd_retry++;
573*1da177e4SLinus Torvalds 				printk("IDE register error\n");
574*1da177e4SLinus Torvalds 				set_mb_power(bay, 0);
575*1da177e4SLinus Torvalds 			} else {
576*1da177e4SLinus Torvalds 				printk(KERN_DEBUG "media-bay %d is ide%d\n", i, bay->cd_index);
577*1da177e4SLinus Torvalds 				MBDBG("mediabay %d IDE ready\n", i);
578*1da177e4SLinus Torvalds 			}
579*1da177e4SLinus Torvalds 			break;
580*1da177e4SLinus Torvalds 	    	} else if (bay->timer > 0)
581*1da177e4SLinus Torvalds 			bay->timer -= msecs_to_jiffies(MB_POLL_DELAY);
582*1da177e4SLinus Torvalds 	    	if (bay->timer <= 0) {
583*1da177e4SLinus Torvalds 			printk("\nIDE Timeout in bay %d !, IDE state is: 0x%02x\n",
584*1da177e4SLinus Torvalds 			       i, readb(bay->cd_base + 0x70));
585*1da177e4SLinus Torvalds 			MBDBG("mediabay%d: nIDE Timeout !\n", i);
586*1da177e4SLinus Torvalds 			set_mb_power(bay, 0);
587*1da177e4SLinus Torvalds 			bay->timer = 0;
588*1da177e4SLinus Torvalds 	    	}
589*1da177e4SLinus Torvalds 		break;
590*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */
591*1da177e4SLinus Torvalds 
592*1da177e4SLinus Torvalds 	case mb_powering_down:
593*1da177e4SLinus Torvalds 	    	bay->state = mb_empty;
594*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
595*1da177e4SLinus Torvalds     	        if (bay->cd_index >= 0) {
596*1da177e4SLinus Torvalds 			printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i,
597*1da177e4SLinus Torvalds 			       bay->cd_index);
598*1da177e4SLinus Torvalds 			ide_unregister(bay->cd_index);
599*1da177e4SLinus Torvalds 			bay->cd_index = -1;
600*1da177e4SLinus Torvalds 		}
601*1da177e4SLinus Torvalds 	    	if (bay->cd_retry) {
602*1da177e4SLinus Torvalds 			if (bay->cd_retry > MAX_CD_RETRIES) {
603*1da177e4SLinus Torvalds 				/* Should add an error sound (sort of beep in dmasound) */
604*1da177e4SLinus Torvalds 				printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i);
605*1da177e4SLinus Torvalds 			} else {
606*1da177e4SLinus Torvalds 				/* Force a new power down/up sequence */
607*1da177e4SLinus Torvalds 				bay->content_id = MB_NO;
608*1da177e4SLinus Torvalds 			}
609*1da177e4SLinus Torvalds 	    	}
610*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */
611*1da177e4SLinus Torvalds 		MBDBG("mediabay%d: end of power down\n", i);
612*1da177e4SLinus Torvalds 	    	break;
613*1da177e4SLinus Torvalds 	}
614*1da177e4SLinus Torvalds }
615*1da177e4SLinus Torvalds 
616*1da177e4SLinus Torvalds /*
617*1da177e4SLinus Torvalds  * This procedure runs as a kernel thread to poll the media bay
618*1da177e4SLinus Torvalds  * once each tick and register and unregister the IDE interface
619*1da177e4SLinus Torvalds  * with the IDE driver.  It needs to be a thread because
620*1da177e4SLinus Torvalds  * ide_register can't be called from interrupt context.
621*1da177e4SLinus Torvalds  */
622*1da177e4SLinus Torvalds static int __pmac media_bay_task(void *x)
623*1da177e4SLinus Torvalds {
624*1da177e4SLinus Torvalds 	int	i;
625*1da177e4SLinus Torvalds 
626*1da177e4SLinus Torvalds 	strcpy(current->comm, "media-bay");
627*1da177e4SLinus Torvalds #ifdef MB_IGNORE_SIGNALS
628*1da177e4SLinus Torvalds 	sigfillset(&current->blocked);
629*1da177e4SLinus Torvalds #endif
630*1da177e4SLinus Torvalds 
631*1da177e4SLinus Torvalds 	for (;;) {
632*1da177e4SLinus Torvalds 		for (i = 0; i < media_bay_count; ++i) {
633*1da177e4SLinus Torvalds 			down(&media_bays[i].lock);
634*1da177e4SLinus Torvalds 			if (!media_bays[i].sleeping)
635*1da177e4SLinus Torvalds 				media_bay_step(i);
636*1da177e4SLinus Torvalds 			up(&media_bays[i].lock);
637*1da177e4SLinus Torvalds 		}
638*1da177e4SLinus Torvalds 
639*1da177e4SLinus Torvalds 		msleep_interruptible(MB_POLL_DELAY);
640*1da177e4SLinus Torvalds 		if (signal_pending(current))
641*1da177e4SLinus Torvalds 			return 0;
642*1da177e4SLinus Torvalds 	}
643*1da177e4SLinus Torvalds }
644*1da177e4SLinus Torvalds 
645*1da177e4SLinus Torvalds static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match)
646*1da177e4SLinus Torvalds {
647*1da177e4SLinus Torvalds 	struct media_bay_info* bay;
648*1da177e4SLinus Torvalds 	u32 __iomem *regbase;
649*1da177e4SLinus Torvalds 	struct device_node *ofnode;
650*1da177e4SLinus Torvalds 	int i;
651*1da177e4SLinus Torvalds 
652*1da177e4SLinus Torvalds 	ofnode = mdev->ofdev.node;
653*1da177e4SLinus Torvalds 
654*1da177e4SLinus Torvalds 	if (macio_resource_count(mdev) < 1)
655*1da177e4SLinus Torvalds 		return -ENODEV;
656*1da177e4SLinus Torvalds 	if (macio_request_resources(mdev, "media-bay"))
657*1da177e4SLinus Torvalds 		return -EBUSY;
658*1da177e4SLinus Torvalds 	/* Media bay registers are located at the beginning of the
659*1da177e4SLinus Torvalds          * mac-io chip, we get the parent address for now (hrm...)
660*1da177e4SLinus Torvalds          */
661*1da177e4SLinus Torvalds 	regbase = (u32 __iomem *)
662*1da177e4SLinus Torvalds 		ioremap(ofnode->parent->addrs[0].address, 0x100);
663*1da177e4SLinus Torvalds 	if (regbase == NULL) {
664*1da177e4SLinus Torvalds 		macio_release_resources(mdev);
665*1da177e4SLinus Torvalds 		return -ENOMEM;
666*1da177e4SLinus Torvalds 	}
667*1da177e4SLinus Torvalds 
668*1da177e4SLinus Torvalds 	i = media_bay_count++;
669*1da177e4SLinus Torvalds 	bay = &media_bays[i];
670*1da177e4SLinus Torvalds 	bay->mdev = mdev;
671*1da177e4SLinus Torvalds 	bay->base = regbase;
672*1da177e4SLinus Torvalds 	bay->index = i;
673*1da177e4SLinus Torvalds 	bay->ops = match->data;
674*1da177e4SLinus Torvalds 	bay->sleeping = 0;
675*1da177e4SLinus Torvalds 	init_MUTEX(&bay->lock);
676*1da177e4SLinus Torvalds 
677*1da177e4SLinus Torvalds 	/* Init HW probing */
678*1da177e4SLinus Torvalds 	if (bay->ops->init)
679*1da177e4SLinus Torvalds 		bay->ops->init(bay);
680*1da177e4SLinus Torvalds 
681*1da177e4SLinus Torvalds 	printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", i, bay->ops->name);
682*1da177e4SLinus Torvalds 
683*1da177e4SLinus Torvalds 	/* Force an immediate detect */
684*1da177e4SLinus Torvalds 	set_mb_power(bay, 0);
685*1da177e4SLinus Torvalds 	msleep(MB_POWER_DELAY);
686*1da177e4SLinus Torvalds 	bay->content_id = MB_NO;
687*1da177e4SLinus Torvalds 	bay->last_value = bay->ops->content(bay);
688*1da177e4SLinus Torvalds 	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
689*1da177e4SLinus Torvalds 	bay->state = mb_empty;
690*1da177e4SLinus Torvalds 	do {
691*1da177e4SLinus Torvalds 		msleep(MB_POLL_DELAY);
692*1da177e4SLinus Torvalds 		media_bay_step(i);
693*1da177e4SLinus Torvalds 	} while((bay->state != mb_empty) &&
694*1da177e4SLinus Torvalds 		(bay->state != mb_up));
695*1da177e4SLinus Torvalds 
696*1da177e4SLinus Torvalds 	/* Mark us ready by filling our mdev data */
697*1da177e4SLinus Torvalds 	macio_set_drvdata(mdev, bay);
698*1da177e4SLinus Torvalds 
699*1da177e4SLinus Torvalds 	/* Startup kernel thread */
700*1da177e4SLinus Torvalds 	if (i == 0)
701*1da177e4SLinus Torvalds 		kernel_thread(media_bay_task, NULL, CLONE_KERNEL);
702*1da177e4SLinus Torvalds 
703*1da177e4SLinus Torvalds 	return 0;
704*1da177e4SLinus Torvalds 
705*1da177e4SLinus Torvalds }
706*1da177e4SLinus Torvalds 
707*1da177e4SLinus Torvalds static int __pmac media_bay_suspend(struct macio_dev *mdev, u32 state)
708*1da177e4SLinus Torvalds {
709*1da177e4SLinus Torvalds 	struct media_bay_info	*bay = macio_get_drvdata(mdev);
710*1da177e4SLinus Torvalds 
711*1da177e4SLinus Torvalds 	if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) {
712*1da177e4SLinus Torvalds 		down(&bay->lock);
713*1da177e4SLinus Torvalds 		bay->sleeping = 1;
714*1da177e4SLinus Torvalds 		set_mb_power(bay, 0);
715*1da177e4SLinus Torvalds 		up(&bay->lock);
716*1da177e4SLinus Torvalds 		msleep(MB_POLL_DELAY);
717*1da177e4SLinus Torvalds 		mdev->ofdev.dev.power.power_state = state;
718*1da177e4SLinus Torvalds 	}
719*1da177e4SLinus Torvalds 	return 0;
720*1da177e4SLinus Torvalds }
721*1da177e4SLinus Torvalds 
722*1da177e4SLinus Torvalds static int __pmac media_bay_resume(struct macio_dev *mdev)
723*1da177e4SLinus Torvalds {
724*1da177e4SLinus Torvalds 	struct media_bay_info	*bay = macio_get_drvdata(mdev);
725*1da177e4SLinus Torvalds 
726*1da177e4SLinus Torvalds 	if (mdev->ofdev.dev.power.power_state != 0) {
727*1da177e4SLinus Torvalds 		mdev->ofdev.dev.power.power_state = 0;
728*1da177e4SLinus Torvalds 
729*1da177e4SLinus Torvalds 	       	/* We re-enable the bay using it's previous content
730*1da177e4SLinus Torvalds 	       	   only if it did not change. Note those bozo timings,
731*1da177e4SLinus Torvalds 	       	   they seem to help the 3400 get it right.
732*1da177e4SLinus Torvalds 	       	 */
733*1da177e4SLinus Torvalds 	       	/* Force MB power to 0 */
734*1da177e4SLinus Torvalds 		down(&bay->lock);
735*1da177e4SLinus Torvalds 	       	set_mb_power(bay, 0);
736*1da177e4SLinus Torvalds 		msleep(MB_POWER_DELAY);
737*1da177e4SLinus Torvalds 	       	if (bay->ops->content(bay) != bay->content_id) {
738*1da177e4SLinus Torvalds 			printk("mediabay%d: content changed during sleep...\n", bay->index);
739*1da177e4SLinus Torvalds 			up(&bay->lock);
740*1da177e4SLinus Torvalds 	       		return 0;
741*1da177e4SLinus Torvalds 		}
742*1da177e4SLinus Torvalds 	       	set_mb_power(bay, 1);
743*1da177e4SLinus Torvalds 	       	bay->last_value = bay->content_id;
744*1da177e4SLinus Torvalds 	       	bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY);
745*1da177e4SLinus Torvalds 	       	bay->timer = msecs_to_jiffies(MB_POWER_DELAY);
746*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
747*1da177e4SLinus Torvalds 	       	bay->cd_retry = 0;
748*1da177e4SLinus Torvalds #endif
749*1da177e4SLinus Torvalds 	       	do {
750*1da177e4SLinus Torvalds 			msleep(MB_POLL_DELAY);
751*1da177e4SLinus Torvalds 	       		media_bay_step(bay->index);
752*1da177e4SLinus Torvalds 	       	} while((bay->state != mb_empty) &&
753*1da177e4SLinus Torvalds 	       		(bay->state != mb_up));
754*1da177e4SLinus Torvalds 		bay->sleeping = 0;
755*1da177e4SLinus Torvalds 		up(&bay->lock);
756*1da177e4SLinus Torvalds 	}
757*1da177e4SLinus Torvalds 	return 0;
758*1da177e4SLinus Torvalds }
759*1da177e4SLinus Torvalds 
760*1da177e4SLinus Torvalds 
761*1da177e4SLinus Torvalds /* Definitions of "ops" structures.
762*1da177e4SLinus Torvalds  */
763*1da177e4SLinus Torvalds static struct mb_ops ohare_mb_ops __pmacdata = {
764*1da177e4SLinus Torvalds 	.name		= "Ohare",
765*1da177e4SLinus Torvalds 	.content	= ohare_mb_content,
766*1da177e4SLinus Torvalds 	.power		= ohare_mb_power,
767*1da177e4SLinus Torvalds 	.setup_bus	= ohare_mb_setup_bus,
768*1da177e4SLinus Torvalds 	.un_reset	= ohare_mb_un_reset,
769*1da177e4SLinus Torvalds 	.un_reset_ide	= ohare_mb_un_reset_ide,
770*1da177e4SLinus Torvalds };
771*1da177e4SLinus Torvalds 
772*1da177e4SLinus Torvalds static struct mb_ops heathrow_mb_ops __pmacdata = {
773*1da177e4SLinus Torvalds 	.name		= "Heathrow",
774*1da177e4SLinus Torvalds 	.content	= heathrow_mb_content,
775*1da177e4SLinus Torvalds 	.power		= heathrow_mb_power,
776*1da177e4SLinus Torvalds 	.setup_bus	= heathrow_mb_setup_bus,
777*1da177e4SLinus Torvalds 	.un_reset	= heathrow_mb_un_reset,
778*1da177e4SLinus Torvalds 	.un_reset_ide	= heathrow_mb_un_reset_ide,
779*1da177e4SLinus Torvalds };
780*1da177e4SLinus Torvalds 
781*1da177e4SLinus Torvalds static struct mb_ops keylargo_mb_ops __pmacdata = {
782*1da177e4SLinus Torvalds 	.name		= "KeyLargo",
783*1da177e4SLinus Torvalds 	.init		= keylargo_mb_init,
784*1da177e4SLinus Torvalds 	.content	= keylargo_mb_content,
785*1da177e4SLinus Torvalds 	.power		= keylargo_mb_power,
786*1da177e4SLinus Torvalds 	.setup_bus	= keylargo_mb_setup_bus,
787*1da177e4SLinus Torvalds 	.un_reset	= keylargo_mb_un_reset,
788*1da177e4SLinus Torvalds 	.un_reset_ide	= keylargo_mb_un_reset_ide,
789*1da177e4SLinus Torvalds };
790*1da177e4SLinus Torvalds 
791*1da177e4SLinus Torvalds /*
792*1da177e4SLinus Torvalds  * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL
793*1da177e4SLinus Torvalds  * register is always set when there is something in the media bay.
794*1da177e4SLinus Torvalds  * This causes problems for the interrupt code if we attach an interrupt
795*1da177e4SLinus Torvalds  * handler to the media-bay interrupt, because it tends to go into
796*1da177e4SLinus Torvalds  * an infinite loop calling the media bay interrupt handler.
797*1da177e4SLinus Torvalds  * Therefore we do it all by polling the media bay once each tick.
798*1da177e4SLinus Torvalds  */
799*1da177e4SLinus Torvalds 
800*1da177e4SLinus Torvalds static struct of_match media_bay_match[] =
801*1da177e4SLinus Torvalds {
802*1da177e4SLinus Torvalds 	{
803*1da177e4SLinus Torvalds 	.name		= "media-bay",
804*1da177e4SLinus Torvalds 	.type		= OF_ANY_MATCH,
805*1da177e4SLinus Torvalds 	.compatible	= "keylargo-media-bay",
806*1da177e4SLinus Torvalds 	.data		= &keylargo_mb_ops,
807*1da177e4SLinus Torvalds 	},
808*1da177e4SLinus Torvalds 	{
809*1da177e4SLinus Torvalds 	.name		= "media-bay",
810*1da177e4SLinus Torvalds 	.type		= OF_ANY_MATCH,
811*1da177e4SLinus Torvalds 	.compatible	= "heathrow-media-bay",
812*1da177e4SLinus Torvalds 	.data		= &heathrow_mb_ops,
813*1da177e4SLinus Torvalds 	},
814*1da177e4SLinus Torvalds 	{
815*1da177e4SLinus Torvalds 	.name		= "media-bay",
816*1da177e4SLinus Torvalds 	.type		= OF_ANY_MATCH,
817*1da177e4SLinus Torvalds 	.compatible	= "ohare-media-bay",
818*1da177e4SLinus Torvalds 	.data		= &ohare_mb_ops,
819*1da177e4SLinus Torvalds 	},
820*1da177e4SLinus Torvalds 	{},
821*1da177e4SLinus Torvalds };
822*1da177e4SLinus Torvalds 
823*1da177e4SLinus Torvalds static struct macio_driver media_bay_driver =
824*1da177e4SLinus Torvalds {
825*1da177e4SLinus Torvalds 	.name		= "media-bay",
826*1da177e4SLinus Torvalds 	.match_table	= media_bay_match,
827*1da177e4SLinus Torvalds 	.probe		= media_bay_attach,
828*1da177e4SLinus Torvalds 	.suspend	= media_bay_suspend,
829*1da177e4SLinus Torvalds 	.resume		= media_bay_resume
830*1da177e4SLinus Torvalds };
831*1da177e4SLinus Torvalds 
832*1da177e4SLinus Torvalds static int __init media_bay_init(void)
833*1da177e4SLinus Torvalds {
834*1da177e4SLinus Torvalds 	int i;
835*1da177e4SLinus Torvalds 
836*1da177e4SLinus Torvalds 	for (i=0; i<MAX_BAYS; i++) {
837*1da177e4SLinus Torvalds 		memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info));
838*1da177e4SLinus Torvalds 		media_bays[i].content_id	= -1;
839*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE
840*1da177e4SLinus Torvalds 		media_bays[i].cd_index		= -1;
841*1da177e4SLinus Torvalds #endif
842*1da177e4SLinus Torvalds 	}
843*1da177e4SLinus Torvalds 	if (_machine != _MACH_Pmac)
844*1da177e4SLinus Torvalds 		return -ENODEV;
845*1da177e4SLinus Torvalds 
846*1da177e4SLinus Torvalds 	macio_register_driver(&media_bay_driver);
847*1da177e4SLinus Torvalds 
848*1da177e4SLinus Torvalds 	return 0;
849*1da177e4SLinus Torvalds }
850*1da177e4SLinus Torvalds 
851*1da177e4SLinus Torvalds device_initcall(media_bay_init);
852