Linux Audio

Check our new training course

Loading...
  1/*
  2 * Samsung Standard Definition Output (SDO) driver
  3 *
  4 * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  5 *
  6 * Tomasz Stanislawski, <t.stanislaws@samsung.com>
  7 *
  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
 12 */
 13
 14#include <linux/clk.h>
 15#include <linux/delay.h>
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/interrupt.h>
 19#include <linux/io.h>
 20#include <linux/irq.h>
 21#include <linux/platform_device.h>
 22#include <linux/pm_runtime.h>
 23#include <linux/regulator/consumer.h>
 24#include <linux/slab.h>
 25
 26#include <media/v4l2-subdev.h>
 27
 28#include "regs-sdo.h"
 29
 30MODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
 31MODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
 32MODULE_LICENSE("GPL");
 33
 34#define SDO_DEFAULT_STD	V4L2_STD_PAL
 35
 36struct sdo_format {
 37	v4l2_std_id id;
 38	/* all modes are 720 pixels wide */
 39	unsigned int height;
 40	unsigned int cookie;
 41};
 42
 43struct sdo_device {
 44	/** pointer to device parent */
 45	struct device *dev;
 46	/** base address of SDO registers */
 47	void __iomem *regs;
 48	/** SDO interrupt */
 49	unsigned int irq;
 50	/** DAC source clock */
 51	struct clk *sclk_dac;
 52	/** DAC clock */
 53	struct clk *dac;
 54	/** DAC physical interface */
 55	struct clk *dacphy;
 56	/** clock for control of VPLL */
 57	struct clk *fout_vpll;
 58	/** regulator for SDO IP power */
 59	struct regulator *vdac;
 60	/** regulator for SDO plug detection */
 61	struct regulator *vdet;
 62	/** subdev used as device interface */
 63	struct v4l2_subdev sd;
 64	/** current format */
 65	const struct sdo_format *fmt;
 66};
 67
 68static inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
 69{
 70	return container_of(sd, struct sdo_device, sd);
 71}
 72
 73static inline
 74void sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
 75{
 76	u32 old = readl(sdev->regs + reg_id);
 77	value = (value & mask) | (old & ~mask);
 78	writel(value, sdev->regs + reg_id);
 79}
 80
 81static inline
 82void sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
 83{
 84	writel(value, sdev->regs + reg_id);
 85}
 86
 87static inline
 88u32 sdo_read(struct sdo_device *sdev, u32 reg_id)
 89{
 90	return readl(sdev->regs + reg_id);
 91}
 92
 93static irqreturn_t sdo_irq_handler(int irq, void *dev_data)
 94{
 95	struct sdo_device *sdev = dev_data;
 96
 97	/* clear interrupt */
 98	sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
 99	return IRQ_HANDLED;
100}
101
102static void sdo_reg_debug(struct sdo_device *sdev)
103{
104#define DBGREG(reg_id) \
105	dev_info(sdev->dev, #reg_id " = %08x\n", \
106		sdo_read(sdev, reg_id))
107
108	DBGREG(SDO_CLKCON);
109	DBGREG(SDO_CONFIG);
110	DBGREG(SDO_VBI);
111	DBGREG(SDO_DAC);
112	DBGREG(SDO_IRQ);
113	DBGREG(SDO_IRQMASK);
114	DBGREG(SDO_VERSION);
115}
116
117static const struct sdo_format sdo_format[] = {
118	{ V4L2_STD_PAL_N,	.height = 576, .cookie = SDO_PAL_N },
119	{ V4L2_STD_PAL_Nc,	.height = 576, .cookie = SDO_PAL_NC },
120	{ V4L2_STD_PAL_M,	.height = 480, .cookie = SDO_PAL_M },
121	{ V4L2_STD_PAL_60,	.height = 480, .cookie = SDO_PAL_60 },
122	{ V4L2_STD_NTSC_443,	.height = 480, .cookie = SDO_NTSC_443 },
123	{ V4L2_STD_PAL,		.height = 576, .cookie = SDO_PAL_BGHID },
124	{ V4L2_STD_NTSC_M,	.height = 480, .cookie = SDO_NTSC_M },
125};
126
127static const struct sdo_format *sdo_find_format(v4l2_std_id id)
128{
129	int i;
130	for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
131		if (sdo_format[i].id & id)
132			return &sdo_format[i];
133	return NULL;
134}
135
136static int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
137{
138	*std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
139		V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
140		V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
141	return 0;
142}
143
144static int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
145{
146	struct sdo_device *sdev = sd_to_sdev(sd);
147	const struct sdo_format *fmt;
148	fmt = sdo_find_format(std);
149	if (fmt == NULL)
150		return -EINVAL;
151	sdev->fmt = fmt;
152	return 0;
153}
154
155static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
156{
157	*std = sd_to_sdev(sd)->fmt->id;
158	return 0;
159}
160
161static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
162	struct v4l2_mbus_framefmt *fmt)
163{
164	struct sdo_device *sdev = sd_to_sdev(sd);
165
166	if (!sdev->fmt)
167		return -ENXIO;
168	/* all modes are 720 pixels wide */
169	fmt->width = 720;
170	fmt->height = sdev->fmt->height;
171	fmt->code = V4L2_MBUS_FMT_FIXED;
172	fmt->field = V4L2_FIELD_INTERLACED;
173	fmt->colorspace = V4L2_COLORSPACE_JPEG;
174	return 0;
175}
176
177static int sdo_s_power(struct v4l2_subdev *sd, int on)
178{
179	struct sdo_device *sdev = sd_to_sdev(sd);
180	struct device *dev = sdev->dev;
181	int ret;
182
183	dev_info(dev, "sdo_s_power(%d)\n", on);
184
185	if (on)
186		ret = pm_runtime_get_sync(dev);
187	else
188		ret = pm_runtime_put_sync(dev);
189
190	/* only values < 0 indicate errors */
191	return IS_ERR_VALUE(ret) ? ret : 0;
192}
193
194static int sdo_streamon(struct sdo_device *sdev)
195{
196	/* set proper clock for Timing Generator */
197	clk_set_rate(sdev->fout_vpll, 54000000);
198	dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
199	clk_get_rate(sdev->fout_vpll));
200	/* enable clock in SDO */
201	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
202	clk_enable(sdev->dacphy);
203	/* enable DAC */
204	sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
205	sdo_reg_debug(sdev);
206	return 0;
207}
208
209static int sdo_streamoff(struct sdo_device *sdev)
210{
211	int tries;
212
213	sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
214	clk_disable(sdev->dacphy);
215	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
216	for (tries = 100; tries; --tries) {
217		if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
218			break;
219		mdelay(1);
220	}
221	if (tries == 0)
222		dev_err(sdev->dev, "failed to stop streaming\n");
223	return tries ? 0 : -EIO;
224}
225
226static int sdo_s_stream(struct v4l2_subdev *sd, int on)
227{
228	struct sdo_device *sdev = sd_to_sdev(sd);
229	return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
230}
231
232static const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
233	.s_power = sdo_s_power,
234};
235
236static const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
237	.s_std_output = sdo_s_std_output,
238	.g_std_output = sdo_g_std_output,
239	.g_tvnorms_output = sdo_g_tvnorms_output,
240	.g_mbus_fmt = sdo_g_mbus_fmt,
241	.s_stream = sdo_s_stream,
242};
243
244static const struct v4l2_subdev_ops sdo_sd_ops = {
245	.core = &sdo_sd_core_ops,
246	.video = &sdo_sd_video_ops,
247};
248
249static int sdo_runtime_suspend(struct device *dev)
250{
251	struct v4l2_subdev *sd = dev_get_drvdata(dev);
252	struct sdo_device *sdev = sd_to_sdev(sd);
253
254	dev_info(dev, "suspend\n");
255	regulator_disable(sdev->vdet);
256	regulator_disable(sdev->vdac);
257	clk_disable(sdev->sclk_dac);
258	return 0;
259}
260
261static int sdo_runtime_resume(struct device *dev)
262{
263	struct v4l2_subdev *sd = dev_get_drvdata(dev);
264	struct sdo_device *sdev = sd_to_sdev(sd);
265
266	dev_info(dev, "resume\n");
267	clk_enable(sdev->sclk_dac);
268	regulator_enable(sdev->vdac);
269	regulator_enable(sdev->vdet);
270
271	/* software reset */
272	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
273	mdelay(10);
274	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
275
276	/* setting TV mode */
277	sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
278	/* XXX: forcing interlaced mode using undocumented bit */
279	sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
280	/* turn all VBI off */
281	sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
282		SDO_CVBS_CLOSED_CAPTION_MASK);
283	/* turn all post processing off */
284	sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
285		SDO_COMPENSATION_CVBS_COMP_OFF);
286	sdo_reg_debug(sdev);
287	return 0;
288}
289
290static const struct dev_pm_ops sdo_pm_ops = {
291	.runtime_suspend = sdo_runtime_suspend,
292	.runtime_resume	 = sdo_runtime_resume,
293};
294
295static int __devinit sdo_probe(struct platform_device *pdev)
296{
297	struct device *dev = &pdev->dev;
298	struct sdo_device *sdev;
299	struct resource *res;
300	int ret = 0;
301	struct clk *sclk_vpll;
302
303	dev_info(dev, "probe start\n");
304	sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
305	if (!sdev) {
306		dev_err(dev, "not enough memory.\n");
307		ret = -ENOMEM;
308		goto fail;
309	}
310	sdev->dev = dev;
311
312	/* mapping registers */
313	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
314	if (res == NULL) {
315		dev_err(dev, "get memory resource failed.\n");
316		ret = -ENXIO;
317		goto fail;
318	}
319
320	sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
321	if (sdev->regs == NULL) {
322		dev_err(dev, "register mapping failed.\n");
323		ret = -ENXIO;
324		goto fail;
325	}
326
327	/* acquiring interrupt */
328	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
329	if (res == NULL) {
330		dev_err(dev, "get interrupt resource failed.\n");
331		ret = -ENXIO;
332		goto fail;
333	}
334	ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
335			       "s5p-sdo", sdev);
336	if (ret) {
337		dev_err(dev, "request interrupt failed.\n");
338		goto fail;
339	}
340	sdev->irq = res->start;
341
342	/* acquire clocks */
343	sdev->sclk_dac = clk_get(dev, "sclk_dac");
344	if (IS_ERR_OR_NULL(sdev->sclk_dac)) {
345		dev_err(dev, "failed to get clock 'sclk_dac'\n");
346		ret = -ENXIO;
347		goto fail;
348	}
349	sdev->dac = clk_get(dev, "dac");
350	if (IS_ERR_OR_NULL(sdev->dac)) {
351		dev_err(dev, "failed to get clock 'dac'\n");
352		ret = -ENXIO;
353		goto fail_sclk_dac;
354	}
355	sdev->dacphy = clk_get(dev, "dacphy");
356	if (IS_ERR_OR_NULL(sdev->dacphy)) {
357		dev_err(dev, "failed to get clock 'dacphy'\n");
358		ret = -ENXIO;
359		goto fail_dac;
360	}
361	sclk_vpll = clk_get(dev, "sclk_vpll");
362	if (IS_ERR_OR_NULL(sclk_vpll)) {
363		dev_err(dev, "failed to get clock 'sclk_vpll'\n");
364		ret = -ENXIO;
365		goto fail_dacphy;
366	}
367	clk_set_parent(sdev->sclk_dac, sclk_vpll);
368	clk_put(sclk_vpll);
369	sdev->fout_vpll = clk_get(dev, "fout_vpll");
370	if (IS_ERR_OR_NULL(sdev->fout_vpll)) {
371		dev_err(dev, "failed to get clock 'fout_vpll'\n");
372		goto fail_dacphy;
373	}
374	dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
375
376	/* acquire regulator */
377	sdev->vdac = regulator_get(dev, "vdd33a_dac");
378	if (IS_ERR_OR_NULL(sdev->vdac)) {
379		dev_err(dev, "failed to get regulator 'vdac'\n");
380		goto fail_fout_vpll;
381	}
382	sdev->vdet = regulator_get(dev, "vdet");
383	if (IS_ERR_OR_NULL(sdev->vdet)) {
384		dev_err(dev, "failed to get regulator 'vdet'\n");
385		goto fail_vdac;
386	}
387
388	/* enable gate for dac clock, because mixer uses it */
389	clk_enable(sdev->dac);
390
391	/* configure power management */
392	pm_runtime_enable(dev);
393
394	/* configuration of interface subdevice */
395	v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
396	sdev->sd.owner = THIS_MODULE;
397	strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
398
399	/* set default format */
400	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
401	BUG_ON(sdev->fmt == NULL);
402
403	/* keeping subdev in device's private for use by other drivers */
404	dev_set_drvdata(dev, &sdev->sd);
405
406	dev_info(dev, "probe succeeded\n");
407	return 0;
408
409fail_vdac:
410	regulator_put(sdev->vdac);
411fail_fout_vpll:
412	clk_put(sdev->fout_vpll);
413fail_dacphy:
414	clk_put(sdev->dacphy);
415fail_dac:
416	clk_put(sdev->dac);
417fail_sclk_dac:
418	clk_put(sdev->sclk_dac);
419fail:
420	dev_info(dev, "probe failed\n");
421	return ret;
422}
423
424static int __devexit sdo_remove(struct platform_device *pdev)
425{
426	struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
427	struct sdo_device *sdev = sd_to_sdev(sd);
428
429	pm_runtime_disable(&pdev->dev);
430	clk_disable(sdev->dac);
431	regulator_put(sdev->vdet);
432	regulator_put(sdev->vdac);
433	clk_put(sdev->fout_vpll);
434	clk_put(sdev->dacphy);
435	clk_put(sdev->dac);
436	clk_put(sdev->sclk_dac);
437
438	dev_info(&pdev->dev, "remove successful\n");
439	return 0;
440}
441
442static struct platform_driver sdo_driver __refdata = {
443	.probe = sdo_probe,
444	.remove = __devexit_p(sdo_remove),
445	.driver = {
446		.name = "s5p-sdo",
447		.owner = THIS_MODULE,
448		.pm = &sdo_pm_ops,
449	}
450};
451
452module_platform_driver(sdo_driver);