2 * MMC glue driver for iPAQ h3900
4 * Copyright (c) 2005 Phil Blundell
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/module.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/tty.h>
15 #include <linux/sched.h>
16 #include <linux/delay.h>
18 #include <linux/err.h>
19 #include <linux/soc-old.h>
20 #include <linux/soc/tmio_mmc.h>
22 #include <asm/mach-types.h>
23 #include <asm/hardware.h>
24 #include <asm/setup.h>
26 #include <asm/mach/arch.h>
27 #include <asm/arch/h3900-asic.h>
29 #include <linux/soc/asic2_base.h>
30 #include <linux/soc/asic3_base.h>
32 extern struct platform_device h3900_asic2
, h3900_asic3
;
34 static unsigned long shared
;
35 static int clock_enabled
;
37 #define asic2 &h3900_asic2.dev
38 #define asic3 &h3900_asic3.dev
40 static void h3900_set_mmc_clock (struct platform_device
*sdev
, int status
)
43 case MMC_CLOCK_ENABLED
:
45 unsigned long val
, flags
;
47 /* Enable clock from asic2 */
48 asic2_shared_add (asic2
, &shared
, ASIC_SHARED_CLOCK_EX1
);
49 asic2_clock_enable (asic2
, ASIC2_CLOCK_SD_2
, 1);
50 asic3_set_clock_cdex (asic3
, CLOCK_CDEX_EX0
, CLOCK_CDEX_EX0
);
53 /* Enable the host clock */
54 asic3_set_clock_sel (asic3
, CLOCK_SEL_SD_HCLK_SEL
| CLOCK_SEL_SD_BCLK_SEL
, CLOCK_SEL_SD_HCLK_SEL
);
55 asic3_set_clock_cdex (asic3
, CLOCK_CDEX_SD_HOST
| CLOCK_CDEX_SD_BUS
, CLOCK_CDEX_SD_HOST
);
57 asic3_set_clock_cdex (asic3
, CLOCK_CDEX_EX1
, CLOCK_CDEX_EX1
);
59 local_irq_save (flags
);
60 val
= asic3_read_register (asic3
, _IPAQ_ASIC3_EXTCF_Base
+ _IPAQ_ASIC3_EXTCF_Select
);
61 val
|= ASIC3_EXTCF_SD_MEM_ENABLE
;
62 asic3_write_register (asic3
, _IPAQ_ASIC3_EXTCF_Base
+ _IPAQ_ASIC3_EXTCF_Select
, val
);
64 val
= asic3_read_register (asic3
, _IPAQ_ASIC3_SDHWCTRL_Base
+ _IPAQ_ASIC3_SDHWCTRL_SDConf
);
65 val
&= ~(ASIC3_SDHWCTRL_SUSPEND
| ASIC3_SDHWCTRL_PCLR
); // wake up
66 asic3_write_register (asic3
, _IPAQ_ASIC3_SDHWCTRL_Base
+ _IPAQ_ASIC3_SDHWCTRL_SDConf
, val
);
67 local_irq_restore (flags
);
72 printk("h3900_mmc: clock enabled\n");
74 printk(KERN_ERR
"h3900_mmc: clock was already enabled\n");
80 asic2_clock_enable (asic2
, ASIC2_CLOCK_SD_2
, 0);
81 asic2_shared_release (asic2
, &shared
, ASIC_SHARED_CLOCK_EX1
);
83 printk("h3900_mmc: clock disabled\n");
85 printk(KERN_ERR
"h3900_mmc: clock was already disabled\n");
91 static struct tmio_mmc_hwconfig h3900_mmc_hwconfig
= {
92 .set_mmc_clock
= h3900_set_mmc_clock
,
97 h3900_mmc_probe (struct device
*dev
)
99 struct platform_device
*pdev
= to_platform_device (dev
);
102 if (pdev
->num_resources
== 0)
105 mmc_irq
= (int)pdev
->resource
[0].start
;
107 return asic3_register_mmc (asic3
, mmc_irq
, &h3900_mmc_hwconfig
);
111 h3900_mmc_remove (struct device
*dev
)
113 return asic3_unregister_mmc (asic3
);
116 static struct device_driver h3900_mmc_device_driver
= {
118 .bus
= &platform_bus_type
,
120 .probe
= h3900_mmc_probe
,
121 .remove
= h3900_mmc_remove
,
125 h3900_mmc_init (void)
128 retval
= driver_register (&h3900_mmc_device_driver
);
133 h3900_mmc_exit (void)
135 driver_unregister (&h3900_mmc_device_driver
);
138 module_init (h3900_mmc_init
)
139 module_exit (h3900_mmc_exit
)
141 MODULE_LICENSE("GPL");
142 MODULE_AUTHOR("Phil Blundell <pb@handhelds.org>");
143 MODULE_DESCRIPTION("Glue driver for h3900 MMC");
144 MODULE_SUPPORTED_DEVICE("h3900_mmc");