sdo_drv.c revision cf48f56c27ecfe94fbea363db6e8e0bacbd525ed
19a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski/*
29a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * Samsung Standard Definition Output (SDO) driver
39a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski *
49a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
59a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski *
69a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * Tomasz Stanislawski, <t.stanislaws@samsung.com>
79a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski *
89a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * This program is free software; you can redistribute it and/or modify
99a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * it under the terms of the GNU General Public License as published
109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * by the Free Software Foundiation. either version 2 of the License,
119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski * or (at your option) any later version
129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski */
139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/clk.h>
159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/delay.h>
169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/kernel.h>
179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/module.h>
189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/interrupt.h>
199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/io.h>
209a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/irq.h>
219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/platform_device.h>
229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/pm_runtime.h>
239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/regulator/consumer.h>
249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <linux/slab.h>
259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include <media/v4l2-subdev.h>
279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#include "regs-sdo.h"
299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz StanislawskiMODULE_AUTHOR("Tomasz Stanislawski, <t.stanislaws@samsung.com>");
319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz StanislawskiMODULE_DESCRIPTION("Samsung Standard Definition Output (SDO)");
329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz StanislawskiMODULE_LICENSE("GPL");
339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#define SDO_DEFAULT_STD	V4L2_STD_PAL
359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistruct sdo_format {
379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	v4l2_std_id id;
389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* all modes are 720 pixels wide */
399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	unsigned int height;
409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	unsigned int cookie;
419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistruct sdo_device {
449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** pointer to device parent */
459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct device *dev;
469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** base address of SDO registers */
479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	void __iomem *regs;
489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** SDO interrupt */
499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	unsigned int irq;
509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** DAC source clock */
519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *sclk_dac;
529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** DAC clock */
539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *dac;
549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** DAC physical interface */
559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *dacphy;
569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** clock for control of VPLL */
579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *fout_vpll;
589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** regulator for SDO IP power */
599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct regulator *vdac;
609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** regulator for SDO plug detection */
619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct regulator *vdet;
629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** subdev used as device interface */
639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev sd;
649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** current format */
659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	const struct sdo_format *fmt;
669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return container_of(sd, struct sdo_device, sd);
719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskivoid sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	u32 old = readl(sdev->regs + reg_id);
779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	value = (value & mask) | (old & ~mask);
789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	writel(value, sdev->regs + reg_id);
799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskivoid sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	writel(value, sdev->regs + reg_id);
859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskiu32 sdo_read(struct sdo_device *sdev, u32 reg_id)
899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return readl(sdev->regs + reg_id);
919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
939a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic irqreturn_t sdo_irq_handler(int irq, void *dev_data)
949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = dev_data;
969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* clear interrupt */
989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return IRQ_HANDLED;
1009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic void sdo_reg_debug(struct sdo_device *sdev)
1039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#define DBGREG(reg_id) \
1059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(sdev->dev, #reg_id " = %08x\n", \
1069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		sdo_read(sdev, reg_id))
1079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_CLKCON);
1099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_CONFIG);
1109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_VBI);
1119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_DAC);
1129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_IRQ);
1139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_IRQMASK);
1149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_VERSION);
1159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct sdo_format sdo_format[] = {
1189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_N,	.height = 576, .cookie = SDO_PAL_N },
1199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_Nc,	.height = 576, .cookie = SDO_PAL_NC },
1209a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_M,	.height = 480, .cookie = SDO_PAL_M },
1219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_60,	.height = 480, .cookie = SDO_PAL_60 },
1229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_NTSC_443,	.height = 480, .cookie = SDO_NTSC_443 },
1239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL,		.height = 576, .cookie = SDO_PAL_BGHID },
1249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_NTSC_M,	.height = 480, .cookie = SDO_NTSC_M },
1259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
1269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct sdo_format *sdo_find_format(v4l2_std_id id)
1289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int i;
1309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
1319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		if (sdo_format[i].id & id)
1329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski			return &sdo_format[i];
1339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return NULL;
1349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
1379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	*std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
1399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
1409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
1419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
1459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	const struct sdo_format *fmt;
1489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt = sdo_find_format(std);
1499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (fmt == NULL)
1509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		return -EINVAL;
1519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fmt = fmt;
1529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
1569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	*std = sd_to_sdev(sd)->fmt->id;
1589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
1629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_mbus_framefmt *fmt)
1639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (!sdev->fmt)
1679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		return -ENXIO;
1689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* all modes are 720 pixels wide */
1699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->width = 720;
1709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->height = sdev->fmt->height;
1719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->code = V4L2_MBUS_FMT_FIXED;
1729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->field = V4L2_FIELD_INTERLACED;
1730689133b7fadd2e10f4bddca36c895223a541c6cTomasz Stanislawski	fmt->colorspace = V4L2_COLORSPACE_JPEG;
1749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_power(struct v4l2_subdev *sd, int on)
1789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct device *dev = sdev->dev;
1819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int ret;
1829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "sdo_s_power(%d)\n", on);
1849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (on)
1869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = pm_runtime_get_sync(dev);
1879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	else
1889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = pm_runtime_put_sync(dev);
1899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* only values < 0 indicate errors */
1919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return IS_ERR_VALUE(ret) ? ret : 0;
1929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1939a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_streamon(struct sdo_device *sdev)
1959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* set proper clock for Timing Generator */
1979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_set_rate(sdev->fout_vpll, 54000000);
1989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
1999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_get_rate(sdev->fout_vpll));
2009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable clock in SDO */
2019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
2029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_enable(sdev->dacphy);
2039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable DAC */
2049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
2059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_reg_debug(sdev);
2069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
2079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_streamoff(struct sdo_device *sdev)
2109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int tries;
2129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
2149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_disable(sdev->dacphy);
2159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
2169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	for (tries = 100; tries; --tries) {
2179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
2189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski			break;
2199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		mdelay(1);
2209a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
2219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (tries == 0)
2229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(sdev->dev, "failed to stop streaming\n");
2239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return tries ? 0 : -EIO;
2249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_stream(struct v4l2_subdev *sd, int on)
2279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
2299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
2309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
2339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_power = sdo_s_power,
2349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
2379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_std_output = sdo_s_std_output,
2389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_std_output = sdo_g_std_output,
2399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_tvnorms_output = sdo_g_tvnorms_output,
2409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_mbus_fmt = sdo_g_mbus_fmt,
2419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_stream = sdo_s_stream,
2429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_ops sdo_sd_ops = {
2459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.core = &sdo_sd_core_ops,
2469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.video = &sdo_sd_video_ops,
2479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_runtime_suspend(struct device *dev)
2509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(dev);
2529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
2539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "suspend\n");
2559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_disable(sdev->vdet);
2569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_disable(sdev->vdac);
2579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_disable(sdev->sclk_dac);
2589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
2599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_runtime_resume(struct device *dev)
2629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(dev);
2649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
2659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "resume\n");
2679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_enable(sdev->sclk_dac);
2689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_enable(sdev->vdac);
2699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_enable(sdev->vdet);
2709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* software reset */
2729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
2739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	mdelay(10);
2749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
2759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* setting TV mode */
2779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
2789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* XXX: forcing interlaced mode using undocumented bit */
2799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
2809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* turn all VBI off */
2819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
2829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		SDO_CVBS_CLOSED_CAPTION_MASK);
2839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* turn all post processing off */
2849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
2859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		SDO_COMPENSATION_CVBS_COMP_OFF);
2869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_reg_debug(sdev);
2879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
2889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct dev_pm_ops sdo_pm_ops = {
2919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.runtime_suspend = sdo_runtime_suspend,
2929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.runtime_resume	 = sdo_runtime_resume,
2939a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int __devinit sdo_probe(struct platform_device *pdev)
2969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct device *dev = &pdev->dev;
2989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev;
2999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct resource *res;
3009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int ret = 0;
3019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *sclk_vpll;
3029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe start\n");
304e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall	sdev = devm_kzalloc(&pdev->dev, sizeof *sdev, GFP_KERNEL);
3059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (!sdev) {
3069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "not enough memory.\n");
3079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENOMEM;
3089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail;
3099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dev = dev;
3119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* mapping registers */
3139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (res == NULL) {
3159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "get memory resource failed.\n");
3169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
317e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
320e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall	sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
3219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (sdev->regs == NULL) {
3229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "register mapping failed.\n");
3239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
324e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquiring interrupt */
3289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (res == NULL) {
3309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "get interrupt resource failed.\n");
3319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
332e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
334e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall	ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
335e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall			       "s5p-sdo", sdev);
3369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (ret) {
3379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "request interrupt failed.\n");
338e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->irq = res->start;
3419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquire clocks */
3439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->sclk_dac = clk_get(dev, "sclk_dac");
344cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->sclk_dac)) {
3459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'sclk_dac'\n");
346cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->sclk_dac);
347e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dac = clk_get(dev, "dac");
350cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->dac)) {
3519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'dac'\n");
352cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->dac);
3539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_sclk_dac;
3549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dacphy = clk_get(dev, "dacphy");
356cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->dacphy)) {
3579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'dacphy'\n");
358cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->dacphy);
3599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dac;
3609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sclk_vpll = clk_get(dev, "sclk_vpll");
362cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sclk_vpll)) {
3639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'sclk_vpll'\n");
364cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sclk_vpll);
3659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dacphy;
3669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_set_parent(sdev->sclk_dac, sclk_vpll);
3689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sclk_vpll);
3699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fout_vpll = clk_get(dev, "fout_vpll");
370cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->fout_vpll)) {
3719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'fout_vpll'\n");
372cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->fout_vpll);
3739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dacphy;
3749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
3769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquire regulator */
37800d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat	sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
379cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->vdac)) {
3809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get regulator 'vdac'\n");
381cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->vdac);
3829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_fout_vpll;
3839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
38400d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat	sdev->vdet = devm_regulator_get(dev, "vdet");
385cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->vdet)) {
3869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get regulator 'vdet'\n");
387cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->vdet);
38800d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat		goto fail_fout_vpll;
3899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable gate for dac clock, because mixer uses it */
3929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_enable(sdev->dac);
3939a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* configure power management */
3959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	pm_runtime_enable(dev);
3969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* configuration of interface subdevice */
3989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
3999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->sd.owner = THIS_MODULE;
4009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	strlcpy(sdev->sd.name, "s5p-sdo", sizeof sdev->sd.name);
4019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* set default format */
4039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
4049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	BUG_ON(sdev->fmt == NULL);
4059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* keeping subdev in device's private for use by other drivers */
4079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_set_drvdata(dev, &sdev->sd);
4089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe succeeded\n");
4109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
4119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_fout_vpll:
4139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->fout_vpll);
4149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_dacphy:
4159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dacphy);
4169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_dac:
4179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dac);
4189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_sclk_dac:
4199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->sclk_dac);
4209a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail:
4219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe failed\n");
4229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return ret;
4239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
4249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int __devexit sdo_remove(struct platform_device *pdev)
4269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
4279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
4289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
4299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	pm_runtime_disable(&pdev->dev);
4319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_disable(sdev->dac);
4329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->fout_vpll);
4339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dacphy);
4349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dac);
4359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->sclk_dac);
4369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(&pdev->dev, "remove successful\n");
4389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
4399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
4409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic struct platform_driver sdo_driver __refdata = {
4429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.probe = sdo_probe,
4439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.remove = __devexit_p(sdo_remove),
4449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.driver = {
4459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.name = "s5p-sdo",
4469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.owner = THIS_MODULE,
4479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.pm = &sdo_pm_ops,
4489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
4499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
4509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4511d6629b1561ad34a6e6d17ece00bd65e1bab3724Axel Linmodule_platform_driver(sdo_driver);
452