add new hdmi driver and update sdmmc driver

This commit is contained in:
kfx 2011-05-04 11:27:54 +08:00
parent 289204a92f
commit 3901afba10
30 changed files with 6733 additions and 36 deletions

View File

@ -640,7 +640,7 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
.flags = 0,
},
#endif
#if defined (CONFIG_ANX7150)
#if defined (CONFIG_ANX7150) || defined (CONFIG_ANX7150_NEW)
{
.type = "anx7150",
.addr = 0x39, //0x39, 0x3d

View File

@ -80,9 +80,10 @@ enum {
MRQ_RESET_CTRL_ERR, //15
MRQ_RESET_CTRL_DONE, //16
MRQ_DMA_SET_ERR, //17
MRQ_STOP_DMA, //18
MRQ_DMA_DONE, //19
MRQ_REQUEST_DONE, //20
MRQ_START_DMA, //18
MRQ_STOP_DMA, //19
MRQ_DMA_DONE, //20
MRQ_REQUEST_DONE, //21
};
enum rk29_sdmmc_state {
STATE_IDLE = 0,
@ -461,6 +462,24 @@ static int send_stop_cmd(struct rk29_sdmmc *host)
return 0;
}
}
static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host)
{
struct mmc_data *data = host->mrq->data;
if (data)
dma_unmap_sg(host->dev, data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE : DMA_FROM_DEVICE));
}
static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host)
{
rk29_sdmmc_set_mrq_status(host, MRQ_STOP_DMA);
rk29_sdmmc_dma_cleanup(host);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH);
rk29_sdmmc_write(host->regs, SDMMC_CTRL,
(rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE));
}
static void rk29_sdmmc_request_done(struct rk29_sdmmc *host,struct mmc_request *mrq)
{
@ -471,6 +490,10 @@ static void rk29_sdmmc_request_done(struct rk29_sdmmc *host,struct mmc_request *
rk29_sdmmc_write(host->regs, SDMMC_INTMASK,
rk29_sdmmc_read(host->regs, SDMMC_INTMASK) &
~(SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS));
if(!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) &&
rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA))
rk29_sdmmc_stop_dma(host);
if(mrq->stop && !rk29_sdmmc_test_mrq_status(host, MRQ_STOP_START_DONE))
send_stop_cmd(host);
if(mrq->cmd->opcode == 17|| mrq->cmd->opcode == 51){
@ -668,7 +691,8 @@ static int rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *data
for (i = 0; i < dma_len; i++)
rk29_dma_enqueue(host->dma_info.chn, host, sg_dma_address(&data->sg[i]),sg_dma_len(&data->sg[i])); // data->sg->dma_address, data->sg->length);
rk29_sdmmc_write(host->regs, SDMMC_CTRL, (rk29_sdmmc_read(host->regs, SDMMC_CTRL))|SDMMC_CTRL_DMA_ENABLE);// enable dma
rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START);
rk29_dma_ctrl(host->dma_info.chn, RK29_DMAOP_START);
rk29_sdmmc_set_mrq_status(host, MRQ_START_DMA);
return 0;
}
static int rk29_sdmmc_test_cmd_start(struct rk29_sdmmc *host)
@ -748,6 +772,12 @@ static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
dev_info(host->dev, "mrq = NULL!!!!!\n");
if(host->mrq)
rk29_sdmmc_show_info(host);
if((!rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) &&
rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)) ||
(rk29_sdmmc_test_mrq_status(host, MRQ_STOP_DMA) &&
!rk29_sdmmc_test_mrq_status(host, MRQ_START_DMA)))
dev_warn(host->dev, "start_dma but no stop_dma, or no start_dma but stop_dma\n");
WARN_ON(host->mrq);
host->old_mrq_status = host->mrq_status;
host->mrq_status = 0;
@ -831,24 +861,6 @@ static void rk29_sdmmc_request_end(struct rk29_sdmmc *host)
if(host->mrq)
rk29_sdmmc_request_done(host, host->mrq);
}
static void rk29_sdmmc_dma_cleanup(struct rk29_sdmmc *host)
{
struct mmc_data *data = host->mrq->data;
if (data)
dma_unmap_sg(host->dev, data->sg, data->sg_len,
((data->flags & MMC_DATA_WRITE)
? DMA_TO_DEVICE : DMA_FROM_DEVICE));
}
static void rk29_sdmmc_stop_dma(struct rk29_sdmmc *host)
{
rk29_sdmmc_set_mrq_status(host, MRQ_STOP_DMA);
rk29_sdmmc_dma_cleanup(host);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_STOP);
rk29_dma_ctrl(host->dma_info.chn,RK29_DMAOP_FLUSH);
rk29_sdmmc_write(host->regs, SDMMC_CTRL,
(rk29_sdmmc_read(host->regs, SDMMC_CTRL))&(~SDMMC_CTRL_DMA_ENABLE));
}
static void rk29_sdmmc_command_complete(struct rk29_sdmmc *host,
struct mmc_command *cmd)

View File

