#include <media/cec.h>
#include <soc/imx8/soc.h>
-#include "imx-cec.h"
+#include "imx-hdp.h"
#define CEC_NAME "hdp-cec"
#define REG_ADDR_OFF 1
-#define B0_SILICON_ID 0x20
-
#define MAX_LA_IDX 4
#define MAX_LA_VAL 15
#define set_la_valid F_LOG_ADDR_VALID0
#define get_la_valid F_LOG_ADDR_VALID0_RD
-u32 cec_read(void __iomem *base, u32 reg)
+u32 cec_read(struct imx_cec_dev *cec, u32 offset)
{
- return readl(base + (reg << 2));
+ struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+ struct hdp_mem *mem = &hdp->mem;
+ u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+ u32 value;
+
+ hdp->rw->read_reg(mem, addr, &value);
+ return value;
}
-void cec_write(void __iomem *base, u32 reg, u32 val)
+void cec_write(struct imx_cec_dev *cec, u32 offset, u32 value)
{
- return writel(val, base + (reg << 2));
+ struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+ struct hdp_mem *mem = &hdp->mem;
+ u32 addr = (offset << 2) + ADDR_HDP_CEC_BASE;
+
+ hdp->rw->write_reg(mem, addr, value);
}
void cec_clear_rx_buffer(struct imx_cec_dev *cec)
{
- cec_write(cec->reg_base, RX_CLEAR_BUF, 1);
- cec_write(cec->reg_base, RX_CLEAR_BUF, 0);
+ cec_write(cec, RX_CLEAR_BUF, 1);
+ cec_write(cec, RX_CLEAR_BUF, 0);
}
void cec_set_divider(struct imx_cec_dev *cec)
{
/* Set clock divider */
-
if (cec->clk_div == 0) {
dev_warn(cec->dev,
"Warning. Clock divider is 0. Changing to 1.\n");
- cec_write(cec->reg_base, CLK_DIV_MSB, 0);
- cec_write(cec->reg_base, CLK_DIV_LSB, 1);
+ cec_write(cec, CLK_DIV_MSB, 0);
+ cec_write(cec, CLK_DIV_LSB, 1);
} else {
- cec_write(cec->reg_base, CLK_DIV_MSB,
+ cec_write(cec, CLK_DIV_MSB,
(cec->clk_div >> 8) & 0xFF);
- cec_write(cec->reg_base, CLK_DIV_LSB, cec->clk_div & 0xFF);
+ cec_write(cec, CLK_DIV_LSB, cec->clk_div & 0xFF);
}
}
int len;
int i;
- cec_write(cec->reg_base, RX_MSG_CMD, CEC_RX_READ);
+ cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
- len = cec_read(cec->reg_base, RX_MSG_LENGTH);
+ len = cec_read(cec, RX_MSG_LENGTH);
msg->len = len + 1;
- dev_dbg(cec->dev, "RX msg len =%d\n", len);
+ dev_dbg(cec->dev, "RX MSG len =%d\n", len);
/* Read RX MSG bytes */
for (i = 0; i < msg->len; ++i) {
- msg->msg[i] = (uint8_t) cec_read(cec->reg_base,
- RX_MSG_DATA1 +
- (i * REG_ADDR_OFF));
+ msg->msg[i] = (u8) cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
+ dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
}
- cec_write(cec->reg_base, RX_MSG_CMD, CEC_RX_STOP);
+ cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
return true;
}
u32 cec_write_message(struct imx_cec_dev *cec, struct cec_msg *msg)
{
- uint8_t i;
+ u8 i;
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
if (msg->len > CEC_MAX_MSG_SIZE) {
dev_err(cec->dev, "Invalid MSG size!\n");
/* Write Message to register */
for (i = 0; i < msg->len; ++i) {
- cec_write(cec->reg_base, TX_MSG_HEADER + (i * REG_ADDR_OFF),
+ cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
msg->msg[i]);
}
/* Write Message Length (payload + opcode) */
- cec_write(cec->reg_base, TX_MSG_LENGTH, msg->len - 1);
+ cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_TRANSMIT);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
return true;
}
void cec_abort_tx_transfer(struct imx_cec_dev *cec)
{
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_ABORT);
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
}
u32 imx_cec_set_logical_addr(struct imx_cec_dev *cec, u32 la)
{
- uint8_t i;
- uint8_t la_reg;
+ u8 i;
+ u8 la_reg;
if ((la >= MAX_LA_VAL)) {
dev_err(cec->dev, "Error logical Addr\n");
for (i = 0; i < MAX_LA_IDX; ++i) {
la_reg =
- cec_read(cec->reg_base,
- LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
+ cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
if (get_la_valid(la_reg))
continue;
la = set_la(la) | set_la_valid(1);
- cec_write(cec->reg_base,
- LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
+ cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
return true;
}
break;
/* Check TX State */
- sts = cec_read(cec->reg_base, TX_MSG_STATUS);
+ sts = cec_read(cec, TX_MSG_STATUS);
switch (sts) {
case CEC_STS_SUCCESS:
cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0,
0);
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
break;
case CEC_STS_ERROR:
- cec_write(cec->reg_base, TX_MSG_CMD, CEC_TX_STOP);
+ cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
cec_transmit_done(cec->adap,
CEC_TX_STATUS_MAX_RETRIES |
CEC_TX_STATUS_ERROR, 0, 0, 0, 1);
}
/* Check RX State */
- sts = cec_read(cec->reg_base, RX_MSG_STATUS);
- num_rx_msgs = cec_read(cec->reg_base, NUM_OF_MSG_RX_BUF);
+ sts = cec_read(cec, RX_MSG_STATUS);
+ num_rx_msgs = cec_read(cec, NUM_OF_MSG_RX_BUF);
switch (sts) {
case CEC_STS_SUCCESS:
if (num_rx_msgs == 0xf)
struct imx_cec_dev *cec = adap->priv;
if (enable) {
- cec_write(cec->reg_base, DB_L_TIMER, 0x10);
+ cec_write(cec, DB_L_TIMER, 0x10);
cec_set_divider(cec);
} else {
cec_set_divider(cec);
.adap_transmit = imx_cec_adap_transmit,
};
-static int imx_cec_probe(struct platform_device *pdev)
+int imx_cec_register(struct imx_cec_dev *cec)
{
- struct device *dev = &pdev->dev;
- struct resource *res;
- struct imx_cec_dev *cec;
+ struct imx_hdp *hdp = container_of(cec, struct imx_hdp, cec);
+ struct device *dev = hdp->dev;
int ret;
- cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
- if (!cec)
- return -ENOMEM;
-
- cec->dev = dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- cec->reg_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(cec->reg_base))
- return PTR_ERR(cec->reg_base);
-
- /* hdmi core clock is 133MHz */
- cec->clk_div = 1330;
+ /* Set CEC clock divider */
+ if (hdp->clks.clk_core)
+ cec->clk_div = clk_get_rate(hdp->clks.clk_core) / 100000;
+ else
+ /* Default HDMI core clock rate 133MHz */
+ cec->clk_div = 1330;
cec->adap = cec_allocate_adapter(&imx_cec_adap_ops, cec,
CEC_NAME,
ret = PTR_ERR_OR_ZERO(cec->adap);
if (ret)
return ret;
- ret = cec_register_adapter(cec->adap, &pdev->dev);
+ ret = cec_register_adapter(cec->adap, dev);
if (ret) {
cec_delete_adapter(cec->adap);
return ret;
}
- platform_set_drvdata(pdev, cec);
+ cec->dev = dev;
cec->cec_worker = kthread_create(cec_poll_worker, cec, "hdp-cec");
if (IS_ERR(cec->cec_worker)) {
return 0;
}
-static int imx_cec_remove(struct platform_device *pdev)
+int imx_cec_unregister(struct imx_cec_dev *cec)
{
- struct imx_cec_dev *cec = platform_get_drvdata(pdev);
-
if (cec->cec_worker) {
kthread_stop(cec->cec_worker);
cec->cec_worker = NULL;
return 0;
}
-static const struct of_device_id imx_cec_match[] = {
- {
- .compatible = "fsl,imx8-hdp-cec",
- },
- {},
-};
-
-static struct platform_driver imx_cec_pdrv = {
- .probe = imx_cec_probe,
- .remove = imx_cec_remove,
- .driver = {
- .name = CEC_NAME,
- .of_match_table = imx_cec_match,
- },
-};
-
-module_platform_driver(imx_cec_pdrv);
-
MODULE_AUTHOR("Sandor.Yu@NXP.com");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("NXP IMX HDP CEC driver");