media: rc: ir-hix5hd2: add hi3796cv300-ir support
The IR device on Hi3796CV300 SoC is mostly same as hix5hd2, except the following two things. - IR_CLK offset is 0x60 instead of 0x48. - It needs to set an extra bit in IR_ENABLE register to enable IR. The following changes are made to deal with them. - Define a SoC specific data to accommodate IR_CLK offset and the flag telling requirement of extra enable bit. - Create function hix5hd2_ir_enable() to handle IR enabling. The original hix5hd2_ir_enable() is all about managing IR clock, so gets renamed to hix5hd2_ir_clk_enable(). - Device table hix5hd2_ir_table[] gets moved forward, as it's being used by hix5hd2_ir_probe() now. Signed-off-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Родитель
61cd2d5ca0
Коммит
e4b9b6454d
|
@ -37,10 +37,13 @@
|
|||
#define INT_CLR_RCV BIT(16)
|
||||
#define INT_CLR_RCVTIMEOUT (BIT(16) | BIT(17))
|
||||
|
||||
#define IR_CLK 0x48
|
||||
#define IR_CLK_ENABLE BIT(4)
|
||||
#define IR_CLK_RESET BIT(5)
|
||||
|
||||
/* IR_ENABLE register bits */
|
||||
#define IR_ENABLE_EN BIT(0)
|
||||
#define IR_ENABLE_EN_EXTRA BIT(8)
|
||||
|
||||
#define IR_CFG_WIDTH_MASK 0xffff
|
||||
#define IR_CFG_WIDTH_SHIFT 16
|
||||
#define IR_CFG_FORMAT_MASK 0x3
|
||||
|
@ -58,6 +61,23 @@
|
|||
|
||||
#define IR_HIX5HD2_NAME "hix5hd2-ir"
|
||||
|
||||
/* Need to set extra bit for enabling IR */
|
||||
#define HIX5HD2_FLAG_EXTRA_ENABLE BIT(0)
|
||||
|
||||
struct hix5hd2_soc_data {
|
||||
u32 clk_reg;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static const struct hix5hd2_soc_data hix5hd2_data = {
|
||||
.clk_reg = 0x48,
|
||||
};
|
||||
|
||||
static const struct hix5hd2_soc_data hi3796cv300_data = {
|
||||
.clk_reg = 0x60,
|
||||
.flags = HIX5HD2_FLAG_EXTRA_ENABLE,
|
||||
};
|
||||
|
||||
struct hix5hd2_ir_priv {
|
||||
int irq;
|
||||
void __iomem *base;
|
||||
|
@ -66,15 +86,17 @@ struct hix5hd2_ir_priv {
|
|||
struct regmap *regmap;
|
||||
struct clk *clock;
|
||||
unsigned long rate;
|
||||
const struct hix5hd2_soc_data *socdata;
|
||||
};
|
||||
|
||||
static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
|
||||
static int hix5hd2_ir_clk_enable(struct hix5hd2_ir_priv *dev, bool on)
|
||||
{
|
||||
u32 clk_reg = dev->socdata->clk_reg;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
if (dev->regmap) {
|
||||
regmap_read(dev->regmap, IR_CLK, &val);
|
||||
regmap_read(dev->regmap, clk_reg, &val);
|
||||
if (on) {
|
||||
val &= ~IR_CLK_RESET;
|
||||
val |= IR_CLK_ENABLE;
|
||||
|
@ -82,7 +104,7 @@ static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
|
|||
val &= ~IR_CLK_ENABLE;
|
||||
val |= IR_CLK_RESET;
|
||||
}
|
||||
regmap_write(dev->regmap, IR_CLK, val);
|
||||
regmap_write(dev->regmap, clk_reg, val);
|
||||
} else {
|
||||
if (on)
|
||||
ret = clk_prepare_enable(dev->clock);
|
||||
|
@ -92,12 +114,23 @@ static int hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static inline void hix5hd2_ir_enable(struct hix5hd2_ir_priv *priv)
|
||||
{
|
||||
u32 val = IR_ENABLE_EN;
|
||||
|
||||
if (priv->socdata->flags & HIX5HD2_FLAG_EXTRA_ENABLE)
|
||||
val |= IR_ENABLE_EN_EXTRA;
|
||||
|
||||
writel_relaxed(val, priv->base + IR_ENABLE);
|
||||
}
|
||||
|
||||
static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
|
||||
{
|
||||
int timeout = 10000;
|
||||
u32 val, rate;
|
||||
|
||||
writel_relaxed(0x01, priv->base + IR_ENABLE);
|
||||
hix5hd2_ir_enable(priv);
|
||||
|
||||
while (readl_relaxed(priv->base + IR_BUSY)) {
|
||||
if (timeout--) {
|
||||
udelay(1);
|
||||
|
@ -128,13 +161,13 @@ static int hix5hd2_ir_open(struct rc_dev *rdev)
|
|||
struct hix5hd2_ir_priv *priv = rdev->priv;
|
||||
int ret;
|
||||
|
||||
ret = hix5hd2_ir_enable(priv, true);
|
||||
ret = hix5hd2_ir_clk_enable(priv, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hix5hd2_ir_config(priv);
|
||||
if (ret) {
|
||||
hix5hd2_ir_enable(priv, false);
|
||||
hix5hd2_ir_clk_enable(priv, false);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
@ -144,7 +177,7 @@ static void hix5hd2_ir_close(struct rc_dev *rdev)
|
|||
{
|
||||
struct hix5hd2_ir_priv *priv = rdev->priv;
|
||||
|
||||
hix5hd2_ir_enable(priv, false);
|
||||
hix5hd2_ir_clk_enable(priv, false);
|
||||
}
|
||||
|
||||
static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
|
||||
|
@ -205,6 +238,13 @@ static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct of_device_id hix5hd2_ir_table[] = {
|
||||
{ .compatible = "hisilicon,hix5hd2-ir", &hix5hd2_data, },
|
||||
{ .compatible = "hisilicon,hi3796cv300-ir", &hi3796cv300_data, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
|
||||
|
||||
static int hix5hd2_ir_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rc_dev *rdev;
|
||||
|
@ -212,6 +252,7 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct hix5hd2_ir_priv *priv;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct of_device_id *of_id;
|
||||
const char *map_name;
|
||||
int ret;
|
||||
|
||||
|
@ -219,6 +260,13 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
of_id = of_match_device(hix5hd2_ir_table, dev);
|
||||
if (!of_id) {
|
||||
dev_err(dev, "Unable to initialize IR data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
priv->socdata = of_id->data;
|
||||
|
||||
priv->regmap = syscon_regmap_lookup_by_phandle(node,
|
||||
"hisilicon,power-syscon");
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
|
@ -309,7 +357,7 @@ static int hix5hd2_ir_suspend(struct device *dev)
|
|||
struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clock);
|
||||
hix5hd2_ir_enable(priv, false);
|
||||
hix5hd2_ir_clk_enable(priv, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -319,17 +367,18 @@ static int hix5hd2_ir_resume(struct device *dev)
|
|||
struct hix5hd2_ir_priv *priv = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = hix5hd2_ir_enable(priv, true);
|
||||
ret = hix5hd2_ir_clk_enable(priv, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clock);
|
||||
if (ret) {
|
||||
hix5hd2_ir_enable(priv, false);
|
||||
hix5hd2_ir_clk_enable(priv, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
writel_relaxed(0x01, priv->base + IR_ENABLE);
|
||||
hix5hd2_ir_enable(priv);
|
||||
|
||||
writel_relaxed(0x00, priv->base + IR_INTM);
|
||||
writel_relaxed(0xff, priv->base + IR_INTC);
|
||||
writel_relaxed(0x01, priv->base + IR_START);
|
||||
|
@ -341,12 +390,6 @@ static int hix5hd2_ir_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(hix5hd2_ir_pm_ops, hix5hd2_ir_suspend,
|
||||
hix5hd2_ir_resume);
|
||||
|
||||
static const struct of_device_id hix5hd2_ir_table[] = {
|
||||
{ .compatible = "hisilicon,hix5hd2-ir", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hix5hd2_ir_table);
|
||||
|
||||
static struct platform_driver hix5hd2_ir_driver = {
|
||||
.driver = {
|
||||
.name = IR_HIX5HD2_NAME,
|
||||
|
|
Загрузка…
Ссылка в новой задаче