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 24MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>"); 25MODULE_DESCRIPTION("Samsung HDMI Physical interface driver"); 26MODULE_LICENSE("GPL"); 27 28struct hdmiphy_conf { 29 u32 preset; 30 const u8 *data; 31}; 32 33static 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 40static 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 47static 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 54static 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 61static 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 70const 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 79static int hdmiphy_s_power(struct v4l2_subdev *sd, int on) 80{ 81 /* to be implemented */ 82 return 0; 83} 84 85static 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 112static 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 132static const struct v4l2_subdev_core_ops hdmiphy_core_ops = { 133 .s_power = hdmiphy_s_power, 134}; 135 136static 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 141static const struct v4l2_subdev_ops hdmiphy_ops = { 142 .core = &hdmiphy_core_ops, 143 .video = &hdmiphy_video_ops, 144}; 145 146static 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 156static int __devexit hdmiphy_remove(struct i2c_client *client) 157{ 158 dev_info(&client->dev, "remove successful\n"); 159 return 0; 160} 161 162static const struct i2c_device_id hdmiphy_id[] = { 163 { "hdmiphy", 0 }, 164 { }, 165}; 166MODULE_DEVICE_TABLE(i2c, hdmiphy_id); 167 168static 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 178module_i2c_driver(hdmiphy_driver); 179