pandora: defconfig: update
[pandora-kernel.git] / drivers / media / video / s5p-tv / hdmiphy_drv.c
1 /*
2  * Samsung HDMI Physical interface driver
3  *
4  * Copyright (C) 2010-2011 Samsung Electronics Co.Ltd
5  * Author: Tomasz Stanislawski <t.stanislaws@samsung.com>
6  *
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.
11  */
12
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>
21
22 #include <media/v4l2-subdev.h>
23
24 MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
25 MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
26 MODULE_LICENSE("GPL");
27
28 struct hdmiphy_conf {
29         u32 preset;
30         const u8 *data;
31 };
32
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,
38 };
39
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,
45 };
46
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,
52 };
53
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,
59 };
60
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 },
68 };
69
70 const u8 *hdmiphy_preset2conf(u32 preset)
71 {
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;
77 }
78
79 static int hdmiphy_s_power(struct v4l2_subdev *sd, int on)
80 {
81         /* to be implemented */
82         return 0;
83 }
84
85 static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
86         struct v4l2_dv_preset *preset)
87 {
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;
93
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;
99         }
100
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;
107         }
108
109         return 0;
110 }
111
112 static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable)
113 {
114         struct i2c_client *client = v4l2_get_subdevdata(sd);
115         struct device *dev = &client->dev;
116         u8 buffer[2];
117         int ret;
118
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;
123
124         ret = i2c_master_send(client, buffer, 2);
125         if (ret != 2) {
126                 dev_err(dev, "stream (%d) failed\n", enable);
127                 return -EIO;
128         }
129         return 0;
130 }
131
132 static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
133         .s_power =  hdmiphy_s_power,
134 };
135
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,
139 };
140
141 static const struct v4l2_subdev_ops hdmiphy_ops = {
142         .core = &hdmiphy_core_ops,
143         .video = &hdmiphy_video_ops,
144 };
145
146 static int __devinit hdmiphy_probe(struct i2c_client *client,
147         const struct i2c_device_id *id)
148 {
149         static struct v4l2_subdev sd;
150
151         v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
152         dev_info(&client->dev, "probe successful\n");
153         return 0;
154 }
155
156 static int __devexit hdmiphy_remove(struct i2c_client *client)
157 {
158         dev_info(&client->dev, "remove successful\n");
159         return 0;
160 }
161
162 static const struct i2c_device_id hdmiphy_id[] = {
163         { "hdmiphy", 0 },
164         { },
165 };
166 MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
167
168 static struct i2c_driver hdmiphy_driver = {
169         .driver = {
170                 .name   = "s5p-hdmiphy",
171                 .owner  = THIS_MODULE,
172         },
173         .probe          = hdmiphy_probe,
174         .remove         = __devexit_p(hdmiphy_remove),
175         .id_table = hdmiphy_id,
176 };
177
178 static int __init hdmiphy_init(void)
179 {
180         return i2c_add_driver(&hdmiphy_driver);
181 }
182 module_init(hdmiphy_init);
183
184 static void __exit hdmiphy_exit(void)
185 {
186         i2c_del_driver(&hdmiphy_driver);
187 }
188 module_exit(hdmiphy_exit);