Commit 64e8867ba8098b69889c1af94997a5ba2348fb26
Committed by
Samuel Ortiz
1 parent
6f2af72a24
Exists in
master
and in
7 other branches
mfd: tmio_mmc hardware abstraction for CNF area
This patch abstracts out the CNF area code from tmio_mmc which is not present in all hardware that can use this driver. This is required so that we can support non-toshiba based hardware. ASIC3 support by Philipp Zabel Signed-off-by: Ian Molton <ian@mnementh.co.uk> Signed-off-by: Magnus Damm <damm@opensource.se> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 9 changed files with 323 additions and 149 deletions Side-by-side Diff
drivers/mfd/Makefile
... | ... | @@ -11,9 +11,9 @@ |
11 | 11 | |
12 | 12 | obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o |
13 | 13 | |
14 | -obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o | |
15 | -obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o | |
16 | -obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o | |
14 | +obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o | |
15 | +obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o | |
16 | +obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o | |
17 | 17 | |
18 | 18 | obj-$(CONFIG_MFD_WM8400) += wm8400-core.o |
19 | 19 | wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o |
drivers/mfd/asic3.c
... | ... | @@ -80,6 +80,7 @@ |
80 | 80 | u16 irq_bothedge[4]; |
81 | 81 | struct gpio_chip gpio; |
82 | 82 | struct device *dev; |
83 | + void __iomem *tmio_cnf; | |
83 | 84 | |
84 | 85 | struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; |
85 | 86 | }; |
86 | 87 | |
... | ... | @@ -685,8 +686,24 @@ |
685 | 686 | .resources = ds1wm_resources, |
686 | 687 | }; |
687 | 688 | |
689 | +static void asic3_mmc_pwr(struct platform_device *pdev, int state) | |
690 | +{ | |
691 | + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | |
692 | + | |
693 | + tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state); | |
694 | +} | |
695 | + | |
696 | +static void asic3_mmc_clk_div(struct platform_device *pdev, int state) | |
697 | +{ | |
698 | + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); | |
699 | + | |
700 | + tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state); | |
701 | +} | |
702 | + | |
688 | 703 | static struct tmio_mmc_data asic3_mmc_data = { |
689 | - .hclk = 24576000, | |
704 | + .hclk = 24576000, | |
705 | + .set_pwr = asic3_mmc_pwr, | |
706 | + .set_clk_div = asic3_mmc_clk_div, | |
690 | 707 | }; |
691 | 708 | |
692 | 709 | static struct resource asic3_mmc_resources[] = { |
... | ... | @@ -696,11 +713,6 @@ |
696 | 713 | .flags = IORESOURCE_MEM, |
697 | 714 | }, |
698 | 715 | { |
699 | - .start = ASIC3_SD_CONFIG_BASE, | |
700 | - .end = ASIC3_SD_CONFIG_BASE + 0x1ff, | |
701 | - .flags = IORESOURCE_MEM, | |
702 | - }, | |
703 | - { | |
704 | 716 | .start = 0, |
705 | 717 | .end = 0, |
706 | 718 | .flags = IORESOURCE_IRQ, |
... | ... | @@ -743,6 +755,10 @@ |
743 | 755 | asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), |
744 | 756 | ASIC3_SDHWCTRL_SDPWR, 1); |
745 | 757 | |
758 | + /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */ | |
759 | + tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift, | |
760 | + ASIC3_SD_CTRL_BASE >> 1); | |
761 | + | |
746 | 762 | return 0; |
747 | 763 | } |
748 | 764 | |
749 | 765 | |
... | ... | @@ -797,10 +813,15 @@ |
797 | 813 | asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); |
798 | 814 | |
799 | 815 | /* MMC */ |
816 | + asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + | |
817 | + mem_sdio->start, 0x400 >> asic->bus_shift); | |
818 | + if (!asic->tmio_cnf) { | |
819 | + ret = -ENOMEM; | |
820 | + dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); | |
821 | + goto out; | |
822 | + } | |
800 | 823 | asic3_mmc_resources[0].start >>= asic->bus_shift; |
801 | 824 | asic3_mmc_resources[0].end >>= asic->bus_shift; |
802 | - asic3_mmc_resources[1].start >>= asic->bus_shift; | |
803 | - asic3_mmc_resources[1].end >>= asic->bus_shift; | |
804 | 825 | |
805 | 826 | asic3_cell_mmc.platform_data = &asic3_cell_mmc; |
806 | 827 | asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); |
807 | 828 | |
... | ... | @@ -820,7 +841,10 @@ |
820 | 841 | |
821 | 842 | static void asic3_mfd_remove(struct platform_device *pdev) |
822 | 843 | { |
844 | + struct asic3 *asic = platform_get_drvdata(pdev); | |
845 | + | |
823 | 846 | mfd_remove_devices(&pdev->dev); |
847 | + iounmap(asic->tmio_cnf); | |
824 | 848 | } |
825 | 849 | |
826 | 850 | /* Core */ |
drivers/mfd/t7l66xb.c
... | ... | @@ -38,6 +38,19 @@ |
38 | 38 | T7L66XB_CELL_MMC, |
39 | 39 | }; |
40 | 40 | |
41 | +static const struct resource t7l66xb_mmc_resources[] = { | |
42 | + { | |
43 | + .start = 0x800, | |
44 | + .end = 0x9ff, | |
45 | + .flags = IORESOURCE_MEM, | |
46 | + }, | |
47 | + { | |
48 | + .start = IRQ_T7L66XB_MMC, | |
49 | + .end = IRQ_T7L66XB_MMC, | |
50 | + .flags = IORESOURCE_IRQ, | |
51 | + }, | |
52 | +}; | |
53 | + | |
41 | 54 | #define SCR_REVID 0x08 /* b Revision ID */ |
42 | 55 | #define SCR_IMR 0x42 /* b Interrupt Mask */ |
43 | 56 | #define SCR_DEV_CTL 0xe0 /* b Device control */ |
... | ... | @@ -83,6 +96,9 @@ |
83 | 96 | |
84 | 97 | spin_unlock_irqrestore(&t7l66xb->lock, flags); |
85 | 98 | |
99 | + tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, | |
100 | + t7l66xb_mmc_resources[0].start & 0xfffe); | |
101 | + | |
86 | 102 | return 0; |
87 | 103 | } |
88 | 104 | |
89 | 105 | |
90 | 106 | |
... | ... | @@ -106,30 +122,30 @@ |
106 | 122 | return 0; |
107 | 123 | } |
108 | 124 | |
125 | +static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) | |
126 | +{ | |
127 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
128 | + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | |
129 | + | |
130 | + tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); | |
131 | +} | |
132 | + | |
133 | +static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) | |
134 | +{ | |
135 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
136 | + struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | |
137 | + | |
138 | + tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); | |
139 | +} | |
140 | + | |
109 | 141 | /*--------------------------------------------------------------------------*/ |
110 | 142 | |
111 | 143 | static struct tmio_mmc_data t7166xb_mmc_data = { |
112 | 144 | .hclk = 24000000, |
145 | + .set_pwr = t7l66xb_mmc_pwr, | |
146 | + .set_clk_div = t7l66xb_mmc_clk_div, | |
113 | 147 | }; |
114 | 148 | |
115 | -static const struct resource t7l66xb_mmc_resources[] = { | |
116 | - { | |
117 | - .start = 0x800, | |
118 | - .end = 0x9ff, | |
119 | - .flags = IORESOURCE_MEM, | |
120 | - }, | |
121 | - { | |
122 | - .start = 0x200, | |
123 | - .end = 0x2ff, | |
124 | - .flags = IORESOURCE_MEM, | |
125 | - }, | |
126 | - { | |
127 | - .start = IRQ_T7L66XB_MMC, | |
128 | - .end = IRQ_T7L66XB_MMC, | |
129 | - .flags = IORESOURCE_IRQ, | |
130 | - }, | |
131 | -}; | |
132 | - | |
133 | 149 | static const struct resource t7l66xb_nand_resources[] = { |
134 | 150 | { |
135 | 151 | .start = 0xc00, |
... | ... | @@ -281,6 +297,9 @@ |
281 | 297 | clk_enable(t7l66xb->clk48m); |
282 | 298 | if (pdata && pdata->resume) |
283 | 299 | pdata->resume(dev); |
300 | + | |
301 | + tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0, | |
302 | + t7l66xb_mmc_resources[0].start & 0xfffe); | |
284 | 303 | |
285 | 304 | return 0; |
286 | 305 | } |
drivers/mfd/tc6387xb.c
... | ... | @@ -22,28 +22,52 @@ |
22 | 22 | TC6387XB_CELL_MMC, |
23 | 23 | }; |
24 | 24 | |
25 | +struct tc6387xb { | |
26 | + void __iomem *scr; | |
27 | + struct clk *clk32k; | |
28 | + struct resource rscr; | |
29 | +}; | |
30 | + | |
31 | +static struct resource tc6387xb_mmc_resources[] = { | |
32 | + { | |
33 | + .start = 0x800, | |
34 | + .end = 0x9ff, | |
35 | + .flags = IORESOURCE_MEM, | |
36 | + }, | |
37 | + { | |
38 | + .start = 0, | |
39 | + .end = 0, | |
40 | + .flags = IORESOURCE_IRQ, | |
41 | + }, | |
42 | +}; | |
43 | + | |
44 | +/*--------------------------------------------------------------------------*/ | |
45 | + | |
25 | 46 | #ifdef CONFIG_PM |
26 | 47 | static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) |
27 | 48 | { |
28 | - struct clk *clk32k = platform_get_drvdata(dev); | |
49 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
29 | 50 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; |
30 | 51 | |
31 | 52 | if (pdata && pdata->suspend) |
32 | 53 | pdata->suspend(dev); |
33 | - clk_disable(clk32k); | |
54 | + clk_disable(tc6387xb->clk32k); | |
34 | 55 | |
35 | 56 | return 0; |
36 | 57 | } |
37 | 58 | |
38 | 59 | static int tc6387xb_resume(struct platform_device *dev) |
39 | 60 | { |
40 | - struct clk *clk32k = platform_get_drvdata(dev); | |
61 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
41 | 62 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; |
42 | 63 | |
43 | - clk_enable(clk32k); | |
64 | + clk_enable(tc6387xb->clk32k); | |
44 | 65 | if (pdata && pdata->resume) |
45 | 66 | pdata->resume(dev); |
46 | 67 | |
68 | + tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0, | |
69 | + tc6387xb_mmc_resources[0].start & 0xfffe); | |
70 | + | |
47 | 71 | return 0; |
48 | 72 | } |
49 | 73 | #else |
50 | 74 | |
51 | 75 | |
52 | 76 | |
53 | 77 | |
54 | 78 | |
55 | 79 | |
56 | 80 | |
57 | 81 | |
... | ... | @@ -53,49 +77,53 @@ |
53 | 77 | |
54 | 78 | /*--------------------------------------------------------------------------*/ |
55 | 79 | |
80 | +static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) | |
81 | +{ | |
82 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
83 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
84 | + | |
85 | + tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); | |
86 | +} | |
87 | + | |
88 | +static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) | |
89 | +{ | |
90 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
91 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
92 | + | |
93 | + tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); | |
94 | +} | |
95 | + | |
96 | + | |
56 | 97 | static int tc6387xb_mmc_enable(struct platform_device *mmc) |
57 | 98 | { |
58 | 99 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
59 | - struct clk *clk32k = platform_get_drvdata(dev); | |
100 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
60 | 101 | |
61 | - clk_enable(clk32k); | |
102 | + clk_enable(tc6387xb->clk32k); | |
62 | 103 | |
104 | + tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0, | |
105 | + tc6387xb_mmc_resources[0].start & 0xfffe); | |
106 | + | |
63 | 107 | return 0; |
64 | 108 | } |
65 | 109 | |
66 | 110 | static int tc6387xb_mmc_disable(struct platform_device *mmc) |
67 | 111 | { |
68 | 112 | struct platform_device *dev = to_platform_device(mmc->dev.parent); |
69 | - struct clk *clk32k = platform_get_drvdata(dev); | |
113 | + struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | |
70 | 114 | |
71 | - clk_disable(clk32k); | |
115 | + clk_disable(tc6387xb->clk32k); | |
72 | 116 | |
73 | 117 | return 0; |
74 | 118 | } |
75 | 119 | |
76 | -/*--------------------------------------------------------------------------*/ | |
77 | - | |
78 | 120 | static struct tmio_mmc_data tc6387xb_mmc_data = { |
79 | 121 | .hclk = 24000000, |
122 | + .set_pwr = tc6387xb_mmc_pwr, | |
123 | + .set_clk_div = tc6387xb_mmc_clk_div, | |
80 | 124 | }; |
81 | 125 | |
82 | -static struct resource tc6387xb_mmc_resources[] = { | |
83 | - { | |
84 | - .start = 0x800, | |
85 | - .end = 0x9ff, | |
86 | - .flags = IORESOURCE_MEM, | |
87 | - }, | |
88 | - { | |
89 | - .start = 0x200, | |
90 | - .end = 0x2ff, | |
91 | - .flags = IORESOURCE_MEM, | |
92 | - }, | |
93 | - { | |
94 | - .start = 0, | |
95 | - .end = 0, | |
96 | - .flags = IORESOURCE_IRQ, | |
97 | - }, | |
98 | -}; | |
126 | +/*--------------------------------------------------------------------------*/ | |
99 | 127 | |
100 | 128 | static struct mfd_cell tc6387xb_cells[] = { |
101 | 129 | [TC6387XB_CELL_MMC] = { |
102 | 130 | |
... | ... | @@ -111,8 +139,9 @@ |
111 | 139 | static int tc6387xb_probe(struct platform_device *dev) |
112 | 140 | { |
113 | 141 | struct tc6387xb_platform_data *pdata = dev->dev.platform_data; |
114 | - struct resource *iomem; | |
142 | + struct resource *iomem, *rscr; | |
115 | 143 | struct clk *clk32k; |
144 | + struct tc6387xb *tc6387xb; | |
116 | 145 | int irq, ret; |
117 | 146 | |
118 | 147 | iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); |
119 | 148 | |
120 | 149 | |
121 | 150 | |
122 | 151 | |
123 | 152 | |
... | ... | @@ -120,19 +149,41 @@ |
120 | 149 | return -EINVAL; |
121 | 150 | } |
122 | 151 | |
152 | + tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL); | |
153 | + if (!tc6387xb) | |
154 | + return -ENOMEM; | |
155 | + | |
123 | 156 | ret = platform_get_irq(dev, 0); |
124 | 157 | if (ret >= 0) |
125 | 158 | irq = ret; |
126 | 159 | else |
127 | - goto err_resource; | |
160 | + goto err_no_irq; | |
128 | 161 | |
129 | 162 | clk32k = clk_get(&dev->dev, "CLK_CK32K"); |
130 | 163 | if (IS_ERR(clk32k)) { |
131 | 164 | ret = PTR_ERR(clk32k); |
165 | + goto err_no_clk; | |
166 | + } | |
167 | + | |
168 | + rscr = &tc6387xb->rscr; | |
169 | + rscr->name = "tc6387xb-core"; | |
170 | + rscr->start = iomem->start; | |
171 | + rscr->end = iomem->start + 0xff; | |
172 | + rscr->flags = IORESOURCE_MEM; | |
173 | + | |
174 | + ret = request_resource(iomem, rscr); | |
175 | + if (ret) | |
132 | 176 | goto err_resource; |
177 | + | |
178 | + tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1); | |
179 | + if (!tc6387xb->scr) { | |
180 | + ret = -ENOMEM; | |
181 | + goto err_ioremap; | |
133 | 182 | } |
134 | - platform_set_drvdata(dev, clk32k); | |
135 | 183 | |
184 | + tc6387xb->clk32k = clk32k; | |
185 | + platform_set_drvdata(dev, tc6387xb); | |
186 | + | |
136 | 187 | if (pdata && pdata->enable) |
137 | 188 | pdata->enable(dev); |
138 | 189 | |
139 | 190 | |
... | ... | @@ -149,8 +200,13 @@ |
149 | 200 | if (!ret) |
150 | 201 | return 0; |
151 | 202 | |
152 | - clk_put(clk32k); | |
203 | +err_ioremap: | |
204 | + release_resource(&tc6387xb->rscr); | |
153 | 205 | err_resource: |
206 | + clk_put(clk32k); | |
207 | +err_no_clk: | |
208 | +err_no_irq: | |
209 | + kfree(tc6387xb); | |
154 | 210 | return ret; |
155 | 211 | } |
156 | 212 |
drivers/mfd/tc6393xb.c
... | ... | @@ -136,10 +136,6 @@ |
136 | 136 | return 0; |
137 | 137 | } |
138 | 138 | |
139 | -static struct tmio_mmc_data tc6393xb_mmc_data = { | |
140 | - .hclk = 24000000, | |
141 | -}; | |
142 | - | |
143 | 139 | static struct resource __devinitdata tc6393xb_nand_resources[] = { |
144 | 140 | { |
145 | 141 | .start = 0x1000, |
... | ... | @@ -165,11 +161,6 @@ |
165 | 161 | .flags = IORESOURCE_MEM, |
166 | 162 | }, |
167 | 163 | { |
168 | - .start = 0x200, | |
169 | - .end = 0x2ff, | |
170 | - .flags = IORESOURCE_MEM, | |
171 | - }, | |
172 | - { | |
173 | 164 | .start = IRQ_TC6393_MMC, |
174 | 165 | .end = IRQ_TC6393_MMC, |
175 | 166 | .flags = IORESOURCE_IRQ, |
... | ... | @@ -346,6 +337,50 @@ |
346 | 337 | } |
347 | 338 | EXPORT_SYMBOL(tc6393xb_lcd_mode); |
348 | 339 | |
340 | +static int tc6393xb_mmc_enable(struct platform_device *mmc) | |
341 | +{ | |
342 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
343 | + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | |
344 | + | |
345 | + tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, | |
346 | + tc6393xb_mmc_resources[0].start & 0xfffe); | |
347 | + | |
348 | + return 0; | |
349 | +} | |
350 | + | |
351 | +static int tc6393xb_mmc_resume(struct platform_device *mmc) | |
352 | +{ | |
353 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
354 | + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | |
355 | + | |
356 | + tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, | |
357 | + tc6393xb_mmc_resources[0].start & 0xfffe); | |
358 | + | |
359 | + return 0; | |
360 | +} | |
361 | + | |
362 | +static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) | |
363 | +{ | |
364 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
365 | + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | |
366 | + | |
367 | + tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); | |
368 | +} | |
369 | + | |
370 | +static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) | |
371 | +{ | |
372 | + struct platform_device *dev = to_platform_device(mmc->dev.parent); | |
373 | + struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | |
374 | + | |
375 | + tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); | |
376 | +} | |
377 | + | |
378 | +static struct tmio_mmc_data tc6393xb_mmc_data = { | |
379 | + .hclk = 24000000, | |
380 | + .set_pwr = tc6393xb_mmc_pwr, | |
381 | + .set_clk_div = tc6393xb_mmc_clk_div, | |
382 | +}; | |
383 | + | |
349 | 384 | static struct mfd_cell __devinitdata tc6393xb_cells[] = { |
350 | 385 | [TC6393XB_CELL_NAND] = { |
351 | 386 | .name = "tmio-nand", |
... | ... | @@ -355,6 +390,8 @@ |
355 | 390 | }, |
356 | 391 | [TC6393XB_CELL_MMC] = { |
357 | 392 | .name = "tmio-mmc", |
393 | + .enable = tc6393xb_mmc_enable, | |
394 | + .resume = tc6393xb_mmc_resume, | |
358 | 395 | .driver_data = &tc6393xb_mmc_data, |
359 | 396 | .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), |
360 | 397 | .resources = tc6393xb_mmc_resources, |
drivers/mfd/tmio_core.c
1 | +/* | |
2 | + * Copyright(c) 2009 Ian Molton <spyro@f2s.com> | |
3 | + * | |
4 | + * This program is free software; you can redistribute it and/or modify | |
5 | + * it under the terms of the GNU General Public License version 2 as | |
6 | + * published by the Free Software Foundation. | |
7 | + */ | |
8 | + | |
9 | +#include <linux/mfd/tmio.h> | |
10 | + | |
11 | +int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) | |
12 | +{ | |
13 | + /* Enable the MMC/SD Control registers */ | |
14 | + sd_config_write16(cnf, shift, CNF_CMD, SDCREN); | |
15 | + sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); | |
16 | + | |
17 | + /* Disable SD power during suspend */ | |
18 | + sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01); | |
19 | + | |
20 | + /* The below is required but why? FIXME */ | |
21 | + sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f); | |
22 | + | |
23 | + /* Power down SD bus */ | |
24 | + sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00); | |
25 | + | |
26 | + return 0; | |
27 | +} | |
28 | +EXPORT_SYMBOL(tmio_core_mmc_enable); | |
29 | + | |
30 | +int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base) | |
31 | +{ | |
32 | + | |
33 | + /* Enable the MMC/SD Control registers */ | |
34 | + sd_config_write16(cnf, shift, CNF_CMD, SDCREN); | |
35 | + sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe); | |
36 | + | |
37 | + return 0; | |
38 | +} | |
39 | +EXPORT_SYMBOL(tmio_core_mmc_resume); | |
40 | + | |
41 | +void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state) | |
42 | +{ | |
43 | + sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00); | |
44 | +} | |
45 | +EXPORT_SYMBOL(tmio_core_mmc_pwr); | |
46 | + | |
47 | +void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state) | |
48 | +{ | |
49 | + sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0); | |
50 | +} | |
51 | +EXPORT_SYMBOL(tmio_core_mmc_clk_div); |
drivers/mmc/host/tmio_mmc.c
... | ... | @@ -46,7 +46,9 @@ |
46 | 46 | clk |= 0x100; |
47 | 47 | } |
48 | 48 | |
49 | - sd_config_write8(host, CNF_SD_CLK_MODE, clk >> 22); | |
49 | + if (host->set_clk_div) | |
50 | + host->set_clk_div(host->pdev, (clk>>22) & 1); | |
51 | + | |
50 | 52 | sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff); |
51 | 53 | } |
52 | 54 | |
53 | 55 | |
... | ... | @@ -427,12 +429,13 @@ |
427 | 429 | /* Power sequence - OFF -> ON -> UP */ |
428 | 430 | switch (ios->power_mode) { |
429 | 431 | case MMC_POWER_OFF: /* power down SD bus */ |
430 | - sd_config_write8(host, CNF_PWR_CTL_2, 0x00); | |
432 | + if (host->set_pwr) | |
433 | + host->set_pwr(host->pdev, 0); | |
431 | 434 | tmio_mmc_clk_stop(host); |
432 | 435 | break; |
433 | 436 | case MMC_POWER_ON: /* power up SD bus */ |
434 | - | |
435 | - sd_config_write8(host, CNF_PWR_CTL_2, 0x02); | |
437 | + if (host->set_pwr) | |
438 | + host->set_pwr(host->pdev, 1); | |
436 | 439 | break; |
437 | 440 | case MMC_POWER_UP: /* start bus clock */ |
438 | 441 | tmio_mmc_clk_start(host); |
439 | 442 | |
440 | 443 | |
... | ... | @@ -485,21 +488,15 @@ |
485 | 488 | { |
486 | 489 | struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; |
487 | 490 | struct mmc_host *mmc = platform_get_drvdata(dev); |
488 | - struct tmio_mmc_host *host = mmc_priv(mmc); | |
489 | 491 | int ret = 0; |
490 | 492 | |
491 | 493 | /* Tell the MFD core we are ready to be enabled */ |
492 | - if (cell->enable) { | |
493 | - ret = cell->enable(dev); | |
494 | + if (cell->resume) { | |
495 | + ret = cell->resume(dev); | |
494 | 496 | if (ret) |
495 | 497 | goto out; |
496 | 498 | } |
497 | 499 | |
498 | - /* Enable the MMC/SD Control registers */ | |
499 | - sd_config_write16(host, CNF_CMD, SDCREN); | |
500 | - sd_config_write32(host, CNF_CTL_BASE, | |
501 | - (dev->resource[0].start >> host->bus_shift) & 0xfffe); | |
502 | - | |
503 | 500 | mmc_resume_host(mmc); |
504 | 501 | |
505 | 502 | out: |
506 | 503 | |
507 | 504 | |
... | ... | @@ -514,17 +511,16 @@ |
514 | 511 | { |
515 | 512 | struct mfd_cell *cell = (struct mfd_cell *)dev->dev.platform_data; |
516 | 513 | struct tmio_mmc_data *pdata; |
517 | - struct resource *res_ctl, *res_cnf; | |
514 | + struct resource *res_ctl; | |
518 | 515 | struct tmio_mmc_host *host; |
519 | 516 | struct mmc_host *mmc; |
520 | 517 | int ret = -EINVAL; |
521 | 518 | |
522 | - if (dev->num_resources != 3) | |
519 | + if (dev->num_resources != 2) | |
523 | 520 | goto out; |
524 | 521 | |
525 | 522 | res_ctl = platform_get_resource(dev, IORESOURCE_MEM, 0); |
526 | - res_cnf = platform_get_resource(dev, IORESOURCE_MEM, 1); | |
527 | - if (!res_ctl || !res_cnf) | |
523 | + if (!res_ctl) | |
528 | 524 | goto out; |
529 | 525 | |
530 | 526 | pdata = cell->driver_data; |
531 | 527 | |
... | ... | @@ -539,8 +535,12 @@ |
539 | 535 | |
540 | 536 | host = mmc_priv(mmc); |
541 | 537 | host->mmc = mmc; |
538 | + host->pdev = dev; | |
542 | 539 | platform_set_drvdata(dev, mmc); |
543 | 540 | |
541 | + host->set_pwr = pdata->set_pwr; | |
542 | + host->set_clk_div = pdata->set_clk_div; | |
543 | + | |
544 | 544 | /* SD control register space size is 0x200, 0x400 for bus_shift=1 */ |
545 | 545 | host->bus_shift = resource_size(res_ctl) >> 10; |
546 | 546 | |
... | ... | @@ -548,10 +548,6 @@ |
548 | 548 | if (!host->ctl) |
549 | 549 | goto host_free; |
550 | 550 | |
551 | - host->cnf = ioremap(res_cnf->start, resource_size(res_cnf)); | |
552 | - if (!host->cnf) | |
553 | - goto unmap_ctl; | |
554 | - | |
555 | 551 | mmc->ops = &tmio_mmc_ops; |
556 | 552 | mmc->caps = MMC_CAP_4_BIT_DATA; |
557 | 553 | mmc->f_max = pdata->hclk; |
558 | 554 | |
... | ... | @@ -562,23 +558,9 @@ |
562 | 558 | if (cell->enable) { |
563 | 559 | ret = cell->enable(dev); |
564 | 560 | if (ret) |
565 | - goto unmap_cnf; | |
561 | + goto unmap_ctl; | |
566 | 562 | } |
567 | 563 | |
568 | - /* Enable the MMC/SD Control registers */ | |
569 | - sd_config_write16(host, CNF_CMD, SDCREN); | |
570 | - sd_config_write32(host, CNF_CTL_BASE, | |
571 | - (dev->resource[0].start >> host->bus_shift) & 0xfffe); | |
572 | - | |
573 | - /* Disable SD power during suspend */ | |
574 | - sd_config_write8(host, CNF_PWR_CTL_3, 0x01); | |
575 | - | |
576 | - /* The below is required but why? FIXME */ | |
577 | - sd_config_write8(host, CNF_STOP_CLK_CTL, 0x1f); | |
578 | - | |
579 | - /* Power down SD bus*/ | |
580 | - sd_config_write8(host, CNF_PWR_CTL_2, 0x00); | |
581 | - | |
582 | 564 | tmio_mmc_clk_stop(host); |
583 | 565 | reset(host); |
584 | 566 | |
585 | 567 | |
... | ... | @@ -586,14 +568,14 @@ |
586 | 568 | if (ret >= 0) |
587 | 569 | host->irq = ret; |
588 | 570 | else |
589 | - goto unmap_cnf; | |
571 | + goto unmap_ctl; | |
590 | 572 | |
591 | 573 | disable_mmc_irqs(host, TMIO_MASK_ALL); |
592 | 574 | |
593 | 575 | ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED | |
594 | 576 | IRQF_TRIGGER_FALLING, dev_name(&dev->dev), host); |
595 | 577 | if (ret) |
596 | - goto unmap_cnf; | |
578 | + goto unmap_ctl; | |
597 | 579 | |
598 | 580 | mmc_add_host(mmc); |
599 | 581 | |
... | ... | @@ -605,8 +587,6 @@ |
605 | 587 | |
606 | 588 | return 0; |
607 | 589 | |
608 | -unmap_cnf: | |
609 | - iounmap(host->cnf); | |
610 | 590 | unmap_ctl: |
611 | 591 | iounmap(host->ctl); |
612 | 592 | host_free: |
... | ... | @@ -626,7 +606,6 @@ |
626 | 606 | mmc_remove_host(mmc); |
627 | 607 | free_irq(host->irq, host); |
628 | 608 | iounmap(host->ctl); |
629 | - iounmap(host->cnf); | |
630 | 609 | mmc_free_host(mmc); |
631 | 610 | } |
632 | 611 |
drivers/mmc/host/tmio_mmc.h
... | ... | @@ -11,26 +11,6 @@ |
11 | 11 | |
12 | 12 | #include <linux/highmem.h> |
13 | 13 | |
14 | -#define CNF_CMD 0x04 | |
15 | -#define CNF_CTL_BASE 0x10 | |
16 | -#define CNF_INT_PIN 0x3d | |
17 | -#define CNF_STOP_CLK_CTL 0x40 | |
18 | -#define CNF_GCLK_CTL 0x41 | |
19 | -#define CNF_SD_CLK_MODE 0x42 | |
20 | -#define CNF_PIN_STATUS 0x44 | |
21 | -#define CNF_PWR_CTL_1 0x48 | |
22 | -#define CNF_PWR_CTL_2 0x49 | |
23 | -#define CNF_PWR_CTL_3 0x4a | |
24 | -#define CNF_CARD_DETECT_MODE 0x4c | |
25 | -#define CNF_SD_SLOT 0x50 | |
26 | -#define CNF_EXT_GCLK_CTL_1 0xf0 | |
27 | -#define CNF_EXT_GCLK_CTL_2 0xf1 | |
28 | -#define CNF_EXT_GCLK_CTL_3 0xf9 | |
29 | -#define CNF_SD_LED_EN_1 0xfa | |
30 | -#define CNF_SD_LED_EN_2 0xfe | |
31 | - | |
32 | -#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ | |
33 | - | |
34 | 14 | #define CTL_SD_CMD 0x00 |
35 | 15 | #define CTL_ARG_REG 0x04 |
36 | 16 | #define CTL_STOP_INTERNAL_ACTION 0x08 |
... | ... | @@ -110,7 +90,6 @@ |
110 | 90 | |
111 | 91 | |
112 | 92 | struct tmio_mmc_host { |
113 | - void __iomem *cnf; | |
114 | 93 | void __iomem *ctl; |
115 | 94 | unsigned long bus_shift; |
116 | 95 | struct mmc_command *cmd; |
117 | 96 | |
... | ... | @@ -119,10 +98,16 @@ |
119 | 98 | struct mmc_host *mmc; |
120 | 99 | int irq; |
121 | 100 | |
101 | + /* Callbacks for clock / power control */ | |
102 | + void (*set_pwr)(struct platform_device *host, int state); | |
103 | + void (*set_clk_div)(struct platform_device *host, int state); | |
104 | + | |
122 | 105 | /* pio related stuff */ |
123 | 106 | struct scatterlist *sg_ptr; |
124 | 107 | unsigned int sg_len; |
125 | 108 | unsigned int sg_off; |
109 | + | |
110 | + struct platform_device *pdev; | |
126 | 111 | }; |
127 | 112 | |
128 | 113 | #include <linux/io.h> |
... | ... | @@ -161,25 +146,6 @@ |
161 | 146 | { |
162 | 147 | writew(val, host->ctl + (addr << host->bus_shift)); |
163 | 148 | writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); |
164 | -} | |
165 | - | |
166 | -static inline void sd_config_write8(struct tmio_mmc_host *host, int addr, | |
167 | - u8 val) | |
168 | -{ | |
169 | - writeb(val, host->cnf + (addr << host->bus_shift)); | |
170 | -} | |
171 | - | |
172 | -static inline void sd_config_write16(struct tmio_mmc_host *host, int addr, | |
173 | - u16 val) | |
174 | -{ | |
175 | - writew(val, host->cnf + (addr << host->bus_shift)); | |
176 | -} | |
177 | - | |
178 | -static inline void sd_config_write32(struct tmio_mmc_host *host, int addr, | |
179 | - u32 val) | |
180 | -{ | |
181 | - writew(val, host->cnf + (addr << host->bus_shift)); | |
182 | - writew(val >> 16, host->cnf + ((addr + 2) << host->bus_shift)); | |
183 | 149 | } |
184 | 150 | |
185 | 151 | #include <linux/scatterlist.h> |
include/linux/mfd/tmio.h
... | ... | @@ -2,6 +2,8 @@ |
2 | 2 | #define MFD_TMIO_H |
3 | 3 | |
4 | 4 | #include <linux/fb.h> |
5 | +#include <linux/io.h> | |
6 | +#include <linux/platform_device.h> | |
5 | 7 | |
6 | 8 | #define tmio_ioread8(addr) readb(addr) |
7 | 9 | #define tmio_ioread16(addr) readw(addr) |
8 | 10 | |
... | ... | @@ -18,11 +20,48 @@ |
18 | 20 | writew((val) >> 16, (addr) + 2); \ |
19 | 21 | } while (0) |
20 | 22 | |
23 | +#define CNF_CMD 0x04 | |
24 | +#define CNF_CTL_BASE 0x10 | |
25 | +#define CNF_INT_PIN 0x3d | |
26 | +#define CNF_STOP_CLK_CTL 0x40 | |
27 | +#define CNF_GCLK_CTL 0x41 | |
28 | +#define CNF_SD_CLK_MODE 0x42 | |
29 | +#define CNF_PIN_STATUS 0x44 | |
30 | +#define CNF_PWR_CTL_1 0x48 | |
31 | +#define CNF_PWR_CTL_2 0x49 | |
32 | +#define CNF_PWR_CTL_3 0x4a | |
33 | +#define CNF_CARD_DETECT_MODE 0x4c | |
34 | +#define CNF_SD_SLOT 0x50 | |
35 | +#define CNF_EXT_GCLK_CTL_1 0xf0 | |
36 | +#define CNF_EXT_GCLK_CTL_2 0xf1 | |
37 | +#define CNF_EXT_GCLK_CTL_3 0xf9 | |
38 | +#define CNF_SD_LED_EN_1 0xfa | |
39 | +#define CNF_SD_LED_EN_2 0xfe | |
40 | + | |
41 | +#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ | |
42 | + | |
43 | +#define sd_config_write8(base, shift, reg, val) \ | |
44 | + tmio_iowrite8((val), (base) + ((reg) << (shift))) | |
45 | +#define sd_config_write16(base, shift, reg, val) \ | |
46 | + tmio_iowrite16((val), (base) + ((reg) << (shift))) | |
47 | +#define sd_config_write32(base, shift, reg, val) \ | |
48 | + do { \ | |
49 | + tmio_iowrite16((val), (base) + ((reg) << (shift))); \ | |
50 | + tmio_iowrite16((val) >> 16, (base) + ((reg + 2) << (shift))); \ | |
51 | + } while (0) | |
52 | + | |
53 | +int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); | |
54 | +int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); | |
55 | +void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state); | |
56 | +void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state); | |
57 | + | |
21 | 58 | /* |
22 | 59 | * data for the MMC controller |
23 | 60 | */ |
24 | 61 | struct tmio_mmc_data { |
25 | 62 | const unsigned int hclk; |
63 | + void (*set_pwr)(struct platform_device *host, int state); | |
64 | + void (*set_clk_div)(struct platform_device *host, int state); | |
26 | 65 | }; |
27 | 66 | |
28 | 67 | /* |