Commit f7354e6c authored by Sylwester Nawrocki's avatar Sylwester Nawrocki Committed by Mauro Carvalho Chehab

[media] exynos4-is: Add support for Exynos5250 MIPI-CSIS

Add compatible property for the Exynos5250 and enable the frame start
and frame end interrupts. These interrupts are needed for the Exynos5
FIMC-IS firmware. The driver enables those interrupt only where available,
depending on the 'compatible' property. This can be optimized further,
by exposing some API at the subdev driver, so the host driver can enable
extra interrupts only for the image processing chains involving FIMC-IS.
Signed-off-by: default avatarShaik Ameer Basha <shaik.ameer@samsung.com>
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 086eca29
...@@ -5,8 +5,8 @@ Required properties: ...@@ -5,8 +5,8 @@ Required properties:
- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110), - compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110),
"samsung,exynos4210-csis" for Exynos4210 (S5PC210), "samsung,exynos4210-csis" for Exynos4210 (S5PC210),
"samsung,exynos4212-csis" for Exynos4212/Exynos4412 "samsung,exynos4212-csis" for Exynos4212/Exynos4412,
SoC series; "samsung,exynos5250-csis" for Exynos5250;
- reg : offset and length of the register set for the device; - reg : offset and length of the register set for the device;
- interrupts : should contain MIPI CSIS interrupt; the format of the - interrupts : should contain MIPI CSIS interrupt; the format of the
interrupt specifier depends on the interrupt controller; interrupt specifier depends on the interrupt controller;
......
/* /*
* Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
* *
* Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
* Sylwester Nawrocki <s.nawrocki@samsung.com> * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -66,11 +66,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); ...@@ -66,11 +66,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* Interrupt mask */ /* Interrupt mask */
#define S5PCSIS_INTMSK 0x10 #define S5PCSIS_INTMSK 0x10
#define S5PCSIS_INTMSK_EN_ALL 0xf000103f
#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31) #define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31)
#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30) #define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30)
#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29) #define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29)
#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28) #define S5PCSIS_INTMSK_ODD_AFTER (1 << 28)
#define S5PCSIS_INTMSK_FRAME_START (1 << 27)
#define S5PCSIS_INTMSK_FRAME_END (1 << 26)
#define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 12) #define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 12)
#define S5PCSIS_INTMSK_ERR_LOST_FS (1 << 5) #define S5PCSIS_INTMSK_ERR_LOST_FS (1 << 5)
#define S5PCSIS_INTMSK_ERR_LOST_FE (1 << 4) #define S5PCSIS_INTMSK_ERR_LOST_FE (1 << 4)
...@@ -78,6 +79,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); ...@@ -78,6 +79,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define S5PCSIS_INTMSK_ERR_ECC (1 << 2) #define S5PCSIS_INTMSK_ERR_ECC (1 << 2)
#define S5PCSIS_INTMSK_ERR_CRC (1 << 1) #define S5PCSIS_INTMSK_ERR_CRC (1 << 1)
#define S5PCSIS_INTMSK_ERR_UNKNOWN (1 << 0) #define S5PCSIS_INTMSK_ERR_UNKNOWN (1 << 0)
#define S5PCSIS_INTMSK_EXYNOS4_EN_ALL 0xf000103f
#define S5PCSIS_INTMSK_EXYNOS5_EN_ALL 0xfc00103f
/* Interrupt source */ /* Interrupt source */
#define S5PCSIS_INTSRC 0x14 #define S5PCSIS_INTSRC 0x14
...@@ -88,6 +91,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); ...@@ -88,6 +91,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28) #define S5PCSIS_INTSRC_ODD_AFTER (1 << 28)
#define S5PCSIS_INTSRC_ODD (0x3 << 28) #define S5PCSIS_INTSRC_ODD (0x3 << 28)
#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28) #define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28)
#define S5PCSIS_INTSRC_FRAME_START (1 << 27)
#define S5PCSIS_INTSRC_FRAME_END (1 << 26)
#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12) #define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12)
#define S5PCSIS_INTSRC_ERR_LOST_FS (1 << 5) #define S5PCSIS_INTSRC_ERR_LOST_FS (1 << 5)
#define S5PCSIS_INTSRC_ERR_LOST_FE (1 << 4) #define S5PCSIS_INTSRC_ERR_LOST_FE (1 << 4)
...@@ -151,6 +156,9 @@ static const struct s5pcsis_event s5pcsis_events[] = { ...@@ -151,6 +156,9 @@ static const struct s5pcsis_event s5pcsis_events[] = {
{ S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" }, { S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" },
{ S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" }, { S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" },
{ S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" }, { S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" },
/* Frame start/end */
{ S5PCSIS_INTSRC_FRAME_START, "Frame Start" },
{ S5PCSIS_INTSRC_FRAME_END, "Frame End" },
}; };
#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
...@@ -159,6 +167,11 @@ struct csis_pktbuf { ...@@ -159,6 +167,11 @@ struct csis_pktbuf {
unsigned int len; unsigned int len;
}; };
struct csis_drvdata {
/* Mask of all used interrupts in S5PCSIS_INTMSK register */
u32 interrupt_mask;
};
/** /**
* struct csis_state - the driver's internal state data structure * struct csis_state - the driver's internal state data structure
* @lock: mutex serializing the subdev and power management operations, * @lock: mutex serializing the subdev and power management operations,
...@@ -171,6 +184,7 @@ struct csis_pktbuf { ...@@ -171,6 +184,7 @@ struct csis_pktbuf {
* @supplies: CSIS regulator supplies * @supplies: CSIS regulator supplies
* @clock: CSIS clocks * @clock: CSIS clocks
* @irq: requested s5p-mipi-csis irq number * @irq: requested s5p-mipi-csis irq number
* @interrupt_mask: interrupt mask of the all used interrupts
* @flags: the state variable for power and streaming control * @flags: the state variable for power and streaming control
* @clock_frequency: device bus clock frequency * @clock_frequency: device bus clock frequency
* @hs_settle: HS-RX settle time * @hs_settle: HS-RX settle time
...@@ -193,6 +207,7 @@ struct csis_state { ...@@ -193,6 +207,7 @@ struct csis_state {
struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
struct clk *clock[NUM_CSIS_CLOCKS]; struct clk *clock[NUM_CSIS_CLOCKS];
int irq; int irq;
u32 interrupt_mask;
u32 flags; u32 flags;
u32 clk_frequency; u32 clk_frequency;
...@@ -274,9 +289,10 @@ static const struct csis_pix_format *find_csis_format( ...@@ -274,9 +289,10 @@ static const struct csis_pix_format *find_csis_format(
static void s5pcsis_enable_interrupts(struct csis_state *state, bool on) static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
{ {
u32 val = s5pcsis_read(state, S5PCSIS_INTMSK); u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
if (on)
val = on ? val | S5PCSIS_INTMSK_EN_ALL : val |= state->interrupt_mask;
val & ~S5PCSIS_INTMSK_EN_ALL; else
val &= ~state->interrupt_mask;
s5pcsis_write(state, S5PCSIS_INTMSK, val); s5pcsis_write(state, S5PCSIS_INTMSK, val);
} }
...@@ -771,8 +787,12 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, ...@@ -771,8 +787,12 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
#define s5pcsis_parse_dt(pdev, state) (-ENOSYS) #define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
#endif #endif
static const struct of_device_id s5pcsis_of_match[];
static int s5pcsis_probe(struct platform_device *pdev) static int s5pcsis_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id;
const struct csis_drvdata *drv_data;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *mem_res; struct resource *mem_res;
struct csis_state *state; struct csis_state *state;
...@@ -787,10 +807,19 @@ static int s5pcsis_probe(struct platform_device *pdev) ...@@ -787,10 +807,19 @@ static int s5pcsis_probe(struct platform_device *pdev)
spin_lock_init(&state->slock); spin_lock_init(&state->slock);
state->pdev = pdev; state->pdev = pdev;
if (dev->of_node) if (dev->of_node) {
of_id = of_match_node(s5pcsis_of_match, dev->of_node);
if (WARN_ON(of_id == NULL))
return -EINVAL;
drv_data = of_id->data;
state->interrupt_mask = drv_data->interrupt_mask;
ret = s5pcsis_parse_dt(pdev, state); ret = s5pcsis_parse_dt(pdev, state);
else } else {
ret = s5pcsis_get_platform_data(pdev, state); ret = s5pcsis_get_platform_data(pdev, state);
}
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -994,9 +1023,25 @@ static const struct dev_pm_ops s5pcsis_pm_ops = { ...@@ -994,9 +1023,25 @@ static const struct dev_pm_ops s5pcsis_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume)
}; };
static const struct csis_drvdata exynos4_csis_drvdata = {
.interrupt_mask = S5PCSIS_INTMSK_EXYNOS4_EN_ALL,
};
static const struct csis_drvdata exynos5_csis_drvdata = {
.interrupt_mask = S5PCSIS_INTMSK_EXYNOS5_EN_ALL,
};
static const struct of_device_id s5pcsis_of_match[] = { static const struct of_device_id s5pcsis_of_match[] = {
{ .compatible = "samsung,s5pv210-csis" }, {
{ .compatible = "samsung,exynos4210-csis" }, .compatible = "samsung,s5pv210-csis",
.data = &exynos4_csis_drvdata,
}, {
.compatible = "samsung,exynos4210-csis",
.data = &exynos4_csis_drvdata,
}, {
.compatible = "samsung,exynos5250-csis",
.data = &exynos5_csis_drvdata,
},
{ /* sentinel */ }, { /* sentinel */ },
}; };
MODULE_DEVICE_TABLE(of, s5pcsis_of_match); MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment