diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/mcp-sa11x0.c | 141 |
1 files changed, 99 insertions, 42 deletions
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 703e76a77005..4d06db72bb9c 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c | |||
@@ -13,6 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/io.h> | ||
16 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
17 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
18 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
@@ -30,34 +31,44 @@ | |||
30 | #define DRIVER_NAME "sa11x0-mcp" | 31 | #define DRIVER_NAME "sa11x0-mcp" |
31 | 32 | ||
32 | struct mcp_sa11x0 { | 33 | struct mcp_sa11x0 { |
33 | u32 mccr0; | 34 | void __iomem *base0; |
34 | u32 mccr1; | 35 | void __iomem *base1; |
36 | u32 mccr0; | ||
37 | u32 mccr1; | ||
35 | }; | 38 | }; |
36 | 39 | ||
40 | /* Register offsets */ | ||
41 | #define MCCR0(m) ((m)->base0 + 0x00) | ||
42 | #define MCDR0(m) ((m)->base0 + 0x08) | ||
43 | #define MCDR1(m) ((m)->base0 + 0x0c) | ||
44 | #define MCDR2(m) ((m)->base0 + 0x10) | ||
45 | #define MCSR(m) ((m)->base0 + 0x18) | ||
46 | #define MCCR1(m) ((m)->base1 + 0x00) | ||
47 | |||
37 | #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) | 48 | #define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp)) |
38 | 49 | ||
39 | static void | 50 | static void |
40 | mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) | 51 | mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor) |
41 | { | 52 | { |
42 | unsigned int mccr0; | 53 | struct mcp_sa11x0 *m = priv(mcp); |
43 | 54 | ||
44 | divisor /= 32; | 55 | divisor /= 32; |
45 | 56 | ||
46 | mccr0 = Ser4MCCR0 & ~0x00007f00; | 57 | m->mccr0 &= ~0x00007f00; |
47 | mccr0 |= divisor << 8; | 58 | m->mccr0 |= divisor << 8; |
48 | Ser4MCCR0 = mccr0; | 59 | writel_relaxed(m->mccr0, MCCR0(m)); |
49 | } | 60 | } |
50 | 61 | ||
51 | static void | 62 | static void |
52 | mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) | 63 | mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) |
53 | { | 64 | { |
54 | unsigned int mccr0; | 65 | struct mcp_sa11x0 *m = priv(mcp); |
55 | 66 | ||
56 | divisor /= 32; | 67 | divisor /= 32; |
57 | 68 | ||
58 | mccr0 = Ser4MCCR0 & ~0x0000007f; | 69 | m->mccr0 &= ~0x0000007f; |
59 | mccr0 |= divisor; | 70 | m->mccr0 |= divisor; |
60 | Ser4MCCR0 = mccr0; | 71 | writel_relaxed(m->mccr0, MCCR0(m)); |
61 | } | 72 | } |
62 | 73 | ||
63 | /* | 74 | /* |
@@ -69,14 +80,15 @@ mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor) | |||
69 | static void | 80 | static void |
70 | mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) | 81 | mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) |
71 | { | 82 | { |
83 | struct mcp_sa11x0 *m = priv(mcp); | ||
72 | int ret = -ETIME; | 84 | int ret = -ETIME; |
73 | int i; | 85 | int i; |
74 | 86 | ||
75 | Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff); | 87 | writel_relaxed(reg << 17 | MCDR2_Wr | (val & 0xffff), MCDR2(m)); |
76 | 88 | ||
77 | for (i = 0; i < 2; i++) { | 89 | for (i = 0; i < 2; i++) { |
78 | udelay(mcp->rw_timeout); | 90 | udelay(mcp->rw_timeout); |
79 | if (Ser4MCSR & MCSR_CWC) { | 91 | if (readl_relaxed(MCSR(m)) & MCSR_CWC) { |
80 | ret = 0; | 92 | ret = 0; |
81 | break; | 93 | break; |
82 | } | 94 | } |
@@ -95,15 +107,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val) | |||
95 | static unsigned int | 107 | static unsigned int |
96 | mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) | 108 | mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) |
97 | { | 109 | { |
110 | struct mcp_sa11x0 *m = priv(mcp); | ||
98 | int ret = -ETIME; | 111 | int ret = -ETIME; |
99 | int i; | 112 | int i; |
100 | 113 | ||
101 | Ser4MCDR2 = reg << 17 | MCDR2_Rd; | 114 | writel_relaxed(reg << 17 | MCDR2_Rd, MCDR2(m)); |
102 | 115 | ||
103 | for (i = 0; i < 2; i++) { | 116 | for (i = 0; i < 2; i++) { |
104 | udelay(mcp->rw_timeout); | 117 | udelay(mcp->rw_timeout); |
105 | if (Ser4MCSR & MCSR_CRC) { | 118 | if (readl_relaxed(MCSR(m)) & MCSR_CRC) { |
106 | ret = Ser4MCDR2 & 0xffff; | 119 | ret = readl_relaxed(MCDR2(m)) & 0xffff; |
107 | break; | 120 | break; |
108 | } | 121 | } |
109 | } | 122 | } |
@@ -116,13 +129,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg) | |||
116 | 129 | ||
117 | static void mcp_sa11x0_enable(struct mcp *mcp) | 130 | static void mcp_sa11x0_enable(struct mcp *mcp) |
118 | { | 131 | { |
119 | Ser4MCSR = -1; | 132 | struct mcp_sa11x0 *m = priv(mcp); |
120 | Ser4MCCR0 |= MCCR0_MCE; | 133 | |
134 | writel(-1, MCSR(m)); | ||
135 | m->mccr0 |= MCCR0_MCE; | ||
136 | writel_relaxed(m->mccr0, MCCR0(m)); | ||
121 | } | 137 | } |
122 | 138 | ||
123 | static void mcp_sa11x0_disable(struct mcp *mcp) | 139 | static void mcp_sa11x0_disable(struct mcp *mcp) |
124 | { | 140 | { |
125 | Ser4MCCR0 &= ~MCCR0_MCE; | 141 | struct mcp_sa11x0 *m = priv(mcp); |
142 | |||
143 | m->mccr0 &= ~MCCR0_MCE; | ||
144 | writel_relaxed(m->mccr0, MCCR0(m)); | ||
126 | } | 145 | } |
127 | 146 | ||
128 | /* | 147 | /* |
@@ -137,22 +156,38 @@ static struct mcp_ops mcp_sa11x0 = { | |||
137 | .disable = mcp_sa11x0_disable, | 156 | .disable = mcp_sa11x0_disable, |
138 | }; | 157 | }; |
139 | 158 | ||
140 | static int mcp_sa11x0_probe(struct platform_device *pdev) | 159 | static int mcp_sa11x0_probe(struct platform_device *dev) |
141 | { | 160 | { |
142 | struct mcp_plat_data *data = pdev->dev.platform_data; | 161 | struct mcp_plat_data *data = dev->dev.platform_data; |
162 | struct resource *mem0, *mem1; | ||
163 | struct mcp_sa11x0 *m; | ||
143 | struct mcp *mcp; | 164 | struct mcp *mcp; |
144 | int ret; | 165 | int ret; |
145 | 166 | ||
146 | if (!data) | 167 | if (!data) |
147 | return -ENODEV; | 168 | return -ENODEV; |
148 | 169 | ||
149 | if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) | 170 | mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); |
150 | return -EBUSY; | 171 | mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); |
172 | if (!mem0 || !mem1) | ||
173 | return -ENXIO; | ||
174 | |||
175 | if (!request_mem_region(mem0->start, resource_size(mem0), | ||
176 | DRIVER_NAME)) { | ||
177 | ret = -EBUSY; | ||
178 | goto err_mem0; | ||
179 | } | ||
151 | 180 | ||
152 | mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0)); | 181 | if (!request_mem_region(mem1->start, resource_size(mem1), |
182 | DRIVER_NAME)) { | ||
183 | ret = -EBUSY; | ||
184 | goto err_mem1; | ||
185 | } | ||
186 | |||
187 | mcp = mcp_host_alloc(&dev->dev, sizeof(struct mcp_sa11x0)); | ||
153 | if (!mcp) { | 188 | if (!mcp) { |
154 | ret = -ENOMEM; | 189 | ret = -ENOMEM; |
155 | goto release; | 190 | goto err_alloc; |
156 | } | 191 | } |
157 | 192 | ||
158 | mcp->owner = THIS_MODULE; | 193 | mcp->owner = THIS_MODULE; |
@@ -160,7 +195,18 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
160 | mcp->sclk_rate = data->sclk_rate; | 195 | mcp->sclk_rate = data->sclk_rate; |
161 | mcp->gpio_base = data->gpio_base; | 196 | mcp->gpio_base = data->gpio_base; |
162 | 197 | ||
163 | platform_set_drvdata(pdev, mcp); | 198 | m = priv(mcp); |
199 | m->mccr0 = data->mccr0 | 0x7f7f; | ||
200 | m->mccr1 = data->mccr1; | ||
201 | |||
202 | m->base0 = ioremap(mem0->start, resource_size(mem0)); | ||
203 | m->base1 = ioremap(mem1->start, resource_size(mem1)); | ||
204 | if (!m->base0 || !m->base1) { | ||
205 | ret = -ENOMEM; | ||
206 | goto err_ioremap; | ||
207 | } | ||
208 | |||
209 | platform_set_drvdata(dev, mcp); | ||
164 | 210 | ||
165 | if (machine_is_assabet()) { | 211 | if (machine_is_assabet()) { |
166 | ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); | 212 | ASSABET_BCR_set(ASSABET_BCR_CODEC_RST); |
@@ -170,9 +216,9 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
170 | * Initialise device. Note that we initially | 216 | * Initialise device. Note that we initially |
171 | * set the sampling rate to minimum. | 217 | * set the sampling rate to minimum. |
172 | */ | 218 | */ |
173 | Ser4MCSR = -1; | 219 | writel_relaxed(-1, MCSR(m)); |
174 | Ser4MCCR1 = data->mccr1; | 220 | writel_relaxed(m->mccr1, MCCR1(m)); |
175 | Ser4MCCR0 = data->mccr0 | 0x7f7f; | 221 | writel_relaxed(m->mccr0, MCCR0(m)); |
176 | 222 | ||
177 | /* | 223 | /* |
178 | * Calculate the read/write timeout (us) from the bit clock | 224 | * Calculate the read/write timeout (us) from the bit clock |
@@ -184,46 +230,57 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
184 | 230 | ||
185 | ret = mcp_host_add(mcp); | 231 | ret = mcp_host_add(mcp); |
186 | if (ret == 0) | 232 | if (ret == 0) |
187 | goto out; | 233 | return 0; |
188 | 234 | ||
189 | mcp_host_free(mcp); | 235 | platform_set_drvdata(dev, NULL); |
190 | release: | ||
191 | release_mem_region(0x80060000, 0x60); | ||
192 | platform_set_drvdata(pdev, NULL); | ||
193 | 236 | ||
194 | out: | 237 | err_ioremap: |
238 | iounmap(m->base1); | ||
239 | iounmap(m->base0); | ||
240 | mcp_host_free(mcp); | ||
241 | err_alloc: | ||
242 | release_mem_region(mem1->start, resource_size(mem1)); | ||
243 | err_mem1: | ||
244 | release_mem_region(mem0->start, resource_size(mem0)); | ||
245 | err_mem0: | ||
195 | return ret; | 246 | return ret; |
196 | } | 247 | } |
197 | 248 | ||
198 | static int mcp_sa11x0_remove(struct platform_device *dev) | 249 | static int mcp_sa11x0_remove(struct platform_device *dev) |
199 | { | 250 | { |
200 | struct mcp *mcp = platform_get_drvdata(dev); | 251 | struct mcp *mcp = platform_get_drvdata(dev); |
252 | struct mcp_sa11x0 *m = priv(mcp); | ||
253 | struct resource *mem0, *mem1; | ||
254 | |||
255 | mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
256 | mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); | ||
201 | 257 | ||
202 | platform_set_drvdata(dev, NULL); | 258 | platform_set_drvdata(dev, NULL); |
203 | mcp_host_del(mcp); | 259 | mcp_host_del(mcp); |
260 | iounmap(m->base1); | ||
261 | iounmap(m->base0); | ||
204 | mcp_host_free(mcp); | 262 | mcp_host_free(mcp); |
205 | release_mem_region(0x80060000, 0x60); | 263 | release_mem_region(mem1->start, resource_size(mem1)); |
264 | release_mem_region(mem0->start, resource_size(mem0)); | ||
206 | 265 | ||
207 | return 0; | 266 | return 0; |
208 | } | 267 | } |
209 | 268 | ||
210 | static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) | 269 | static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state) |
211 | { | 270 | { |
212 | struct mcp *mcp = platform_get_drvdata(dev); | 271 | struct mcp_sa11x0 *m = priv(platform_get_drvdata(dev)); |
213 | 272 | ||
214 | priv(mcp)->mccr0 = Ser4MCCR0; | 273 | writel(m->mccr0 & ~MCCR0_MCE, MCCR0(m)); |
215 | priv(mcp)->mccr1 = Ser4MCCR1; | ||
216 | Ser4MCCR0 &= ~MCCR0_MCE; | ||
217 | 274 | ||
218 | return 0; | 275 | return 0; |
219 | } | 276 | } |
220 | 277 | ||
221 | static int mcp_sa11x0_resume(struct platform_device *dev) | 278 | static int mcp_sa11x0_resume(struct platform_device *dev) |
222 | { | 279 | { |
223 | struct mcp *mcp = platform_get_drvdata(dev); | 280 | struct mcp_sa11x0 *m = priv(platform_get_drvdata(dev)); |
224 | 281 | ||
225 | Ser4MCCR1 = priv(mcp)->mccr1; | 282 | writel_relaxed(m->mccr1, MCCR1(m)); |
226 | Ser4MCCR0 = priv(mcp)->mccr0; | 283 | writel_relaxed(m->mccr0, MCCR0(m)); |
227 | 284 | ||
228 | return 0; | 285 | return 0; |
229 | } | 286 | } |