2 * Samsung TV Mixer driver
4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published
10 * by the Free Software Foundiation. either version 2 of the License,
11 * or (at your option) any later version
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
19 #include <linux/interrupt.h>
20 #include <linux/irq.h>
22 #include <linux/delay.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/clk.h>
26 MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
27 MODULE_DESCRIPTION("Samsung MIXER");
28 MODULE_LICENSE("GPL");
30 /* --------- DRIVER PARAMETERS ---------- */
32 static struct mxr_output_conf mxr_output_conf
[] = {
34 .output_name
= "S5P HDMI connector",
35 .module_name
= "s5p-hdmi",
39 .output_name
= "S5P SDO connector",
40 .module_name
= "s5p-sdo",
45 void mxr_get_mbus_fmt(struct mxr_device
*mdev
,
46 struct v4l2_mbus_framefmt
*mbus_fmt
)
48 struct v4l2_subdev
*sd
;
51 mutex_lock(&mdev
->mutex
);
53 ret
= v4l2_subdev_call(sd
, video
, g_mbus_fmt
, mbus_fmt
);
54 WARN(ret
, "failed to get mbus_fmt for output %s\n", sd
->name
);
55 mutex_unlock(&mdev
->mutex
);
58 void mxr_streamer_get(struct mxr_device
*mdev
)
60 mutex_lock(&mdev
->mutex
);
62 mxr_dbg(mdev
, "%s(%d)\n", __func__
, mdev
->n_streamer
);
63 if (mdev
->n_streamer
== 1) {
64 struct v4l2_subdev
*sd
= to_outsd(mdev
);
65 struct v4l2_mbus_framefmt mbus_fmt
;
66 struct mxr_resources
*res
= &mdev
->res
;
69 if (to_output(mdev
)->cookie
== 0)
70 clk_set_parent(res
->sclk_mixer
, res
->sclk_dac
);
72 clk_set_parent(res
->sclk_mixer
, res
->sclk_hdmi
);
73 mxr_reg_s_output(mdev
, to_output(mdev
)->cookie
);
75 ret
= v4l2_subdev_call(sd
, video
, g_mbus_fmt
, &mbus_fmt
);
76 WARN(ret
, "failed to get mbus_fmt for output %s\n", sd
->name
);
77 ret
= v4l2_subdev_call(sd
, video
, s_stream
, 1);
78 WARN(ret
, "starting stream failed for output %s\n", sd
->name
);
80 mxr_reg_set_mbus_fmt(mdev
, &mbus_fmt
);
81 mxr_reg_streamon(mdev
);
82 ret
= mxr_reg_wait4vsync(mdev
);
83 WARN(ret
, "failed to get vsync (%d) from output\n", ret
);
85 mutex_unlock(&mdev
->mutex
);
87 /* FIXME: what to do when streaming fails? */
90 void mxr_streamer_put(struct mxr_device
*mdev
)
92 mutex_lock(&mdev
->mutex
);
94 mxr_dbg(mdev
, "%s(%d)\n", __func__
, mdev
->n_streamer
);
95 if (mdev
->n_streamer
== 0) {
97 struct v4l2_subdev
*sd
= to_outsd(mdev
);
99 mxr_reg_streamoff(mdev
);
100 /* vsync applies Mixer setup */
101 ret
= mxr_reg_wait4vsync(mdev
);
102 WARN(ret
, "failed to get vsync (%d) from output\n", ret
);
103 ret
= v4l2_subdev_call(sd
, video
, s_stream
, 0);
104 WARN(ret
, "stopping stream failed for output %s\n", sd
->name
);
106 WARN(mdev
->n_streamer
< 0, "negative number of streamers (%d)\n",
108 mutex_unlock(&mdev
->mutex
);
112 void mxr_output_get(struct mxr_device
*mdev
)
114 mutex_lock(&mdev
->mutex
);
116 mxr_dbg(mdev
, "%s(%d)\n", __func__
, mdev
->n_output
);
117 /* turn on auxiliary driver */
118 if (mdev
->n_output
== 1)
119 v4l2_subdev_call(to_outsd(mdev
), core
, s_power
, 1);
120 mutex_unlock(&mdev
->mutex
);
123 void mxr_output_put(struct mxr_device
*mdev
)
125 mutex_lock(&mdev
->mutex
);
127 mxr_dbg(mdev
, "%s(%d)\n", __func__
, mdev
->n_output
);
128 /* turn on auxiliary driver */
129 if (mdev
->n_output
== 0)
130 v4l2_subdev_call(to_outsd(mdev
), core
, s_power
, 0);
131 WARN(mdev
->n_output
< 0, "negative number of output users (%d)\n",
133 mutex_unlock(&mdev
->mutex
);
136 int mxr_power_get(struct mxr_device
*mdev
)
138 int ret
= pm_runtime_get_sync(mdev
->dev
);
140 /* returning 1 means that power is already enabled,
141 * so zero success be returned */
142 if (IS_ERR_VALUE(ret
))
147 void mxr_power_put(struct mxr_device
*mdev
)
149 pm_runtime_put_sync(mdev
->dev
);
152 /* --------- RESOURCE MANAGEMENT -------------*/
154 static int mxr_acquire_plat_resources(struct mxr_device
*mdev
,
155 struct platform_device
*pdev
)
157 struct resource
*res
;
160 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "mxr");
162 mxr_err(mdev
, "get memory resource failed.\n");
167 mdev
->res
.mxr_regs
= ioremap(res
->start
, resource_size(res
));
168 if (mdev
->res
.mxr_regs
== NULL
) {
169 mxr_err(mdev
, "register mapping failed.\n");
174 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "vp");
176 mxr_err(mdev
, "get memory resource failed.\n");
181 mdev
->res
.vp_regs
= ioremap(res
->start
, resource_size(res
));
182 if (mdev
->res
.vp_regs
== NULL
) {
183 mxr_err(mdev
, "register mapping failed.\n");
188 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "irq");
190 mxr_err(mdev
, "get interrupt resource failed.\n");
195 ret
= request_irq(res
->start
, mxr_irq_handler
, 0, "s5p-mixer", mdev
);
197 mxr_err(mdev
, "request interrupt failed.\n");
200 mdev
->res
.irq
= res
->start
;
205 iounmap(mdev
->res
.vp_regs
);
208 iounmap(mdev
->res
.mxr_regs
);
214 static void mxr_resource_clear_clocks(struct mxr_resources
*res
)
216 res
->mixer
= ERR_PTR(-EINVAL
);
217 res
->vp
= ERR_PTR(-EINVAL
);
218 res
->sclk_mixer
= ERR_PTR(-EINVAL
);
219 res
->sclk_hdmi
= ERR_PTR(-EINVAL
);
220 res
->sclk_dac
= ERR_PTR(-EINVAL
);
223 static void mxr_release_plat_resources(struct mxr_device
*mdev
)
225 free_irq(mdev
->res
.irq
, mdev
);
226 iounmap(mdev
->res
.vp_regs
);
227 iounmap(mdev
->res
.mxr_regs
);
230 static void mxr_release_clocks(struct mxr_device
*mdev
)
232 struct mxr_resources
*res
= &mdev
->res
;
234 if (!IS_ERR(res
->sclk_dac
))
235 clk_put(res
->sclk_dac
);
236 if (!IS_ERR(res
->sclk_hdmi
))
237 clk_put(res
->sclk_hdmi
);
238 if (!IS_ERR(res
->sclk_mixer
))
239 clk_put(res
->sclk_mixer
);
240 if (!IS_ERR(res
->vp
))
242 if (!IS_ERR(res
->mixer
))
246 static int mxr_acquire_clocks(struct mxr_device
*mdev
)
248 struct mxr_resources
*res
= &mdev
->res
;
249 struct device
*dev
= mdev
->dev
;
251 mxr_resource_clear_clocks(res
);
253 res
->mixer
= clk_get(dev
, "mixer");
254 if (IS_ERR(res
->mixer
)) {
255 mxr_err(mdev
, "failed to get clock 'mixer'\n");
258 res
->vp
= clk_get(dev
, "vp");
259 if (IS_ERR(res
->vp
)) {
260 mxr_err(mdev
, "failed to get clock 'vp'\n");
263 res
->sclk_mixer
= clk_get(dev
, "sclk_mixer");
264 if (IS_ERR(res
->sclk_mixer
)) {
265 mxr_err(mdev
, "failed to get clock 'sclk_mixer'\n");
268 res
->sclk_hdmi
= clk_get(dev
, "sclk_hdmi");
269 if (IS_ERR(res
->sclk_hdmi
)) {
270 mxr_err(mdev
, "failed to get clock 'sclk_hdmi'\n");
273 res
->sclk_dac
= clk_get(dev
, "sclk_dac");
274 if (IS_ERR(res
->sclk_dac
)) {
275 mxr_err(mdev
, "failed to get clock 'sclk_dac'\n");
281 mxr_release_clocks(mdev
);
285 static int mxr_acquire_resources(struct mxr_device
*mdev
,
286 struct platform_device
*pdev
)
289 ret
= mxr_acquire_plat_resources(mdev
, pdev
);
294 ret
= mxr_acquire_clocks(mdev
);
298 mxr_info(mdev
, "resources acquired\n");
302 mxr_release_plat_resources(mdev
);
304 mxr_err(mdev
, "resources acquire failed\n");
308 static void mxr_release_resources(struct mxr_device
*mdev
)
310 mxr_release_clocks(mdev
);
311 mxr_release_plat_resources(mdev
);
312 memset(&mdev
->res
, 0, sizeof(mdev
->res
));
313 mxr_resource_clear_clocks(&mdev
->res
);
316 static void mxr_release_layers(struct mxr_device
*mdev
)
320 for (i
= 0; i
< ARRAY_SIZE(mdev
->layer
); ++i
)
322 mxr_layer_release(mdev
->layer
[i
]);
325 static int mxr_acquire_layers(struct mxr_device
*mdev
,
326 struct mxr_platform_data
*pdata
)
328 mdev
->layer
[0] = mxr_graph_layer_create(mdev
, 0);
329 mdev
->layer
[1] = mxr_graph_layer_create(mdev
, 1);
330 mdev
->layer
[2] = mxr_vp_layer_create(mdev
, 0);
332 if (!mdev
->layer
[0] || !mdev
->layer
[1] || !mdev
->layer
[2]) {
333 mxr_err(mdev
, "failed to acquire layers\n");
340 mxr_release_layers(mdev
);
344 /* ---------- POWER MANAGEMENT ----------- */
346 static int mxr_runtime_resume(struct device
*dev
)
348 struct mxr_device
*mdev
= to_mdev(dev
);
349 struct mxr_resources
*res
= &mdev
->res
;
351 mxr_dbg(mdev
, "resume - start\n");
352 mutex_lock(&mdev
->mutex
);
354 clk_enable(res
->mixer
);
356 clk_enable(res
->sclk_mixer
);
357 /* apply default configuration */
359 mxr_dbg(mdev
, "resume - finished\n");
361 mutex_unlock(&mdev
->mutex
);
365 static int mxr_runtime_suspend(struct device
*dev
)
367 struct mxr_device
*mdev
= to_mdev(dev
);
368 struct mxr_resources
*res
= &mdev
->res
;
369 mxr_dbg(mdev
, "suspend - start\n");
370 mutex_lock(&mdev
->mutex
);
371 /* turn clocks off */
372 clk_disable(res
->sclk_mixer
);
373 clk_disable(res
->vp
);
374 clk_disable(res
->mixer
);
375 mutex_unlock(&mdev
->mutex
);
376 mxr_dbg(mdev
, "suspend - finished\n");
380 static const struct dev_pm_ops mxr_pm_ops
= {
381 .runtime_suspend
= mxr_runtime_suspend
,
382 .runtime_resume
= mxr_runtime_resume
,
385 /* --------- DRIVER INITIALIZATION ---------- */
387 static int mxr_probe(struct platform_device
*pdev
)
389 struct device
*dev
= &pdev
->dev
;
390 struct mxr_platform_data
*pdata
= dev
->platform_data
;
391 struct mxr_device
*mdev
;
394 /* mdev does not exist yet so no mxr_dbg is used */
395 dev_info(dev
, "probe start\n");
397 mdev
= kzalloc(sizeof(*mdev
), GFP_KERNEL
);
399 dev_err(dev
, "not enough memory.\n");
404 /* setup pointer to master device */
407 mutex_init(&mdev
->mutex
);
408 spin_lock_init(&mdev
->reg_slock
);
409 init_waitqueue_head(&mdev
->event_queue
);
411 /* acquire resources: regs, irqs, clocks, regulators */
412 ret
= mxr_acquire_resources(mdev
, pdev
);
416 /* configure resources for video output */
417 ret
= mxr_acquire_video(mdev
, mxr_output_conf
,
418 ARRAY_SIZE(mxr_output_conf
));
422 /* configure layers */
423 ret
= mxr_acquire_layers(mdev
, pdata
);
427 pm_runtime_enable(dev
);
429 mxr_info(mdev
, "probe successful\n");
433 mxr_release_video(mdev
);
436 mxr_release_resources(mdev
);
442 dev_info(dev
, "probe failed\n");
446 static int mxr_remove(struct platform_device
*pdev
)
448 struct device
*dev
= &pdev
->dev
;
449 struct mxr_device
*mdev
= to_mdev(dev
);
451 pm_runtime_disable(dev
);
453 mxr_release_layers(mdev
);
454 mxr_release_video(mdev
);
455 mxr_release_resources(mdev
);
459 dev_info(dev
, "remove successful\n");
463 static struct platform_driver mxr_driver __refdata
= {
465 .remove
= mxr_remove
,
467 .name
= MXR_DRIVER_NAME
,
468 .owner
= THIS_MODULE
,
473 static int __init
mxr_init(void)
476 static const char banner
[] __initconst
=
477 "Samsung TV Mixer driver, "
478 "(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
479 pr_info("%s\n", banner
);
481 /* Loading auxiliary modules */
482 for (i
= 0; i
< ARRAY_SIZE(mxr_output_conf
); ++i
)
483 request_module(mxr_output_conf
[i
].module_name
);
485 ret
= platform_driver_register(&mxr_driver
);
487 pr_err("s5p-tv: registration of MIXER driver failed\n");
493 module_init(mxr_init
);
495 static void __exit
mxr_exit(void)
497 platform_driver_unregister(&mxr_driver
);
499 module_exit(mxr_exit
);