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;
580495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	/** vpll rate before sdo stream was on */
590495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	unsigned long vpll_rate;
609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** regulator for SDO IP power */
619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct regulator *vdac;
629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** regulator for SDO plug detection */
639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct regulator *vdet;
649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** subdev used as device interface */
659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev sd;
669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/** current format */
679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	const struct sdo_format *fmt;
689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline struct sdo_device *sd_to_sdev(struct v4l2_subdev *sd)
719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return container_of(sd, struct sdo_device, sd);
739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskivoid sdo_write_mask(struct sdo_device *sdev, u32 reg_id, u32 value, u32 mask)
779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	u32 old = readl(sdev->regs + reg_id);
799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	value = (value & mask) | (old & ~mask);
809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	writel(value, sdev->regs + reg_id);
819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskivoid sdo_write(struct sdo_device *sdev, u32 reg_id, u32 value)
859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	writel(value, sdev->regs + reg_id);
879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic inline
909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskiu32 sdo_read(struct sdo_device *sdev, u32 reg_id)
919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return readl(sdev->regs + reg_id);
939a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic irqreturn_t sdo_irq_handler(int irq, void *dev_data)
969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = dev_data;
989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* clear interrupt */
1009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_IRQ, ~0, SDO_VSYNC_IRQ_PEND);
1019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return IRQ_HANDLED;
1029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic void sdo_reg_debug(struct sdo_device *sdev)
1059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski#define DBGREG(reg_id) \
1079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(sdev->dev, #reg_id " = %08x\n", \
1089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		sdo_read(sdev, reg_id))
1099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_CLKCON);
1119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_CONFIG);
1129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_VBI);
1139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_DAC);
1149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_IRQ);
1159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_IRQMASK);
1169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	DBGREG(SDO_VERSION);
1179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct sdo_format sdo_format[] = {
1209a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_N,	.height = 576, .cookie = SDO_PAL_N },
1219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_Nc,	.height = 576, .cookie = SDO_PAL_NC },
1229a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_M,	.height = 480, .cookie = SDO_PAL_M },
1239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL_60,	.height = 480, .cookie = SDO_PAL_60 },
1249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_NTSC_443,	.height = 480, .cookie = SDO_NTSC_443 },
1259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_PAL,		.height = 576, .cookie = SDO_PAL_BGHID },
1269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	{ V4L2_STD_NTSC_M,	.height = 480, .cookie = SDO_NTSC_M },
1279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
1289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct sdo_format *sdo_find_format(v4l2_std_id id)
1309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int i;
1329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	for (i = 0; i < ARRAY_SIZE(sdo_format); ++i)
1339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		if (sdo_format[i].id & id)
1349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski			return &sdo_format[i];
1359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return NULL;
1369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_tvnorms_output(struct v4l2_subdev *sd, v4l2_std_id *std)
1399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	*std = V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL |
1419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		V4L2_STD_PAL_N | V4L2_STD_PAL_Nc |
1429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		V4L2_STD_NTSC_443 | V4L2_STD_PAL_60;
1439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
1479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	const struct sdo_format *fmt;
1509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt = sdo_find_format(std);
1519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (fmt == NULL)
1529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		return -EINVAL;
1539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fmt = fmt;
1549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std)
1589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	*std = sd_to_sdev(sd)->fmt->id;
1609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
1649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_mbus_framefmt *fmt)
1659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (!sdev->fmt)
1699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		return -ENXIO;
1709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* all modes are 720 pixels wide */
1719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->width = 720;
1729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->height = sdev->fmt->height;
1739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->code = V4L2_MBUS_FMT_FIXED;
1749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	fmt->field = V4L2_FIELD_INTERLACED;
1750689133b7fadd2e10f4bddca36c895223a541c6cTomasz Stanislawski	fmt->colorspace = V4L2_COLORSPACE_JPEG;
1769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
1779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_power(struct v4l2_subdev *sd, int on)
1809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
1829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct device *dev = sdev->dev;
1839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int ret;
1849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "sdo_s_power(%d)\n", on);
1869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (on)
1889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = pm_runtime_get_sync(dev);
1899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	else
1909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = pm_runtime_put_sync(dev);
1919a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* only values < 0 indicate errors */
193d8e8b40c067c3242b32ebe835f6bc6247fd67454Mauro Carvalho Chehab	return ret < 0 ? ret : 0;
1949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
1959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
1969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_streamon(struct sdo_device *sdev)
1979a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
1980495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	int ret;
1990495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk
2009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* set proper clock for Timing Generator */
2010495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	sdev->vpll_rate = clk_get_rate(sdev->fout_vpll);
2020495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	ret = clk_set_rate(sdev->fout_vpll, 54000000);
2030495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	if (ret < 0) {
2040495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk		dev_err(sdev->dev, "Failed to set vpll rate\n");
2050495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk		return ret;
2060495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	}
2079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
2089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_get_rate(sdev->fout_vpll));
2099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable clock in SDO */
2109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
211a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	ret = clk_prepare_enable(sdev->dacphy);
2120495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	if (ret < 0) {
213a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk		dev_err(sdev->dev, "clk_prepare_enable(dacphy) failed\n");
2140495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk		goto fail;
2150495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	}
2169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable DAC */
2179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
2189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_reg_debug(sdev);
2199a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
2200495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk
2210495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczukfail:
2220495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
2230495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	clk_set_rate(sdev->fout_vpll, sdev->vpll_rate);
2240495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	return ret;
2259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_streamoff(struct sdo_device *sdev)
2289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int tries;
2309a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
232a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	clk_disable_unprepare(sdev->dacphy);
2339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
2349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	for (tries = 100; tries; --tries) {
2359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
2369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski			break;
2379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		mdelay(1);
2389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
2399a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (tries == 0)
2409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(sdev->dev, "failed to stop streaming\n");
2410495d405f319171ac1cb6276019fc49a382fa295Mateusz Krawczuk	clk_set_rate(sdev->fout_vpll, sdev->vpll_rate);
2429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return tries ? 0 : -EIO;
2439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_s_stream(struct v4l2_subdev *sd, int on)
2469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
2489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return on ? sdo_streamon(sdev) : sdo_streamoff(sdev);
2499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_core_ops sdo_sd_core_ops = {
2529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_power = sdo_s_power,
2539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_video_ops sdo_sd_video_ops = {
2569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_std_output = sdo_s_std_output,
2579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_std_output = sdo_g_std_output,
2589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_tvnorms_output = sdo_g_tvnorms_output,
2599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.g_mbus_fmt = sdo_g_mbus_fmt,
2609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.s_stream = sdo_s_stream,
2619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct v4l2_subdev_ops sdo_sd_ops = {
2649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.core = &sdo_sd_core_ops,
2659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.video = &sdo_sd_video_ops,
2669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
2679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_runtime_suspend(struct device *dev)
2699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2709a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(dev);
2719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
2729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "suspend\n");
2749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_disable(sdev->vdet);
2759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	regulator_disable(sdev->vdac);
276a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	clk_disable_unprepare(sdev->sclk_dac);
2779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
2789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
2799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic int sdo_runtime_resume(struct device *dev)
2819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
2829a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(dev);
2839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
284d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	int ret;
2859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
2869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "resume\n");
287d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki
288a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	ret = clk_prepare_enable(sdev->sclk_dac);
289d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	if (ret < 0)
290d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki		return ret;
291d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki
292d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	ret = regulator_enable(sdev->vdac);
293d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	if (ret < 0)
294d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki		goto dac_clk_dis;
295d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki
296d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	ret = regulator_enable(sdev->vdet);
297d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	if (ret < 0)
298d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki		goto vdac_r_dis;
2999a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* software reset */
3019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_SW_RESET);
3029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	mdelay(10);
3039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_SW_RESET);
3049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3059a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* setting TV mode */
3069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CONFIG, sdev->fmt->cookie, SDO_STANDARD_MASK);
3079a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* XXX: forcing interlaced mode using undocumented bit */
3089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CONFIG, 0, SDO_PROGRESSIVE);
3099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* turn all VBI off */
3109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_VBI, 0, SDO_CVBS_WSS_INS |
3119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		SDO_CVBS_CLOSED_CAPTION_MASK);
3129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* turn all post processing off */
3139a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_write_mask(sdev, SDO_CCCON, ~0, SDO_COMPENSATION_BHS_ADJ_OFF |
3149a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		SDO_COMPENSATION_CVBS_COMP_OFF);
3159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdo_reg_debug(sdev);
3169a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
317d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki
318d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrockivdac_r_dis:
319d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	regulator_disable(sdev->vdac);
320d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrockidac_clk_dis:
321a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	clk_disable_unprepare(sdev->sclk_dac);
322d285837eaf5e363ac0ab1bf6deb110e007325949Sylwester Nawrocki	return ret;
3239a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
3249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic const struct dev_pm_ops sdo_pm_ops = {
3269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.runtime_suspend = sdo_runtime_suspend,
3279a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.runtime_resume	 = sdo_runtime_resume,
3289a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
3299a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3304c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int sdo_probe(struct platform_device *pdev)
3319a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
3329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct device *dev = &pdev->dev;
3339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev;
3349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct resource *res;
3359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	int ret = 0;
3369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct clk *sclk_vpll;
3379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe start\n");
33980f0dee21c7ec39f76f90548c9f08a0e7ec9b3faSachin Kamat	sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
3409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (!sdev) {
3419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "not enough memory.\n");
3429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENOMEM;
3439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail;
3449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dev = dev;
3469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* mapping registers */
3489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
3499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (res == NULL) {
3509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "get memory resource failed.\n");
3519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
352e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
355e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall	sdev->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
3569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (sdev->regs == NULL) {
3579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "register mapping failed.\n");
3589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
359e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquiring interrupt */
3639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
3649a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (res == NULL) {
3659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "get interrupt resource failed.\n");
3669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		ret = -ENXIO;
367e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
369e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall	ret = devm_request_irq(&pdev->dev, res->start, sdo_irq_handler, 0,
370e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall			       "s5p-sdo", sdev);
3719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	if (ret) {
3729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "request interrupt failed.\n");
373e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->irq = res->start;
3769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
3779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquire clocks */
3789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->sclk_dac = clk_get(dev, "sclk_dac");
379cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->sclk_dac)) {
3809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'sclk_dac'\n");
381cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->sclk_dac);
382e861dccc6d8d870d764ed950417cfb0e65889b90Julia Lawall		goto fail;
3839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dac = clk_get(dev, "dac");
385cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->dac)) {
3869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'dac'\n");
387cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->dac);
3889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_sclk_dac;
3899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3909a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->dacphy = clk_get(dev, "dacphy");
391cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->dacphy)) {
3929a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'dacphy'\n");
393cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->dacphy);
3949a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dac;
3959a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
3969a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sclk_vpll = clk_get(dev, "sclk_vpll");
397cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sclk_vpll)) {
3989a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'sclk_vpll'\n");
399cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sclk_vpll);
4009a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dacphy;
4019a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
4029a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_set_parent(sdev->sclk_dac, sclk_vpll);
4039a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sclk_vpll);
4049a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fout_vpll = clk_get(dev, "fout_vpll");
405cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->fout_vpll)) {
4069a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get clock 'fout_vpll'\n");
407cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->fout_vpll);
4089a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_dacphy;
4099a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
4109a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "fout_vpll.rate = %lu\n", clk_get_rate(sclk_vpll));
4119a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4129a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* acquire regulator */
41300d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat	sdev->vdac = devm_regulator_get(dev, "vdd33a_dac");
414cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->vdac)) {
4159a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get regulator 'vdac'\n");
416cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->vdac);
4179a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		goto fail_fout_vpll;
4189a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
41900d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat	sdev->vdet = devm_regulator_get(dev, "vdet");
420cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki	if (IS_ERR(sdev->vdet)) {
4219a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		dev_err(dev, "failed to get regulator 'vdet'\n");
422cf48f56c27ecfe94fbea363db6e8e0bacbd525edSylwester Nawrocki		ret = PTR_ERR(sdev->vdet);
42300d98c1bd6fe93de6db6a99ed25b4b7d96a402ecSachin Kamat		goto fail_fout_vpll;
4249a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
4259a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4269a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* enable gate for dac clock, because mixer uses it */
427a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	ret = clk_prepare_enable(sdev->dac);
428a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	if (ret < 0) {
429a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk		dev_err(dev, "clk_prepare_enable(dac) failed\n");
430a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk		goto fail_fout_vpll;
431a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	}
4329a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4339a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* configure power management */
4349a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	pm_runtime_enable(dev);
4359a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4369a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* configuration of interface subdevice */
4379a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	v4l2_subdev_init(&sdev->sd, &sdo_sd_ops);
4389a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->sd.owner = THIS_MODULE;
43980f0dee21c7ec39f76f90548c9f08a0e7ec9b3faSachin Kamat	strlcpy(sdev->sd.name, "s5p-sdo", sizeof(sdev->sd.name));
4409a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4419a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* set default format */
4429a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	sdev->fmt = sdo_find_format(SDO_DEFAULT_STD);
4439a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	BUG_ON(sdev->fmt == NULL);
4449a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4459a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	/* keeping subdev in device's private for use by other drivers */
4469a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_set_drvdata(dev, &sdev->sd);
4479a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4489a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe succeeded\n");
4499a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
4509a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4519a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_fout_vpll:
4529a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->fout_vpll);
4539a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_dacphy:
4549a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dacphy);
4559a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_dac:
4569a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dac);
4579a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail_sclk_dac:
4589a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->sclk_dac);
4599a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskifail:
4609a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(dev, "probe failed\n");
4619a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return ret;
4629a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
4639a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4644c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int sdo_remove(struct platform_device *pdev)
4659a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski{
4669a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev);
4679a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	struct sdo_device *sdev = sd_to_sdev(sd);
4689a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4699a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	pm_runtime_disable(&pdev->dev);
470a889c11519b425dce284c6233cfb4629f519ccacMateusz Krawczuk	clk_disable_unprepare(sdev->dac);
4719a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->fout_vpll);
4729a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dacphy);
4739a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->dac);
4749a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	clk_put(sdev->sclk_dac);
4759a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4769a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	dev_info(&pdev->dev, "remove successful\n");
4779a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	return 0;
4789a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski}
4799a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4809a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawskistatic struct platform_driver sdo_driver __refdata = {
4819a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.probe = sdo_probe,
4824c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman	.remove = sdo_remove,
4839a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	.driver = {
4849a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.name = "s5p-sdo",
4859a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.owner = THIS_MODULE,
4869a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski		.pm = &sdo_pm_ops,
4879a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski	}
4889a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski};
4899a498400fede652a5ada51e74ae47bba99c7ed07Tomasz Stanislawski
4901d6629b1561ad34a6e6d17ece00bd65e1bab3724Axel Linmodule_platform_driver(sdo_driver);
491