162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Driver for the media bay on the PowerBook 3400 and 2400. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1998 Paul Mackerras. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Various evolutions by Benjamin Herrenschmidt & Henry Worth 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/types.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/timer.h> 1562306a36Sopenharmony_ci#include <linux/stddef.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/kthread.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci#include <linux/pgtable.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <asm/io.h> 2262306a36Sopenharmony_ci#include <asm/machdep.h> 2362306a36Sopenharmony_ci#include <asm/pmac_feature.h> 2462306a36Sopenharmony_ci#include <asm/mediabay.h> 2562306a36Sopenharmony_ci#include <asm/sections.h> 2662306a36Sopenharmony_ci#include <asm/ohare.h> 2762306a36Sopenharmony_ci#include <asm/heathrow.h> 2862306a36Sopenharmony_ci#include <asm/keylargo.h> 2962306a36Sopenharmony_ci#include <linux/adb.h> 3062306a36Sopenharmony_ci#include <linux/pmu.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) 3362306a36Sopenharmony_ci#define MB_FCR8(bay, r) (((volatile u8 __iomem *)((bay)->base)) + (r)) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) 3662306a36Sopenharmony_ci#define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) 3762306a36Sopenharmony_ci#define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) 3862306a36Sopenharmony_ci#define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) 3962306a36Sopenharmony_ci#define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) 4062306a36Sopenharmony_ci#define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct media_bay_info; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct mb_ops { 4562306a36Sopenharmony_ci char* name; 4662306a36Sopenharmony_ci void (*init)(struct media_bay_info *bay); 4762306a36Sopenharmony_ci u8 (*content)(struct media_bay_info *bay); 4862306a36Sopenharmony_ci void (*power)(struct media_bay_info *bay, int on_off); 4962306a36Sopenharmony_ci int (*setup_bus)(struct media_bay_info *bay, u8 device_id); 5062306a36Sopenharmony_ci void (*un_reset)(struct media_bay_info *bay); 5162306a36Sopenharmony_ci void (*un_reset_ide)(struct media_bay_info *bay); 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistruct media_bay_info { 5562306a36Sopenharmony_ci u32 __iomem *base; 5662306a36Sopenharmony_ci int content_id; 5762306a36Sopenharmony_ci int state; 5862306a36Sopenharmony_ci int last_value; 5962306a36Sopenharmony_ci int value_count; 6062306a36Sopenharmony_ci int timer; 6162306a36Sopenharmony_ci struct macio_dev *mdev; 6262306a36Sopenharmony_ci const struct mb_ops* ops; 6362306a36Sopenharmony_ci int index; 6462306a36Sopenharmony_ci int cached_gpio; 6562306a36Sopenharmony_ci int sleeping; 6662306a36Sopenharmony_ci int user_lock; 6762306a36Sopenharmony_ci struct mutex lock; 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define MAX_BAYS 2 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic struct media_bay_info media_bays[MAX_BAYS]; 7362306a36Sopenharmony_cistatic int media_bay_count = 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Wait that number of ms between each step in normal polling mode 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci#define MB_POLL_DELAY 25 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * Consider the media-bay ID value stable if it is the same for 8262306a36Sopenharmony_ci * this number of milliseconds 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci#define MB_STABLE_DELAY 100 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* Wait after powering up the media bay this delay in ms 8762306a36Sopenharmony_ci * timeout bumped for some powerbooks 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci#define MB_POWER_DELAY 200 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Hold the media-bay reset signal true for this many ticks 9362306a36Sopenharmony_ci * after a device is inserted before releasing it. 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define MB_RESET_DELAY 50 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * Wait this long after the reset signal is released and before doing 9962306a36Sopenharmony_ci * further operations. After this delay, the IDE reset signal is released 10062306a36Sopenharmony_ci * too for an IDE device 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci#define MB_SETUP_DELAY 100 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted 10662306a36Sopenharmony_ci * (or until the device is ready) before calling into the driver 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci#define MB_IDE_WAIT 1000 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * States of a media bay 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cienum { 11462306a36Sopenharmony_ci mb_empty = 0, /* Idle */ 11562306a36Sopenharmony_ci mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */ 11662306a36Sopenharmony_ci mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */ 11762306a36Sopenharmony_ci mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */ 11862306a36Sopenharmony_ci mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */ 11962306a36Sopenharmony_ci mb_up, /* Media bay full */ 12062306a36Sopenharmony_ci mb_powering_down /* Powering down (avoid too fast down/up) */ 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define MB_POWER_SOUND 0x08 12462306a36Sopenharmony_ci#define MB_POWER_FLOPPY 0x04 12562306a36Sopenharmony_ci#define MB_POWER_ATA 0x02 12662306a36Sopenharmony_ci#define MB_POWER_PCI 0x01 12762306a36Sopenharmony_ci#define MB_POWER_OFF 0x00 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Functions for polling content of media bay 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic u8 13462306a36Sopenharmony_ciohare_mb_content(struct media_bay_info *bay) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic u8 14062306a36Sopenharmony_ciheathrow_mb_content(struct media_bay_info *bay) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic u8 14662306a36Sopenharmony_cikeylargo_mb_content(struct media_bay_info *bay) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int new_gpio; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; 15162306a36Sopenharmony_ci if (new_gpio) { 15262306a36Sopenharmony_ci bay->cached_gpio = new_gpio; 15362306a36Sopenharmony_ci return MB_NO; 15462306a36Sopenharmony_ci } else if (bay->cached_gpio != new_gpio) { 15562306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 15662306a36Sopenharmony_ci (void)MB_IN32(bay, KEYLARGO_MBCR); 15762306a36Sopenharmony_ci udelay(5); 15862306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 15962306a36Sopenharmony_ci (void)MB_IN32(bay, KEYLARGO_MBCR); 16062306a36Sopenharmony_ci udelay(5); 16162306a36Sopenharmony_ci bay->cached_gpio = new_gpio; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* 16762306a36Sopenharmony_ci * Functions for powering up/down the bay, puts the bay device 16862306a36Sopenharmony_ci * into reset state as well 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void 17262306a36Sopenharmony_ciohare_mb_power(struct media_bay_info* bay, int on_off) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci if (on_off) { 17562306a36Sopenharmony_ci /* Power up device, assert it's reset line */ 17662306a36Sopenharmony_ci MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N); 17762306a36Sopenharmony_ci MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N); 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci /* Disable all devices */ 18062306a36Sopenharmony_ci MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK); 18162306a36Sopenharmony_ci MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 18262306a36Sopenharmony_ci /* Cut power from bay, release reset line */ 18362306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N); 18462306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 18562306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci MB_BIC(bay, OHARE_MBCR, 0x00000F00); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void 19162306a36Sopenharmony_ciheathrow_mb_power(struct media_bay_info* bay, int on_off) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci if (on_off) { 19462306a36Sopenharmony_ci /* Power up device, assert it's reset line */ 19562306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 19662306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 19762306a36Sopenharmony_ci } else { 19862306a36Sopenharmony_ci /* Disable all devices */ 19962306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); 20062306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 20162306a36Sopenharmony_ci /* Cut power from bay, release reset line */ 20262306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 20362306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 20462306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic void 21062306a36Sopenharmony_cikeylargo_mb_power(struct media_bay_info* bay, int on_off) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci if (on_off) { 21362306a36Sopenharmony_ci /* Power up device, assert it's reset line */ 21462306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 21562306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci /* Disable all devices */ 21862306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); 21962306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 22062306a36Sopenharmony_ci /* Cut power from bay, release reset line */ 22162306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 22262306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 22362306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* 22962306a36Sopenharmony_ci * Functions for configuring the media bay for a given type of device, 23062306a36Sopenharmony_ci * enable the related busses 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int 23462306a36Sopenharmony_ciohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci switch(device_id) { 23762306a36Sopenharmony_ci case MB_FD: 23862306a36Sopenharmony_ci case MB_FD1: 23962306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); 24062306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci case MB_CD: 24362306a36Sopenharmony_ci MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); 24462306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci case MB_PCI: 24762306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return -ENODEV; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int 25462306a36Sopenharmony_ciheathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci switch(device_id) { 25762306a36Sopenharmony_ci case MB_FD: 25862306a36Sopenharmony_ci case MB_FD1: 25962306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); 26062306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci case MB_CD: 26362306a36Sopenharmony_ci MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 26462306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci case MB_PCI: 26762306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci return -ENODEV; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int 27462306a36Sopenharmony_cikeylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci switch(device_id) { 27762306a36Sopenharmony_ci case MB_CD: 27862306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); 27962306a36Sopenharmony_ci MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 28062306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci case MB_PCI: 28362306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci case MB_SOUND: 28662306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); 28762306a36Sopenharmony_ci return 0; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci return -ENODEV; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* 29362306a36Sopenharmony_ci * Functions for tweaking resets 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void 29762306a36Sopenharmony_ciohare_mb_un_reset(struct media_bay_info* bay) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void keylargo_mb_init(struct media_bay_info *bay) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void heathrow_mb_un_reset(struct media_bay_info* bay) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void keylargo_mb_un_reset(struct media_bay_info* bay) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic void ohare_mb_un_reset_ide(struct media_bay_info* bay) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void heathrow_mb_un_reset_ide(struct media_bay_info* bay) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void keylargo_mb_un_reset_ide(struct media_bay_info* bay) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic inline void set_mb_power(struct media_bay_info* bay, int onoff) 33362306a36Sopenharmony_ci{ 33462306a36Sopenharmony_ci /* Power up up and assert the bay reset line */ 33562306a36Sopenharmony_ci if (onoff) { 33662306a36Sopenharmony_ci bay->ops->power(bay, 1); 33762306a36Sopenharmony_ci bay->state = mb_powering_up; 33862306a36Sopenharmony_ci pr_debug("mediabay%d: powering up\n", bay->index); 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci /* Make sure everything is powered down & disabled */ 34162306a36Sopenharmony_ci bay->ops->power(bay, 0); 34262306a36Sopenharmony_ci bay->state = mb_powering_down; 34362306a36Sopenharmony_ci pr_debug("mediabay%d: powering down\n", bay->index); 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic void poll_media_bay(struct media_bay_info* bay) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int id = bay->ops->content(bay); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci static char *mb_content_types[] = { 35362306a36Sopenharmony_ci "a floppy drive", 35462306a36Sopenharmony_ci "a floppy drive", 35562306a36Sopenharmony_ci "an unsupported audio device", 35662306a36Sopenharmony_ci "an ATA device", 35762306a36Sopenharmony_ci "an unsupported PCI device", 35862306a36Sopenharmony_ci "an unknown device", 35962306a36Sopenharmony_ci }; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (id != bay->last_value) { 36262306a36Sopenharmony_ci bay->last_value = id; 36362306a36Sopenharmony_ci bay->value_count = 0; 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci if (id == bay->content_id) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci bay->value_count += msecs_to_jiffies(MB_POLL_DELAY); 37062306a36Sopenharmony_ci if (bay->value_count >= msecs_to_jiffies(MB_STABLE_DELAY)) { 37162306a36Sopenharmony_ci /* If the device type changes without going thru 37262306a36Sopenharmony_ci * "MB_NO", we force a pass by "MB_NO" to make sure 37362306a36Sopenharmony_ci * things are properly reset 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci if ((id != MB_NO) && (bay->content_id != MB_NO)) { 37662306a36Sopenharmony_ci id = MB_NO; 37762306a36Sopenharmony_ci pr_debug("mediabay%d: forcing MB_NO\n", bay->index); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci pr_debug("mediabay%d: switching to %d\n", bay->index, id); 38062306a36Sopenharmony_ci set_mb_power(bay, id != MB_NO); 38162306a36Sopenharmony_ci bay->content_id = id; 38262306a36Sopenharmony_ci if (id >= MB_NO || id < 0) 38362306a36Sopenharmony_ci printk(KERN_INFO "mediabay%d: Bay is now empty\n", bay->index); 38462306a36Sopenharmony_ci else 38562306a36Sopenharmony_ci printk(KERN_INFO "mediabay%d: Bay contains %s\n", 38662306a36Sopenharmony_ci bay->index, mb_content_types[id]); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ciint check_media_bay(struct macio_dev *baydev) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct media_bay_info* bay; 39362306a36Sopenharmony_ci int id; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (baydev == NULL) 39662306a36Sopenharmony_ci return MB_NO; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* This returns an instant snapshot, not locking, sine 39962306a36Sopenharmony_ci * we may be called with the bay lock held. The resulting 40062306a36Sopenharmony_ci * fuzzyness of the result if called at the wrong time is 40162306a36Sopenharmony_ci * not actually a huge deal 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci bay = macio_get_drvdata(baydev); 40462306a36Sopenharmony_ci if (bay == NULL) 40562306a36Sopenharmony_ci return MB_NO; 40662306a36Sopenharmony_ci id = bay->content_id; 40762306a36Sopenharmony_ci if (bay->state != mb_up) 40862306a36Sopenharmony_ci return MB_NO; 40962306a36Sopenharmony_ci if (id == MB_FD1) 41062306a36Sopenharmony_ci return MB_FD; 41162306a36Sopenharmony_ci return id; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(check_media_bay); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_civoid lock_media_bay(struct macio_dev *baydev) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct media_bay_info* bay; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (baydev == NULL) 42062306a36Sopenharmony_ci return; 42162306a36Sopenharmony_ci bay = macio_get_drvdata(baydev); 42262306a36Sopenharmony_ci if (bay == NULL) 42362306a36Sopenharmony_ci return; 42462306a36Sopenharmony_ci mutex_lock(&bay->lock); 42562306a36Sopenharmony_ci bay->user_lock = 1; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(lock_media_bay); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_civoid unlock_media_bay(struct macio_dev *baydev) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct media_bay_info* bay; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (baydev == NULL) 43462306a36Sopenharmony_ci return; 43562306a36Sopenharmony_ci bay = macio_get_drvdata(baydev); 43662306a36Sopenharmony_ci if (bay == NULL) 43762306a36Sopenharmony_ci return; 43862306a36Sopenharmony_ci if (bay->user_lock) { 43962306a36Sopenharmony_ci bay->user_lock = 0; 44062306a36Sopenharmony_ci mutex_unlock(&bay->lock); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(unlock_media_bay); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int mb_broadcast_hotplug(struct device *dev, void *data) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct media_bay_info* bay = data; 44862306a36Sopenharmony_ci struct macio_dev *mdev; 44962306a36Sopenharmony_ci struct macio_driver *drv; 45062306a36Sopenharmony_ci int state; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (dev->bus != &macio_bus_type) 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci state = bay->state == mb_up ? bay->content_id : MB_NO; 45662306a36Sopenharmony_ci if (state == MB_FD1) 45762306a36Sopenharmony_ci state = MB_FD; 45862306a36Sopenharmony_ci mdev = to_macio_device(dev); 45962306a36Sopenharmony_ci drv = to_macio_driver(dev->driver); 46062306a36Sopenharmony_ci if (dev->driver && drv->mediabay_event) 46162306a36Sopenharmony_ci drv->mediabay_event(mdev, state); 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void media_bay_step(int i) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct media_bay_info* bay = &media_bays[i]; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* We don't poll when powering down */ 47062306a36Sopenharmony_ci if (bay->state != mb_powering_down) 47162306a36Sopenharmony_ci poll_media_bay(bay); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* If timer expired run state machine */ 47462306a36Sopenharmony_ci if (bay->timer != 0) { 47562306a36Sopenharmony_ci bay->timer -= msecs_to_jiffies(MB_POLL_DELAY); 47662306a36Sopenharmony_ci if (bay->timer > 0) 47762306a36Sopenharmony_ci return; 47862306a36Sopenharmony_ci bay->timer = 0; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci switch(bay->state) { 48262306a36Sopenharmony_ci case mb_powering_up: 48362306a36Sopenharmony_ci if (bay->ops->setup_bus(bay, bay->last_value) < 0) { 48462306a36Sopenharmony_ci pr_debug("mediabay%d: device not supported (kind:%d)\n", 48562306a36Sopenharmony_ci i, bay->content_id); 48662306a36Sopenharmony_ci set_mb_power(bay, 0); 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci bay->timer = msecs_to_jiffies(MB_RESET_DELAY); 49062306a36Sopenharmony_ci bay->state = mb_enabling_bay; 49162306a36Sopenharmony_ci pr_debug("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case mb_enabling_bay: 49462306a36Sopenharmony_ci bay->ops->un_reset(bay); 49562306a36Sopenharmony_ci bay->timer = msecs_to_jiffies(MB_SETUP_DELAY); 49662306a36Sopenharmony_ci bay->state = mb_resetting; 49762306a36Sopenharmony_ci pr_debug("mediabay%d: releasing bay reset (kind:%d)\n", 49862306a36Sopenharmony_ci i, bay->content_id); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci case mb_resetting: 50162306a36Sopenharmony_ci if (bay->content_id != MB_CD) { 50262306a36Sopenharmony_ci pr_debug("mediabay%d: bay is up (kind:%d)\n", i, 50362306a36Sopenharmony_ci bay->content_id); 50462306a36Sopenharmony_ci bay->state = mb_up; 50562306a36Sopenharmony_ci device_for_each_child(&bay->mdev->ofdev.dev, 50662306a36Sopenharmony_ci bay, mb_broadcast_hotplug); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci pr_debug("mediabay%d: releasing ATA reset (kind:%d)\n", 51062306a36Sopenharmony_ci i, bay->content_id); 51162306a36Sopenharmony_ci bay->ops->un_reset_ide(bay); 51262306a36Sopenharmony_ci bay->timer = msecs_to_jiffies(MB_IDE_WAIT); 51362306a36Sopenharmony_ci bay->state = mb_ide_resetting; 51462306a36Sopenharmony_ci break; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci case mb_ide_resetting: 51762306a36Sopenharmony_ci pr_debug("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id); 51862306a36Sopenharmony_ci bay->state = mb_up; 51962306a36Sopenharmony_ci device_for_each_child(&bay->mdev->ofdev.dev, 52062306a36Sopenharmony_ci bay, mb_broadcast_hotplug); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci case mb_powering_down: 52462306a36Sopenharmony_ci bay->state = mb_empty; 52562306a36Sopenharmony_ci device_for_each_child(&bay->mdev->ofdev.dev, 52662306a36Sopenharmony_ci bay, mb_broadcast_hotplug); 52762306a36Sopenharmony_ci pr_debug("mediabay%d: end of power down\n", i); 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/* 53362306a36Sopenharmony_ci * This procedure runs as a kernel thread to poll the media bay 53462306a36Sopenharmony_ci * once each tick and register and unregister the IDE interface 53562306a36Sopenharmony_ci * with the IDE driver. It needs to be a thread because 53662306a36Sopenharmony_ci * ide_register can't be called from interrupt context. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_cistatic int media_bay_task(void *x) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci int i; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci while (!kthread_should_stop()) { 54362306a36Sopenharmony_ci for (i = 0; i < media_bay_count; ++i) { 54462306a36Sopenharmony_ci mutex_lock(&media_bays[i].lock); 54562306a36Sopenharmony_ci if (!media_bays[i].sleeping) 54662306a36Sopenharmony_ci media_bay_step(i); 54762306a36Sopenharmony_ci mutex_unlock(&media_bays[i].lock); 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci msleep_interruptible(MB_POLL_DELAY); 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int media_bay_attach(struct macio_dev *mdev, 55662306a36Sopenharmony_ci const struct of_device_id *match) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct media_bay_info* bay; 55962306a36Sopenharmony_ci u32 __iomem *regbase; 56062306a36Sopenharmony_ci struct device_node *ofnode; 56162306a36Sopenharmony_ci unsigned long base; 56262306a36Sopenharmony_ci int i; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ofnode = mdev->ofdev.dev.of_node; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (macio_resource_count(mdev) < 1) 56762306a36Sopenharmony_ci return -ENODEV; 56862306a36Sopenharmony_ci if (macio_request_resources(mdev, "media-bay")) 56962306a36Sopenharmony_ci return -EBUSY; 57062306a36Sopenharmony_ci /* Media bay registers are located at the beginning of the 57162306a36Sopenharmony_ci * mac-io chip, for now, we trick and align down the first 57262306a36Sopenharmony_ci * resource passed in 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_ci base = macio_resource_start(mdev, 0) & 0xffff0000u; 57562306a36Sopenharmony_ci regbase = (u32 __iomem *)ioremap(base, 0x100); 57662306a36Sopenharmony_ci if (regbase == NULL) { 57762306a36Sopenharmony_ci macio_release_resources(mdev); 57862306a36Sopenharmony_ci return -ENOMEM; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci i = media_bay_count++; 58262306a36Sopenharmony_ci bay = &media_bays[i]; 58362306a36Sopenharmony_ci bay->mdev = mdev; 58462306a36Sopenharmony_ci bay->base = regbase; 58562306a36Sopenharmony_ci bay->index = i; 58662306a36Sopenharmony_ci bay->ops = match->data; 58762306a36Sopenharmony_ci bay->sleeping = 0; 58862306a36Sopenharmony_ci mutex_init(&bay->lock); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* Init HW probing */ 59162306a36Sopenharmony_ci if (bay->ops->init) 59262306a36Sopenharmony_ci bay->ops->init(bay); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", i, bay->ops->name); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* Force an immediate detect */ 59762306a36Sopenharmony_ci set_mb_power(bay, 0); 59862306a36Sopenharmony_ci msleep(MB_POWER_DELAY); 59962306a36Sopenharmony_ci bay->content_id = MB_NO; 60062306a36Sopenharmony_ci bay->last_value = bay->ops->content(bay); 60162306a36Sopenharmony_ci bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 60262306a36Sopenharmony_ci bay->state = mb_empty; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* Mark us ready by filling our mdev data */ 60562306a36Sopenharmony_ci macio_set_drvdata(mdev, bay); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* Startup kernel thread */ 60862306a36Sopenharmony_ci if (i == 0) 60962306a36Sopenharmony_ci kthread_run(media_bay_task, NULL, "media-bay"); 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return 0; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int media_bay_suspend(struct macio_dev *mdev, pm_message_t state) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct media_bay_info *bay = macio_get_drvdata(mdev); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (state.event != mdev->ofdev.dev.power.power_state.event 62062306a36Sopenharmony_ci && (state.event & PM_EVENT_SLEEP)) { 62162306a36Sopenharmony_ci mutex_lock(&bay->lock); 62262306a36Sopenharmony_ci bay->sleeping = 1; 62362306a36Sopenharmony_ci set_mb_power(bay, 0); 62462306a36Sopenharmony_ci mutex_unlock(&bay->lock); 62562306a36Sopenharmony_ci msleep(MB_POLL_DELAY); 62662306a36Sopenharmony_ci mdev->ofdev.dev.power.power_state = state; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci return 0; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int media_bay_resume(struct macio_dev *mdev) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci struct media_bay_info *bay = macio_get_drvdata(mdev); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (mdev->ofdev.dev.power.power_state.event != PM_EVENT_ON) { 63662306a36Sopenharmony_ci mdev->ofdev.dev.power.power_state = PMSG_ON; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* We re-enable the bay using it's previous content 63962306a36Sopenharmony_ci only if it did not change. Note those bozo timings, 64062306a36Sopenharmony_ci they seem to help the 3400 get it right. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_ci /* Force MB power to 0 */ 64362306a36Sopenharmony_ci mutex_lock(&bay->lock); 64462306a36Sopenharmony_ci set_mb_power(bay, 0); 64562306a36Sopenharmony_ci msleep(MB_POWER_DELAY); 64662306a36Sopenharmony_ci if (bay->ops->content(bay) != bay->content_id) { 64762306a36Sopenharmony_ci printk("mediabay%d: Content changed during sleep...\n", bay->index); 64862306a36Sopenharmony_ci mutex_unlock(&bay->lock); 64962306a36Sopenharmony_ci return 0; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci set_mb_power(bay, 1); 65262306a36Sopenharmony_ci bay->last_value = bay->content_id; 65362306a36Sopenharmony_ci bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 65462306a36Sopenharmony_ci bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 65562306a36Sopenharmony_ci do { 65662306a36Sopenharmony_ci msleep(MB_POLL_DELAY); 65762306a36Sopenharmony_ci media_bay_step(bay->index); 65862306a36Sopenharmony_ci } while((bay->state != mb_empty) && 65962306a36Sopenharmony_ci (bay->state != mb_up)); 66062306a36Sopenharmony_ci bay->sleeping = 0; 66162306a36Sopenharmony_ci mutex_unlock(&bay->lock); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci/* Definitions of "ops" structures. 66862306a36Sopenharmony_ci */ 66962306a36Sopenharmony_cistatic const struct mb_ops ohare_mb_ops = { 67062306a36Sopenharmony_ci .name = "Ohare", 67162306a36Sopenharmony_ci .content = ohare_mb_content, 67262306a36Sopenharmony_ci .power = ohare_mb_power, 67362306a36Sopenharmony_ci .setup_bus = ohare_mb_setup_bus, 67462306a36Sopenharmony_ci .un_reset = ohare_mb_un_reset, 67562306a36Sopenharmony_ci .un_reset_ide = ohare_mb_un_reset_ide, 67662306a36Sopenharmony_ci}; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic const struct mb_ops heathrow_mb_ops = { 67962306a36Sopenharmony_ci .name = "Heathrow", 68062306a36Sopenharmony_ci .content = heathrow_mb_content, 68162306a36Sopenharmony_ci .power = heathrow_mb_power, 68262306a36Sopenharmony_ci .setup_bus = heathrow_mb_setup_bus, 68362306a36Sopenharmony_ci .un_reset = heathrow_mb_un_reset, 68462306a36Sopenharmony_ci .un_reset_ide = heathrow_mb_un_reset_ide, 68562306a36Sopenharmony_ci}; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_cistatic const struct mb_ops keylargo_mb_ops = { 68862306a36Sopenharmony_ci .name = "KeyLargo", 68962306a36Sopenharmony_ci .init = keylargo_mb_init, 69062306a36Sopenharmony_ci .content = keylargo_mb_content, 69162306a36Sopenharmony_ci .power = keylargo_mb_power, 69262306a36Sopenharmony_ci .setup_bus = keylargo_mb_setup_bus, 69362306a36Sopenharmony_ci .un_reset = keylargo_mb_un_reset, 69462306a36Sopenharmony_ci .un_reset_ide = keylargo_mb_un_reset_ide, 69562306a36Sopenharmony_ci}; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/* 69862306a36Sopenharmony_ci * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL 69962306a36Sopenharmony_ci * register is always set when there is something in the media bay. 70062306a36Sopenharmony_ci * This causes problems for the interrupt code if we attach an interrupt 70162306a36Sopenharmony_ci * handler to the media-bay interrupt, because it tends to go into 70262306a36Sopenharmony_ci * an infinite loop calling the media bay interrupt handler. 70362306a36Sopenharmony_ci * Therefore we do it all by polling the media bay once each tick. 70462306a36Sopenharmony_ci */ 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic const struct of_device_id media_bay_match[] = 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci { 70962306a36Sopenharmony_ci .name = "media-bay", 71062306a36Sopenharmony_ci .compatible = "keylargo-media-bay", 71162306a36Sopenharmony_ci .data = &keylargo_mb_ops, 71262306a36Sopenharmony_ci }, 71362306a36Sopenharmony_ci { 71462306a36Sopenharmony_ci .name = "media-bay", 71562306a36Sopenharmony_ci .compatible = "heathrow-media-bay", 71662306a36Sopenharmony_ci .data = &heathrow_mb_ops, 71762306a36Sopenharmony_ci }, 71862306a36Sopenharmony_ci { 71962306a36Sopenharmony_ci .name = "media-bay", 72062306a36Sopenharmony_ci .compatible = "ohare-media-bay", 72162306a36Sopenharmony_ci .data = &ohare_mb_ops, 72262306a36Sopenharmony_ci }, 72362306a36Sopenharmony_ci {}, 72462306a36Sopenharmony_ci}; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic struct macio_driver media_bay_driver = 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci .driver = { 72962306a36Sopenharmony_ci .name = "media-bay", 73062306a36Sopenharmony_ci .of_match_table = media_bay_match, 73162306a36Sopenharmony_ci }, 73262306a36Sopenharmony_ci .probe = media_bay_attach, 73362306a36Sopenharmony_ci .suspend = media_bay_suspend, 73462306a36Sopenharmony_ci .resume = media_bay_resume 73562306a36Sopenharmony_ci}; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int __init media_bay_init(void) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci int i; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci for (i=0; i<MAX_BAYS; i++) { 74262306a36Sopenharmony_ci memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); 74362306a36Sopenharmony_ci media_bays[i].content_id = -1; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci if (!machine_is(powermac)) 74662306a36Sopenharmony_ci return 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci macio_register_driver(&media_bay_driver); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cidevice_initcall(media_bay_init); 754