@ -1,19 +1,32 @@
#
# Display drivers configuration
#
menu "HDMI support"
menu "HDMI"
config HDMI
tristate "hdmi support"
tristate "HDMI support"
if HDMI
config HDMI_OLD
default y
bool "old hdmi support"
help
nothing
if HDMI
source "drivers/video/hdmi/chips/Kconfig"
if HDMI_OLD
source "drivers/video/hdmi/hdmi-old/Kconfig"
endif
config HDMI_NEW
bool "new hdmi support"
help
nothing
if HDMI_NEW
source "drivers/video/hdmi/hdmi-new/Kconfig"
endif
config HDMI_DEBUG
bool "hdmi debug"
help
nothing
endif
endmenu

View File

@ -1,2 +1,2 @@
obj-$(CONFIG_HDMI) += hdmi-core.o hdmi-sysfs.o hdmi-fb.o hdmi-codec.o
obj-$(CONFIG_HDMI) += chips/
obj-$(CONFIG_HDMI_OLD) += hdmi-old/
obj-$(CONFIG_HDMI_NEW) += hdmi-new/

View File

@ -0,0 +1,5 @@
#
# Display drivers configuration
#
source "drivers/video/hdmi/hdmi-new/chips/Kconfig"

View File

@ -0,0 +1,2 @@
obj-y += hdmi-core.o hdmi-sysfs.o hdmi-fb.o hdmi-codec.o
obj-y += chips/

View File

@ -0,0 +1,7 @@
choice
prompt "HDMI chips select"
config ANX7150_NEW
bool "anx7150"
config ANX9030_NEW
bool "anx9030"
endchoice

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_ANX7150_NEW) += anx7150_hw.o anx7150.o

View File

