diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/Kconfig | 11 | ||||
-rw-r--r-- | drivers/ata/Makefile | 2 | ||||
-rw-r--r-- | drivers/ata/pata_pxa.c | 411 | ||||
-rw-r--r-- | drivers/dma/Kconfig | 2 | ||||
-rw-r--r-- | drivers/dma/shdma.c | 8 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 13 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 121 | ||||
-rw-r--r-- | drivers/net/irda/sh_irda.c | 6 | ||||
-rw-r--r-- | drivers/pcmcia/Kconfig | 2 | ||||
-rw-r--r-- | drivers/pcmcia/Makefile | 1 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_balloon3.c | 158 | ||||
-rw-r--r-- | drivers/power/wm97xx_battery.c | 16 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/rtc/rtc-s3c.c | 44 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 4 | ||||
-rw-r--r-- | drivers/serial/s5pv210.c | 8 | ||||
-rw-r--r-- | drivers/serial/samsung.c | 9 | ||||
-rw-r--r-- | drivers/serial/sh-sci.c | 42 | ||||
-rw-r--r-- | drivers/serial/sh-sci.h | 29 | ||||
-rw-r--r-- | drivers/sh/Makefile | 5 | ||||
-rw-r--r-- | drivers/sh/clk-cpg.c | 58 | ||||
-rw-r--r-- | drivers/video/Kconfig | 15 | ||||
-rw-r--r-- | drivers/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/imxfb.c | 19 | ||||
-rw-r--r-- | drivers/video/sh_mipi_dsi.c | 505 | ||||
-rw-r--r-- | drivers/video/sh_mobile_hdmi.c | 1028 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 196 |
27 files changed, 2579 insertions, 145 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 8fae6afd6a3d..65e3e2708371 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig | |||
@@ -651,6 +651,17 @@ config PATA_VIA | |||
651 | 651 | ||
652 | If unsure, say N. | 652 | If unsure, say N. |
653 | 653 | ||
654 | config PATA_PXA | ||
655 | tristate "PXA DMA-capable PATA support" | ||
656 | depends on ARCH_PXA | ||
657 | help | ||
658 | This option enables support for harddrive attached to PXA CPU's bus. | ||
659 | |||
660 | NOTE: This driver utilizes PXA DMA controller, in case your hardware | ||
661 | is not capable of doing MWDMA, use pata_platform instead. | ||
662 | |||
663 | If unsure, say N. | ||
664 | |||
654 | config PATA_WINBOND | 665 | config PATA_WINBOND |
655 | tristate "Winbond SL82C105 PATA support" | 666 | tristate "Winbond SL82C105 PATA support" |
656 | depends on PCI | 667 | depends on PCI |
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 6540632bda08..158eaa961b1e 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile | |||
@@ -91,6 +91,8 @@ obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o | |||
91 | obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o | 91 | obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o |
92 | obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o | 92 | obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o |
93 | 93 | ||
94 | obj-$(CONFIG_PATA_PXA) += pata_pxa.o | ||
95 | |||
94 | # Should be last but two libata driver | 96 | # Should be last but two libata driver |
95 | obj-$(CONFIG_PATA_ACPI) += pata_acpi.o | 97 | obj-$(CONFIG_PATA_ACPI) += pata_acpi.o |
96 | # Should be last but one libata driver | 98 | # Should be last but one libata driver |
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c new file mode 100644 index 000000000000..1898c6ed4b4e --- /dev/null +++ b/drivers/ata/pata_pxa.c | |||
@@ -0,0 +1,411 @@ | |||
1 | /* | ||
2 | * Generic PXA PATA driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2, or (at your option) | ||
9 | * any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; see the file COPYING. If not, write to | ||
18 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/blkdev.h> | ||
25 | #include <linux/ata.h> | ||
26 | #include <linux/libata.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/gpio.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/completion.h> | ||
31 | |||
32 | #include <scsi/scsi_host.h> | ||
33 | |||
34 | #include <mach/pxa2xx-regs.h> | ||
35 | #include <mach/pata_pxa.h> | ||
36 | #include <mach/dma.h> | ||
37 | |||
38 | #define DRV_NAME "pata_pxa" | ||
39 | #define DRV_VERSION "0.1" | ||
40 | |||
41 | struct pata_pxa_data { | ||
42 | uint32_t dma_channel; | ||
43 | struct pxa_dma_desc *dma_desc; | ||
44 | dma_addr_t dma_desc_addr; | ||
45 | uint32_t dma_desc_id; | ||
46 | |||
47 | /* DMA IO physical address */ | ||
48 | uint32_t dma_io_addr; | ||
49 | /* PXA DREQ<0:2> pin selector */ | ||
50 | uint32_t dma_dreq; | ||
51 | /* DMA DCSR register value */ | ||
52 | uint32_t dma_dcsr; | ||
53 | |||
54 | struct completion dma_done; | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * Setup the DMA descriptors. The size is transfer capped at 4k per descriptor, | ||
59 | * if the transfer is longer, it is split into multiple chained descriptors. | ||
60 | */ | ||
61 | static void pxa_load_dmac(struct scatterlist *sg, struct ata_queued_cmd *qc) | ||
62 | { | ||
63 | struct pata_pxa_data *pd = qc->ap->private_data; | ||
64 | |||
65 | uint32_t cpu_len, seg_len; | ||
66 | dma_addr_t cpu_addr; | ||
67 | |||
68 | cpu_addr = sg_dma_address(sg); | ||
69 | cpu_len = sg_dma_len(sg); | ||
70 | |||
71 | do { | ||
72 | seg_len = (cpu_len > 0x1000) ? 0x1000 : cpu_len; | ||
73 | |||
74 | pd->dma_desc[pd->dma_desc_id].ddadr = pd->dma_desc_addr + | ||
75 | ((pd->dma_desc_id + 1) * sizeof(struct pxa_dma_desc)); | ||
76 | |||
77 | pd->dma_desc[pd->dma_desc_id].dcmd = DCMD_BURST32 | | ||
78 | DCMD_WIDTH2 | (DCMD_LENGTH & seg_len); | ||
79 | |||
80 | if (qc->tf.flags & ATA_TFLAG_WRITE) { | ||
81 | pd->dma_desc[pd->dma_desc_id].dsadr = cpu_addr; | ||
82 | pd->dma_desc[pd->dma_desc_id].dtadr = pd->dma_io_addr; | ||
83 | pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCSRCADDR | | ||
84 | DCMD_FLOWTRG; | ||
85 | } else { | ||
86 | pd->dma_desc[pd->dma_desc_id].dsadr = pd->dma_io_addr; | ||
87 | pd->dma_desc[pd->dma_desc_id].dtadr = cpu_addr; | ||
88 | pd->dma_desc[pd->dma_desc_id].dcmd |= DCMD_INCTRGADDR | | ||
89 | DCMD_FLOWSRC; | ||
90 | } | ||
91 | |||
92 | cpu_len -= seg_len; | ||
93 | cpu_addr += seg_len; | ||
94 | pd->dma_desc_id++; | ||
95 | |||
96 | } while (cpu_len); | ||
97 | |||
98 | /* Should not happen */ | ||
99 | if (seg_len & 0x1f) | ||
100 | DALGN |= (1 << pd->dma_dreq); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Prepare taskfile for submission. | ||
105 | */ | ||
106 | static void pxa_qc_prep(struct ata_queued_cmd *qc) | ||
107 | { | ||
108 | struct pata_pxa_data *pd = qc->ap->private_data; | ||
109 | int si = 0; | ||
110 | struct scatterlist *sg; | ||
111 | |||
112 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) | ||
113 | return; | ||
114 | |||
115 | pd->dma_desc_id = 0; | ||
116 | |||
117 | DCSR(pd->dma_channel) = 0; | ||
118 | DALGN &= ~(1 << pd->dma_dreq); | ||
119 | |||
120 | for_each_sg(qc->sg, sg, qc->n_elem, si) | ||
121 | pxa_load_dmac(sg, qc); | ||
122 | |||
123 | pd->dma_desc[pd->dma_desc_id - 1].ddadr = DDADR_STOP; | ||
124 | |||
125 | /* Fire IRQ only at the end of last block */ | ||
126 | pd->dma_desc[pd->dma_desc_id - 1].dcmd |= DCMD_ENDIRQEN; | ||
127 | |||
128 | DDADR(pd->dma_channel) = pd->dma_desc_addr; | ||
129 | DRCMR(pd->dma_dreq) = DRCMR_MAPVLD | pd->dma_channel; | ||
130 | |||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Configure the DMA controller, load the DMA descriptors, but don't start the | ||
135 | * DMA controller yet. Only issue the ATA command. | ||
136 | */ | ||
137 | static void pxa_bmdma_setup(struct ata_queued_cmd *qc) | ||
138 | { | ||
139 | qc->ap->ops->sff_exec_command(qc->ap, &qc->tf); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * Execute the DMA transfer. | ||
144 | */ | ||
145 | static void pxa_bmdma_start(struct ata_queued_cmd *qc) | ||
146 | { | ||
147 | struct pata_pxa_data *pd = qc->ap->private_data; | ||
148 | init_completion(&pd->dma_done); | ||
149 | DCSR(pd->dma_channel) = DCSR_RUN; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Wait until the DMA transfer completes, then stop the DMA controller. | ||
154 | */ | ||
155 | static void pxa_bmdma_stop(struct ata_queued_cmd *qc) | ||
156 | { | ||
157 | struct pata_pxa_data *pd = qc->ap->private_data; | ||
158 | |||
159 | if ((DCSR(pd->dma_channel) & DCSR_RUN) && | ||
160 | wait_for_completion_timeout(&pd->dma_done, HZ)) | ||
161 | dev_err(qc->ap->dev, "Timeout waiting for DMA completion!"); | ||
162 | |||
163 | DCSR(pd->dma_channel) = 0; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * Read DMA status. The bmdma_stop() will take care of properly finishing the | ||
168 | * DMA transfer so we always have DMA-complete interrupt here. | ||
169 | */ | ||
170 | static unsigned char pxa_bmdma_status(struct ata_port *ap) | ||
171 | { | ||
172 | struct pata_pxa_data *pd = ap->private_data; | ||
173 | unsigned char ret = ATA_DMA_INTR; | ||
174 | |||
175 | if (pd->dma_dcsr & DCSR_BUSERR) | ||
176 | ret |= ATA_DMA_ERR; | ||
177 | |||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * No IRQ register present so we do nothing. | ||
183 | */ | ||
184 | static void pxa_irq_clear(struct ata_port *ap) | ||
185 | { | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Check for ATAPI DMA. ATAPI DMA is unsupported by this driver. It's still | ||
190 | * unclear why ATAPI has DMA issues. | ||
191 | */ | ||
192 | static int pxa_check_atapi_dma(struct ata_queued_cmd *qc) | ||
193 | { | ||
194 | return -EOPNOTSUPP; | ||
195 | } | ||
196 | |||
197 | static struct scsi_host_template pxa_ata_sht = { | ||
198 | ATA_BMDMA_SHT(DRV_NAME), | ||
199 | }; | ||
200 | |||
201 | static struct ata_port_operations pxa_ata_port_ops = { | ||
202 | .inherits = &ata_bmdma_port_ops, | ||
203 | .cable_detect = ata_cable_40wire, | ||
204 | |||
205 | .bmdma_setup = pxa_bmdma_setup, | ||
206 | .bmdma_start = pxa_bmdma_start, | ||
207 | .bmdma_stop = pxa_bmdma_stop, | ||
208 | .bmdma_status = pxa_bmdma_status, | ||
209 | |||
210 | .check_atapi_dma = pxa_check_atapi_dma, | ||
211 | |||
212 | .sff_irq_clear = pxa_irq_clear, | ||
213 | |||
214 | .qc_prep = pxa_qc_prep, | ||
215 | }; | ||
216 | |||
217 | /* | ||
218 | * DMA interrupt handler. | ||
219 | */ | ||
220 | static void pxa_ata_dma_irq(int dma, void *port) | ||
221 | { | ||
222 | struct ata_port *ap = port; | ||
223 | struct pata_pxa_data *pd = ap->private_data; | ||
224 | |||
225 | pd->dma_dcsr = DCSR(dma); | ||
226 | DCSR(dma) = pd->dma_dcsr; | ||
227 | |||
228 | if (pd->dma_dcsr & DCSR_STOPSTATE) | ||
229 | complete(&pd->dma_done); | ||
230 | } | ||
231 | |||
232 | static int __devinit pxa_ata_probe(struct platform_device *pdev) | ||
233 | { | ||
234 | struct ata_host *host; | ||
235 | struct ata_port *ap; | ||
236 | struct pata_pxa_data *data; | ||
237 | struct resource *cmd_res; | ||
238 | struct resource *ctl_res; | ||
239 | struct resource *dma_res; | ||
240 | struct resource *irq_res; | ||
241 | struct pata_pxa_pdata *pdata = pdev->dev.platform_data; | ||
242 | int ret = 0; | ||
243 | |||
244 | /* | ||
245 | * Resource validation, three resources are needed: | ||
246 | * - CMD port base address | ||
247 | * - CTL port base address | ||
248 | * - DMA port base address | ||
249 | * - IRQ pin | ||
250 | */ | ||
251 | if (pdev->num_resources != 4) { | ||
252 | dev_err(&pdev->dev, "invalid number of resources\n"); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * CMD port base address | ||
258 | */ | ||
259 | cmd_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
260 | if (unlikely(cmd_res == NULL)) | ||
261 | return -EINVAL; | ||
262 | |||
263 | /* | ||
264 | * CTL port base address | ||
265 | */ | ||
266 | ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
267 | if (unlikely(ctl_res == NULL)) | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* | ||
271 | * DMA port base address | ||
272 | */ | ||
273 | dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
274 | if (unlikely(dma_res == NULL)) | ||
275 | return -EINVAL; | ||
276 | |||
277 | /* | ||
278 | * IRQ pin | ||
279 | */ | ||
280 | irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
281 | if (unlikely(irq_res == NULL)) | ||
282 | return -EINVAL; | ||
283 | |||
284 | /* | ||
285 | * Allocate the host | ||
286 | */ | ||
287 | host = ata_host_alloc(&pdev->dev, 1); | ||
288 | if (!host) | ||
289 | return -ENOMEM; | ||
290 | |||
291 | ap = host->ports[0]; | ||
292 | ap->ops = &pxa_ata_port_ops; | ||
293 | ap->pio_mask = ATA_PIO4; | ||
294 | ap->mwdma_mask = ATA_MWDMA2; | ||
295 | ap->flags = ATA_FLAG_MMIO; | ||
296 | |||
297 | ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, cmd_res->start, | ||
298 | resource_size(cmd_res)); | ||
299 | ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start, | ||
300 | resource_size(ctl_res)); | ||
301 | ap->ioaddr.bmdma_addr = devm_ioremap(&pdev->dev, dma_res->start, | ||
302 | resource_size(dma_res)); | ||
303 | |||
304 | /* | ||
305 | * Adjust register offsets | ||
306 | */ | ||
307 | ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; | ||
308 | ap->ioaddr.data_addr = ap->ioaddr.cmd_addr + | ||
309 | (ATA_REG_DATA << pdata->reg_shift); | ||
310 | ap->ioaddr.error_addr = ap->ioaddr.cmd_addr + | ||
311 | (ATA_REG_ERR << pdata->reg_shift); | ||
312 | ap->ioaddr.feature_addr = ap->ioaddr.cmd_addr + | ||
313 | (ATA_REG_FEATURE << pdata->reg_shift); | ||
314 | ap->ioaddr.nsect_addr = ap->ioaddr.cmd_addr + | ||
315 | (ATA_REG_NSECT << pdata->reg_shift); | ||
316 | ap->ioaddr.lbal_addr = ap->ioaddr.cmd_addr + | ||
317 | (ATA_REG_LBAL << pdata->reg_shift); | ||
318 | ap->ioaddr.lbam_addr = ap->ioaddr.cmd_addr + | ||
319 | (ATA_REG_LBAM << pdata->reg_shift); | ||
320 | ap->ioaddr.lbah_addr = ap->ioaddr.cmd_addr + | ||
321 | (ATA_REG_LBAH << pdata->reg_shift); | ||
322 | ap->ioaddr.device_addr = ap->ioaddr.cmd_addr + | ||
323 | (ATA_REG_DEVICE << pdata->reg_shift); | ||
324 | ap->ioaddr.status_addr = ap->ioaddr.cmd_addr + | ||
325 | (ATA_REG_STATUS << pdata->reg_shift); | ||
326 | ap->ioaddr.command_addr = ap->ioaddr.cmd_addr + | ||
327 | (ATA_REG_CMD << pdata->reg_shift); | ||
328 | |||
329 | /* | ||
330 | * Allocate and load driver's internal data structure | ||
331 | */ | ||
332 | data = devm_kzalloc(&pdev->dev, sizeof(struct pata_pxa_data), | ||
333 | GFP_KERNEL); | ||
334 | if (!data) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | ap->private_data = data; | ||
338 | data->dma_dreq = pdata->dma_dreq; | ||
339 | data->dma_io_addr = dma_res->start; | ||
340 | |||
341 | /* | ||
342 | * Allocate space for the DMA descriptors | ||
343 | */ | ||
344 | data->dma_desc = dmam_alloc_coherent(&pdev->dev, PAGE_SIZE, | ||
345 | &data->dma_desc_addr, GFP_KERNEL); | ||
346 | if (!data->dma_desc) | ||
347 | return -EINVAL; | ||
348 | |||
349 | /* | ||
350 | * Request the DMA channel | ||
351 | */ | ||
352 | data->dma_channel = pxa_request_dma(DRV_NAME, DMA_PRIO_LOW, | ||
353 | pxa_ata_dma_irq, ap); | ||
354 | if (data->dma_channel < 0) | ||
355 | return -EBUSY; | ||
356 | |||
357 | /* | ||
358 | * Stop and clear the DMA channel | ||
359 | */ | ||
360 | DCSR(data->dma_channel) = 0; | ||
361 | |||
362 | /* | ||
363 | * Activate the ATA host | ||
364 | */ | ||
365 | ret = ata_host_activate(host, irq_res->start, ata_sff_interrupt, | ||
366 | pdata->irq_flags, &pxa_ata_sht); | ||
367 | if (ret) | ||
368 | pxa_free_dma(data->dma_channel); | ||
369 | |||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | static int __devexit pxa_ata_remove(struct platform_device *pdev) | ||
374 | { | ||
375 | struct ata_host *host = dev_get_drvdata(&pdev->dev); | ||
376 | struct pata_pxa_data *data = host->ports[0]->private_data; | ||
377 | |||
378 | pxa_free_dma(data->dma_channel); | ||
379 | |||
380 | ata_host_detach(host); | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static struct platform_driver pxa_ata_driver = { | ||
386 | .probe = pxa_ata_probe, | ||
387 | .remove = __devexit_p(pxa_ata_remove), | ||
388 | .driver = { | ||
389 | .name = DRV_NAME, | ||
390 | .owner = THIS_MODULE, | ||
391 | }, | ||
392 | }; | ||
393 | |||
394 | static int __init pxa_ata_init(void) | ||
395 | { | ||
396 | return platform_driver_register(&pxa_ata_driver); | ||
397 | } | ||
398 | |||
399 | static void __exit pxa_ata_exit(void) | ||
400 | { | ||
401 | platform_driver_unregister(&pxa_ata_driver); | ||
402 | } | ||
403 | |||
404 | module_init(pxa_ata_init); | ||
405 | module_exit(pxa_ata_exit); | ||
406 | |||
407 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
408 | MODULE_DESCRIPTION("DMA-capable driver for PATA on PXA CPU"); | ||
409 | MODULE_LICENSE("GPL"); | ||
410 | MODULE_VERSION(DRV_VERSION); | ||
411 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index fed57634b6c1..9520cf02edc8 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig | |||
@@ -141,7 +141,7 @@ config TXX9_DMAC | |||
141 | 141 | ||
142 | config SH_DMAE | 142 | config SH_DMAE |
143 | tristate "Renesas SuperH DMAC support" | 143 | tristate "Renesas SuperH DMAC support" |
144 | depends on SUPERH && SH_DMA | 144 | depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE) |
145 | depends on !SH_DMA_API | 145 | depends on !SH_DMA_API |
146 | select DMA_ENGINE | 146 | select DMA_ENGINE |
147 | help | 147 | help |
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c index a2a519fd2a24..fb64cf36ba61 100644 --- a/drivers/dma/shdma.c +++ b/drivers/dma/shdma.c | |||
@@ -816,7 +816,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data) | |||
816 | return ret; | 816 | return ret; |
817 | } | 817 | } |
818 | 818 | ||
819 | #if defined(CONFIG_CPU_SH4) | 819 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) |
820 | static irqreturn_t sh_dmae_err(int irq, void *data) | 820 | static irqreturn_t sh_dmae_err(int irq, void *data) |
821 | { | 821 | { |
822 | struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; | 822 | struct sh_dmae_device *shdev = (struct sh_dmae_device *)data; |
@@ -1057,7 +1057,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) | |||
1057 | /* Default transfer size of 32 bytes requires 32-byte alignment */ | 1057 | /* Default transfer size of 32 bytes requires 32-byte alignment */ |
1058 | shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; | 1058 | shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE; |
1059 | 1059 | ||
1060 | #if defined(CONFIG_CPU_SH4) | 1060 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) |
1061 | chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); | 1061 | chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); |
1062 | 1062 | ||
1063 | if (!chanirq_res) | 1063 | if (!chanirq_res) |
@@ -1082,7 +1082,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) | |||
1082 | 1082 | ||
1083 | #else | 1083 | #else |
1084 | chanirq_res = errirq_res; | 1084 | chanirq_res = errirq_res; |
1085 | #endif /* CONFIG_CPU_SH4 */ | 1085 | #endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */ |
1086 | 1086 | ||
1087 | if (chanirq_res->start == chanirq_res->end && | 1087 | if (chanirq_res->start == chanirq_res->end && |
1088 | !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { | 1088 | !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { |
@@ -1129,7 +1129,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev) | |||
1129 | chan_probe_err: | 1129 | chan_probe_err: |
1130 | sh_dmae_chan_remove(shdev); | 1130 | sh_dmae_chan_remove(shdev); |
1131 | eirqres: | 1131 | eirqres: |
1132 | #if defined(CONFIG_CPU_SH4) | 1132 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) |
1133 | free_irq(errirq, shdev); | 1133 | free_irq(errirq, shdev); |
1134 | eirq_err: | 1134 | eirq_err: |
1135 | #endif | 1135 | #endif |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index bceafbfa7268..15a9702e2941 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -521,12 +521,19 @@ config I2C_PXA_SLAVE | |||
521 | is necessary for systems where the PXA may be a target on the | 521 | is necessary for systems where the PXA may be a target on the |
522 | I2C bus. | 522 | I2C bus. |
523 | 523 | ||
524 | config HAVE_S3C2410_I2C | ||
525 | bool | ||
526 | help | ||
527 | This will include I2C support for Samsung SoCs. If you want to | ||
528 | include I2C support for any machine, kindly select this in the | ||
529 | respective Kconfig file. | ||
530 | |||
524 | config I2C_S3C2410 | 531 | config I2C_S3C2410 |
525 | tristate "S3C2410 I2C Driver" | 532 | tristate "S3C2410 I2C Driver" |
526 | depends on ARCH_S3C2410 || ARCH_S3C64XX | 533 | depends on HAVE_S3C2410_I2C |
527 | help | 534 | help |
528 | Say Y here to include support for I2C controller in the | 535 | Say Y here to include support for I2C controller in the |
529 | Samsung S3C2410 based System-on-Chip devices. | 536 | Samsung SoCs. |
530 | 537 | ||
531 | config I2C_S6000 | 538 | config I2C_S6000 |
532 | tristate "S6000 I2C support" | 539 | tristate "S6000 I2C support" |
@@ -549,7 +556,7 @@ config I2C_SH7760 | |||
549 | 556 | ||
550 | config I2C_SH_MOBILE | 557 | config I2C_SH_MOBILE |
551 | tristate "SuperH Mobile I2C Controller" | 558 | tristate "SuperH Mobile I2C Controller" |
552 | depends on SUPERH | 559 | depends on SUPERH || ARCH_SHMOBILE |
553 | help | 560 | help |
554 | If you say yes to this option, support will be included for the | 561 | If you say yes to this option, support will be included for the |
555 | built-in I2C interface on the Renesas SH-Mobile processor. | 562 | built-in I2C interface on the Renesas SH-Mobile processor. |
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index ffb405d7c6f2..598c49acaeb5 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c | |||
@@ -119,8 +119,10 @@ struct sh_mobile_i2c_data { | |||
119 | struct i2c_adapter adap; | 119 | struct i2c_adapter adap; |
120 | 120 | ||
121 | struct clk *clk; | 121 | struct clk *clk; |
122 | u_int8_t icic; | ||
122 | u_int8_t iccl; | 123 | u_int8_t iccl; |
123 | u_int8_t icch; | 124 | u_int8_t icch; |
125 | u_int8_t flags; | ||
124 | 126 | ||
125 | spinlock_t lock; | 127 | spinlock_t lock; |
126 | wait_queue_head_t wait; | 128 | wait_queue_head_t wait; |
@@ -129,15 +131,17 @@ struct sh_mobile_i2c_data { | |||
129 | int sr; | 131 | int sr; |
130 | }; | 132 | }; |
131 | 133 | ||
134 | #define IIC_FLAG_HAS_ICIC67 (1 << 0) | ||
135 | |||
132 | #define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ | 136 | #define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */ |
133 | 137 | ||
134 | /* Register offsets */ | 138 | /* Register offsets */ |
135 | #define ICDR(pd) (pd->reg + 0x00) | 139 | #define ICDR 0x00 |
136 | #define ICCR(pd) (pd->reg + 0x04) | 140 | #define ICCR 0x04 |
137 | #define ICSR(pd) (pd->reg + 0x08) | 141 | #define ICSR 0x08 |
138 | #define ICIC(pd) (pd->reg + 0x0c) | 142 | #define ICIC 0x0c |
139 | #define ICCL(pd) (pd->reg + 0x10) | 143 | #define ICCL 0x10 |
140 | #define ICCH(pd) (pd->reg + 0x14) | 144 | #define ICCH 0x14 |
141 | 145 | ||
142 | /* Register bits */ | 146 | /* Register bits */ |
143 | #define ICCR_ICE 0x80 | 147 | #define ICCR_ICE 0x80 |
@@ -155,11 +159,32 @@ struct sh_mobile_i2c_data { | |||
155 | #define ICSR_WAIT 0x02 | 159 | #define ICSR_WAIT 0x02 |
156 | #define ICSR_DTE 0x01 | 160 | #define ICSR_DTE 0x01 |
157 | 161 | ||
162 | #define ICIC_ICCLB8 0x80 | ||
163 | #define ICIC_ICCHB8 0x40 | ||
158 | #define ICIC_ALE 0x08 | 164 | #define ICIC_ALE 0x08 |
159 | #define ICIC_TACKE 0x04 | 165 | #define ICIC_TACKE 0x04 |
160 | #define ICIC_WAITE 0x02 | 166 | #define ICIC_WAITE 0x02 |
161 | #define ICIC_DTEE 0x01 | 167 | #define ICIC_DTEE 0x01 |
162 | 168 | ||
169 | static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data) | ||
170 | { | ||
171 | if (offs == ICIC) | ||
172 | data |= pd->icic; | ||
173 | |||
174 | iowrite8(data, pd->reg + offs); | ||
175 | } | ||
176 | |||
177 | static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs) | ||
178 | { | ||
179 | return ioread8(pd->reg + offs); | ||
180 | } | ||
181 | |||
182 | static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, | ||
183 | unsigned char set, unsigned char clr) | ||
184 | { | ||
185 | iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); | ||
186 | } | ||
187 | |||
163 | static void activate_ch(struct sh_mobile_i2c_data *pd) | 188 | static void activate_ch(struct sh_mobile_i2c_data *pd) |
164 | { | 189 | { |
165 | unsigned long i2c_clk; | 190 | unsigned long i2c_clk; |
@@ -187,6 +212,14 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) | |||
187 | else | 212 | else |
188 | pd->iccl = (u_int8_t)(num/denom); | 213 | pd->iccl = (u_int8_t)(num/denom); |
189 | 214 | ||
215 | /* one more bit of ICCL in ICIC */ | ||
216 | if (pd->flags & IIC_FLAG_HAS_ICIC67) { | ||
217 | if ((num/denom) > 0xff) | ||
218 | pd->icic |= ICIC_ICCLB8; | ||
219 | else | ||
220 | pd->icic &= ~ICIC_ICCLB8; | ||
221 | } | ||
222 | |||
190 | /* Calculate the value for icch. From the data sheet: | 223 | /* Calculate the value for icch. From the data sheet: |
191 | icch = (p clock / transfer rate) * (H / (L + H)) */ | 224 | icch = (p clock / transfer rate) * (H / (L + H)) */ |
192 | num = i2c_clk * 4; | 225 | num = i2c_clk * 4; |
@@ -196,25 +229,33 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) | |||
196 | else | 229 | else |
197 | pd->icch = (u_int8_t)(num/denom); | 230 | pd->icch = (u_int8_t)(num/denom); |
198 | 231 | ||
232 | /* one more bit of ICCH in ICIC */ | ||
233 | if (pd->flags & IIC_FLAG_HAS_ICIC67) { | ||
234 | if ((num/denom) > 0xff) | ||
235 | pd->icic |= ICIC_ICCHB8; | ||
236 | else | ||
237 | pd->icic &= ~ICIC_ICCHB8; | ||
238 | } | ||
239 | |||
199 | /* Enable channel and configure rx ack */ | 240 | /* Enable channel and configure rx ack */ |
200 | iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); | 241 | iic_set_clr(pd, ICCR, ICCR_ICE, 0); |
201 | 242 | ||
202 | /* Mask all interrupts */ | 243 | /* Mask all interrupts */ |
203 | iowrite8(0, ICIC(pd)); | 244 | iic_wr(pd, ICIC, 0); |
204 | 245 | ||
205 | /* Set the clock */ | 246 | /* Set the clock */ |
206 | iowrite8(pd->iccl, ICCL(pd)); | 247 | iic_wr(pd, ICCL, pd->iccl); |
207 | iowrite8(pd->icch, ICCH(pd)); | 248 | iic_wr(pd, ICCH, pd->icch); |
208 | } | 249 | } |
209 | 250 | ||
210 | static void deactivate_ch(struct sh_mobile_i2c_data *pd) | 251 | static void deactivate_ch(struct sh_mobile_i2c_data *pd) |
211 | { | 252 | { |
212 | /* Clear/disable interrupts */ | 253 | /* Clear/disable interrupts */ |
213 | iowrite8(0, ICSR(pd)); | 254 | iic_wr(pd, ICSR, 0); |
214 | iowrite8(0, ICIC(pd)); | 255 | iic_wr(pd, ICIC, 0); |
215 | 256 | ||
216 | /* Disable channel */ | 257 | /* Disable channel */ |
217 | iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); | 258 | iic_set_clr(pd, ICCR, 0, ICCR_ICE); |
218 | 259 | ||
219 | /* Disable clock and mark device as idle */ | 260 | /* Disable clock and mark device as idle */ |
220 | clk_disable(pd->clk); | 261 | clk_disable(pd->clk); |
@@ -233,35 +274,35 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, | |||
233 | 274 | ||
234 | switch (op) { | 275 | switch (op) { |
235 | case OP_START: /* issue start and trigger DTE interrupt */ | 276 | case OP_START: /* issue start and trigger DTE interrupt */ |
236 | iowrite8(0x94, ICCR(pd)); | 277 | iic_wr(pd, ICCR, 0x94); |
237 | break; | 278 | break; |
238 | case OP_TX_FIRST: /* disable DTE interrupt and write data */ | 279 | case OP_TX_FIRST: /* disable DTE interrupt and write data */ |
239 | iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd)); | 280 | iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE); |
240 | iowrite8(data, ICDR(pd)); | 281 | iic_wr(pd, ICDR, data); |
241 | break; | 282 | break; |
242 | case OP_TX: /* write data */ | 283 | case OP_TX: /* write data */ |
243 | iowrite8(data, ICDR(pd)); | 284 | iic_wr(pd, ICDR, data); |
244 | break; | 285 | break; |
245 | case OP_TX_STOP: /* write data and issue a stop afterwards */ | 286 | case OP_TX_STOP: /* write data and issue a stop afterwards */ |
246 | iowrite8(data, ICDR(pd)); | 287 | iic_wr(pd, ICDR, data); |
247 | iowrite8(0x90, ICCR(pd)); | 288 | iic_wr(pd, ICCR, 0x90); |
248 | break; | 289 | break; |
249 | case OP_TX_TO_RX: /* select read mode */ | 290 | case OP_TX_TO_RX: /* select read mode */ |
250 | iowrite8(0x81, ICCR(pd)); | 291 | iic_wr(pd, ICCR, 0x81); |
251 | break; | 292 | break; |
252 | case OP_RX: /* just read data */ | 293 | case OP_RX: /* just read data */ |
253 | ret = ioread8(ICDR(pd)); | 294 | ret = iic_rd(pd, ICDR); |
254 | break; | 295 | break; |
255 | case OP_RX_STOP: /* enable DTE interrupt, issue stop */ | 296 | case OP_RX_STOP: /* enable DTE interrupt, issue stop */ |
256 | iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, | 297 | iic_wr(pd, ICIC, |
257 | ICIC(pd)); | 298 | ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); |
258 | iowrite8(0xc0, ICCR(pd)); | 299 | iic_wr(pd, ICCR, 0xc0); |
259 | break; | 300 | break; |
260 | case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ | 301 | case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ |
261 | iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE, | 302 | iic_wr(pd, ICIC, |
262 | ICIC(pd)); | 303 | ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); |
263 | ret = ioread8(ICDR(pd)); | 304 | ret = iic_rd(pd, ICDR); |
264 | iowrite8(0xc0, ICCR(pd)); | 305 | iic_wr(pd, ICCR, 0xc0); |
265 | break; | 306 | break; |
266 | } | 307 | } |
267 | 308 | ||
@@ -367,7 +408,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) | |||
367 | unsigned char sr; | 408 | unsigned char sr; |
368 | int wakeup; | 409 | int wakeup; |
369 | 410 | ||
370 | sr = ioread8(ICSR(pd)); | 411 | sr = iic_rd(pd, ICSR); |
371 | pd->sr |= sr; /* remember state */ | 412 | pd->sr |= sr; /* remember state */ |
372 | 413 | ||
373 | dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, | 414 | dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, |
@@ -376,7 +417,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) | |||
376 | 417 | ||
377 | if (sr & (ICSR_AL | ICSR_TACK)) { | 418 | if (sr & (ICSR_AL | ICSR_TACK)) { |
378 | /* don't interrupt transaction - continue to issue stop */ | 419 | /* don't interrupt transaction - continue to issue stop */ |
379 | iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd)); | 420 | iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK)); |
380 | wakeup = 0; | 421 | wakeup = 0; |
381 | } else if (pd->msg->flags & I2C_M_RD) | 422 | } else if (pd->msg->flags & I2C_M_RD) |
382 | wakeup = sh_mobile_i2c_isr_rx(pd); | 423 | wakeup = sh_mobile_i2c_isr_rx(pd); |
@@ -384,7 +425,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) | |||
384 | wakeup = sh_mobile_i2c_isr_tx(pd); | 425 | wakeup = sh_mobile_i2c_isr_tx(pd); |
385 | 426 | ||
386 | if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ | 427 | if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */ |
387 | iowrite8(sr & ~ICSR_WAIT, ICSR(pd)); | 428 | iic_wr(pd, ICSR, sr & ~ICSR_WAIT); |
388 | 429 | ||
389 | if (wakeup) { | 430 | if (wakeup) { |
390 | pd->sr |= SW_DONE; | 431 | pd->sr |= SW_DONE; |
@@ -402,21 +443,21 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg) | |||
402 | } | 443 | } |
403 | 444 | ||
404 | /* Initialize channel registers */ | 445 | /* Initialize channel registers */ |
405 | iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); | 446 | iic_set_clr(pd, ICCR, 0, ICCR_ICE); |
406 | 447 | ||
407 | /* Enable channel and configure rx ack */ | 448 | /* Enable channel and configure rx ack */ |
408 | iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd)); | 449 | iic_set_clr(pd, ICCR, ICCR_ICE, 0); |
409 | 450 | ||
410 | /* Set the clock */ | 451 | /* Set the clock */ |
411 | iowrite8(pd->iccl, ICCL(pd)); | 452 | iic_wr(pd, ICCL, pd->iccl); |
412 | iowrite8(pd->icch, ICCH(pd)); | 453 | iic_wr(pd, ICCH, pd->icch); |
413 | 454 | ||
414 | pd->msg = usr_msg; | 455 | pd->msg = usr_msg; |
415 | pd->pos = -1; | 456 | pd->pos = -1; |
416 | pd->sr = 0; | 457 | pd->sr = 0; |
417 | 458 | ||
418 | /* Enable all interrupts to begin with */ | 459 | /* Enable all interrupts to begin with */ |
419 | iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd)); | 460 | iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); |
420 | return 0; | 461 | return 0; |
421 | } | 462 | } |
422 | 463 | ||
@@ -451,7 +492,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, | |||
451 | 492 | ||
452 | retry_count = 1000; | 493 | retry_count = 1000; |
453 | again: | 494 | again: |
454 | val = ioread8(ICSR(pd)); | 495 | val = iic_rd(pd, ICSR); |
455 | 496 | ||
456 | dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); | 497 | dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr); |
457 | 498 | ||
@@ -576,6 +617,12 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) | |||
576 | goto err_irq; | 617 | goto err_irq; |
577 | } | 618 | } |
578 | 619 | ||
620 | /* The IIC blocks on SH-Mobile ARM processors | ||
621 | * come with two new bits in ICIC. | ||
622 | */ | ||
623 | if (size > 0x17) | ||
624 | pd->flags |= IIC_FLAG_HAS_ICIC67; | ||
625 | |||
579 | /* Enable Runtime PM for this device. | 626 | /* Enable Runtime PM for this device. |
580 | * | 627 | * |
581 | * Also tell the Runtime PM core to ignore children | 628 | * Also tell the Runtime PM core to ignore children |
diff --git a/drivers/net/irda/sh_irda.c b/drivers/net/irda/sh_irda.c index edd5666f0ffb..9e3f4f54281d 100644 --- a/drivers/net/irda/sh_irda.c +++ b/drivers/net/irda/sh_irda.c | |||
@@ -748,7 +748,6 @@ static int __devinit sh_irda_probe(struct platform_device *pdev) | |||
748 | struct net_device *ndev; | 748 | struct net_device *ndev; |
749 | struct sh_irda_self *self; | 749 | struct sh_irda_self *self; |
750 | struct resource *res; | 750 | struct resource *res; |
751 | char clk_name[8]; | ||
752 | int irq; | 751 | int irq; |
753 | int err = -ENOMEM; | 752 | int err = -ENOMEM; |
754 | 753 | ||
@@ -775,10 +774,9 @@ static int __devinit sh_irda_probe(struct platform_device *pdev) | |||
775 | if (err) | 774 | if (err) |
776 | goto err_mem_2; | 775 | goto err_mem_2; |
777 | 776 | ||
778 | snprintf(clk_name, sizeof(clk_name), "irda%d", pdev->id); | 777 | self->clk = clk_get(&pdev->dev, NULL); |
779 | self->clk = clk_get(&pdev->dev, clk_name); | ||
780 | if (IS_ERR(self->clk)) { | 778 | if (IS_ERR(self->clk)) { |
781 | dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); | 779 | dev_err(&pdev->dev, "cannot get irda clock\n"); |
782 | goto err_mem_3; | 780 | goto err_mem_3; |
783 | } | 781 | } |
784 | 782 | ||
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index c988514eb551..c80a7a6e7698 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -215,7 +215,7 @@ config PCMCIA_PXA2XX | |||
215 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ | 215 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ |
216 | || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ | 216 | || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ |
217 | || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \ | 217 | || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \ |
218 | || MACH_VPAC270) | 218 | || MACH_VPAC270 || MACH_BALLOON3) |
219 | select PCMCIA_SOC_COMMON | 219 | select PCMCIA_SOC_COMMON |
220 | help | 220 | help |
221 | Say Y here to include support for the PXA2xx PCMCIA controller | 221 | Say Y here to include support for the PXA2xx PCMCIA controller |
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 7a2b1604bf1c..8d9386a22eb3 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -69,6 +69,7 @@ pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o | |||
69 | pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o | 69 | pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o |
70 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o | 70 | pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o |
71 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o | 71 | pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o |
72 | pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o | ||
72 | 73 | ||
73 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) | 74 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y) |
74 | 75 | ||
diff --git a/drivers/pcmcia/pxa2xx_balloon3.c b/drivers/pcmcia/pxa2xx_balloon3.c new file mode 100644 index 000000000000..dbbdd0063202 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_balloon3.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_balloon3.c | ||
3 | * | ||
4 | * Balloon3 PCMCIA specific routines. | ||
5 | * | ||
6 | * Author: Nick Bane | ||
7 | * Created: June, 2006 | ||
8 | * Copyright: Toby Churchill Ltd | ||
9 | * Derived from pxa2xx_mainstone.c, by Nico Pitre | ||
10 | * | ||
11 | * Various modification by Marek Vasut <marek.vasut@gmail.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/gpio.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/io.h> | ||
25 | |||
26 | #include <mach/balloon3.h> | ||
27 | |||
28 | #include "soc_common.h" | ||
29 | |||
30 | /* | ||
31 | * These are a list of interrupt sources that provokes a polled | ||
32 | * check of status | ||
33 | */ | ||
34 | static struct pcmcia_irqs irqs[] = { | ||
35 | { 0, BALLOON3_S0_CD_IRQ, "PCMCIA0 CD" }, | ||
36 | { 0, BALLOON3_BP_NSTSCHG_IRQ, "PCMCIA0 STSCHG" }, | ||
37 | }; | ||
38 | |||
39 | static int balloon3_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
40 | { | ||
41 | uint16_t ver; | ||
42 | int ret; | ||
43 | static void __iomem *fpga_ver; | ||
44 | |||
45 | ver = __raw_readw(BALLOON3_FPGA_VER); | ||
46 | if (ver > 0x0201) | ||
47 | pr_warn("The FPGA code, version 0x%04x, is newer than rel-0.3. " | ||
48 | "PCMCIA/CF support might be broken in this version!", | ||
49 | ver); | ||
50 | |||
51 | skt->socket.pci_irq = BALLOON3_BP_CF_NRDY_IRQ; | ||
52 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
53 | } | ||
54 | |||
55 | static void balloon3_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
56 | { | ||
57 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
58 | } | ||
59 | |||
60 | static unsigned long balloon3_pcmcia_status[2] = { | ||
61 | BALLOON3_CF_nSTSCHG_BVD1, | ||
62 | BALLOON3_CF_nSTSCHG_BVD1 | ||
63 | }; | ||
64 | |||
65 | static void balloon3_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
66 | struct pcmcia_state *state) | ||
67 | { | ||
68 | uint16_t status; | ||
69 | int flip; | ||
70 | |||
71 | /* This actually reads the STATUS register */ | ||
72 | status = __raw_readw(BALLOON3_CF_STATUS_REG); | ||
73 | flip = (status ^ balloon3_pcmcia_status[skt->nr]) | ||
74 | & BALLOON3_CF_nSTSCHG_BVD1; | ||
75 | /* | ||
76 | * Workaround for STSCHG which can't be deasserted: | ||
77 | * We therefore disable/enable corresponding IRQs | ||
78 | * as needed to avoid IRQ locks. | ||
79 | */ | ||
80 | if (flip) { | ||
81 | balloon3_pcmcia_status[skt->nr] = status; | ||
82 | if (status & BALLOON3_CF_nSTSCHG_BVD1) | ||
83 | enable_irq(BALLOON3_BP_NSTSCHG_IRQ); | ||
84 | else | ||
85 | disable_irq(BALLOON3_BP_NSTSCHG_IRQ); | ||
86 | } | ||
87 | |||
88 | state->detect = !gpio_get_value(BALLOON3_GPIO_S0_CD); | ||
89 | state->ready = !!(status & BALLOON3_CF_nIRQ); | ||
90 | state->bvd1 = !!(status & BALLOON3_CF_nSTSCHG_BVD1); | ||
91 | state->bvd2 = 0; /* not available */ | ||
92 | state->vs_3v = 1; /* Always true its a CF card */ | ||
93 | state->vs_Xv = 0; /* not available */ | ||
94 | state->wrprot = 0; /* not available */ | ||
95 | } | ||
96 | |||
97 | static int balloon3_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
98 | const socket_state_t *state) | ||
99 | { | ||
100 | __raw_writew((state->flags & SS_RESET) ? BALLOON3_CF_RESET : 0, | ||
101 | BALLOON3_CF_CONTROL_REG); | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static void balloon3_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
106 | { | ||
107 | } | ||
108 | |||
109 | static void balloon3_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
110 | { | ||
111 | } | ||
112 | |||
113 | static struct pcmcia_low_level balloon3_pcmcia_ops = { | ||
114 | .owner = THIS_MODULE, | ||
115 | .hw_init = balloon3_pcmcia_hw_init, | ||
116 | .hw_shutdown = balloon3_pcmcia_hw_shutdown, | ||
117 | .socket_state = balloon3_pcmcia_socket_state, | ||
118 | .configure_socket = balloon3_pcmcia_configure_socket, | ||
119 | .socket_init = balloon3_pcmcia_socket_init, | ||
120 | .socket_suspend = balloon3_pcmcia_socket_suspend, | ||
121 | .first = 0, | ||
122 | .nr = 1, | ||
123 | }; | ||
124 | |||
125 | static struct platform_device *balloon3_pcmcia_device; | ||
126 | |||
127 | static int __init balloon3_pcmcia_init(void) | ||
128 | { | ||
129 | int ret; | ||
130 | |||
131 | balloon3_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
132 | if (!balloon3_pcmcia_device) | ||
133 | return -ENOMEM; | ||
134 | |||
135 | ret = platform_device_add_data(balloon3_pcmcia_device, | ||
136 | &balloon3_pcmcia_ops, sizeof(balloon3_pcmcia_ops)); | ||
137 | |||
138 | if (!ret) | ||
139 | ret = platform_device_add(balloon3_pcmcia_device); | ||
140 | |||
141 | if (ret) | ||
142 | platform_device_put(balloon3_pcmcia_device); | ||
143 | |||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static void __exit balloon3_pcmcia_exit(void) | ||
148 | { | ||
149 | platform_device_unregister(balloon3_pcmcia_device); | ||
150 | } | ||
151 | |||
152 | module_init(balloon3_pcmcia_init); | ||
153 | module_exit(balloon3_pcmcia_exit); | ||
154 | |||
155 | MODULE_LICENSE("GPL"); | ||
156 | MODULE_AUTHOR("Nick Bane <nick@cecomputing.co.uk>"); | ||
157 | MODULE_ALIAS("platform:pxa2xx-pcmcia"); | ||
158 | MODULE_DESCRIPTION("Balloon3 board CF/PCMCIA driver"); | ||
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index 4e8afce0c818..5071d85ec12d 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c | |||
@@ -29,7 +29,6 @@ static DEFINE_MUTEX(bat_lock); | |||
29 | static struct work_struct bat_work; | 29 | static struct work_struct bat_work; |
30 | static struct mutex work_lock; | 30 | static struct mutex work_lock; |
31 | static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; | 31 | static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; |
32 | static struct wm97xx_batt_info *gpdata; | ||
33 | static enum power_supply_property *prop; | 32 | static enum power_supply_property *prop; |
34 | 33 | ||
35 | static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) | 34 | static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) |
@@ -172,12 +171,6 @@ static int __devinit wm97xx_bat_probe(struct platform_device *dev) | |||
172 | struct wm97xx_pdata *wmdata = dev->dev.platform_data; | 171 | struct wm97xx_pdata *wmdata = dev->dev.platform_data; |
173 | struct wm97xx_batt_pdata *pdata; | 172 | struct wm97xx_batt_pdata *pdata; |
174 | 173 | ||
175 | if (gpdata) { | ||
176 | dev_err(&dev->dev, "Do not pass platform_data through " | ||
177 | "wm97xx_bat_set_pdata!\n"); | ||
178 | return -EINVAL; | ||
179 | } | ||
180 | |||
181 | if (!wmdata) { | 174 | if (!wmdata) { |
182 | dev_err(&dev->dev, "No platform data supplied\n"); | 175 | dev_err(&dev->dev, "No platform data supplied\n"); |
183 | return -EINVAL; | 176 | return -EINVAL; |
@@ -308,15 +301,6 @@ static void __exit wm97xx_bat_exit(void) | |||
308 | platform_driver_unregister(&wm97xx_bat_driver); | 301 | platform_driver_unregister(&wm97xx_bat_driver); |
309 | } | 302 | } |
310 | 303 | ||
311 | /* The interface is deprecated, as well as linux/wm97xx_batt.h */ | ||
312 | void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data); | ||
313 | |||
314 | void wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) | ||
315 | { | ||
316 | gpdata = data; | ||
317 | } | ||
318 | EXPORT_SYMBOL_GPL(wm97xx_bat_set_pdata); | ||
319 | |||
320 | module_init(wm97xx_bat_init); | 304 | module_init(wm97xx_bat_init); |
321 | module_exit(wm97xx_bat_exit); | 305 | module_exit(wm97xx_bat_exit); |
322 | 306 | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 06cb8d6823aa..48ca7132cc05 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -674,9 +674,16 @@ config RTC_DRV_OMAP | |||
674 | DA8xx/OMAP-L13x chips. This driver can also be built as a | 674 | DA8xx/OMAP-L13x chips. This driver can also be built as a |
675 | module called rtc-omap. | 675 | module called rtc-omap. |
676 | 676 | ||
677 | config HAVE_S3C_RTC | ||
678 | bool | ||
679 | help | ||
680 | This will include RTC support for Samsung SoCs. If | ||
681 | you want to include RTC support for any machine, kindly | ||
682 | select this in the respective mach-XXXX/Kconfig file. | ||
683 | |||
677 | config RTC_DRV_S3C | 684 | config RTC_DRV_S3C |
678 | tristate "Samsung S3C series SoC RTC" | 685 | tristate "Samsung S3C series SoC RTC" |
679 | depends on ARCH_S3C2410 || ARCH_S3C64XX | 686 | depends on ARCH_S3C2410 || ARCH_S3C64XX || HAVE_S3C_RTC |
680 | help | 687 | help |
681 | RTC (Realtime Clock) driver for the clock inbuilt into the | 688 | RTC (Realtime Clock) driver for the clock inbuilt into the |
682 | Samsung S3C24XX series of SoCs. This can provide periodic | 689 | Samsung S3C24XX series of SoCs. This can provide periodic |
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 70b68d35f969..a0d3ec89d412 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c | |||
@@ -1,5 +1,8 @@ | |||
1 | /* drivers/rtc/rtc-s3c.c | 1 | /* drivers/rtc/rtc-s3c.c |
2 | * | 2 | * |
3 | * Copyright (c) 2010 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com/ | ||
5 | * | ||
3 | * Copyright (c) 2004,2006 Simtec Electronics | 6 | * Copyright (c) 2004,2006 Simtec Electronics |
4 | * Ben Dooks, <ben@simtec.co.uk> | 7 | * Ben Dooks, <ben@simtec.co.uk> |
5 | * http://armlinux.simtec.co.uk/ | 8 | * http://armlinux.simtec.co.uk/ |
@@ -39,6 +42,7 @@ enum s3c_cpu_type { | |||
39 | 42 | ||
40 | static struct resource *s3c_rtc_mem; | 43 | static struct resource *s3c_rtc_mem; |
41 | 44 | ||
45 | static struct clk *rtc_clk; | ||
42 | static void __iomem *s3c_rtc_base; | 46 | static void __iomem *s3c_rtc_base; |
43 | static int s3c_rtc_alarmno = NO_IRQ; | 47 | static int s3c_rtc_alarmno = NO_IRQ; |
44 | static int s3c_rtc_tickno = NO_IRQ; | 48 | static int s3c_rtc_tickno = NO_IRQ; |
@@ -53,6 +57,10 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id) | |||
53 | struct rtc_device *rdev = id; | 57 | struct rtc_device *rdev = id; |
54 | 58 | ||
55 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); | 59 | rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF); |
60 | |||
61 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | ||
62 | writeb(S3C2410_INTP_ALM, s3c_rtc_base + S3C2410_INTP); | ||
63 | |||
56 | return IRQ_HANDLED; | 64 | return IRQ_HANDLED; |
57 | } | 65 | } |
58 | 66 | ||
@@ -61,6 +69,10 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id) | |||
61 | struct rtc_device *rdev = id; | 69 | struct rtc_device *rdev = id; |
62 | 70 | ||
63 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); | 71 | rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF); |
72 | |||
73 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | ||
74 | writeb(S3C2410_INTP_TIC, s3c_rtc_base + S3C2410_INTP); | ||
75 | |||
64 | return IRQ_HANDLED; | 76 | return IRQ_HANDLED; |
65 | } | 77 | } |
66 | 78 | ||
@@ -94,7 +106,7 @@ static int s3c_rtc_setpie(struct device *dev, int enabled) | |||
94 | if (enabled) | 106 | if (enabled) |
95 | tmp |= S3C64XX_RTCCON_TICEN; | 107 | tmp |= S3C64XX_RTCCON_TICEN; |
96 | 108 | ||
97 | writeb(tmp, s3c_rtc_base + S3C2410_RTCCON); | 109 | writew(tmp, s3c_rtc_base + S3C2410_RTCCON); |
98 | } else { | 110 | } else { |
99 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); | 111 | tmp = readb(s3c_rtc_base + S3C2410_TICNT); |
100 | tmp &= ~S3C2410_TICNT_ENABLE; | 112 | tmp &= ~S3C2410_TICNT_ENABLE; |
@@ -128,7 +140,7 @@ static int s3c_rtc_setfreq(struct device *dev, int freq) | |||
128 | 140 | ||
129 | tmp |= (rtc_dev->max_user_freq / freq)-1; | 141 | tmp |= (rtc_dev->max_user_freq / freq)-1; |
130 | 142 | ||
131 | writeb(tmp, s3c_rtc_base + S3C2410_TICNT); | 143 | writel(tmp, s3c_rtc_base + S3C2410_TICNT); |
132 | spin_unlock_irq(&s3c_rtc_pie_lock); | 144 | spin_unlock_irq(&s3c_rtc_pie_lock); |
133 | 145 | ||
134 | return 0; | 146 | return 0; |
@@ -431,6 +443,10 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev) | |||
431 | s3c_rtc_setpie(&dev->dev, 0); | 443 | s3c_rtc_setpie(&dev->dev, 0); |
432 | s3c_rtc_setaie(0); | 444 | s3c_rtc_setaie(0); |
433 | 445 | ||
446 | clk_disable(rtc_clk); | ||
447 | clk_put(rtc_clk); | ||
448 | rtc_clk = NULL; | ||
449 | |||
434 | iounmap(s3c_rtc_base); | 450 | iounmap(s3c_rtc_base); |
435 | release_resource(s3c_rtc_mem); | 451 | release_resource(s3c_rtc_mem); |
436 | kfree(s3c_rtc_mem); | 452 | kfree(s3c_rtc_mem); |
@@ -442,6 +458,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
442 | { | 458 | { |
443 | struct rtc_device *rtc; | 459 | struct rtc_device *rtc; |
444 | struct resource *res; | 460 | struct resource *res; |
461 | unsigned int tmp, i; | ||
445 | int ret; | 462 | int ret; |
446 | 463 | ||
447 | pr_debug("%s: probe=%p\n", __func__, pdev); | 464 | pr_debug("%s: probe=%p\n", __func__, pdev); |
@@ -488,6 +505,16 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
488 | goto err_nomap; | 505 | goto err_nomap; |
489 | } | 506 | } |
490 | 507 | ||
508 | rtc_clk = clk_get(&pdev->dev, "rtc"); | ||
509 | if (IS_ERR(rtc_clk)) { | ||
510 | dev_err(&pdev->dev, "failed to find rtc clock source\n"); | ||
511 | ret = PTR_ERR(rtc_clk); | ||
512 | rtc_clk = NULL; | ||
513 | goto err_clk; | ||
514 | } | ||
515 | |||
516 | clk_enable(rtc_clk); | ||
517 | |||
491 | /* check to see if everything is setup correctly */ | 518 | /* check to see if everything is setup correctly */ |
492 | 519 | ||
493 | s3c_rtc_enable(pdev, 1); | 520 | s3c_rtc_enable(pdev, 1); |
@@ -510,6 +537,15 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
510 | 537 | ||
511 | s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; | 538 | s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data; |
512 | 539 | ||
540 | /* Check RTC Time */ | ||
541 | |||
542 | for (i = S3C2410_RTCSEC; i <= S3C2410_RTCYEAR; i += 0x4) { | ||
543 | tmp = readb(s3c_rtc_base + i); | ||
544 | |||
545 | if ((tmp & 0xf) > 0x9 || ((tmp >> 4) & 0xf) > 0x9) | ||
546 | writeb(0, s3c_rtc_base + i); | ||
547 | } | ||
548 | |||
513 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) | 549 | if (s3c_rtc_cpu_type == TYPE_S3C64XX) |
514 | rtc->max_user_freq = 32768; | 550 | rtc->max_user_freq = 32768; |
515 | else | 551 | else |
@@ -523,6 +559,10 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev) | |||
523 | 559 | ||
524 | err_nortc: | 560 | err_nortc: |
525 | s3c_rtc_enable(pdev, 0); | 561 | s3c_rtc_enable(pdev, 0); |
562 | clk_disable(rtc_clk); | ||
563 | clk_put(rtc_clk); | ||
564 | |||
565 | err_clk: | ||
526 | iounmap(s3c_rtc_base); | 566 | iounmap(s3c_rtc_base); |
527 | 567 | ||
528 | err_nomap: | 568 | err_nomap: |
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index a22e60c06f48..12900f7083b0 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig | |||
@@ -536,8 +536,8 @@ config SERIAL_S3C6400 | |||
536 | 536 | ||
537 | config SERIAL_S5PV210 | 537 | config SERIAL_S5PV210 |
538 | tristate "Samsung S5PV210 Serial port support" | 538 | tristate "Samsung S5PV210 Serial port support" |
539 | depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442) | 539 | depends on SERIAL_SAMSUNG && (CPU_S5PV210 || CPU_S5P6442 || CPU_S5PV310) |
540 | select SERIAL_SAMSUNG_UARTS_4 if CPU_S5PV210 | 540 | select SERIAL_SAMSUNG_UARTS_4 if (CPU_S5PV210 || CPU_S5PV310) |
541 | default y | 541 | default y |
542 | help | 542 | help |
543 | Serial port support for Samsung's S5P Family of SoC's | 543 | Serial port support for Samsung's S5P Family of SoC's |
diff --git a/drivers/serial/s5pv210.c b/drivers/serial/s5pv210.c index 4a789e5361a4..6ebccd70a707 100644 --- a/drivers/serial/s5pv210.c +++ b/drivers/serial/s5pv210.c | |||
@@ -28,8 +28,12 @@ | |||
28 | static int s5pv210_serial_setsource(struct uart_port *port, | 28 | static int s5pv210_serial_setsource(struct uart_port *port, |
29 | struct s3c24xx_uart_clksrc *clk) | 29 | struct s3c24xx_uart_clksrc *clk) |
30 | { | 30 | { |
31 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; | ||
31 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | 32 | unsigned long ucon = rd_regl(port, S3C2410_UCON); |
32 | 33 | ||
34 | if ((cfg->clocks_size) == 1) | ||
35 | return 0; | ||
36 | |||
33 | if (strcmp(clk->name, "pclk") == 0) | 37 | if (strcmp(clk->name, "pclk") == 0) |
34 | ucon &= ~S5PV210_UCON_CLKMASK; | 38 | ucon &= ~S5PV210_UCON_CLKMASK; |
35 | else if (strcmp(clk->name, "uclk1") == 0) | 39 | else if (strcmp(clk->name, "uclk1") == 0) |
@@ -47,10 +51,14 @@ static int s5pv210_serial_setsource(struct uart_port *port, | |||
47 | static int s5pv210_serial_getsource(struct uart_port *port, | 51 | static int s5pv210_serial_getsource(struct uart_port *port, |
48 | struct s3c24xx_uart_clksrc *clk) | 52 | struct s3c24xx_uart_clksrc *clk) |
49 | { | 53 | { |
54 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; | ||
50 | u32 ucon = rd_regl(port, S3C2410_UCON); | 55 | u32 ucon = rd_regl(port, S3C2410_UCON); |
51 | 56 | ||
52 | clk->divisor = 1; | 57 | clk->divisor = 1; |
53 | 58 | ||
59 | if ((cfg->clocks_size) == 1) | ||
60 | return 0; | ||
61 | |||
54 | switch (ucon & S5PV210_UCON_CLKMASK) { | 62 | switch (ucon & S5PV210_UCON_CLKMASK) { |
55 | case S5PV210_UCON_PCLK: | 63 | case S5PV210_UCON_PCLK: |
56 | clk->name = "pclk"; | 64 | clk->name = "pclk"; |
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index a9d6c5626a0a..b1156ba8ad14 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c | |||
@@ -705,8 +705,13 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, | |||
705 | if (ourport->info->has_divslot) { | 705 | if (ourport->info->has_divslot) { |
706 | unsigned int div = ourport->baudclk_rate / baud; | 706 | unsigned int div = ourport->baudclk_rate / baud; |
707 | 707 | ||
708 | udivslot = udivslot_table[div & 15]; | 708 | if (cfg->has_fracval) { |
709 | dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); | 709 | udivslot = (div & 15); |
710 | dbg("fracval = %04x\n", udivslot); | ||
711 | } else { | ||
712 | udivslot = udivslot_table[div & 15]; | ||
713 | dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); | ||
714 | } | ||
710 | } | 715 | } |
711 | 716 | ||
712 | switch (termios->c_cflag & CSIZE) { | 717 | switch (termios->c_cflag & CSIZE) { |
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 5f90fcd7d107..c291b3add1d2 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c | |||
@@ -346,6 +346,27 @@ static int scif_rxfill(struct uart_port *port) | |||
346 | return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; | 346 | return sci_in(port, SCFDR) & SCIF2_RFDC_MASK; |
347 | } | 347 | } |
348 | } | 348 | } |
349 | #elif defined(CONFIG_ARCH_SH7372) | ||
350 | static int scif_txfill(struct uart_port *port) | ||
351 | { | ||
352 | if (port->type == PORT_SCIFA) | ||
353 | return sci_in(port, SCFDR) >> 8; | ||
354 | else | ||
355 | return sci_in(port, SCTFDR); | ||
356 | } | ||
357 | |||
358 | static int scif_txroom(struct uart_port *port) | ||
359 | { | ||
360 | return port->fifosize - scif_txfill(port); | ||
361 | } | ||
362 | |||
363 | static int scif_rxfill(struct uart_port *port) | ||
364 | { | ||
365 | if (port->type == PORT_SCIFA) | ||
366 | return sci_in(port, SCFDR) & SCIF_RFDC_MASK; | ||
367 | else | ||
368 | return sci_in(port, SCRFDR); | ||
369 | } | ||
349 | #else | 370 | #else |
350 | static int scif_txfill(struct uart_port *port) | 371 | static int scif_txfill(struct uart_port *port) |
351 | { | 372 | { |
@@ -683,7 +704,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) | |||
683 | u16 ssr = sci_in(port, SCxSR); | 704 | u16 ssr = sci_in(port, SCxSR); |
684 | 705 | ||
685 | /* Disable future Rx interrupts */ | 706 | /* Disable future Rx interrupts */ |
686 | if (port->type == PORT_SCIFA) { | 707 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { |
687 | disable_irq_nosync(irq); | 708 | disable_irq_nosync(irq); |
688 | scr |= 0x4000; | 709 | scr |= 0x4000; |
689 | } else { | 710 | } else { |
@@ -928,7 +949,7 @@ static void sci_dma_tx_complete(void *arg) | |||
928 | 949 | ||
929 | if (!uart_circ_empty(xmit)) { | 950 | if (!uart_circ_empty(xmit)) { |
930 | schedule_work(&s->work_tx); | 951 | schedule_work(&s->work_tx); |
931 | } else if (port->type == PORT_SCIFA) { | 952 | } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { |
932 | u16 ctrl = sci_in(port, SCSCR); | 953 | u16 ctrl = sci_in(port, SCSCR); |
933 | sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE); | 954 | sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE); |
934 | } | 955 | } |
@@ -1184,7 +1205,7 @@ static void sci_start_tx(struct uart_port *port) | |||
1184 | unsigned short ctrl; | 1205 | unsigned short ctrl; |
1185 | 1206 | ||
1186 | #ifdef CONFIG_SERIAL_SH_SCI_DMA | 1207 | #ifdef CONFIG_SERIAL_SH_SCI_DMA |
1187 | if (port->type == PORT_SCIFA) { | 1208 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { |
1188 | u16 new, scr = sci_in(port, SCSCR); | 1209 | u16 new, scr = sci_in(port, SCSCR); |
1189 | if (s->chan_tx) | 1210 | if (s->chan_tx) |
1190 | new = scr | 0x8000; | 1211 | new = scr | 0x8000; |
@@ -1197,7 +1218,7 @@ static void sci_start_tx(struct uart_port *port) | |||
1197 | s->cookie_tx < 0) | 1218 | s->cookie_tx < 0) |
1198 | schedule_work(&s->work_tx); | 1219 | schedule_work(&s->work_tx); |
1199 | #endif | 1220 | #endif |
1200 | if (!s->chan_tx || port->type == PORT_SCIFA) { | 1221 | if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { |
1201 | /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ | 1222 | /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ |
1202 | ctrl = sci_in(port, SCSCR); | 1223 | ctrl = sci_in(port, SCSCR); |
1203 | sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE); | 1224 | sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE); |
@@ -1210,7 +1231,7 @@ static void sci_stop_tx(struct uart_port *port) | |||
1210 | 1231 | ||
1211 | /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ | 1232 | /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ |
1212 | ctrl = sci_in(port, SCSCR); | 1233 | ctrl = sci_in(port, SCSCR); |
1213 | if (port->type == PORT_SCIFA) | 1234 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) |
1214 | ctrl &= ~0x8000; | 1235 | ctrl &= ~0x8000; |
1215 | ctrl &= ~SCI_CTRL_FLAGS_TIE; | 1236 | ctrl &= ~SCI_CTRL_FLAGS_TIE; |
1216 | sci_out(port, SCSCR, ctrl); | 1237 | sci_out(port, SCSCR, ctrl); |
@@ -1222,7 +1243,7 @@ static void sci_start_rx(struct uart_port *port) | |||
1222 | 1243 | ||
1223 | /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ | 1244 | /* Set RIE (Receive Interrupt Enable) bit in SCSCR */ |
1224 | ctrl |= sci_in(port, SCSCR); | 1245 | ctrl |= sci_in(port, SCSCR); |
1225 | if (port->type == PORT_SCIFA) | 1246 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) |
1226 | ctrl &= ~0x4000; | 1247 | ctrl &= ~0x4000; |
1227 | sci_out(port, SCSCR, ctrl); | 1248 | sci_out(port, SCSCR, ctrl); |
1228 | } | 1249 | } |
@@ -1233,7 +1254,7 @@ static void sci_stop_rx(struct uart_port *port) | |||
1233 | 1254 | ||
1234 | /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ | 1255 | /* Clear RIE (Receive Interrupt Enable) bit in SCSCR */ |
1235 | ctrl = sci_in(port, SCSCR); | 1256 | ctrl = sci_in(port, SCSCR); |
1236 | if (port->type == PORT_SCIFA) | 1257 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) |
1237 | ctrl &= ~0x4000; | 1258 | ctrl &= ~0x4000; |
1238 | ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); | 1259 | ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE); |
1239 | sci_out(port, SCSCR, ctrl); | 1260 | sci_out(port, SCSCR, ctrl); |
@@ -1271,7 +1292,7 @@ static void rx_timer_fn(unsigned long arg) | |||
1271 | struct uart_port *port = &s->port; | 1292 | struct uart_port *port = &s->port; |
1272 | u16 scr = sci_in(port, SCSCR); | 1293 | u16 scr = sci_in(port, SCSCR); |
1273 | 1294 | ||
1274 | if (port->type == PORT_SCIFA) { | 1295 | if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { |
1275 | scr &= ~0x4000; | 1296 | scr &= ~0x4000; |
1276 | enable_irq(s->irqs[1]); | 1297 | enable_irq(s->irqs[1]); |
1277 | } | 1298 | } |
@@ -1524,6 +1545,8 @@ static const char *sci_type(struct uart_port *port) | |||
1524 | return "scif"; | 1545 | return "scif"; |
1525 | case PORT_SCIFA: | 1546 | case PORT_SCIFA: |
1526 | return "scifa"; | 1547 | return "scifa"; |
1548 | case PORT_SCIFB: | ||
1549 | return "scifb"; | ||
1527 | } | 1550 | } |
1528 | 1551 | ||
1529 | return NULL; | 1552 | return NULL; |
@@ -1612,6 +1635,9 @@ static int __devinit sci_init_single(struct platform_device *dev, | |||
1612 | port->line = index; | 1635 | port->line = index; |
1613 | 1636 | ||
1614 | switch (p->type) { | 1637 | switch (p->type) { |
1638 | case PORT_SCIFB: | ||
1639 | port->fifosize = 256; | ||
1640 | break; | ||
1615 | case PORT_SCIFA: | 1641 | case PORT_SCIFA: |
1616 | port->fifosize = 64; | 1642 | port->fifosize = 64; |
1617 | break; | 1643 | break; |
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index f70c49f915fa..9b52f77a9305 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h | |||
@@ -322,7 +322,7 @@ | |||
322 | #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ | 322 | #define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\ |
323 | static inline unsigned int sci_##name##_in(struct uart_port *port) \ | 323 | static inline unsigned int sci_##name##_in(struct uart_port *port) \ |
324 | { \ | 324 | { \ |
325 | if (port->type == PORT_SCIF) { \ | 325 | if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ |
326 | SCI_IN(scif_size, scif_offset) \ | 326 | SCI_IN(scif_size, scif_offset) \ |
327 | } else { /* PORT_SCI or PORT_SCIFA */ \ | 327 | } else { /* PORT_SCI or PORT_SCIFA */ \ |
328 | SCI_IN(sci_size, sci_offset); \ | 328 | SCI_IN(sci_size, sci_offset); \ |
@@ -330,7 +330,7 @@ | |||
330 | } \ | 330 | } \ |
331 | static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ | 331 | static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \ |
332 | { \ | 332 | { \ |
333 | if (port->type == PORT_SCIF) { \ | 333 | if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \ |
334 | SCI_OUT(scif_size, scif_offset, value) \ | 334 | SCI_OUT(scif_size, scif_offset, value) \ |
335 | } else { /* PORT_SCI or PORT_SCIFA */ \ | 335 | } else { /* PORT_SCI or PORT_SCIFA */ \ |
336 | SCI_OUT(sci_size, sci_offset, value); \ | 336 | SCI_OUT(sci_size, sci_offset, value); \ |
@@ -384,8 +384,12 @@ | |||
384 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ | 384 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ |
385 | defined(CONFIG_CPU_SUBTYPE_SH7721) || \ | 385 | defined(CONFIG_CPU_SUBTYPE_SH7721) || \ |
386 | defined(CONFIG_ARCH_SH7367) || \ | 386 | defined(CONFIG_ARCH_SH7367) || \ |
387 | defined(CONFIG_ARCH_SH7377) || \ | 387 | defined(CONFIG_ARCH_SH7377) |
388 | defined(CONFIG_ARCH_SH7372) | 388 | #define SCIF_FNS(name, scif_offset, scif_size) \ |
389 | CPU_SCIF_FNS(name, scif_offset, scif_size) | ||
390 | #elif defined(CONFIG_ARCH_SH7372) | ||
391 | #define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \ | ||
392 | CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) | ||
389 | #define SCIF_FNS(name, scif_offset, scif_size) \ | 393 | #define SCIF_FNS(name, scif_offset, scif_size) \ |
390 | CPU_SCIF_FNS(name, scif_offset, scif_size) | 394 | CPU_SCIF_FNS(name, scif_offset, scif_size) |
391 | #else | 395 | #else |
@@ -422,8 +426,7 @@ | |||
422 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ | 426 | defined(CONFIG_CPU_SUBTYPE_SH7720) || \ |
423 | defined(CONFIG_CPU_SUBTYPE_SH7721) || \ | 427 | defined(CONFIG_CPU_SUBTYPE_SH7721) || \ |
424 | defined(CONFIG_ARCH_SH7367) || \ | 428 | defined(CONFIG_ARCH_SH7367) || \ |
425 | defined(CONFIG_ARCH_SH7377) || \ | 429 | defined(CONFIG_ARCH_SH7377) |
426 | defined(CONFIG_ARCH_SH7372) | ||
427 | 430 | ||
428 | SCIF_FNS(SCSMR, 0x00, 16) | 431 | SCIF_FNS(SCSMR, 0x00, 16) |
429 | SCIF_FNS(SCBRR, 0x04, 8) | 432 | SCIF_FNS(SCBRR, 0x04, 8) |
@@ -436,6 +439,20 @@ SCIF_FNS(SCFDR, 0x1c, 16) | |||
436 | SCIF_FNS(SCxTDR, 0x20, 8) | 439 | SCIF_FNS(SCxTDR, 0x20, 8) |
437 | SCIF_FNS(SCxRDR, 0x24, 8) | 440 | SCIF_FNS(SCxRDR, 0x24, 8) |
438 | SCIF_FNS(SCLSR, 0x00, 0) | 441 | SCIF_FNS(SCLSR, 0x00, 0) |
442 | #elif defined(CONFIG_ARCH_SH7372) | ||
443 | SCIF_FNS(SCSMR, 0x00, 16) | ||
444 | SCIF_FNS(SCBRR, 0x04, 8) | ||
445 | SCIF_FNS(SCSCR, 0x08, 16) | ||
446 | SCIF_FNS(SCTDSR, 0x0c, 16) | ||
447 | SCIF_FNS(SCFER, 0x10, 16) | ||
448 | SCIF_FNS(SCxSR, 0x14, 16) | ||
449 | SCIF_FNS(SCFCR, 0x18, 16) | ||
450 | SCIF_FNS(SCFDR, 0x1c, 16) | ||
451 | SCIF_FNS(SCTFDR, 0x38, 16) | ||
452 | SCIF_FNS(SCRFDR, 0x3c, 16) | ||
453 | SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8) | ||
454 | SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8) | ||
455 | SCIF_FNS(SCLSR, 0x00, 0) | ||
439 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ | 456 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\ |
440 | defined(CONFIG_CPU_SUBTYPE_SH7724) | 457 | defined(CONFIG_CPU_SUBTYPE_SH7724) |
441 | SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) | 458 | SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16) |
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 78bb5127abd0..08fc653a825c 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile | |||
@@ -1,9 +1,10 @@ | |||
1 | # | 1 | # |
2 | # Makefile for the SuperH specific drivers. | 2 | # Makefile for the SuperH specific drivers. |
3 | # | 3 | # |
4 | obj-y := clk.o intc.o | ||
5 | |||
4 | obj-$(CONFIG_SUPERHYWAY) += superhyway/ | 6 | obj-$(CONFIG_SUPERHYWAY) += superhyway/ |
5 | obj-$(CONFIG_MAPLE) += maple/ | 7 | obj-$(CONFIG_MAPLE) += maple/ |
8 | |||
6 | obj-$(CONFIG_GENERIC_GPIO) += pfc.o | 9 | obj-$(CONFIG_GENERIC_GPIO) += pfc.o |
7 | obj-$(CONFIG_SUPERH) += clk.o | ||
8 | obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o | 10 | obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o |
9 | obj-y += intc.o | ||
diff --git a/drivers/sh/clk-cpg.c b/drivers/sh/clk-cpg.c index f5c80ba9ab1c..8c024b984ed8 100644 --- a/drivers/sh/clk-cpg.c +++ b/drivers/sh/clk-cpg.c | |||
@@ -68,6 +68,39 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk) | |||
68 | return clk->freq_table[idx].frequency; | 68 | return clk->freq_table[idx].frequency; |
69 | } | 69 | } |
70 | 70 | ||
71 | static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) | ||
72 | { | ||
73 | struct clk_div_mult_table *table = &sh_clk_div6_table; | ||
74 | u32 value; | ||
75 | int ret, i; | ||
76 | |||
77 | if (!clk->parent_table || !clk->parent_num) | ||
78 | return -EINVAL; | ||
79 | |||
80 | /* Search the parent */ | ||
81 | for (i = 0; i < clk->parent_num; i++) | ||
82 | if (clk->parent_table[i] == parent) | ||
83 | break; | ||
84 | |||
85 | if (i == clk->parent_num) | ||
86 | return -ENODEV; | ||
87 | |||
88 | ret = clk_reparent(clk, parent); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | value = __raw_readl(clk->enable_reg) & | ||
93 | ~(((1 << clk->src_width) - 1) << clk->src_shift); | ||
94 | |||
95 | __raw_writel(value | (i << clk->src_shift), clk->enable_reg); | ||
96 | |||
97 | /* Rebuild the frequency table */ | ||
98 | clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, | ||
99 | table, &clk->arch_flags); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
71 | static int sh_clk_div6_set_rate(struct clk *clk, | 104 | static int sh_clk_div6_set_rate(struct clk *clk, |
72 | unsigned long rate, int algo_id) | 105 | unsigned long rate, int algo_id) |
73 | { | 106 | { |
@@ -117,7 +150,17 @@ static struct clk_ops sh_clk_div6_clk_ops = { | |||
117 | .disable = sh_clk_div6_disable, | 150 | .disable = sh_clk_div6_disable, |
118 | }; | 151 | }; |
119 | 152 | ||
120 | int __init sh_clk_div6_register(struct clk *clks, int nr) | 153 | static struct clk_ops sh_clk_div6_reparent_clk_ops = { |
154 | .recalc = sh_clk_div6_recalc, | ||
155 | .round_rate = sh_clk_div_round_rate, | ||
156 | .set_rate = sh_clk_div6_set_rate, | ||
157 | .enable = sh_clk_div6_enable, | ||
158 | .disable = sh_clk_div6_disable, | ||
159 | .set_parent = sh_clk_div6_set_parent, | ||
160 | }; | ||
161 | |||
162 | static int __init sh_clk_div6_register_ops(struct clk *clks, int nr, | ||
163 | struct clk_ops *ops) | ||
121 | { | 164 | { |
122 | struct clk *clkp; | 165 | struct clk *clkp; |
123 | void *freq_table; | 166 | void *freq_table; |
@@ -136,7 +179,7 @@ int __init sh_clk_div6_register(struct clk *clks, int nr) | |||
136 | for (k = 0; !ret && (k < nr); k++) { | 179 | for (k = 0; !ret && (k < nr); k++) { |
137 | clkp = clks + k; | 180 | clkp = clks + k; |
138 | 181 | ||
139 | clkp->ops = &sh_clk_div6_clk_ops; | 182 | clkp->ops = ops; |
140 | clkp->id = -1; | 183 | clkp->id = -1; |
141 | clkp->freq_table = freq_table + (k * freq_table_size); | 184 | clkp->freq_table = freq_table + (k * freq_table_size); |
142 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; | 185 | clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; |
@@ -147,6 +190,17 @@ int __init sh_clk_div6_register(struct clk *clks, int nr) | |||
147 | return ret; | 190 | return ret; |
148 | } | 191 | } |
149 | 192 | ||
193 | int __init sh_clk_div6_register(struct clk *clks, int nr) | ||
194 | { | ||
195 | return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops); | ||
196 | } | ||
197 | |||
198 | int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) | ||
199 | { | ||
200 | return sh_clk_div6_register_ops(clks, nr, | ||
201 | &sh_clk_div6_reparent_clk_ops); | ||
202 | } | ||
203 | |||
150 | static unsigned long sh_clk_div4_recalc(struct clk *clk) | 204 | static unsigned long sh_clk_div4_recalc(struct clk *clk) |
151 | { | 205 | { |
152 | struct clk_div4_table *d4t = clk->priv; | 206 | struct clk_div4_table *d4t = clk->priv; |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c9d4de2dd53f..8b31fdfefc98 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1896,6 +1896,13 @@ config FB_W100 | |||
1896 | 1896 | ||
1897 | If unsure, say N. | 1897 | If unsure, say N. |
1898 | 1898 | ||
1899 | config SH_MIPI_DSI | ||
1900 | tristate | ||
1901 | depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK | ||
1902 | |||
1903 | config SH_LCD_MIPI_DSI | ||
1904 | bool | ||
1905 | |||
1899 | config FB_SH_MOBILE_LCDC | 1906 | config FB_SH_MOBILE_LCDC |
1900 | tristate "SuperH Mobile LCDC framebuffer support" | 1907 | tristate "SuperH Mobile LCDC framebuffer support" |
1901 | depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK | 1908 | depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK |
@@ -1904,9 +1911,17 @@ config FB_SH_MOBILE_LCDC | |||
1904 | select FB_SYS_IMAGEBLIT | 1911 | select FB_SYS_IMAGEBLIT |
1905 | select FB_SYS_FOPS | 1912 | select FB_SYS_FOPS |
1906 | select FB_DEFERRED_IO | 1913 | select FB_DEFERRED_IO |
1914 | select SH_MIPI_DSI if SH_LCD_MIPI_DSI | ||
1907 | ---help--- | 1915 | ---help--- |
1908 | Frame buffer driver for the on-chip SH-Mobile LCD controller. | 1916 | Frame buffer driver for the on-chip SH-Mobile LCD controller. |
1909 | 1917 | ||
1918 | config FB_SH_MOBILE_HDMI | ||
1919 | tristate "SuperH Mobile HDMI controller support" | ||
1920 | depends on FB_SH_MOBILE_LCDC | ||
1921 | select FB_MODE_HELPERS | ||
1922 | ---help--- | ||
1923 | Driver for the on-chip SH-Mobile HDMI controller. | ||
1924 | |||
1910 | config FB_TMIO | 1925 | config FB_TMIO |
1911 | tristate "Toshiba Mobile IO FrameBuffer support" | 1926 | tristate "Toshiba Mobile IO FrameBuffer support" |
1912 | depends on FB && MFD_CORE | 1927 | depends on FB && MFD_CORE |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f56a9cae2157..485e8ed1318c 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -123,6 +123,8 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o | |||
123 | obj-$(CONFIG_FB_PS3) += ps3fb.o | 123 | obj-$(CONFIG_FB_PS3) += ps3fb.o |
124 | obj-$(CONFIG_FB_SM501) += sm501fb.o | 124 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
125 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 125 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
126 | obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o | ||
127 | obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o | ||
126 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o | 128 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o |
127 | obj-$(CONFIG_FB_OMAP) += omap/ | 129 | obj-$(CONFIG_FB_OMAP) += omap/ |
128 | obj-y += omap2/ | 130 | obj-y += omap2/ |
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 43f0639b1c10..5c363d026f64 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c | |||
@@ -40,6 +40,12 @@ | |||
40 | */ | 40 | */ |
41 | #define DEBUG_VAR 1 | 41 | #define DEBUG_VAR 1 |
42 | 42 | ||
43 | #if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \ | ||
44 | (defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) && \ | ||
45 | defined(CONFIG_FB_IMX_MODULE)) | ||
46 | #define PWMR_BACKLIGHT_AVAILABLE | ||
47 | #endif | ||
48 | |||
43 | #define DRIVER_NAME "imx-fb" | 49 | #define DRIVER_NAME "imx-fb" |
44 | 50 | ||
45 | #define LCDC_SSA 0x00 | 51 | #define LCDC_SSA 0x00 |
@@ -175,7 +181,9 @@ struct imxfb_info { | |||
175 | 181 | ||
176 | struct imx_fb_videomode *mode; | 182 | struct imx_fb_videomode *mode; |
177 | int num_modes; | 183 | int num_modes; |
184 | #ifdef PWMR_BACKLIGHT_AVAILABLE | ||
178 | struct backlight_device *bl; | 185 | struct backlight_device *bl; |
186 | #endif | ||
179 | 187 | ||
180 | void (*lcd_power)(int); | 188 | void (*lcd_power)(int); |
181 | void (*backlight_power)(int); | 189 | void (*backlight_power)(int); |
@@ -450,8 +458,7 @@ static int imxfb_set_par(struct fb_info *info) | |||
450 | return 0; | 458 | return 0; |
451 | } | 459 | } |
452 | 460 | ||
453 | 461 | #ifdef PWMR_BACKLIGHT_AVAILABLE | |
454 | |||
455 | static int imxfb_bl_get_brightness(struct backlight_device *bl) | 462 | static int imxfb_bl_get_brightness(struct backlight_device *bl) |
456 | { | 463 | { |
457 | struct imxfb_info *fbi = bl_get_data(bl); | 464 | struct imxfb_info *fbi = bl_get_data(bl); |
@@ -516,6 +523,7 @@ static void imxfb_exit_backlight(struct imxfb_info *fbi) | |||
516 | if (fbi->bl) | 523 | if (fbi->bl) |
517 | backlight_device_unregister(fbi->bl); | 524 | backlight_device_unregister(fbi->bl); |
518 | } | 525 | } |
526 | #endif | ||
519 | 527 | ||
520 | static void imxfb_enable_controller(struct imxfb_info *fbi) | 528 | static void imxfb_enable_controller(struct imxfb_info *fbi) |
521 | { | 529 | { |
@@ -647,6 +655,9 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf | |||
647 | fbi->regs + LCDC_SIZE); | 655 | fbi->regs + LCDC_SIZE); |
648 | 656 | ||
649 | writel(fbi->pcr, fbi->regs + LCDC_PCR); | 657 | writel(fbi->pcr, fbi->regs + LCDC_PCR); |
658 | #ifndef PWMR_BACKLIGHT_AVAILABLE | ||
659 | writel(fbi->pwmr, fbi->regs + LCDC_PWMR); | ||
660 | #endif | ||
650 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); | 661 | writel(fbi->lscr1, fbi->regs + LCDC_LSCR1); |
651 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); | 662 | writel(fbi->dmacr, fbi->regs + LCDC_DMACR); |
652 | 663 | ||
@@ -847,7 +858,9 @@ static int __init imxfb_probe(struct platform_device *pdev) | |||
847 | 858 | ||
848 | imxfb_enable_controller(fbi); | 859 | imxfb_enable_controller(fbi); |
849 | fbi->pdev = pdev; | 860 | fbi->pdev = pdev; |
861 | #ifdef PWMR_BACKLIGHT_AVAILABLE | ||
850 | imxfb_init_backlight(fbi); | 862 | imxfb_init_backlight(fbi); |
863 | #endif | ||
851 | 864 | ||
852 | return 0; | 865 | return 0; |
853 | 866 | ||
@@ -885,7 +898,9 @@ static int __devexit imxfb_remove(struct platform_device *pdev) | |||
885 | 898 | ||
886 | imxfb_disable_controller(fbi); | 899 | imxfb_disable_controller(fbi); |
887 | 900 | ||
901 | #ifdef PWMR_BACKLIGHT_AVAILABLE | ||
888 | imxfb_exit_backlight(fbi); | 902 | imxfb_exit_backlight(fbi); |
903 | #endif | ||
889 | unregister_framebuffer(info); | 904 | unregister_framebuffer(info); |
890 | 905 | ||
891 | pdata = pdev->dev.platform_data; | 906 | pdata = pdev->dev.platform_data; |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c new file mode 100644 index 000000000000..5699ce0c1780 --- /dev/null +++ b/drivers/video/sh_mipi_dsi.c | |||
@@ -0,0 +1,505 @@ | |||
1 | /* | ||
2 | * Renesas SH-mobile MIPI DSI support | ||
3 | * | ||
4 | * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
5 | * | ||
6 | * This is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of version 2 of the GNU General Public License as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/clk.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/types.h> | ||
19 | |||
20 | #include <video/mipi_display.h> | ||
21 | #include <video/sh_mipi_dsi.h> | ||
22 | #include <video/sh_mobile_lcdc.h> | ||
23 | |||
24 | #define CMTSRTCTR 0x80d0 | ||
25 | #define CMTSRTREQ 0x8070 | ||
26 | |||
27 | #define DSIINTE 0x0060 | ||
28 | |||
29 | /* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */ | ||
30 | #define MAX_SH_MIPI_DSI 2 | ||
31 | |||
32 | struct sh_mipi { | ||
33 | void __iomem *base; | ||
34 | struct clk *dsit_clk; | ||
35 | struct clk *dsip_clk; | ||
36 | }; | ||
37 | |||
38 | static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI]; | ||
39 | |||
40 | /* Protect the above array */ | ||
41 | static DEFINE_MUTEX(array_lock); | ||
42 | |||
43 | static struct sh_mipi *sh_mipi_by_handle(int handle) | ||
44 | { | ||
45 | if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0) | ||
46 | return NULL; | ||
47 | |||
48 | return mipi_dsi[handle]; | ||
49 | } | ||
50 | |||
51 | static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd, | ||
52 | u8 cmd, u8 param) | ||
53 | { | ||
54 | u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8); | ||
55 | int cnt = 100; | ||
56 | |||
57 | /* transmit a short packet to LCD panel */ | ||
58 | iowrite32(1 | data, mipi->base + 0x80d0); /* CMTSRTCTR */ | ||
59 | iowrite32(1, mipi->base + 0x8070); /* CMTSRTREQ */ | ||
60 | |||
61 | while ((ioread32(mipi->base + 0x8070) & 1) && --cnt) | ||
62 | udelay(1); | ||
63 | |||
64 | return cnt ? 0 : -ETIMEDOUT; | ||
65 | } | ||
66 | |||
67 | #define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \ | ||
68 | -EINVAL : (c) - 1) | ||
69 | |||
70 | static int sh_mipi_dcs(int handle, u8 cmd) | ||
71 | { | ||
72 | struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle)); | ||
73 | if (!mipi) | ||
74 | return -ENODEV; | ||
75 | return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0); | ||
76 | } | ||
77 | |||
78 | static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param) | ||
79 | { | ||
80 | struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle)); | ||
81 | if (!mipi) | ||
82 | return -ENODEV; | ||
83 | return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd, | ||
84 | param); | ||
85 | } | ||
86 | |||
87 | static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable) | ||
88 | { | ||
89 | /* | ||
90 | * enable LCDC data tx, transition to LPS after completion of each HS | ||
91 | * packet | ||
92 | */ | ||
93 | iowrite32(0x00000002 | enable, mipi->base + 0x8000); /* DTCTR */ | ||
94 | } | ||
95 | |||
96 | static void sh_mipi_shutdown(struct platform_device *pdev) | ||
97 | { | ||
98 | struct sh_mipi *mipi = platform_get_drvdata(pdev); | ||
99 | |||
100 | sh_mipi_dsi_enable(mipi, false); | ||
101 | } | ||
102 | |||
103 | static void mipi_display_on(void *arg, struct fb_info *info) | ||
104 | { | ||
105 | struct sh_mipi *mipi = arg; | ||
106 | |||
107 | sh_mipi_dsi_enable(mipi, true); | ||
108 | } | ||
109 | |||
110 | static void mipi_display_off(void *arg) | ||
111 | { | ||
112 | struct sh_mipi *mipi = arg; | ||
113 | |||
114 | sh_mipi_dsi_enable(mipi, false); | ||
115 | } | ||
116 | |||
117 | static int __init sh_mipi_setup(struct sh_mipi *mipi, | ||
118 | struct sh_mipi_dsi_info *pdata) | ||
119 | { | ||
120 | void __iomem *base = mipi->base; | ||
121 | struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; | ||
122 | u32 pctype, datatype, pixfmt; | ||
123 | u32 linelength; | ||
124 | bool yuv; | ||
125 | |||
126 | /* Select data format */ | ||
127 | switch (pdata->data_format) { | ||
128 | case MIPI_RGB888: | ||
129 | pctype = 0; | ||
130 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | ||
131 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | ||
132 | linelength = ch->lcd_cfg.xres * 3; | ||
133 | yuv = false; | ||
134 | break; | ||
135 | case MIPI_RGB565: | ||
136 | pctype = 1; | ||
137 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | ||
138 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | ||
139 | linelength = ch->lcd_cfg.xres * 2; | ||
140 | yuv = false; | ||
141 | break; | ||
142 | case MIPI_RGB666_LP: | ||
143 | pctype = 2; | ||
144 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | ||
145 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | ||
146 | linelength = ch->lcd_cfg.xres * 3; | ||
147 | yuv = false; | ||
148 | break; | ||
149 | case MIPI_RGB666: | ||
150 | pctype = 3; | ||
151 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | ||
152 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | ||
153 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | ||
154 | yuv = false; | ||
155 | break; | ||
156 | case MIPI_BGR888: | ||
157 | pctype = 8; | ||
158 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | ||
159 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | ||
160 | linelength = ch->lcd_cfg.xres * 3; | ||
161 | yuv = false; | ||
162 | break; | ||
163 | case MIPI_BGR565: | ||
164 | pctype = 9; | ||
165 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | ||
166 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | ||
167 | linelength = ch->lcd_cfg.xres * 2; | ||
168 | yuv = false; | ||
169 | break; | ||
170 | case MIPI_BGR666_LP: | ||
171 | pctype = 0xa; | ||
172 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | ||
173 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | ||
174 | linelength = ch->lcd_cfg.xres * 3; | ||
175 | yuv = false; | ||
176 | break; | ||
177 | case MIPI_BGR666: | ||
178 | pctype = 0xb; | ||
179 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | ||
180 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | ||
181 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | ||
182 | yuv = false; | ||
183 | break; | ||
184 | case MIPI_YUYV: | ||
185 | pctype = 4; | ||
186 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | ||
187 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | ||
188 | linelength = ch->lcd_cfg.xres * 2; | ||
189 | yuv = true; | ||
190 | break; | ||
191 | case MIPI_UYVY: | ||
192 | pctype = 5; | ||
193 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | ||
194 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | ||
195 | linelength = ch->lcd_cfg.xres * 2; | ||
196 | yuv = true; | ||
197 | break; | ||
198 | case MIPI_YUV420_L: | ||
199 | pctype = 6; | ||
200 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | ||
201 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | ||
202 | linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; | ||
203 | yuv = true; | ||
204 | break; | ||
205 | case MIPI_YUV420: | ||
206 | pctype = 7; | ||
207 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | ||
208 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | ||
209 | /* Length of U/V line */ | ||
210 | linelength = (ch->lcd_cfg.xres + 1) / 2; | ||
211 | yuv = true; | ||
212 | break; | ||
213 | default: | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | if ((yuv && ch->interface_type != YUV422) || | ||
218 | (!yuv && ch->interface_type != RGB24)) | ||
219 | return -EINVAL; | ||
220 | |||
221 | /* reset DSI link */ | ||
222 | iowrite32(0x00000001, base); /* SYSCTRL */ | ||
223 | /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ | ||
224 | udelay(50); | ||
225 | iowrite32(0x00000000, base); /* SYSCTRL */ | ||
226 | |||
227 | /* setup DSI link */ | ||
228 | |||
229 | /* | ||
230 | * Default = ULPS enable | | ||
231 | * Contention detection enabled | | ||
232 | * EoT packet transmission enable | | ||
233 | * CRC check enable | | ||
234 | * ECC check enable | ||
235 | * additionally enable first two lanes | ||
236 | */ | ||
237 | iowrite32(0x00003703, base + 0x04); /* SYSCONF */ | ||
238 | /* | ||
239 | * T_wakeup = 0x7000 | ||
240 | * T_hs-trail = 3 | ||
241 | * T_hs-prepare = 3 | ||
242 | * T_clk-trail = 3 | ||
243 | * T_clk-prepare = 2 | ||
244 | */ | ||
245 | iowrite32(0x70003332, base + 0x08); /* TIMSET */ | ||
246 | /* no responses requested */ | ||
247 | iowrite32(0x00000000, base + 0x18); /* RESREQSET0 */ | ||
248 | /* request response to packets of type 0x28 */ | ||
249 | iowrite32(0x00000100, base + 0x1c); /* RESREQSET1 */ | ||
250 | /* High-speed transmission timeout, default 0xffffffff */ | ||
251 | iowrite32(0x0fffffff, base + 0x20); /* HSTTOVSET */ | ||
252 | /* LP reception timeout, default 0xffffffff */ | ||
253 | iowrite32(0x0fffffff, base + 0x24); /* LPRTOVSET */ | ||
254 | /* Turn-around timeout, default 0xffffffff */ | ||
255 | iowrite32(0x0fffffff, base + 0x28); /* TATOVSET */ | ||
256 | /* Peripheral reset timeout, default 0xffffffff */ | ||
257 | iowrite32(0x0fffffff, base + 0x2c); /* PRTOVSET */ | ||
258 | /* Enable timeout counters */ | ||
259 | iowrite32(0x00000f00, base + 0x30); /* DSICTRL */ | ||
260 | /* Interrupts not used, disable all */ | ||
261 | iowrite32(0, base + DSIINTE); | ||
262 | /* DSI-Tx bias on */ | ||
263 | iowrite32(0x00000001, base + 0x70); /* PHYCTRL */ | ||
264 | udelay(200); | ||
265 | /* Deassert resets, power on, set multiplier */ | ||
266 | iowrite32(0x03070b01, base + 0x70); /* PHYCTRL */ | ||
267 | |||
268 | /* setup l-bridge */ | ||
269 | |||
270 | /* | ||
271 | * Enable transmission of all packets, | ||
272 | * transmit LPS after each HS packet completion | ||
273 | */ | ||
274 | iowrite32(0x00000006, base + 0x8000); /* DTCTR */ | ||
275 | /* VSYNC width = 2 (<< 17) */ | ||
276 | iowrite32(0x00040000 | (pctype << 12) | datatype, base + 0x8020); /* VMCTR1 */ | ||
277 | /* | ||
278 | * Non-burst mode with sync pulses: VSE and HSE are output, | ||
279 | * HSA period allowed, no commands in LP | ||
280 | */ | ||
281 | iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ | ||
282 | /* | ||
283 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see | ||
284 | * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default | ||
285 | * (unused, since VMCTR2[HSABM] = 0) | ||
286 | */ | ||
287 | iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ | ||
288 | |||
289 | msleep(5); | ||
290 | |||
291 | /* setup LCD panel */ | ||
292 | |||
293 | /* cf. drivers/video/omap/lcd_mipid.c */ | ||
294 | sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE); | ||
295 | msleep(120); | ||
296 | /* | ||
297 | * [7] - Page Address Mode | ||
298 | * [6] - Column Address Mode | ||
299 | * [5] - Page / Column Address Mode | ||
300 | * [4] - Display Device Line Refresh Order | ||
301 | * [3] - RGB/BGR Order | ||
302 | * [2] - Display Data Latch Data Order | ||
303 | * [1] - Flip Horizontal | ||
304 | * [0] - Flip Vertical | ||
305 | */ | ||
306 | sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00); | ||
307 | /* cf. set_data_lines() */ | ||
308 | sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT, | ||
309 | pixfmt << 4); | ||
310 | sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int __init sh_mipi_probe(struct platform_device *pdev) | ||
316 | { | ||
317 | struct sh_mipi *mipi; | ||
318 | struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data; | ||
319 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
320 | unsigned long rate, f_current; | ||
321 | int idx = pdev->id, ret; | ||
322 | char dsip_clk[] = "dsi.p_clk"; | ||
323 | |||
324 | if (!res || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) | ||
325 | return -ENODEV; | ||
326 | |||
327 | mutex_lock(&array_lock); | ||
328 | if (idx < 0) | ||
329 | for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) | ||
330 | ; | ||
331 | |||
332 | if (idx == ARRAY_SIZE(mipi_dsi)) { | ||
333 | ret = -EBUSY; | ||
334 | goto efindslot; | ||
335 | } | ||
336 | |||
337 | mipi = kzalloc(sizeof(*mipi), GFP_KERNEL); | ||
338 | if (!mipi) { | ||
339 | ret = -ENOMEM; | ||
340 | goto ealloc; | ||
341 | } | ||
342 | |||
343 | if (!request_mem_region(res->start, resource_size(res), pdev->name)) { | ||
344 | dev_err(&pdev->dev, "MIPI register region already claimed\n"); | ||
345 | ret = -EBUSY; | ||
346 | goto ereqreg; | ||
347 | } | ||
348 | |||
349 | mipi->base = ioremap(res->start, resource_size(res)); | ||
350 | if (!mipi->base) { | ||
351 | ret = -ENOMEM; | ||
352 | goto emap; | ||
353 | } | ||
354 | |||
355 | mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk"); | ||
356 | if (IS_ERR(mipi->dsit_clk)) { | ||
357 | ret = PTR_ERR(mipi->dsit_clk); | ||
358 | goto eclktget; | ||
359 | } | ||
360 | |||
361 | f_current = clk_get_rate(mipi->dsit_clk); | ||
362 | /* 80MHz required by the datasheet */ | ||
363 | rate = clk_round_rate(mipi->dsit_clk, 80000000); | ||
364 | if (rate > 0 && rate != f_current) | ||
365 | ret = clk_set_rate(mipi->dsit_clk, rate); | ||
366 | else | ||
367 | ret = rate; | ||
368 | if (ret < 0) | ||
369 | goto esettrate; | ||
370 | |||
371 | dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); | ||
372 | |||
373 | sprintf(dsip_clk, "dsi%1.1dp_clk", idx); | ||
374 | mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk); | ||
375 | if (IS_ERR(mipi->dsip_clk)) { | ||
376 | ret = PTR_ERR(mipi->dsip_clk); | ||
377 | goto eclkpget; | ||
378 | } | ||
379 | |||
380 | f_current = clk_get_rate(mipi->dsip_clk); | ||
381 | /* Between 10 and 50MHz */ | ||
382 | rate = clk_round_rate(mipi->dsip_clk, 24000000); | ||
383 | if (rate > 0 && rate != f_current) | ||
384 | ret = clk_set_rate(mipi->dsip_clk, rate); | ||
385 | else | ||
386 | ret = rate; | ||
387 | if (ret < 0) | ||
388 | goto esetprate; | ||
389 | |||
390 | dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate); | ||
391 | |||
392 | msleep(10); | ||
393 | |||
394 | ret = clk_enable(mipi->dsit_clk); | ||
395 | if (ret < 0) | ||
396 | goto eclkton; | ||
397 | |||
398 | ret = clk_enable(mipi->dsip_clk); | ||
399 | if (ret < 0) | ||
400 | goto eclkpon; | ||
401 | |||
402 | mipi_dsi[idx] = mipi; | ||
403 | |||
404 | ret = sh_mipi_setup(mipi, pdata); | ||
405 | if (ret < 0) | ||
406 | goto emipisetup; | ||
407 | |||
408 | mutex_unlock(&array_lock); | ||
409 | platform_set_drvdata(pdev, mipi); | ||
410 | |||
411 | /* Set up LCDC callbacks */ | ||
412 | pdata->lcd_chan->board_cfg.board_data = mipi; | ||
413 | pdata->lcd_chan->board_cfg.display_on = mipi_display_on; | ||
414 | pdata->lcd_chan->board_cfg.display_off = mipi_display_off; | ||
415 | |||
416 | return 0; | ||
417 | |||
418 | emipisetup: | ||
419 | mipi_dsi[idx] = NULL; | ||
420 | clk_disable(mipi->dsip_clk); | ||
421 | eclkpon: | ||
422 | clk_disable(mipi->dsit_clk); | ||
423 | eclkton: | ||
424 | esetprate: | ||
425 | clk_put(mipi->dsip_clk); | ||
426 | eclkpget: | ||
427 | esettrate: | ||
428 | clk_put(mipi->dsit_clk); | ||
429 | eclktget: | ||
430 | iounmap(mipi->base); | ||
431 | emap: | ||
432 | release_mem_region(res->start, resource_size(res)); | ||
433 | ereqreg: | ||
434 | kfree(mipi); | ||
435 | ealloc: | ||
436 | efindslot: | ||
437 | mutex_unlock(&array_lock); | ||
438 | |||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | static int __exit sh_mipi_remove(struct platform_device *pdev) | ||
443 | { | ||
444 | struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data; | ||
445 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
446 | struct sh_mipi *mipi = platform_get_drvdata(pdev); | ||
447 | int i, ret; | ||
448 | |||
449 | mutex_lock(&array_lock); | ||
450 | |||
451 | for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++) | ||
452 | ; | ||
453 | |||
454 | if (i == ARRAY_SIZE(mipi_dsi)) { | ||
455 | ret = -EINVAL; | ||
456 | } else { | ||
457 | ret = 0; | ||
458 | mipi_dsi[i] = NULL; | ||
459 | } | ||
460 | |||
461 | mutex_unlock(&array_lock); | ||
462 | |||
463 | if (ret < 0) | ||
464 | return ret; | ||
465 | |||
466 | pdata->lcd_chan->board_cfg.display_on = NULL; | ||
467 | pdata->lcd_chan->board_cfg.display_off = NULL; | ||
468 | pdata->lcd_chan->board_cfg.board_data = NULL; | ||
469 | |||
470 | clk_disable(mipi->dsip_clk); | ||
471 | clk_disable(mipi->dsit_clk); | ||
472 | clk_put(mipi->dsit_clk); | ||
473 | clk_put(mipi->dsip_clk); | ||
474 | iounmap(mipi->base); | ||
475 | if (res) | ||
476 | release_mem_region(res->start, resource_size(res)); | ||
477 | platform_set_drvdata(pdev, NULL); | ||
478 | kfree(mipi); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static struct platform_driver sh_mipi_driver = { | ||
484 | .remove = __exit_p(sh_mipi_remove), | ||
485 | .shutdown = sh_mipi_shutdown, | ||
486 | .driver = { | ||
487 | .name = "sh-mipi-dsi", | ||
488 | }, | ||
489 | }; | ||
490 | |||
491 | static int __init sh_mipi_init(void) | ||
492 | { | ||
493 | return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe); | ||
494 | } | ||
495 | module_init(sh_mipi_init); | ||
496 | |||
497 | static void __exit sh_mipi_exit(void) | ||
498 | { | ||
499 | platform_driver_unregister(&sh_mipi_driver); | ||
500 | } | ||
501 | module_exit(sh_mipi_exit); | ||
502 | |||
503 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
504 | MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver"); | ||
505 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c new file mode 100644 index 000000000000..2fde08cc66bf --- /dev/null +++ b/drivers/video/sh_mobile_hdmi.c | |||
@@ -0,0 +1,1028 @@ | |||
1 | /* | ||
2 | * SH-Mobile High-Definition Multimedia Interface (HDMI) driver | ||
3 | * for SLISHDMI13T and SLIPHDMIT IP cores | ||
4 | * | ||
5 | * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/console.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | |||
26 | #include <video/sh_mobile_hdmi.h> | ||
27 | #include <video/sh_mobile_lcdc.h> | ||
28 | |||
29 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ | ||
30 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, | ||
31 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ | ||
32 | #define HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8 0x02 /* bits 15..8 of 20-bit N for Audio Clock Regeneration packet */ | ||
33 | #define HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0 0x03 /* bits 7..0 of 20-bit N for Audio Clock Regeneration packet */ | ||
34 | #define HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS 0x04 /* SPDIF audio sampling frequency, | ||
35 | bits 19..16 of Internal CTS */ | ||
36 | #define HDMI_INTERNAL_CTS_15_8 0x05 /* bits 15..8 of Internal CTS */ | ||
37 | #define HDMI_INTERNAL_CTS_7_0 0x06 /* bits 7..0 of Internal CTS */ | ||
38 | #define HDMI_EXTERNAL_CTS_19_16 0x07 /* External CTS */ | ||
39 | #define HDMI_EXTERNAL_CTS_15_8 0x08 /* External CTS */ | ||
40 | #define HDMI_EXTERNAL_CTS_7_0 0x09 /* External CTS */ | ||
41 | #define HDMI_AUDIO_SETTING_1 0x0A /* Audio setting.1 */ | ||
42 | #define HDMI_AUDIO_SETTING_2 0x0B /* Audio setting.2 */ | ||
43 | #define HDMI_I2S_AUDIO_SET 0x0C /* I2S audio setting */ | ||
44 | #define HDMI_DSD_AUDIO_SET 0x0D /* DSD audio setting */ | ||
45 | #define HDMI_DEBUG_MONITOR_1 0x0E /* Debug monitor.1 */ | ||
46 | #define HDMI_DEBUG_MONITOR_2 0x0F /* Debug monitor.2 */ | ||
47 | #define HDMI_I2S_INPUT_PIN_SWAP 0x10 /* I2S input pin swap */ | ||
48 | #define HDMI_AUDIO_STATUS_BITS_SETTING_1 0x11 /* Audio status bits setting.1 */ | ||
49 | #define HDMI_AUDIO_STATUS_BITS_SETTING_2 0x12 /* Audio status bits setting.2 */ | ||
50 | #define HDMI_CATEGORY_CODE 0x13 /* Category code */ | ||
51 | #define HDMI_SOURCE_NUM_AUDIO_WORD_LEN 0x14 /* Source number/Audio word length */ | ||
52 | #define HDMI_AUDIO_VIDEO_SETTING_1 0x15 /* Audio/Video setting.1 */ | ||
53 | #define HDMI_VIDEO_SETTING_1 0x16 /* Video setting.1 */ | ||
54 | #define HDMI_DEEP_COLOR_MODES 0x17 /* Deep Color Modes */ | ||
55 | |||
56 | /* 12 16- and 10-bit Color space conversion parameters: 0x18..0x2f */ | ||
57 | #define HDMI_COLOR_SPACE_CONVERSION_PARAMETERS 0x18 | ||
58 | |||
59 | #define HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS 0x30 /* External video parameter settings */ | ||
60 | #define HDMI_EXTERNAL_H_TOTAL_7_0 0x31 /* External horizontal total (LSB) */ | ||
61 | #define HDMI_EXTERNAL_H_TOTAL_11_8 0x32 /* External horizontal total (MSB) */ | ||
62 | #define HDMI_EXTERNAL_H_BLANK_7_0 0x33 /* External horizontal blank (LSB) */ | ||
63 | #define HDMI_EXTERNAL_H_BLANK_9_8 0x34 /* External horizontal blank (MSB) */ | ||
64 | #define HDMI_EXTERNAL_H_DELAY_7_0 0x35 /* External horizontal delay (LSB) */ | ||
65 | #define HDMI_EXTERNAL_H_DELAY_9_8 0x36 /* External horizontal delay (MSB) */ | ||
66 | #define HDMI_EXTERNAL_H_DURATION_7_0 0x37 /* External horizontal duration (LSB) */ | ||
67 | #define HDMI_EXTERNAL_H_DURATION_9_8 0x38 /* External horizontal duration (MSB) */ | ||
68 | #define HDMI_EXTERNAL_V_TOTAL_7_0 0x39 /* External vertical total (LSB) */ | ||
69 | #define HDMI_EXTERNAL_V_TOTAL_9_8 0x3A /* External vertical total (MSB) */ | ||
70 | #define HDMI_AUDIO_VIDEO_SETTING_2 0x3B /* Audio/Video setting.2 */ | ||
71 | #define HDMI_EXTERNAL_V_BLANK 0x3D /* External vertical blank */ | ||
72 | #define HDMI_EXTERNAL_V_DELAY 0x3E /* External vertical delay */ | ||
73 | #define HDMI_EXTERNAL_V_DURATION 0x3F /* External vertical duration */ | ||
74 | #define HDMI_CTRL_PKT_MANUAL_SEND_CONTROL 0x40 /* Control packet manual send control */ | ||
75 | #define HDMI_CTRL_PKT_AUTO_SEND 0x41 /* Control packet auto send with VSYNC control */ | ||
76 | #define HDMI_AUTO_CHECKSUM_OPTION 0x42 /* Auto checksum option */ | ||
77 | #define HDMI_VIDEO_SETTING_2 0x45 /* Video setting.2 */ | ||
78 | #define HDMI_OUTPUT_OPTION 0x46 /* Output option */ | ||
79 | #define HDMI_SLIPHDMIT_PARAM_OPTION 0x51 /* SLIPHDMIT parameter option */ | ||
80 | #define HDMI_HSYNC_PMENT_AT_EMB_7_0 0x52 /* HSYNC placement at embedded sync (LSB) */ | ||
81 | #define HDMI_HSYNC_PMENT_AT_EMB_15_8 0x53 /* HSYNC placement at embedded sync (MSB) */ | ||
82 | #define HDMI_VSYNC_PMENT_AT_EMB_7_0 0x54 /* VSYNC placement at embedded sync (LSB) */ | ||
83 | #define HDMI_VSYNC_PMENT_AT_EMB_14_8 0x55 /* VSYNC placement at embedded sync (MSB) */ | ||
84 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_1 0x56 /* SLIPHDMIT parameter settings.1 */ | ||
85 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_2 0x57 /* SLIPHDMIT parameter settings.2 */ | ||
86 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_3 0x58 /* SLIPHDMIT parameter settings.3 */ | ||
87 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_5 0x59 /* SLIPHDMIT parameter settings.5 */ | ||
88 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_6 0x5A /* SLIPHDMIT parameter settings.6 */ | ||
89 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_7 0x5B /* SLIPHDMIT parameter settings.7 */ | ||
90 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_8 0x5C /* SLIPHDMIT parameter settings.8 */ | ||
91 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_9 0x5D /* SLIPHDMIT parameter settings.9 */ | ||
92 | #define HDMI_SLIPHDMIT_PARAM_SETTINGS_10 0x5E /* SLIPHDMIT parameter settings.10 */ | ||
93 | #define HDMI_CTRL_PKT_BUF_INDEX 0x5F /* Control packet buffer index */ | ||
94 | #define HDMI_CTRL_PKT_BUF_ACCESS_HB0 0x60 /* Control packet data buffer access window - HB0 */ | ||
95 | #define HDMI_CTRL_PKT_BUF_ACCESS_HB1 0x61 /* Control packet data buffer access window - HB1 */ | ||
96 | #define HDMI_CTRL_PKT_BUF_ACCESS_HB2 0x62 /* Control packet data buffer access window - HB2 */ | ||
97 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB0 0x63 /* Control packet data buffer access window - PB0 */ | ||
98 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB1 0x64 /* Control packet data buffer access window - PB1 */ | ||
99 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB2 0x65 /* Control packet data buffer access window - PB2 */ | ||
100 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB3 0x66 /* Control packet data buffer access window - PB3 */ | ||
101 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB4 0x67 /* Control packet data buffer access window - PB4 */ | ||
102 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB5 0x68 /* Control packet data buffer access window - PB5 */ | ||
103 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB6 0x69 /* Control packet data buffer access window - PB6 */ | ||
104 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB7 0x6A /* Control packet data buffer access window - PB7 */ | ||
105 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB8 0x6B /* Control packet data buffer access window - PB8 */ | ||
106 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB9 0x6C /* Control packet data buffer access window - PB9 */ | ||
107 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB10 0x6D /* Control packet data buffer access window - PB10 */ | ||
108 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB11 0x6E /* Control packet data buffer access window - PB11 */ | ||
109 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB12 0x6F /* Control packet data buffer access window - PB12 */ | ||
110 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB13 0x70 /* Control packet data buffer access window - PB13 */ | ||
111 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB14 0x71 /* Control packet data buffer access window - PB14 */ | ||
112 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB15 0x72 /* Control packet data buffer access window - PB15 */ | ||
113 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB16 0x73 /* Control packet data buffer access window - PB16 */ | ||
114 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB17 0x74 /* Control packet data buffer access window - PB17 */ | ||
115 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB18 0x75 /* Control packet data buffer access window - PB18 */ | ||
116 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB19 0x76 /* Control packet data buffer access window - PB19 */ | ||
117 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB20 0x77 /* Control packet data buffer access window - PB20 */ | ||
118 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB21 0x78 /* Control packet data buffer access window - PB21 */ | ||
119 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB22 0x79 /* Control packet data buffer access window - PB22 */ | ||
120 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB23 0x7A /* Control packet data buffer access window - PB23 */ | ||
121 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB24 0x7B /* Control packet data buffer access window - PB24 */ | ||
122 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB25 0x7C /* Control packet data buffer access window - PB25 */ | ||
123 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB26 0x7D /* Control packet data buffer access window - PB26 */ | ||
124 | #define HDMI_CTRL_PKT_BUF_ACCESS_PB27 0x7E /* Control packet data buffer access window - PB27 */ | ||
125 | #define HDMI_EDID_KSV_FIFO_ACCESS_WINDOW 0x80 /* EDID/KSV FIFO access window */ | ||
126 | #define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_7_0 0x81 /* DDC bus access frequency control (LSB) */ | ||
127 | #define HDMI_DDC_BUS_ACCESS_FREQ_CTRL_15_8 0x82 /* DDC bus access frequency control (MSB) */ | ||
128 | #define HDMI_INTERRUPT_MASK_1 0x92 /* Interrupt mask.1 */ | ||
129 | #define HDMI_INTERRUPT_MASK_2 0x93 /* Interrupt mask.2 */ | ||
130 | #define HDMI_INTERRUPT_STATUS_1 0x94 /* Interrupt status.1 */ | ||
131 | #define HDMI_INTERRUPT_STATUS_2 0x95 /* Interrupt status.2 */ | ||
132 | #define HDMI_INTERRUPT_MASK_3 0x96 /* Interrupt mask.3 */ | ||
133 | #define HDMI_INTERRUPT_MASK_4 0x97 /* Interrupt mask.4 */ | ||
134 | #define HDMI_INTERRUPT_STATUS_3 0x98 /* Interrupt status.3 */ | ||
135 | #define HDMI_INTERRUPT_STATUS_4 0x99 /* Interrupt status.4 */ | ||
136 | #define HDMI_SOFTWARE_HDCP_CONTROL_1 0x9A /* Software HDCP control.1 */ | ||
137 | #define HDMI_FRAME_COUNTER 0x9C /* Frame counter */ | ||
138 | #define HDMI_FRAME_COUNTER_FOR_RI_CHECK 0x9D /* Frame counter for Ri check */ | ||
139 | #define HDMI_HDCP_CONTROL 0xAF /* HDCP control */ | ||
140 | #define HDMI_RI_FRAME_COUNT_REGISTER 0xB2 /* Ri frame count register */ | ||
141 | #define HDMI_DDC_BUS_CONTROL 0xB7 /* DDC bus control */ | ||
142 | #define HDMI_HDCP_STATUS 0xB8 /* HDCP status */ | ||
143 | #define HDMI_SHA0 0xB9 /* sha0 */ | ||
144 | #define HDMI_SHA1 0xBA /* sha1 */ | ||
145 | #define HDMI_SHA2 0xBB /* sha2 */ | ||
146 | #define HDMI_SHA3 0xBC /* sha3 */ | ||
147 | #define HDMI_SHA4 0xBD /* sha4 */ | ||
148 | #define HDMI_BCAPS_READ 0xBE /* BCAPS read / debug */ | ||
149 | #define HDMI_AKSV_BKSV_7_0_MONITOR 0xBF /* AKSV/BKSV[7:0] monitor */ | ||
150 | #define HDMI_AKSV_BKSV_15_8_MONITOR 0xC0 /* AKSV/BKSV[15:8] monitor */ | ||
151 | #define HDMI_AKSV_BKSV_23_16_MONITOR 0xC1 /* AKSV/BKSV[23:16] monitor */ | ||
152 | #define HDMI_AKSV_BKSV_31_24_MONITOR 0xC2 /* AKSV/BKSV[31:24] monitor */ | ||
153 | #define HDMI_AKSV_BKSV_39_32_MONITOR 0xC3 /* AKSV/BKSV[39:32] monitor */ | ||
154 | #define HDMI_EDID_SEGMENT_POINTER 0xC4 /* EDID segment pointer */ | ||
155 | #define HDMI_EDID_WORD_ADDRESS 0xC5 /* EDID word address */ | ||
156 | #define HDMI_EDID_DATA_FIFO_ADDRESS 0xC6 /* EDID data FIFO address */ | ||
157 | #define HDMI_NUM_OF_HDMI_DEVICES 0xC7 /* Number of HDMI devices */ | ||
158 | #define HDMI_HDCP_ERROR_CODE 0xC8 /* HDCP error code */ | ||
159 | #define HDMI_100MS_TIMER_SET 0xC9 /* 100ms timer setting */ | ||
160 | #define HDMI_5SEC_TIMER_SET 0xCA /* 5sec timer setting */ | ||
161 | #define HDMI_RI_READ_COUNT 0xCB /* Ri read count */ | ||
162 | #define HDMI_AN_SEED 0xCC /* An seed */ | ||
163 | #define HDMI_MAX_NUM_OF_RCIVRS_ALLOWED 0xCD /* Maximum number of receivers allowed */ | ||
164 | #define HDMI_HDCP_MEMORY_ACCESS_CONTROL_1 0xCE /* HDCP memory access control.1 */ | ||
165 | #define HDMI_HDCP_MEMORY_ACCESS_CONTROL_2 0xCF /* HDCP memory access control.2 */ | ||
166 | #define HDMI_HDCP_CONTROL_2 0xD0 /* HDCP Control 2 */ | ||
167 | #define HDMI_HDCP_KEY_MEMORY_CONTROL 0xD2 /* HDCP Key Memory Control */ | ||
168 | #define HDMI_COLOR_SPACE_CONV_CONFIG_1 0xD3 /* Color space conversion configuration.1 */ | ||
169 | #define HDMI_VIDEO_SETTING_3 0xD4 /* Video setting.3 */ | ||
170 | #define HDMI_RI_7_0 0xD5 /* Ri[7:0] */ | ||
171 | #define HDMI_RI_15_8 0xD6 /* Ri[15:8] */ | ||
172 | #define HDMI_PJ 0xD7 /* Pj */ | ||
173 | #define HDMI_SHA_RD 0xD8 /* sha_rd */ | ||
174 | #define HDMI_RI_7_0_SAVED 0xD9 /* Ri[7:0] saved */ | ||
175 | #define HDMI_RI_15_8_SAVED 0xDA /* Ri[15:8] saved */ | ||
176 | #define HDMI_PJ_SAVED 0xDB /* Pj saved */ | ||
177 | #define HDMI_NUM_OF_DEVICES 0xDC /* Number of devices */ | ||
178 | #define HDMI_HOT_PLUG_MSENS_STATUS 0xDF /* Hot plug/MSENS status */ | ||
179 | #define HDMI_BCAPS_WRITE 0xE0 /* bcaps */ | ||
180 | #define HDMI_BSTAT_7_0 0xE1 /* bstat[7:0] */ | ||
181 | #define HDMI_BSTAT_15_8 0xE2 /* bstat[15:8] */ | ||
182 | #define HDMI_BKSV_7_0 0xE3 /* bksv[7:0] */ | ||
183 | #define HDMI_BKSV_15_8 0xE4 /* bksv[15:8] */ | ||
184 | #define HDMI_BKSV_23_16 0xE5 /* bksv[23:16] */ | ||
185 | #define HDMI_BKSV_31_24 0xE6 /* bksv[31:24] */ | ||
186 | #define HDMI_BKSV_39_32 0xE7 /* bksv[39:32] */ | ||
187 | #define HDMI_AN_7_0 0xE8 /* An[7:0] */ | ||
188 | #define HDMI_AN_15_8 0xE9 /* An [15:8] */ | ||
189 | #define HDMI_AN_23_16 0xEA /* An [23:16] */ | ||
190 | #define HDMI_AN_31_24 0xEB /* An [31:24] */ | ||
191 | #define HDMI_AN_39_32 0xEC /* An [39:32] */ | ||
192 | #define HDMI_AN_47_40 0xED /* An [47:40] */ | ||
193 | #define HDMI_AN_55_48 0xEE /* An [55:48] */ | ||
194 | #define HDMI_AN_63_56 0xEF /* An [63:56] */ | ||
195 | #define HDMI_PRODUCT_ID 0xF0 /* Product ID */ | ||
196 | #define HDMI_REVISION_ID 0xF1 /* Revision ID */ | ||
197 | #define HDMI_TEST_MODE 0xFE /* Test mode */ | ||
198 | |||
199 | enum hotplug_state { | ||
200 | HDMI_HOTPLUG_DISCONNECTED, | ||
201 | HDMI_HOTPLUG_CONNECTED, | ||
202 | HDMI_HOTPLUG_EDID_DONE, | ||
203 | }; | ||
204 | |||
205 | struct sh_hdmi { | ||
206 | void __iomem *base; | ||
207 | enum hotplug_state hp_state; | ||
208 | struct clk *hdmi_clk; | ||
209 | struct device *dev; | ||
210 | struct fb_info *info; | ||
211 | struct delayed_work edid_work; | ||
212 | struct fb_var_screeninfo var; | ||
213 | }; | ||
214 | |||
215 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | ||
216 | { | ||
217 | iowrite8(data, hdmi->base + reg); | ||
218 | } | ||
219 | |||
220 | static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg) | ||
221 | { | ||
222 | return ioread8(hdmi->base + reg); | ||
223 | } | ||
224 | |||
225 | /* External video parameter settings */ | ||
226 | static void hdmi_external_video_param(struct sh_hdmi *hdmi) | ||
227 | { | ||
228 | struct fb_var_screeninfo *var = &hdmi->var; | ||
229 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; | ||
230 | u8 sync = 0; | ||
231 | |||
232 | htotal = var->xres + var->right_margin + var->left_margin + var->hsync_len; | ||
233 | |||
234 | hdelay = var->hsync_len + var->left_margin; | ||
235 | hblank = var->right_margin + hdelay; | ||
236 | |||
237 | /* | ||
238 | * Vertical timing looks a bit different in Figure 18, | ||
239 | * but let's try the same first by setting offset = 0 | ||
240 | */ | ||
241 | vtotal = var->yres + var->upper_margin + var->lower_margin + var->vsync_len; | ||
242 | |||
243 | vdelay = var->vsync_len + var->upper_margin; | ||
244 | vblank = var->lower_margin + vdelay; | ||
245 | voffset = min(var->upper_margin / 2, 6U); | ||
246 | |||
247 | /* | ||
248 | * [3]: VSYNC polarity: Positive | ||
249 | * [2]: HSYNC polarity: Positive | ||
250 | * [1]: Interlace/Progressive: Progressive | ||
251 | * [0]: External video settings enable: used. | ||
252 | */ | ||
253 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
254 | sync |= 4; | ||
255 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
256 | sync |= 8; | ||
257 | |||
258 | pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", | ||
259 | htotal, hblank, hdelay, var->hsync_len, | ||
260 | vtotal, vblank, vdelay, var->vsync_len, sync); | ||
261 | |||
262 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | ||
263 | |||
264 | hdmi_write(hdmi, htotal, HDMI_EXTERNAL_H_TOTAL_7_0); | ||
265 | hdmi_write(hdmi, htotal >> 8, HDMI_EXTERNAL_H_TOTAL_11_8); | ||
266 | |||
267 | hdmi_write(hdmi, hblank, HDMI_EXTERNAL_H_BLANK_7_0); | ||
268 | hdmi_write(hdmi, hblank >> 8, HDMI_EXTERNAL_H_BLANK_9_8); | ||
269 | |||
270 | hdmi_write(hdmi, hdelay, HDMI_EXTERNAL_H_DELAY_7_0); | ||
271 | hdmi_write(hdmi, hdelay >> 8, HDMI_EXTERNAL_H_DELAY_9_8); | ||
272 | |||
273 | hdmi_write(hdmi, var->hsync_len, HDMI_EXTERNAL_H_DURATION_7_0); | ||
274 | hdmi_write(hdmi, var->hsync_len >> 8, HDMI_EXTERNAL_H_DURATION_9_8); | ||
275 | |||
276 | hdmi_write(hdmi, vtotal, HDMI_EXTERNAL_V_TOTAL_7_0); | ||
277 | hdmi_write(hdmi, vtotal >> 8, HDMI_EXTERNAL_V_TOTAL_9_8); | ||
278 | |||
279 | hdmi_write(hdmi, vblank, HDMI_EXTERNAL_V_BLANK); | ||
280 | |||
281 | hdmi_write(hdmi, vdelay, HDMI_EXTERNAL_V_DELAY); | ||
282 | |||
283 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); | ||
284 | |||
285 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for manual mode */ | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * sh_hdmi_video_config() | ||
290 | */ | ||
291 | static void sh_hdmi_video_config(struct sh_hdmi *hdmi) | ||
292 | { | ||
293 | /* | ||
294 | * [7:4]: Audio sampling frequency: 48kHz | ||
295 | * [3:1]: Input video format: RGB and YCbCr 4:4:4 (Y on Green) | ||
296 | * [0]: Internal/External DE select: internal | ||
297 | */ | ||
298 | hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1); | ||
299 | |||
300 | /* | ||
301 | * [7:6]: Video output format: RGB 4:4:4 | ||
302 | * [5:4]: Input video data width: 8 bit | ||
303 | * [3:1]: EAV/SAV location: channel 1 | ||
304 | * [0]: Video input color space: RGB | ||
305 | */ | ||
306 | hdmi_write(hdmi, 0x34, HDMI_VIDEO_SETTING_1); | ||
307 | |||
308 | /* | ||
309 | * [7:6]: Together with bit [6] of HDMI_AUDIO_VIDEO_SETTING_2, which is | ||
310 | * left at 0 by default, this configures 24bpp and sets the Color Depth | ||
311 | * (CD) field in the General Control Packet | ||
312 | */ | ||
313 | hdmi_write(hdmi, 0x20, HDMI_DEEP_COLOR_MODES); | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * sh_hdmi_audio_config() | ||
318 | */ | ||
319 | static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) | ||
320 | { | ||
321 | /* | ||
322 | * [7:4] L/R data swap control | ||
323 | * [3:0] appropriate N[19:16] | ||
324 | */ | ||
325 | hdmi_write(hdmi, 0x00, HDMI_L_R_DATA_SWAP_CTRL_RPKT); | ||
326 | /* appropriate N[15:8] */ | ||
327 | hdmi_write(hdmi, 0x18, HDMI_20_BIT_N_FOR_AUDIO_RPKT_15_8); | ||
328 | /* appropriate N[7:0] */ | ||
329 | hdmi_write(hdmi, 0x00, HDMI_20_BIT_N_FOR_AUDIO_RPKT_7_0); | ||
330 | |||
331 | /* [7:4] 48 kHz SPDIF not used */ | ||
332 | hdmi_write(hdmi, 0x20, HDMI_SPDIF_AUDIO_SAMP_FREQ_CTS); | ||
333 | |||
334 | /* | ||
335 | * [6:5] set required down sampling rate if required | ||
336 | * [4:3] set required audio source | ||
337 | */ | ||
338 | hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1); | ||
339 | |||
340 | /* [3:0] set sending channel number for channel status */ | ||
341 | hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2); | ||
342 | |||
343 | /* | ||
344 | * [5:2] set valid I2S source input pin | ||
345 | * [1:0] set input I2S source mode | ||
346 | */ | ||
347 | hdmi_write(hdmi, 0x04, HDMI_I2S_AUDIO_SET); | ||
348 | |||
349 | /* [7:4] set valid DSD source input pin */ | ||
350 | hdmi_write(hdmi, 0x00, HDMI_DSD_AUDIO_SET); | ||
351 | |||
352 | /* [7:0] set appropriate I2S input pin swap settings if required */ | ||
353 | hdmi_write(hdmi, 0x00, HDMI_I2S_INPUT_PIN_SWAP); | ||
354 | |||
355 | /* | ||
356 | * [7] set validity bit for channel status | ||
357 | * [3:0] set original sample frequency for channel status | ||
358 | */ | ||
359 | hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_1); | ||
360 | |||
361 | /* | ||
362 | * [7] set value for channel status | ||
363 | * [6] set value for channel status | ||
364 | * [5] set copyright bit for channel status | ||
365 | * [4:2] set additional information for channel status | ||
366 | * [1:0] set clock accuracy for channel status | ||
367 | */ | ||
368 | hdmi_write(hdmi, 0x00, HDMI_AUDIO_STATUS_BITS_SETTING_2); | ||
369 | |||
370 | /* [7:0] set category code for channel status */ | ||
371 | hdmi_write(hdmi, 0x00, HDMI_CATEGORY_CODE); | ||
372 | |||
373 | /* | ||
374 | * [7:4] set source number for channel status | ||
375 | * [3:0] set word length for channel status | ||
376 | */ | ||
377 | hdmi_write(hdmi, 0x00, HDMI_SOURCE_NUM_AUDIO_WORD_LEN); | ||
378 | |||
379 | /* [7:4] set sample frequency for channel status */ | ||
380 | hdmi_write(hdmi, 0x20, HDMI_AUDIO_VIDEO_SETTING_1); | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * sh_hdmi_phy_config() | ||
385 | */ | ||
386 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | ||
387 | { | ||
388 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ | ||
389 | hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | ||
390 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | ||
391 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | ||
392 | /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ | ||
393 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | ||
394 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | ||
395 | hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | ||
396 | hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | ||
397 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | ||
398 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * sh_hdmi_avi_infoframe_setup() - Auxiliary Video Information InfoFrame CONTROL PACKET | ||
403 | */ | ||
404 | static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | ||
405 | { | ||
406 | /* AVI InfoFrame */ | ||
407 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); | ||
408 | |||
409 | /* Packet Type = 0x82 */ | ||
410 | hdmi_write(hdmi, 0x82, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
411 | |||
412 | /* Version = 0x02 */ | ||
413 | hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
414 | |||
415 | /* Length = 13 (0x0D) */ | ||
416 | hdmi_write(hdmi, 0x0D, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
417 | |||
418 | /* N. A. Checksum */ | ||
419 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0); | ||
420 | |||
421 | /* | ||
422 | * Y = RGB | ||
423 | * A0 = No Data | ||
424 | * B = Bar Data not valid | ||
425 | * S = No Data | ||
426 | */ | ||
427 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); | ||
428 | |||
429 | /* | ||
430 | * C = No Data | ||
431 | * M = 16:9 Picture Aspect Ratio | ||
432 | * R = Same as picture aspect ratio | ||
433 | */ | ||
434 | hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); | ||
435 | |||
436 | /* | ||
437 | * ITC = No Data | ||
438 | * EC = xvYCC601 | ||
439 | * Q = Default (depends on video format) | ||
440 | * SC = No Known non_uniform Scaling | ||
441 | */ | ||
442 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); | ||
443 | |||
444 | /* | ||
445 | * VIC = 1280 x 720p: ignored if external config is used | ||
446 | * Send 2 for 720 x 480p, 16 for 1080p | ||
447 | */ | ||
448 | hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | ||
449 | |||
450 | /* PR = No Repetition */ | ||
451 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); | ||
452 | |||
453 | /* Line Number of End of Top Bar (lower 8 bits) */ | ||
454 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6); | ||
455 | |||
456 | /* Line Number of End of Top Bar (upper 8 bits) */ | ||
457 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7); | ||
458 | |||
459 | /* Line Number of Start of Bottom Bar (lower 8 bits) */ | ||
460 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8); | ||
461 | |||
462 | /* Line Number of Start of Bottom Bar (upper 8 bits) */ | ||
463 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9); | ||
464 | |||
465 | /* Pixel Number of End of Left Bar (lower 8 bits) */ | ||
466 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10); | ||
467 | |||
468 | /* Pixel Number of End of Left Bar (upper 8 bits) */ | ||
469 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB11); | ||
470 | |||
471 | /* Pixel Number of Start of Right Bar (lower 8 bits) */ | ||
472 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB12); | ||
473 | |||
474 | /* Pixel Number of Start of Right Bar (upper 8 bits) */ | ||
475 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB13); | ||
476 | } | ||
477 | |||
478 | /** | ||
479 | * sh_hdmi_audio_infoframe_setup() - Audio InfoFrame of CONTROL PACKET | ||
480 | */ | ||
481 | static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) | ||
482 | { | ||
483 | /* Audio InfoFrame */ | ||
484 | hdmi_write(hdmi, 0x08, HDMI_CTRL_PKT_BUF_INDEX); | ||
485 | |||
486 | /* Packet Type = 0x84 */ | ||
487 | hdmi_write(hdmi, 0x84, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
488 | |||
489 | /* Version Number = 0x01 */ | ||
490 | hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
491 | |||
492 | /* 0 Length = 10 (0x0A) */ | ||
493 | hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
494 | |||
495 | /* n. a. Checksum */ | ||
496 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0); | ||
497 | |||
498 | /* Audio Channel Count = Refer to Stream Header */ | ||
499 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); | ||
500 | |||
501 | /* Refer to Stream Header */ | ||
502 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB2); | ||
503 | |||
504 | /* Format depends on coding type (i.e. CT0...CT3) */ | ||
505 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); | ||
506 | |||
507 | /* Speaker Channel Allocation = Front Right + Front Left */ | ||
508 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | ||
509 | |||
510 | /* Level Shift Value = 0 dB, Down - mix is permitted or no information */ | ||
511 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); | ||
512 | |||
513 | /* Reserved (0) */ | ||
514 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB6); | ||
515 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB7); | ||
516 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB8); | ||
517 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB9); | ||
518 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10); | ||
519 | } | ||
520 | |||
521 | /** | ||
522 | * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET | ||
523 | */ | ||
524 | static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) | ||
525 | { | ||
526 | int i; | ||
527 | |||
528 | /* Gamut Metadata Packet */ | ||
529 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); | ||
530 | |||
531 | /* Packet Type = 0x0A */ | ||
532 | hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
533 | /* Gamut Packet is not used, so default value */ | ||
534 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
535 | /* Gamut Packet is not used, so default value */ | ||
536 | hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
537 | |||
538 | /* GBD bytes 0 through 27 */ | ||
539 | for (i = 0; i <= 27; i++) | ||
540 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ | ||
541 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) | ||
546 | */ | ||
547 | static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) | ||
548 | { | ||
549 | int i; | ||
550 | |||
551 | /* Audio Content Protection Packet (ACP) */ | ||
552 | hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); | ||
553 | |||
554 | /* Packet Type = 0x04 */ | ||
555 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
556 | /* ACP_Type */ | ||
557 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
558 | /* Reserved (0) */ | ||
559 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
560 | |||
561 | /* GBD bytes 0 through 27 */ | ||
562 | for (i = 0; i <= 27; i++) | ||
563 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
564 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
565 | } | ||
566 | |||
567 | /** | ||
568 | * sh_hdmi_isrc1_setup() - ISRC1 Packet | ||
569 | */ | ||
570 | static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) | ||
571 | { | ||
572 | int i; | ||
573 | |||
574 | /* ISRC1 Packet */ | ||
575 | hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); | ||
576 | |||
577 | /* Packet Type = 0x05 */ | ||
578 | hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
579 | /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ | ||
580 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
581 | /* Reserved (0) */ | ||
582 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
583 | |||
584 | /* PB0 UPC_EAN_ISRC_0-15 */ | ||
585 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
586 | for (i = 0; i <= 27; i++) | ||
587 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
588 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * sh_hdmi_isrc2_setup() - ISRC2 Packet | ||
593 | */ | ||
594 | static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) | ||
595 | { | ||
596 | int i; | ||
597 | |||
598 | /* ISRC2 Packet */ | ||
599 | hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); | ||
600 | |||
601 | /* HB0 Packet Type = 0x06 */ | ||
602 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
603 | /* Reserved (0) */ | ||
604 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
605 | /* Reserved (0) */ | ||
606 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
607 | |||
608 | /* PB0 UPC_EAN_ISRC_16-31 */ | ||
609 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
610 | for (i = 0; i <= 27; i++) | ||
611 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
612 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
613 | } | ||
614 | |||
615 | /** | ||
616 | * sh_hdmi_configure() - Initialise HDMI for output | ||
617 | */ | ||
618 | static void sh_hdmi_configure(struct sh_hdmi *hdmi) | ||
619 | { | ||
620 | /* Configure video format */ | ||
621 | sh_hdmi_video_config(hdmi); | ||
622 | |||
623 | /* Configure audio format */ | ||
624 | sh_hdmi_audio_config(hdmi); | ||
625 | |||
626 | /* Configure PHY */ | ||
627 | sh_hdmi_phy_config(hdmi); | ||
628 | |||
629 | /* Auxiliary Video Information (AVI) InfoFrame */ | ||
630 | sh_hdmi_avi_infoframe_setup(hdmi); | ||
631 | |||
632 | /* Audio InfoFrame */ | ||
633 | sh_hdmi_audio_infoframe_setup(hdmi); | ||
634 | |||
635 | /* Gamut Metadata packet */ | ||
636 | sh_hdmi_gamut_metadata_setup(hdmi); | ||
637 | |||
638 | /* Audio Content Protection (ACP) Packet */ | ||
639 | sh_hdmi_acp_setup(hdmi); | ||
640 | |||
641 | /* ISRC1 Packet */ | ||
642 | sh_hdmi_isrc1_setup(hdmi); | ||
643 | |||
644 | /* ISRC2 Packet */ | ||
645 | sh_hdmi_isrc2_setup(hdmi); | ||
646 | |||
647 | /* | ||
648 | * Control packet auto send with VSYNC control: auto send | ||
649 | * General control, Gamut metadata, ISRC, and ACP packets | ||
650 | */ | ||
651 | hdmi_write(hdmi, 0x8E, HDMI_CTRL_PKT_AUTO_SEND); | ||
652 | |||
653 | /* FIXME */ | ||
654 | msleep(10); | ||
655 | |||
656 | /* PS mode b->d, reset PLLA and PLLB */ | ||
657 | hdmi_write(hdmi, 0x4C, HDMI_SYSTEM_CTRL); | ||
658 | |||
659 | udelay(10); | ||
660 | |||
661 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); | ||
662 | } | ||
663 | |||
664 | static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) | ||
665 | { | ||
666 | struct fb_var_screeninfo *var = &hdmi->var; | ||
667 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
668 | struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; | ||
669 | unsigned long height = var->height, width = var->width; | ||
670 | int i; | ||
671 | u8 edid[128]; | ||
672 | |||
673 | /* Read EDID */ | ||
674 | pr_debug("Read back EDID code:"); | ||
675 | for (i = 0; i < 128; i++) { | ||
676 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); | ||
677 | #ifdef DEBUG | ||
678 | if ((i % 16) == 0) { | ||
679 | printk(KERN_CONT "\n"); | ||
680 | printk(KERN_DEBUG "%02X | %02X", i, edid[i]); | ||
681 | } else { | ||
682 | printk(KERN_CONT " %02X", edid[i]); | ||
683 | } | ||
684 | #endif | ||
685 | } | ||
686 | #ifdef DEBUG | ||
687 | printk(KERN_CONT "\n"); | ||
688 | #endif | ||
689 | fb_parse_edid(edid, var); | ||
690 | pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", | ||
691 | var->left_margin, var->xres, var->right_margin, var->hsync_len, | ||
692 | var->upper_margin, var->yres, var->lower_margin, var->vsync_len, | ||
693 | PICOS2KHZ(var->pixclock)); | ||
694 | |||
695 | /* FIXME: Use user-provided configuration instead of EDID */ | ||
696 | var->width = width; | ||
697 | var->xres = lcd_cfg->xres; | ||
698 | var->xres_virtual = lcd_cfg->xres; | ||
699 | var->left_margin = lcd_cfg->left_margin; | ||
700 | var->right_margin = lcd_cfg->right_margin; | ||
701 | var->hsync_len = lcd_cfg->hsync_len; | ||
702 | var->height = height; | ||
703 | var->yres = lcd_cfg->yres; | ||
704 | var->yres_virtual = lcd_cfg->yres * 2; | ||
705 | var->upper_margin = lcd_cfg->upper_margin; | ||
706 | var->lower_margin = lcd_cfg->lower_margin; | ||
707 | var->vsync_len = lcd_cfg->vsync_len; | ||
708 | var->sync = lcd_cfg->sync; | ||
709 | var->pixclock = lcd_cfg->pixclock; | ||
710 | |||
711 | hdmi_external_video_param(hdmi); | ||
712 | } | ||
713 | |||
714 | static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | ||
715 | { | ||
716 | struct sh_hdmi *hdmi = dev_id; | ||
717 | u8 status1, status2, mask1, mask2; | ||
718 | |||
719 | /* mode_b and PLLA and PLLB reset */ | ||
720 | hdmi_write(hdmi, 0x2C, HDMI_SYSTEM_CTRL); | ||
721 | |||
722 | /* How long shall reset be held? */ | ||
723 | udelay(10); | ||
724 | |||
725 | /* mode_b and PLLA and PLLB reset release */ | ||
726 | hdmi_write(hdmi, 0x20, HDMI_SYSTEM_CTRL); | ||
727 | |||
728 | status1 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_1); | ||
729 | status2 = hdmi_read(hdmi, HDMI_INTERRUPT_STATUS_2); | ||
730 | |||
731 | mask1 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_1); | ||
732 | mask2 = hdmi_read(hdmi, HDMI_INTERRUPT_MASK_2); | ||
733 | |||
734 | /* Correct would be to ack only set bits, but the datasheet requires 0xff */ | ||
735 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_1); | ||
736 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); | ||
737 | |||
738 | if (printk_ratelimit()) | ||
739 | pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", | ||
740 | irq, status1, mask1, status2, mask2); | ||
741 | |||
742 | if (!((status1 & mask1) | (status2 & mask2))) { | ||
743 | return IRQ_NONE; | ||
744 | } else if (status1 & 0xc0) { | ||
745 | u8 msens; | ||
746 | |||
747 | /* Datasheet specifies 10ms... */ | ||
748 | udelay(500); | ||
749 | |||
750 | msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); | ||
751 | pr_debug("MSENS 0x%x\n", msens); | ||
752 | /* Check, if hot plug & MSENS pin status are both high */ | ||
753 | if ((msens & 0xC0) == 0xC0) { | ||
754 | /* Display plug in */ | ||
755 | hdmi->hp_state = HDMI_HOTPLUG_CONNECTED; | ||
756 | |||
757 | /* Set EDID word address */ | ||
758 | hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); | ||
759 | /* Set EDID segment pointer */ | ||
760 | hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); | ||
761 | /* Enable EDID interrupt */ | ||
762 | hdmi_write(hdmi, 0xC6, HDMI_INTERRUPT_MASK_1); | ||
763 | } else if (!(status1 & 0x80)) { | ||
764 | /* Display unplug, beware multiple interrupts */ | ||
765 | if (hdmi->hp_state != HDMI_HOTPLUG_DISCONNECTED) | ||
766 | schedule_delayed_work(&hdmi->edid_work, 0); | ||
767 | |||
768 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; | ||
769 | /* display_off will switch back to mode_a */ | ||
770 | } | ||
771 | } else if (status1 & 2) { | ||
772 | /* EDID error interrupt: retry */ | ||
773 | /* Set EDID word address */ | ||
774 | hdmi_write(hdmi, 0x00, HDMI_EDID_WORD_ADDRESS); | ||
775 | /* Set EDID segment pointer */ | ||
776 | hdmi_write(hdmi, 0x00, HDMI_EDID_SEGMENT_POINTER); | ||
777 | } else if (status1 & 4) { | ||
778 | /* Disable EDID interrupt */ | ||
779 | hdmi_write(hdmi, 0xC0, HDMI_INTERRUPT_MASK_1); | ||
780 | hdmi->hp_state = HDMI_HOTPLUG_EDID_DONE; | ||
781 | schedule_delayed_work(&hdmi->edid_work, msecs_to_jiffies(10)); | ||
782 | } | ||
783 | |||
784 | return IRQ_HANDLED; | ||
785 | } | ||
786 | |||
787 | static void hdmi_display_on(void *arg, struct fb_info *info) | ||
788 | { | ||
789 | struct sh_hdmi *hdmi = arg; | ||
790 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
791 | |||
792 | if (info->var.xres != 1280 || info->var.yres != 720) { | ||
793 | dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", | ||
794 | info->var.xres, info->var.yres); | ||
795 | return; | ||
796 | } | ||
797 | |||
798 | pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); | ||
799 | /* | ||
800 | * FIXME: not a good place to store fb_info. And we cannot nullify it | ||
801 | * even on monitor disconnect. What should the lifecycle be? | ||
802 | */ | ||
803 | hdmi->info = info; | ||
804 | switch (hdmi->hp_state) { | ||
805 | case HDMI_HOTPLUG_EDID_DONE: | ||
806 | /* PS mode d->e. All functions are active */ | ||
807 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); | ||
808 | pr_debug("HDMI running\n"); | ||
809 | break; | ||
810 | case HDMI_HOTPLUG_DISCONNECTED: | ||
811 | info->state = FBINFO_STATE_SUSPENDED; | ||
812 | default: | ||
813 | hdmi->var = info->var; | ||
814 | } | ||
815 | } | ||
816 | |||
817 | static void hdmi_display_off(void *arg) | ||
818 | { | ||
819 | struct sh_hdmi *hdmi = arg; | ||
820 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
821 | |||
822 | pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); | ||
823 | /* PS mode e->a */ | ||
824 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); | ||
825 | } | ||
826 | |||
827 | /* Hotplug interrupt occurred, read EDID */ | ||
828 | static void edid_work_fn(struct work_struct *work) | ||
829 | { | ||
830 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); | ||
831 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | ||
832 | |||
833 | pr_debug("%s(%p): begin, hotplug status %d\n", __func__, | ||
834 | pdata->lcd_dev, hdmi->hp_state); | ||
835 | |||
836 | if (!pdata->lcd_dev) | ||
837 | return; | ||
838 | |||
839 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { | ||
840 | pm_runtime_get_sync(hdmi->dev); | ||
841 | /* A device has been plugged in */ | ||
842 | sh_hdmi_read_edid(hdmi); | ||
843 | msleep(10); | ||
844 | sh_hdmi_configure(hdmi); | ||
845 | /* Switched to another (d) power-save mode */ | ||
846 | msleep(10); | ||
847 | |||
848 | if (!hdmi->info) | ||
849 | return; | ||
850 | |||
851 | acquire_console_sem(); | ||
852 | |||
853 | /* HDMI plug in */ | ||
854 | hdmi->info->var = hdmi->var; | ||
855 | if (hdmi->info->state != FBINFO_STATE_RUNNING) | ||
856 | fb_set_suspend(hdmi->info, 0); | ||
857 | else | ||
858 | hdmi_display_on(hdmi, hdmi->info); | ||
859 | |||
860 | release_console_sem(); | ||
861 | } else { | ||
862 | if (!hdmi->info) | ||
863 | return; | ||
864 | |||
865 | acquire_console_sem(); | ||
866 | |||
867 | /* HDMI disconnect */ | ||
868 | fb_set_suspend(hdmi->info, 1); | ||
869 | |||
870 | release_console_sem(); | ||
871 | pm_runtime_put(hdmi->dev); | ||
872 | } | ||
873 | |||
874 | pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); | ||
875 | } | ||
876 | |||
877 | static int __init sh_hdmi_probe(struct platform_device *pdev) | ||
878 | { | ||
879 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | ||
880 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
881 | int irq = platform_get_irq(pdev, 0), ret; | ||
882 | struct sh_hdmi *hdmi; | ||
883 | long rate; | ||
884 | |||
885 | if (!res || !pdata || irq < 0) | ||
886 | return -ENODEV; | ||
887 | |||
888 | hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); | ||
889 | if (!hdmi) { | ||
890 | dev_err(&pdev->dev, "Cannot allocate device data\n"); | ||
891 | return -ENOMEM; | ||
892 | } | ||
893 | |||
894 | hdmi->dev = &pdev->dev; | ||
895 | |||
896 | hdmi->hdmi_clk = clk_get(&pdev->dev, "ick"); | ||
897 | if (IS_ERR(hdmi->hdmi_clk)) { | ||
898 | ret = PTR_ERR(hdmi->hdmi_clk); | ||
899 | dev_err(&pdev->dev, "Unable to get clock: %d\n", ret); | ||
900 | goto egetclk; | ||
901 | } | ||
902 | |||
903 | rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; | ||
904 | |||
905 | rate = clk_round_rate(hdmi->hdmi_clk, rate); | ||
906 | if (rate < 0) { | ||
907 | ret = rate; | ||
908 | dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate); | ||
909 | goto erate; | ||
910 | } | ||
911 | |||
912 | ret = clk_set_rate(hdmi->hdmi_clk, rate); | ||
913 | if (ret < 0) { | ||
914 | dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret); | ||
915 | goto erate; | ||
916 | } | ||
917 | |||
918 | pr_debug("HDMI set frequency %lu\n", rate); | ||
919 | |||
920 | ret = clk_enable(hdmi->hdmi_clk); | ||
921 | if (ret < 0) { | ||
922 | dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret); | ||
923 | goto eclkenable; | ||
924 | } | ||
925 | |||
926 | dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); | ||
927 | |||
928 | if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { | ||
929 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); | ||
930 | ret = -EBUSY; | ||
931 | goto ereqreg; | ||
932 | } | ||
933 | |||
934 | hdmi->base = ioremap(res->start, resource_size(res)); | ||
935 | if (!hdmi->base) { | ||
936 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); | ||
937 | ret = -ENOMEM; | ||
938 | goto emap; | ||
939 | } | ||
940 | |||
941 | platform_set_drvdata(pdev, hdmi); | ||
942 | |||
943 | #if 1 | ||
944 | /* Product and revision IDs are 0 in sh-mobile version */ | ||
945 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", | ||
946 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); | ||
947 | #endif | ||
948 | |||
949 | /* Set up LCDC callbacks */ | ||
950 | pdata->lcd_chan->board_cfg.board_data = hdmi; | ||
951 | pdata->lcd_chan->board_cfg.display_on = hdmi_display_on; | ||
952 | pdata->lcd_chan->board_cfg.display_off = hdmi_display_off; | ||
953 | |||
954 | INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); | ||
955 | |||
956 | pm_runtime_enable(&pdev->dev); | ||
957 | pm_runtime_resume(&pdev->dev); | ||
958 | |||
959 | ret = request_irq(irq, sh_hdmi_hotplug, 0, | ||
960 | dev_name(&pdev->dev), hdmi); | ||
961 | if (ret < 0) { | ||
962 | dev_err(&pdev->dev, "Unable to request irq: %d\n", ret); | ||
963 | goto ereqirq; | ||
964 | } | ||
965 | |||
966 | return 0; | ||
967 | |||
968 | ereqirq: | ||
969 | pm_runtime_disable(&pdev->dev); | ||
970 | iounmap(hdmi->base); | ||
971 | emap: | ||
972 | release_mem_region(res->start, resource_size(res)); | ||
973 | ereqreg: | ||
974 | clk_disable(hdmi->hdmi_clk); | ||
975 | eclkenable: | ||
976 | erate: | ||
977 | clk_put(hdmi->hdmi_clk); | ||
978 | egetclk: | ||
979 | kfree(hdmi); | ||
980 | |||
981 | return ret; | ||
982 | } | ||
983 | |||
984 | static int __exit sh_hdmi_remove(struct platform_device *pdev) | ||
985 | { | ||
986 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | ||
987 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); | ||
988 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
989 | int irq = platform_get_irq(pdev, 0); | ||
990 | |||
991 | pdata->lcd_chan->board_cfg.display_on = NULL; | ||
992 | pdata->lcd_chan->board_cfg.display_off = NULL; | ||
993 | pdata->lcd_chan->board_cfg.board_data = NULL; | ||
994 | |||
995 | free_irq(irq, hdmi); | ||
996 | pm_runtime_disable(&pdev->dev); | ||
997 | cancel_delayed_work_sync(&hdmi->edid_work); | ||
998 | clk_disable(hdmi->hdmi_clk); | ||
999 | clk_put(hdmi->hdmi_clk); | ||
1000 | iounmap(hdmi->base); | ||
1001 | release_mem_region(res->start, resource_size(res)); | ||
1002 | kfree(hdmi); | ||
1003 | |||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static struct platform_driver sh_hdmi_driver = { | ||
1008 | .remove = __exit_p(sh_hdmi_remove), | ||
1009 | .driver = { | ||
1010 | .name = "sh-mobile-hdmi", | ||
1011 | }, | ||
1012 | }; | ||
1013 | |||
1014 | static int __init sh_hdmi_init(void) | ||
1015 | { | ||
1016 | return platform_driver_probe(&sh_hdmi_driver, sh_hdmi_probe); | ||
1017 | } | ||
1018 | module_init(sh_hdmi_init); | ||
1019 | |||
1020 | static void __exit sh_hdmi_exit(void) | ||
1021 | { | ||
1022 | platform_driver_unregister(&sh_hdmi_driver); | ||
1023 | } | ||
1024 | module_exit(sh_hdmi_exit); | ||
1025 | |||
1026 | MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); | ||
1027 | MODULE_DESCRIPTION("SuperH / ARM-shmobile HDMI driver"); | ||
1028 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 12c451a711e9..d72075a9f01c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -56,6 +56,7 @@ static int lcdc_shared_regs[] = { | |||
56 | /* per-channel registers */ | 56 | /* per-channel registers */ |
57 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | 57 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, |
58 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, | 58 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, |
59 | LDHAJR, | ||
59 | NR_CH_REGS }; | 60 | NR_CH_REGS }; |
60 | 61 | ||
61 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { | 62 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { |
@@ -74,6 +75,7 @@ static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { | |||
74 | [LDVLNR] = 0x450, | 75 | [LDVLNR] = 0x450, |
75 | [LDVSYNR] = 0x454, | 76 | [LDVSYNR] = 0x454, |
76 | [LDPMR] = 0x460, | 77 | [LDPMR] = 0x460, |
78 | [LDHAJR] = 0x4a0, | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | 81 | static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { |
@@ -137,6 +139,7 @@ struct sh_mobile_lcdc_priv { | |||
137 | struct clk *dot_clk; | 139 | struct clk *dot_clk; |
138 | unsigned long lddckr; | 140 | unsigned long lddckr; |
139 | struct sh_mobile_lcdc_chan ch[2]; | 141 | struct sh_mobile_lcdc_chan ch[2]; |
142 | struct notifier_block notifier; | ||
140 | unsigned long saved_shared_regs[NR_SHARED_REGS]; | 143 | unsigned long saved_shared_regs[NR_SHARED_REGS]; |
141 | int started; | 144 | int started; |
142 | }; | 145 | }; |
@@ -404,6 +407,56 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | |||
404 | lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ | 407 | lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */ |
405 | } | 408 | } |
406 | 409 | ||
410 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | ||
411 | { | ||
412 | struct fb_var_screeninfo *var = &ch->info->var; | ||
413 | unsigned long h_total, hsync_pos; | ||
414 | u32 tmp; | ||
415 | |||
416 | tmp = ch->ldmt1r_value; | ||
417 | tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; | ||
418 | tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; | ||
419 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; | ||
420 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; | ||
421 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; | ||
422 | tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; | ||
423 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; | ||
424 | lcdc_write_chan(ch, LDMT1R, tmp); | ||
425 | |||
426 | /* setup SYS bus */ | ||
427 | lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); | ||
428 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); | ||
429 | |||
430 | /* horizontal configuration */ | ||
431 | h_total = var->xres + var->hsync_len + | ||
432 | var->left_margin + var->right_margin; | ||
433 | tmp = h_total / 8; /* HTCN */ | ||
434 | tmp |= (var->xres / 8) << 16; /* HDCN */ | ||
435 | lcdc_write_chan(ch, LDHCNR, tmp); | ||
436 | |||
437 | hsync_pos = var->xres + var->right_margin; | ||
438 | tmp = hsync_pos / 8; /* HSYNP */ | ||
439 | tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ | ||
440 | lcdc_write_chan(ch, LDHSYNR, tmp); | ||
441 | |||
442 | /* vertical configuration */ | ||
443 | tmp = var->yres + var->vsync_len + | ||
444 | var->upper_margin + var->lower_margin; /* VTLN */ | ||
445 | tmp |= var->yres << 16; /* VDLN */ | ||
446 | lcdc_write_chan(ch, LDVLNR, tmp); | ||
447 | |||
448 | tmp = var->yres + var->lower_margin; /* VSYNP */ | ||
449 | tmp |= var->vsync_len << 16; /* VSYNW */ | ||
450 | lcdc_write_chan(ch, LDVSYNR, tmp); | ||
451 | |||
452 | /* Adjust horizontal synchronisation for HDMI */ | ||
453 | tmp = ((var->xres & 7) << 24) | | ||
454 | ((h_total & 7) << 16) | | ||
455 | ((var->hsync_len & 7) << 8) | | ||
456 | hsync_pos; | ||
457 | lcdc_write_chan(ch, LDHAJR, tmp); | ||
458 | } | ||
459 | |||
407 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | 460 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) |
408 | { | 461 | { |
409 | struct sh_mobile_lcdc_chan *ch; | 462 | struct sh_mobile_lcdc_chan *ch; |
@@ -470,49 +523,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
470 | if (!ch->enabled) | 523 | if (!ch->enabled) |
471 | continue; | 524 | continue; |
472 | 525 | ||
473 | tmp = ch->ldmt1r_value; | 526 | sh_mobile_lcdc_geometry(ch); |
474 | tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28; | ||
475 | tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27; | ||
476 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0; | ||
477 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0; | ||
478 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0; | ||
479 | tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0; | ||
480 | tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0; | ||
481 | lcdc_write_chan(ch, LDMT1R, tmp); | ||
482 | |||
483 | /* setup SYS bus */ | ||
484 | lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r); | ||
485 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); | ||
486 | |||
487 | /* horizontal configuration */ | ||
488 | tmp = lcd_cfg->xres + lcd_cfg->hsync_len; | ||
489 | tmp += lcd_cfg->left_margin; | ||
490 | tmp += lcd_cfg->right_margin; | ||
491 | tmp /= 8; /* HTCN */ | ||
492 | tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */ | ||
493 | lcdc_write_chan(ch, LDHCNR, tmp); | ||
494 | |||
495 | tmp = lcd_cfg->xres; | ||
496 | tmp += lcd_cfg->right_margin; | ||
497 | tmp /= 8; /* HSYNP */ | ||
498 | tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */ | ||
499 | lcdc_write_chan(ch, LDHSYNR, tmp); | ||
500 | 527 | ||
501 | /* power supply */ | 528 | /* power supply */ |
502 | lcdc_write_chan(ch, LDPMR, 0); | 529 | lcdc_write_chan(ch, LDPMR, 0); |
503 | 530 | ||
504 | /* vertical configuration */ | ||
505 | tmp = lcd_cfg->yres + lcd_cfg->vsync_len; | ||
506 | tmp += lcd_cfg->upper_margin; | ||
507 | tmp += lcd_cfg->lower_margin; /* VTLN */ | ||
508 | tmp |= lcd_cfg->yres << 16; /* VDLN */ | ||
509 | lcdc_write_chan(ch, LDVLNR, tmp); | ||
510 | |||
511 | tmp = lcd_cfg->yres; | ||
512 | tmp += lcd_cfg->lower_margin; /* VSYNP */ | ||
513 | tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */ | ||
514 | lcdc_write_chan(ch, LDVSYNR, tmp); | ||
515 | |||
516 | board_cfg = &ch->cfg.board_cfg; | 531 | board_cfg = &ch->cfg.board_cfg; |
517 | if (board_cfg->setup_sys) | 532 | if (board_cfg->setup_sys) |
518 | ret = board_cfg->setup_sys(board_cfg->board_data, ch, | 533 | ret = board_cfg->setup_sys(board_cfg->board_data, ch, |
@@ -577,7 +592,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
577 | 592 | ||
578 | board_cfg = &ch->cfg.board_cfg; | 593 | board_cfg = &ch->cfg.board_cfg; |
579 | if (board_cfg->display_on) | 594 | if (board_cfg->display_on) |
580 | board_cfg->display_on(board_cfg->board_data); | 595 | board_cfg->display_on(board_cfg->board_data, ch->info); |
581 | } | 596 | } |
582 | 597 | ||
583 | return 0; | 598 | return 0; |
@@ -943,6 +958,62 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { | |||
943 | .runtime_resume = sh_mobile_lcdc_runtime_resume, | 958 | .runtime_resume = sh_mobile_lcdc_runtime_resume, |
944 | }; | 959 | }; |
945 | 960 | ||
961 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, | ||
962 | unsigned long action, void *data) | ||
963 | { | ||
964 | struct fb_event *event = data; | ||
965 | struct fb_info *info = event->info; | ||
966 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
967 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | ||
968 | struct fb_var_screeninfo *var; | ||
969 | |||
970 | if (&ch->lcdc->notifier != nb) | ||
971 | return 0; | ||
972 | |||
973 | dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", | ||
974 | __func__, action, event->data); | ||
975 | |||
976 | switch(action) { | ||
977 | case FB_EVENT_SUSPEND: | ||
978 | if (board_cfg->display_off) | ||
979 | board_cfg->display_off(board_cfg->board_data); | ||
980 | pm_runtime_put(info->device); | ||
981 | break; | ||
982 | case FB_EVENT_RESUME: | ||
983 | var = &info->var; | ||
984 | |||
985 | /* HDMI must be enabled before LCDC configuration */ | ||
986 | if (board_cfg->display_on) | ||
987 | board_cfg->display_on(board_cfg->board_data, ch->info); | ||
988 | |||
989 | /* Check if the new display is not in our modelist */ | ||
990 | if (ch->info->modelist.next && | ||
991 | !fb_match_mode(var, &ch->info->modelist)) { | ||
992 | struct fb_videomode mode; | ||
993 | int ret; | ||
994 | |||
995 | /* Can we handle this display? */ | ||
996 | if (var->xres > ch->cfg.lcd_cfg.xres || | ||
997 | var->yres > ch->cfg.lcd_cfg.yres) | ||
998 | return -ENOMEM; | ||
999 | |||
1000 | /* Add to the modelist */ | ||
1001 | fb_var_to_videomode(&mode, var); | ||
1002 | ret = fb_add_videomode(&mode, &ch->info->modelist); | ||
1003 | if (ret < 0) | ||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | pm_runtime_get_sync(info->device); | ||
1008 | |||
1009 | sh_mobile_lcdc_geometry(ch); | ||
1010 | |||
1011 | break; | ||
1012 | } | ||
1013 | |||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
946 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); | 1017 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); |
947 | 1018 | ||
948 | static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | 1019 | static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) |
@@ -1020,15 +1091,19 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1020 | goto err1; | 1091 | goto err1; |
1021 | } | 1092 | } |
1022 | 1093 | ||
1094 | priv->base = ioremap_nocache(res->start, resource_size(res)); | ||
1095 | if (!priv->base) | ||
1096 | goto err1; | ||
1097 | |||
1023 | error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); | 1098 | error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv); |
1024 | if (error) { | 1099 | if (error) { |
1025 | dev_err(&pdev->dev, "unable to setup clocks\n"); | 1100 | dev_err(&pdev->dev, "unable to setup clocks\n"); |
1026 | goto err1; | 1101 | goto err1; |
1027 | } | 1102 | } |
1028 | 1103 | ||
1029 | priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1); | ||
1030 | |||
1031 | for (i = 0; i < j; i++) { | 1104 | for (i = 0; i < j; i++) { |
1105 | struct fb_var_screeninfo *var; | ||
1106 | struct fb_videomode *lcd_cfg; | ||
1032 | cfg = &priv->ch[i].cfg; | 1107 | cfg = &priv->ch[i].cfg; |
1033 | 1108 | ||
1034 | priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); | 1109 | priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); |
@@ -1039,22 +1114,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1039 | } | 1114 | } |
1040 | 1115 | ||
1041 | info = priv->ch[i].info; | 1116 | info = priv->ch[i].info; |
1117 | var = &info->var; | ||
1118 | lcd_cfg = &cfg->lcd_cfg; | ||
1042 | info->fbops = &sh_mobile_lcdc_ops; | 1119 | info->fbops = &sh_mobile_lcdc_ops; |
1043 | info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres; | 1120 | var->xres = var->xres_virtual = lcd_cfg->xres; |
1044 | info->var.yres = cfg->lcd_cfg.yres; | 1121 | var->yres = lcd_cfg->yres; |
1045 | /* Default Y virtual resolution is 2x panel size */ | 1122 | /* Default Y virtual resolution is 2x panel size */ |
1046 | info->var.yres_virtual = info->var.yres * 2; | 1123 | var->yres_virtual = var->yres * 2; |
1047 | info->var.width = cfg->lcd_size_cfg.width; | 1124 | var->width = cfg->lcd_size_cfg.width; |
1048 | info->var.height = cfg->lcd_size_cfg.height; | 1125 | var->height = cfg->lcd_size_cfg.height; |
1049 | info->var.activate = FB_ACTIVATE_NOW; | 1126 | var->activate = FB_ACTIVATE_NOW; |
1050 | error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp); | 1127 | var->left_margin = lcd_cfg->left_margin; |
1128 | var->right_margin = lcd_cfg->right_margin; | ||
1129 | var->upper_margin = lcd_cfg->upper_margin; | ||
1130 | var->lower_margin = lcd_cfg->lower_margin; | ||
1131 | var->hsync_len = lcd_cfg->hsync_len; | ||
1132 | var->vsync_len = lcd_cfg->vsync_len; | ||
1133 | var->sync = lcd_cfg->sync; | ||
1134 | var->pixclock = lcd_cfg->pixclock; | ||
1135 | |||
1136 | error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); | ||
1051 | if (error) | 1137 | if (error) |
1052 | break; | 1138 | break; |
1053 | 1139 | ||
1054 | info->fix = sh_mobile_lcdc_fix; | 1140 | info->fix = sh_mobile_lcdc_fix; |
1055 | info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8); | 1141 | info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); |
1056 | info->fix.smem_len = info->fix.line_length * | 1142 | info->fix.smem_len = info->fix.line_length * |
1057 | info->var.yres_virtual; | 1143 | var->yres_virtual; |
1058 | 1144 | ||
1059 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, | 1145 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, |
1060 | &priv->ch[i].dma_handle, GFP_KERNEL); | 1146 | &priv->ch[i].dma_handle, GFP_KERNEL); |
@@ -1119,10 +1205,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1119 | ch->cfg.bpp); | 1205 | ch->cfg.bpp); |
1120 | 1206 | ||
1121 | /* deferred io mode: disable clock to save power */ | 1207 | /* deferred io mode: disable clock to save power */ |
1122 | if (info->fbdefio) | 1208 | if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) |
1123 | sh_mobile_lcdc_clk_off(priv); | 1209 | sh_mobile_lcdc_clk_off(priv); |
1124 | } | 1210 | } |
1125 | 1211 | ||
1212 | /* Failure ignored */ | ||
1213 | priv->notifier.notifier_call = sh_mobile_lcdc_notify; | ||
1214 | fb_register_client(&priv->notifier); | ||
1215 | |||
1126 | return 0; | 1216 | return 0; |
1127 | err1: | 1217 | err1: |
1128 | sh_mobile_lcdc_remove(pdev); | 1218 | sh_mobile_lcdc_remove(pdev); |
@@ -1136,6 +1226,8 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev) | |||
1136 | struct fb_info *info; | 1226 | struct fb_info *info; |
1137 | int i; | 1227 | int i; |
1138 | 1228 | ||
1229 | fb_unregister_client(&priv->notifier); | ||
1230 | |||
1139 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) | 1231 | for (i = 0; i < ARRAY_SIZE(priv->ch); i++) |
1140 | if (priv->ch[i].info && priv->ch[i].info->dev) | 1232 | if (priv->ch[i].info && priv->ch[i].info->dev) |
1141 | unregister_framebuffer(priv->ch[i].info); | 1233 | unregister_framebuffer(priv->ch[i].info); |