Merge branch 'for-linus' of git://git.infradead.org/users/sameo/mfd-2.6
[linux-btrfs-devel.git] / drivers / media / video / s5p-tv / hdmiphy_drv.c
blob6693f4aff10819ae166df28f649b80fe395b05b1
1 /*
2 * Samsung HDMI Physical interface driver
4 * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
5 * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/slab.h>
16 #include <linux/clk.h>
17 #include <linux/io.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/err.h>
22 #include <media/v4l2-subdev.h>
24 MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
25 MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
26 MODULE_LICENSE("GPL");
28 struct hdmiphy_conf {
29 u32 preset;
30 const u8 *data;
33 static const u8 hdmiphy_conf27[32] = {
34 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
35 0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
36 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
37 0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
40 static const u8 hdmiphy_conf74_175[32] = {
41 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
42 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
43 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
44 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
47 static const u8 hdmiphy_conf74_25[32] = {
48 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
49 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
50 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
51 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
54 static const u8 hdmiphy_conf148_5[32] = {
55 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
56 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
57 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
58 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
61 static const struct hdmiphy_conf hdmiphy_conf[] = {
62 { V4L2_DV_480P59_94, hdmiphy_conf27 },
63 { V4L2_DV_1080P30, hdmiphy_conf74_175 },
64 { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
65 { V4L2_DV_720P60, hdmiphy_conf74_25 },
66 { V4L2_DV_1080P50, hdmiphy_conf148_5 },
67 { V4L2_DV_1080P60, hdmiphy_conf148_5 },
70 const u8 *hdmiphy_preset2conf(u32 preset)
72 int i;
73 for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
74 if (hdmiphy_conf[i].preset == preset)
75 return hdmiphy_conf[i].data;
76 return NULL;
79 static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
81 /* to be implemented */
82 return 0;
85 static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
86 struct v4l2_dv_preset *preset)
88 const u8 *data;
89 u8 buffer[32];
90 int ret;
91 struct i2c_client *client = v4l2_get_subdevdata(sd);
92 struct device *dev = &client->dev;
94 dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
95 data = hdmiphy_preset2conf(preset->preset);
96 if (!data) {
97 dev_err(dev, "format not supported\n");
98 return -EINVAL;
101 /* storing configuration to the device */
102 memcpy(buffer, data, 32);
103 ret = i2c_master_send(client, buffer, 32);
104 if (ret != 32) {
105 dev_err(dev, "failed to configure HDMIPHY via I2C\n");
106 return -EIO;
109 return 0;
112 static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
114 struct i2c_client *client = v4l2_get_subdevdata(sd);
115 struct device *dev = &client->dev;
116 u8 buffer[2];
117 int ret;
119 dev_info(dev, "s_stream(%d)\n", enable);
120 /* going to/from configuration from/to operation mode */
121 buffer[0] = 0x1f;
122 buffer[1] = enable ? 0x80 : 0x00;
124 ret = i2c_master_send(client, buffer, 2);
125 if (ret != 2) {
126 dev_err(dev, "stream (%d) failed\n", enable);
127 return -EIO;
129 return 0;
132 static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
133 .s_power = hdmiphy_s_power,
136 static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
137 .s_dv_preset = hdmiphy_s_dv_preset,
138 .s_stream = hdmiphy_s_stream,
141 static const struct v4l2_subdev_ops hdmiphy_ops = {
142 .core = &hdmiphy_core_ops,
143 .video = &hdmiphy_video_ops,
146 static int __devinit hdmiphy_probe(struct i2c_client *client,
147 const struct i2c_device_id *id)
149 static struct v4l2_subdev sd;
151 v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
152 dev_info(&client->dev, "probe successful\n");
153 return 0;
156 static int __devexit hdmiphy_remove(struct i2c_client *client)
158 dev_info(&client->dev, "remove successful\n");
159 return 0;
162 static const struct i2c_device_id hdmiphy_id[] = {
163 { "hdmiphy", 0 },
164 { },
166 MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
168 static struct i2c_driver hdmiphy_driver = {
169 .driver = {
170 .name = "s5p-hdmiphy",
171 .owner = THIS_MODULE,
173 .probe = hdmiphy_probe,
174 .remove = __devexit_p(hdmiphy_remove),
175 .id_table = hdmiphy_id,
178 static int __init hdmiphy_init(void)
180 return i2c_add_driver(&hdmiphy_driver);
182 module_init(hdmiphy_init);
184 static void __exit hdmiphy_exit(void)
186 i2c_del_driver(&hdmiphy_driver);
188 module_exit(hdmiphy_exit);