@ -0,0 +1,315 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/hdmi-new.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <mach/gpio.h>
#include <mach/iomux.h>
#include "anx7150.h"
#include "anx7150_hw.h"
int anx7150_i2c_read_p0_reg(struct i2c_client *client, char reg, char *val)
{
client->addr = ANX7150_I2C_ADDR0;
return i2c_master_reg8_recv(client, reg, val, 1, ANX7150_SCL_RATE) > 0? 0: -EINVAL;
}
int anx7150_i2c_write_p0_reg(struct i2c_client *client, char reg, char *val)
{
client->addr = ANX7150_I2C_ADDR0;
return i2c_master_reg8_send(client, reg, val, 1, ANX7150_SCL_RATE) > 0? 0: -EINVAL;
}
int anx7150_i2c_read_p1_reg(struct i2c_client *client, char reg, char *val)
{
client->addr = ANX7150_I2C_ADDR1;
return i2c_master_reg8_recv(client, reg, val, 1, ANX7150_SCL_RATE) > 0? 0: -EINVAL;
}
int anx7150_i2c_write_p1_reg(struct i2c_client *client, char reg, char *val)
{
client->addr = ANX7150_I2C_ADDR1;
return i2c_master_reg8_send(client, reg, val, 1, ANX7150_SCL_RATE) > 0? 0: -EINVAL;
}
static int anx7150_param_chg(struct anx7150_pdata *anx)
{
int resolution_real;
hdmi_switch_fb(anx->hdmi, anx->hdmi->display_on);
resolution_real = ANX7150_Get_Optimal_resolution(anx->hdmi->resolution);
HDMI_Set_Video_Format(resolution_real);
HDMI_Set_Audio_Fs(anx->hdmi->audio_fs);
ANX7150_API_HDCP_ONorOFF(anx->hdmi->hdcp_on);
ANX7150_API_System_Config();
ANX7150_Config_Video(anx->client);
ANX7150_Config_Audio(anx->client);
ANX7150_Config_Packet(anx->client);
ANX7150_HDCP_Process(anx->client, anx->hdmi->display_on);
ANX7150_PLAYBACK_Process();
return 0;
}
static int anx7150_insert(struct hdmi *hdmi)
{
int tmo = 10;
struct anx7150_pdata *anx = hdmi_priv(hdmi);
anx7150_plug(anx->client);
if(anx->is_changed) {
if(ANX7150_Parse_EDID(anx->client,&anx->dev) < 0)
{
dev_info(&anx->client->dev, "parse EDID error\n");
anx7150_unplug(anx->client);
return -1;
}
while(--tmo && ANX7150_GET_SENSE_STATE(anx->client) != 1)
mdelay(10);
if(tmo <= 0)
{
anx7150_unplug(anx->client);
return -1;
}
anx->is_changed = 0;
}
anx7150_param_chg(anx);
return 0;
}
static int anx7150_remove(struct hdmi *hdmi)
{
struct anx7150_pdata *anx = hdmi_priv(hdmi);
anx7150_unplug(anx->client);
hdmi_switch_fb(hdmi, HDMI_DISABLE);
return 0;
}
static int anx7150_display_on(struct hdmi* hdmi)
{
struct anx7150_pdata *anx = hdmi_priv(hdmi);
hdmi->display_on = HDMI_ENABLE;
hdmi_dbg(hdmi->dev, "hdmi display on\n");
anx7150_param_chg(anx);
return 0;
}
static int anx7150_display_off(struct hdmi* hdmi)
{
struct anx7150_pdata *anx = hdmi_priv(hdmi);
hdmi->display_on = HDMI_DISABLE;
anx->dev.hdmi_enable = HDMI_DISABLE;
hdmi_dbg(hdmi->dev, "hdmi display off\n");
anx7150_param_chg(anx);
return 0;
}
static int anx7150_set_param(struct hdmi *hdmi)
{
struct anx7150_pdata *anx = hdmi_priv(hdmi);
anx7150_param_chg(anx);
return 0;
}
static int anx7150_hdmi_precent(struct hdmi *hdmi)
{
struct anx7150_pdata *anx = hdmi_priv(hdmi);
return gpio_get_value(anx->client->irq)?0:1;
}
static struct hdmi_ops anx7150_ops = {
.display_on = anx7150_display_on,
.display_off = anx7150_display_off,
.set_param = anx7150_set_param,
.hdmi_precent = anx7150_hdmi_precent,
.insert = anx7150_insert,
.remove = anx7150_remove,
};
static irqreturn_t anx7150_detect_irq(int irq, void *dev_id);
static void anx7150_detect_work(struct work_struct *work)
{
int ret = 0;
struct anx7150_pdata *anx = container_of(work, struct anx7150_pdata, work.work);
free_irq(anx->irq, anx);
ret = request_irq(anx->irq, anx7150_detect_irq,
anx7150_hdmi_precent(anx->hdmi)? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING,NULL,anx);
dev_info(&anx->client->dev, "det = %d,hpd_status = %d\n",
gpio_get_value(anx->client->irq), anx7150_get_hpd(anx->client));
anx->is_changed = 1;
if(!anx->is_early_suspend)
hdmi_changed(anx->hdmi, 0);
}
static irqreturn_t anx7150_detect_irq(int irq, void *dev_id)
{
struct anx7150_pdata *anx = (struct anx7150_pdata *)dev_id;
disable_irq_nosync(anx->irq);
schedule_delayed_work(&anx->work, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void anx7150_early_suspend(struct early_suspend *h)
{
struct anx7150_pdata *anx = container_of(h,
struct anx7150_pdata,
early_suspend);
dev_info(&anx->client->dev, "anx7150 enter early suspend\n");
anx->is_early_suspend = 1;
flush_delayed_work(&anx->work);
hdmi_suspend(anx->hdmi);
return;
}
static void anx7150_early_resume(struct early_suspend *h)
{
int ret = 0;
struct anx7150_pdata *anx = container_of(h,
struct anx7150_pdata,
early_suspend);
dev_info(&anx->client->dev, "anx7150 exit early suspend\n");
anx->is_early_suspend = 0;
ret = hdmi_resume(anx->hdmi);
return;
}
#endif
static int anx7150_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int ret = 0;
struct hdmi *hdmi = NULL;
struct anx7150_pdata *anx = NULL;
hdmi = hdmi_register(sizeof(struct anx7150_pdata), &client->dev);
if (!hdmi)
{
dev_err(&client->dev, "fail to register hdmi\n");
return -ENOMEM;
}
hdmi->ops = &anx7150_ops;
hdmi->display_on = HDMI_ENABLE;
hdmi->auto_switch = HDMI_DISABLE;
hdmi->hdcp_on = HDMI_DISABLE;
hdmi->audio_fs = HDMI_I2S_DEFAULT_Fs;
hdmi->resolution = HDMI_DEFAULT_RESOLUTION;
anx = hdmi_priv(hdmi);
anx->hdmi = hdmi;
i2c_set_clientdata(client, anx);
anx->client = client;
if((ret = gpio_request(client->irq, "hdmi gpio")) < 0)
{
dev_err(&client->dev, "fail to request gpio %d\n", client->irq);
goto err_hdmi_unregister;
}
gpio_pull_updown(client->irq,0);
gpio_direction_input(client->irq);
anx->irq = gpio_to_irq(client->irq);
INIT_DELAYED_WORK(&anx->work, anx7150_detect_work);
if((ret = request_irq(anx->irq, anx7150_detect_irq,
anx7150_hdmi_precent(hdmi)?IRQF_TRIGGER_RISING:IRQF_TRIGGER_FALLING, NULL, anx)) <0)
{
dev_err(&client->dev, "fail to request hdmi irq\n");
goto err_gpio_free;
}
if(anx7150_detect_device(anx) < 0)
{
dev_err(&client->dev, "anx7150 is not exist\n");
ret = -EIO;
goto err_free_irq;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
anx->early_suspend.suspend = anx7150_early_suspend;
anx->early_suspend.resume = anx7150_early_resume;
anx->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN - 1;
register_early_suspend(&anx->early_suspend);
#endif
anx->is_early_suspend = 0;
anx->is_changed = 1;
hdmi_changed(hdmi, 200);
dev_info(&client->dev, "anx7150 i2c probe ok\n");
return 0;
err_free_irq:
free_irq(anx->irq, hdmi);
err_gpio_free:
gpio_free(client->irq);
err_hdmi_unregister:
hdmi_unregister(hdmi);
anx = NULL;
return ret;
}
static int __devexit anx7150_i2c_remove(struct i2c_client *client)
{
struct anx7150_pdata *anx = (struct anx7150_pdata *)i2c_get_clientdata(client);
struct hdmi *hdmi = anx->hdmi;
free_irq(anx->irq, anx);
gpio_free(client->irq);
hdmi_unregister(hdmi);
anx = NULL;
return 0;
}
static int anx7150_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct anx7150_pdata *anx = (struct anx7150_pdata *)i2c_get_clientdata(client);
return hdmi_suspend(anx->hdmi);
}
static int anx7150_i2c_resume(struct i2c_client *client)
{
int ret = 0;
struct anx7150_pdata *anx = (struct anx7150_pdata *)i2c_get_clientdata(client);
ret = hdmi_resume(anx->hdmi);
return ret;
}
static const struct i2c_device_id anx7150_id[] = {
{ "anx7150", 0 },
{ }
};
static struct i2c_driver anx7150_i2c_driver = {
.driver = {
.name = "anx7150",
.owner = THIS_MODULE,
},
.probe = &anx7150_i2c_probe,
.remove = &anx7150_i2c_remove,
//.suspend = &anx7150_i2c_suspend,
//.resume = &anx7150_i2c_resume,
.id_table = anx7150_id,
};
static int __init anx7150_init(void)
{
return i2c_add_driver(&anx7150_i2c_driver);
}
static void __exit anx7150_exit(void)
{
i2c_del_driver(&anx7150_i2c_driver);
}
//module_init(anx7150_init);
fs_initcall(anx7150_init);
module_exit(anx7150_exit);

View File

@ -0,0 +1,100 @@
#ifndef _ANX7150_H
#define _ANX7150_H
#include <linux/hdmi-new.h>
#include <linux/earlysuspend.h>
#define ANX7150_I2C_ADDR0 0X39
#define ANX7150_I2C_ADDR1 0X3d
#define ANX7150_SCL_RATE 100 * 1000
/* HDMI auto switch */
#define HDMI_AUTO_SWITCH HDMI_ENABLE
/* HDMI reciver status */
#define HDMI_RECIVER_INACTIVE 0
#define HDMI_RECIVER_ACTIVE 1
/* ANX7150 reciver HPD Status */
#define HDMI_RECIVER_UNPLUG 0
#define HDMI_RECIVER_PLUG 1
#define LCD 0
#define HDMI 1
#define RK29_OUTPUT_STATUS_LCD LCD
#define RK29_OUTPUT_STATUS_HDMI HDMI
/* HDMI HDCP ENABLE */
#define ANX7150_HDCP_EN HDMI_DISABLE
/* ANX7150 state machine */
enum{
HDMI_INITIAL = 1,
WAIT_HOTPLUG,
READ_PARSE_EDID,
WAIT_RX_SENSE,
WAIT_HDMI_ENABLE,
SYSTEM_CONFIG,
CONFIG_VIDEO,
CONFIG_AUDIO,
CONFIG_PACKETS,
HDCP_AUTHENTICATION,
PLAY_BACK,
RESET_LINK,
UNKNOWN,
};
struct anx7150_dev_s{
struct i2c_driver *i2c_driver;
struct fasync_struct *async_queue;
struct workqueue_struct *workqueue;
struct delayed_work delay_work;
struct miscdevice *mdev;
void (*notifier_callback)(struct anx7150_dev_s *);
int anx7150_detect;
int resolution_set;
int resolution_real;
int i2s_Fs;
int hdmi_enable;
int hdmi_auto_switch;
int reciver_status;
int HPD_change_cnt;
int HPD_status;
int rk29_output_status;
int hdcp_enable;
int parameter_config;
int rate;
int fb_switch_state;
struct hdmi *hdmi;
};
struct anx7150_pdata {
int irq;
int gpio;
int init;
int is_early_suspend;
int is_changed;
struct delayed_work work;
struct hdmi *hdmi;
struct i2c_client *client;
struct anx7150_dev_s dev;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
};
int anx7150_i2c_read_p0_reg(struct i2c_client *client, char reg, char *val);
int anx7150_i2c_write_p0_reg(struct i2c_client *client, char reg, char *val);
int anx7150_i2c_read_p1_reg(struct i2c_client *client, char reg, char *val);
int anx7150_i2c_write_p1_reg(struct i2c_client *client, char reg, char *val);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
#include <linux/hdmi-new.h>
int hdmi_codec_set_audio_fs(unsigned char audio_fs)
{
return 0;
}

View File

@ -0,0 +1,163 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/hdmi-new.h>
struct class *hdmi_class;
struct hdmi_id_ref_info {
struct hdmi *hdmi;
int id;
int ref;
}ref_info[HDMI_MAX_ID];
#ifdef CONFIG_SYSFS
extern int hdmi_create_attrs(struct hdmi *hdmi);
extern void hdmi_remove_attrs(struct hdmi *hdmi);
#else
static inline int hdmi_create_attrs(struct hdmi *hdmi)
{ return 0; }
static inline void hdmi_remove_attrs(struct hdmi *hdmi) {}
#endif /* CONFIG_SYSFS */
void hdmi_changed(struct hdmi *hdmi, int msec)
{
schedule_delayed_work(&hdmi->changed_work, msecs_to_jiffies(msec));
}
int hdmi_suspend(struct hdmi *hdmi)
{
flush_delayed_work(&hdmi->changed_work);
return hdmi->ops->remove(hdmi);
}
int hdmi_resume(struct hdmi *hdmi)
{
hdmi_changed(hdmi, 1);
return 0;
}
static void hdmi_changed_work(struct work_struct *work)
{
int precent, ret = 0;
struct hdmi *hdmi = container_of(work, struct hdmi,
changed_work.work);
precent = hdmi->ops->hdmi_precent(hdmi);
hdmi_dbg(hdmi->dev, "hdmi %s\n", (precent)?"insert" : "remove");
if(precent)
ret = hdmi->ops->insert(hdmi);
else
ret = hdmi->ops->remove(hdmi);
if(ret < 0)
dev_warn(hdmi->dev, "hdmi changed error\n");
kobject_uevent(&hdmi->dev->kobj, KOBJ_CHANGE);
}
void *hdmi_priv(struct hdmi *hdmi)
{
return (void *)hdmi->priv;
}
struct hdmi *hdmi_register(int extra, struct device *parent)
{
int rc = 0, i;
char name[8];
struct hdmi *hdmi = kzalloc(sizeof(struct hdmi)+ extra, GFP_KERNEL);
if(!hdmi)
return NULL;
for(i = 0; i < HDMI_MAX_ID; i++)
{
if(ref_info[i].ref == 0)
{
ref_info[i].ref = 1;
hdmi->id = i;
break;
}
}
if(i == HDMI_MAX_ID)
{
kfree(hdmi);
return NULL;
}
sprintf(name, "hdmi-%d", hdmi->id);
hdmi->dev = device_create(hdmi_class, parent, 0,
"%s", name);
if (IS_ERR(hdmi->dev)) {
rc = PTR_ERR(hdmi->dev);
goto dev_create_failed;
}
dev_set_drvdata(hdmi->dev, hdmi);
ref_info[i].hdmi = hdmi;
INIT_DELAYED_WORK(&hdmi->changed_work, hdmi_changed_work);
rc = hdmi_create_attrs(hdmi);
if (rc)
goto create_attrs_failed;
goto success;
create_attrs_failed:
device_unregister(hdmi->dev);
dev_create_failed:
hdmi_remove_attrs(hdmi);
kfree(hdmi);
return NULL;
success:
return hdmi;
}
void hdmi_unregister(struct hdmi *hdmi)
{
flush_scheduled_work();
hdmi_remove_attrs(hdmi);
device_unregister(hdmi->dev);
kfree(hdmi);
hdmi = NULL;
ref_info[hdmi->id].ref = 0;
ref_info[hdmi->id].hdmi = NULL;
}
struct hdmi *get_hdmi_struct(int nr)
{
if(ref_info[nr].ref == 0)
return NULL;
else
return ref_info[nr].hdmi;
}
static int __init hdmi_class_init(void)
{
int i;
hdmi_class = class_create(THIS_MODULE, "hdmi");
if (IS_ERR(hdmi_class))
return PTR_ERR(hdmi_class);
for(i = 0; i < HDMI_MAX_ID; i++) {
ref_info[i].id = i;
ref_info[i].ref = 0;
ref_info[i].hdmi = NULL;
}
return 0;
}
static void __exit hdmi_class_exit(void)
{
class_destroy(hdmi_class);
}
EXPORT_SYMBOL(hdmi_changed);
EXPORT_SYMBOL(hdmi_register);
EXPORT_SYMBOL(hdmi_unregister);
EXPORT_SYMBOL(get_hdmi_struct);
subsys_initcall(hdmi_class_init);
module_exit(hdmi_class_exit);

View File

@ -0,0 +1,295 @@
#include <linux/console.h>
#include <linux/fb.h>
#include <linux/completion.h>
#include "../../display/screen/screen.h"
#include <linux/hdmi-new.h>
#include "../../rk29_fb.h"
/* Base */
#define LCD_ACLK 500000000// 312000000
#define OUT_TYPE SCREEN_HDMI
#define OUT_FACE OUT_P888
#define DCLK_POL 1
#define SWAP_RB 0
/* 720p@60Hz Timing */
#define OUT_CLK 74250000
#define H_PW 40
#define H_BP 220
#define H_VD 1280
#define H_FP 110
#define V_PW 5
#define V_BP 20
#define V_VD 720
#define V_FP 5
/* 720p@50Hz Timing */
#define OUT_CLK2 74250000
#define H_PW2 40
#define H_BP2 220
#define H_VD2 1280
#define H_FP2 440
#define V_PW2 5
#define V_BP2 20
#define V_VD2 720
#define V_FP2 5
/* 576p@50Hz Timing */
#define OUT_CLK3 27000000
#define H_PW3 64
#define H_BP3 68
#define H_VD3 720
#define H_FP3 12
#define V_PW3 5
#define V_BP3 39
#define V_VD3 576
#define V_FP3 5
/* 1080p@50Hz Timing */
#define OUT_CLK4 148500000
#define H_PW4 44
#define H_BP4 148
#define H_VD4 1920
#define H_FP4 528
#define V_PW4 5
#define V_BP4 35
#define V_VD4 1080
#define V_FP4 5
extern int FB_Switch_Screen( struct rk29fb_screen *screen, u32 enable );
static int anx7150_init(void)
{
return 0;
}
static int anx7150_standby(u8 enable)
{
return 0;
}
static void hdmi_set_info(struct rk29fb_screen *screen)
{
struct rk29fb_screen *screen2 = screen + 1;
struct rk29fb_screen *screen3 = screen + 2;
struct rk29fb_screen *screen4 = screen + 3;
/* ****************** 720p@60Hz ******************* */
/* screen type & face */
screen->type = OUT_TYPE;
screen->face = OUT_FACE;
/* Screen size */
screen->x_res = H_VD;
screen->y_res = V_VD;
/* Timing */
screen->pixclock = OUT_CLK;
screen4->lcdc_aclk = LCD_ACLK;
screen->left_margin = H_BP;
screen->right_margin = H_FP;
screen->hsync_len = H_PW;
screen->upper_margin = V_BP;
screen->lower_margin = V_FP;
screen->vsync_len = V_PW;
/* Pin polarity */
screen->pin_hsync = 0;
screen->pin_vsync = 0;
screen->pin_den = 0;
screen->pin_dclk = DCLK_POL;
/* Swap rule */
screen->swap_rb = SWAP_RB;
screen->swap_rg = 0;
screen->swap_gb = 0;
screen->swap_delta = 0;
screen->swap_dumy = 0;
/* Operation function*/
screen->init = anx7150_init;
screen->standby = anx7150_standby;
/* ****************** 720p@50Hz ******************* */
/* screen type & face */
screen2->type = OUT_TYPE;
screen2->face = OUT_FACE;
/* Screen size */
screen2->x_res = H_VD2;
screen2->y_res = V_VD2;
/* Timing */
screen2->pixclock = OUT_CLK2;
screen2->lcdc_aclk = LCD_ACLK;
screen2->left_margin = H_BP2;
screen2->right_margin = H_FP2;
screen2->hsync_len = H_PW2;
screen2->upper_margin = V_BP2;
screen2->lower_margin = V_FP2;
screen2->vsync_len = V_PW2;
/* Pin polarity */
screen2->pin_hsync = 0;
screen2->pin_vsync = 0;
screen2->pin_den = 0;
screen2->pin_dclk = DCLK_POL;
/* Swap rule */
screen2->swap_rb = SWAP_RB;
screen2->swap_rg = 0;
screen2->swap_gb = 0;
screen2->swap_delta = 0;
screen2->swap_dumy = 0;
/* Operation function*/
screen2->init = anx7150_init;
screen2->standby = anx7150_standby;
/* ****************** 576p@50Hz ******************* */
/* screen type & face */
screen3->type = OUT_TYPE;
screen3->face = OUT_FACE;
/* Screen size */
screen3->x_res = H_VD3;
screen3->y_res = V_VD3;
/* Timing */
screen3->pixclock = OUT_CLK3;
screen3->lcdc_aclk = LCD_ACLK;
screen3->left_margin = H_BP3;
screen3->right_margin = H_FP3;
screen3->hsync_len = H_PW3;
screen3->upper_margin = V_BP3;
screen3->lower_margin = V_FP3;
screen3->vsync_len = V_PW3;
/* Pin polarity */
screen3->pin_hsync = 0;
screen3->pin_vsync = 0;
screen3->pin_den = 0;
screen3->pin_dclk = DCLK_POL;
/* Swap rule */
screen3->swap_rb = SWAP_RB;
screen3->swap_rg = 0;
screen3->swap_gb = 0;
screen3->swap_delta = 0;
screen3->swap_dumy = 0;
/* Operation function*/
screen3->init = anx7150_init;
screen3->standby = anx7150_standby;
/* ****************** 1080p@50Hz ******************* */
/* screen type & face */
screen4->type = OUT_TYPE;
screen4->face = OUT_FACE;
/* Screen size */
screen4->x_res = H_VD4;
screen4->y_res = V_VD4;
/* Timing */
screen4->pixclock = OUT_CLK4;
screen4->lcdc_aclk = LCD_ACLK;
screen4->left_margin = H_BP4;
screen4->right_margin = H_FP4;
screen4->hsync_len = H_PW4;
screen4->upper_margin = V_BP4;
screen4->lower_margin = V_FP4;
screen4->vsync_len = V_PW4;
/* Pin polarity */
screen4->pin_hsync = 0;
screen4->pin_vsync = 0;
screen4->pin_den = 0;
screen4->pin_dclk = DCLK_POL;
/* Swap rule */
screen4->swap_rb = SWAP_RB;
screen4->swap_rg = 0;
screen4->swap_gb = 0;
screen4->swap_delta = 0;
screen4->swap_dumy = 0;
/* Operation function*/
screen4->init = anx7150_init;
screen4->standby = anx7150_standby;
}
int hdmi_switch_fb(struct hdmi *hdmi, int type)
{
int rc = 0;
struct rk29fb_screen hdmi_info[4];
hdmi_set_info(&hdmi_info[0]);
switch(hdmi->resolution)
{
case HDMI_1280x720p_50Hz:
rc = FB_Switch_Screen(&hdmi_info[1], type);
break;
case HDMI_1280x720p_60Hz:
rc = FB_Switch_Screen(&hdmi_info[0], type);
break;
case HDMI_720x576p_50Hz:
rc = FB_Switch_Screen(&hdmi_info[2], type);
break;
case HDMI_1920x1080p_50Hz:
rc = FB_Switch_Screen(&hdmi_info[3], type);
break;
default:
rc = FB_Switch_Screen(&hdmi_info[1], type);
break;
}
if(hdmi->wait == 1) {
complete(&hdmi->complete);
hdmi->wait = 0;
}
return rc;
}
int hdmi_resolution_changed(struct hdmi *hdmi, int xres, int yres, int video_on)
{
int ret = 0;
if(hdmi->display_on == 0|| hdmi->plug == 0)
return ret;
if(xres > 1280 && hdmi->resolution != HDMI_1920x1080p_50Hz)
{
hdmi->resolution = HDMI_1920x1080p_50Hz;
hdmi->display_on = 1;
hdmi->ops->set_param(hdmi);
ret = 1;
}
else if(xres >1024 && xres <= 1280 && hdmi->resolution != HDMI_1280x720p_50Hz){
hdmi->resolution = HDMI_1280x720p_50Hz;
hdmi->display_on = 1;
hdmi->ops->set_param(hdmi);
ret = 1;
}
/*
else {
if(hdmi->display_on == 1)
hdmi->hdmi_display_off(hdmi);
}*/
return ret;
}
int hdmi_get_default_resolution(void *screen)
{
struct rk29fb_screen hdmi_info[4];
hdmi_set_info(&hdmi_info[0]);
memcpy((struct rk29fb_screen*)screen, &hdmi_info[HDMI_DEFAULT_RESOLUTION], sizeof(struct rk29fb_screen));
return 0;
}
EXPORT_SYMBOL(hdmi_resolution_changed);

View File

@ -0,0 +1,179 @@
#include <linux/ctype.h>
#include <linux/hdmi-new.h>
#include <linux/string.h>
static ssize_t hdmi_show_state_attrs(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct hdmi *hdmi = dev_get_drvdata(dev);
return sprintf(buf, "display_on=%d\n"
//"plug=%d\n"
"--------------------------\n"
"resolution support:\n"
"0 -- 1280x720p_50Hz\n"
"1 -- 1280x720p_60Hz\n"
"2 -- 720x576p_50Hz\n"
"3 -- 1920x1080p_50Hz\n"
"--------------------------\n"
//"auto_switch=%d\n"
"hdcp_on=%d\n"
"audio_fs=%d\n"
"resolution=%d\n",
hdmi->display_on,/*hdmi->plug,*/
/*hdmi->auto_switch,*/ hdmi->hdcp_on,
hdmi->audio_fs, hdmi->resolution);
}
static ssize_t hdmi_restore_state_attrs(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
struct hdmi *hdmi = dev_get_drvdata(dev);
char *p;
const char *q;
int auto_switch = -1, hdcp_on = -1, audio_fs = -1, resolution = -1;
q = buf;
do
{
if((p = strstr(q, "auto_switch=")) != NULL)
{
q = p + 12;
if((sscanf(q, "%d", &auto_switch) == 1) &&
(auto_switch == 0 || auto_switch == 1))
hdmi->auto_switch = auto_switch;
else
{
dev_err(dev, "failed to set hdmi configuration\n");
ret = -EINVAL;
goto exit;
}
}
else if((p = strstr(q, "hdcp_on=")) != NULL)
{
q = p + 8;
if((sscanf(q, "%d", &hdcp_on) == 1) &&
(hdcp_on == 0 || hdcp_on == 1))
hdmi->hdcp_on = hdcp_on;
else
{
dev_err(dev, "failed to set hdmi configuration\n");
ret = -EINVAL;
goto exit;
}
}
else if((p = strstr(q, "audio_fs=")) != NULL)
{
q = p + 9;
if((sscanf(q, "%d", &audio_fs) == 1) &&
(audio_fs >= 0))
hdmi->audio_fs = audio_fs;
else
{
dev_err(dev, "failed to set hdmi configuration\n");
ret = -EINVAL;
goto exit;
}
}
else if((p = strstr(q, "resolution=")) != NULL)
{
q = p + 11;
if((sscanf(q, "%d", &resolution) == 1) &&
(resolution >= 0))
hdmi->resolution = resolution;
else
{
dev_err(dev, "failed to set hdmi configuration\n");
ret = -EINVAL;
goto exit;
}
}
else
break;
}while(*q != 0);
if(auto_switch == -1 &&
hdcp_on == -1 &&
audio_fs == -1 &&
resolution == -1)
{
dev_err(dev, "failed to set hdmi configuration\n");
ret = -EINVAL;
goto exit;
}
if(hdmi->ops->set_param)
ret = hdmi->ops->set_param(hdmi);
else
{
dev_err(dev, "hdmi device is not exist\n");
return ret = 0;
}
exit:
if(ret < 0)
dev_err(dev, "hdmi_restore_state_attrs err\n");
return size;
}
static ssize_t hdmi_show_switch_attrs(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct hdmi *hdmi = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", hdmi->display_on);
}
static ssize_t hdmi_restore_switch_attrs(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
int display_on = 0, ret = 0;
struct hdmi *hdmi = dev_get_drvdata(dev);
sscanf(buf, "%d", &display_on);
if(hdmi->display_on == HDMI_DISABLE && display_on)
ret = hdmi->ops->display_on(hdmi);
else if(hdmi->display_on == HDMI_ENABLE && !display_on)
ret = hdmi->ops->display_off(hdmi);
if(ret < 0)
dev_err(dev, "hdmi_restore_switch_attrs err\n");
return size;
}
static struct device_attribute hdmi_attrs[] = {
__ATTR(state, 0664, hdmi_show_state_attrs, hdmi_restore_state_attrs),
__ATTR(enable, 0664, hdmi_show_switch_attrs, hdmi_restore_switch_attrs),
};
int hdmi_create_attrs(struct hdmi *hdmi)
{
int rc = 0;
int i;
for (i = 0; i < ARRAY_SIZE(hdmi_attrs); i++) {
rc = device_create_file(hdmi->dev, &hdmi_attrs[i]);
if (rc)
goto create_failed;
}
goto succeed;
create_failed:
while (i--)
device_remove_file(hdmi->dev, &hdmi_attrs[i]);
succeed:
return rc;
}
void hdmi_remove_attrs(struct hdmi *hdmi)
{
int i;
for (i = 0; i < ARRAY_SIZE(hdmi_attrs); i++)
device_remove_file(hdmi->dev, &hdmi_attrs[i]);
}

View File

@ -0,0 +1,5 @@
#
# Display drivers configuration
#
source "drivers/video/hdmi/hdmi-old/chips/Kconfig"

View File

@ -0,0 +1,2 @@
obj-y += hdmi-core.o hdmi-sysfs.o hdmi-fb.o hdmi-codec.o
obj-y += chips/

View File

@ -2,9 +2,9 @@
#include <linux/fb.h>
#include <linux/completion.h>
#include "../display/screen/screen.h"
#include "../../display/screen/screen.h"
#include <linux/hdmi.h>
#include "../rk29_fb.h"
#include "../../rk29_fb.h"
/* Base */
@ -292,4 +292,4 @@ int hdmi_get_default_resolution(void *screen)
}
EXPORT_SYMBOL(hdmi_resolution_changed);
EXPORT_SYMBOL(hdmi_resolution_changed);

94
include/linux/hdmi-new.h Executable file
View File

@ -0,0 +1,94 @@
/* include/linux/hdmi.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __LINUX_HDMI_CORE_H
#define __LINUX_HDMI_CORE_H
#include <linux/device.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/completion.h>
#ifdef CONFIG_HDMI_DEBUG
#define hdmi_dbg(dev, format, arg...) \
dev_printk(KERN_INFO , dev , format , ## arg)
#else
#define hdmi_dbg(dev, format, arg...)
#endif
typedef int BOOL;
#define TRUE 1
#define FALSE 0
#define HDMI_DISABLE 0
#define HDMI_ENABLE 1
/* resolution */
#define HDMI_1280x720p_50Hz 0
#define HDMI_1280x720p_60Hz 1
#define HDMI_720x576p_50Hz 2
#define HDMI_1920x1080p_50Hz 3
/* HDMI default resolution */
#define HDMI_DEFAULT_RESOLUTION HDMI_1280x720p_50Hz
/* I2S Fs */
#define HDMI_I2S_Fs_44100 0
#define HDMI_I2S_Fs_48000 2
/* I2S default sample rate */
#define HDMI_I2S_DEFAULT_Fs HDMI_I2S_Fs_44100
#define HDMI_MAX_ID 32
struct hdmi;
struct hdmi_ops{
int (*display_on)(struct hdmi *);
int (*display_off)(struct hdmi *);
int (*set_param)(struct hdmi *);
int (*hdmi_precent)(struct hdmi *);
int (*insert)(struct hdmi *);
int (*remove)(struct hdmi *);
int (*power_off)(struct hdmi *);
};
struct hdmi {
int id;
int wait;
BOOL display_on;
BOOL plug;
BOOL auto_switch;
BOOL hdcp_on;
BOOL param_conf;
u8 resolution;
u8 audio_fs;
struct device *dev;
struct delayed_work changed_work;
struct completion complete;
const struct hdmi_ops *ops;
unsigned long priv[0] ____cacheline_aligned;
};
extern void *hdmi_priv(struct hdmi *hdmi);
extern struct hdmi *hdmi_register(int extra, struct device *parent);
extern void hdmi_unregister(struct hdmi *hdmi);
extern void hdmi_changed(struct hdmi *hdmi, int msec);
extern int hdmi_suspend(struct hdmi *hdmi);
extern int hdmi_resume(struct hdmi *hdmi);
extern int hdmi_codec_set_audio_fs(unsigned char audio_fs);
extern int hdmi_fb_set_resolution(unsigned char resolution);
extern int hdmi_switch_fb(struct hdmi *hdmi, int type);
extern int hdmi_resolution_changed(struct hdmi *hdmi, int xres, int yres, int video_on);
extern struct hdmi *get_hdmi_struct(int nr);
extern int hdmi_get_default_resolution(void *screen);
#endif