This commit is contained in:
Gerben Jan Dijkman 2022-01-11 10:27:31 +01:00
parent 7a100e5a33
commit 83c53a6eef
69 changed files with 1 additions and 12775 deletions

View File

@ -1,35 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 15 Nov 2021 04:09:50 +0100
Subject: [PATCH 01/36] base: property: Swap order of search for connection to
"devcon, graph"
This avoids confusing error in kernel log, when using devcon matching
in DT. Example:
"OF: graph: no port node found in /i2c@ff3d0000/typec-portc@22"
This suggest there's some error because graph based search failed,
but there is no error, because devcon based matching succeeds.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/base/property.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index f1f35b4..68cb945 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1261,10 +1261,10 @@ void *fwnode_connection_find_match(struct fwnode_handle *fwnode,
if (!fwnode || !match)
return NULL;
- ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
+ ret = fwnode_devcon_match(fwnode, con_id, data, match);
if (ret)
return ret;
- return fwnode_devcon_match(fwnode, con_id, data, match);
+ return fwnode_graph_devcon_match(fwnode, con_id, data, match);
}
EXPORT_SYMBOL_GPL(fwnode_connection_find_match);

View File

@ -1,150 +0,0 @@
--- b/drivers/video/fbdev/core/bitblit.c
+++ a/drivers/video/fbdev/core/bitblit.c
@@ -234,7 +234,7 @@
}
static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg)
- int fg, int bg)
{
struct fb_cursor cursor;
struct fbcon_ops *ops = info->fbcon_par;
@@ -247,6 +247,15 @@
cursor.set = 0;
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
--- b/drivers/video/fbdev/core/fbcon.c
+++ a/drivers/video/fbdev/core/fbcon.c
@@ -394,7 +394,7 @@
c = scr_readw((u16 *) vc->vc_pos);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
CM_ERASE : CM_DRAW;
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
console_unlock();
}
@@ -1345,7 +1345,7 @@
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
- ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
}
--- b/drivers/video/fbdev/core/fbcon.h
+++ a/drivers/video/fbdev/core/fbcon.h
@@ -62,7 +62,7 @@
void (*clear_margins)(struct vc_data *vc, struct fb_info *info,
int color, int bottom_only);
void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg);
- int fg, int bg);
int (*update_start)(struct fb_info *info);
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
--- b/drivers/video/fbdev/core/fbcon_ccw.c
+++ a/drivers/video/fbdev/core/fbcon_ccw.c
@@ -219,7 +219,7 @@
}
static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg)
- int fg, int bg)
{
struct fb_cursor cursor;
struct fbcon_ops *ops = info->fbcon_par;
@@ -236,6 +236,15 @@
cursor.set = 0;
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
--- b/drivers/video/fbdev/core/fbcon_cw.c
+++ a/drivers/video/fbdev/core/fbcon_cw.c
@@ -202,7 +202,7 @@
}
static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg)
- int fg, int bg)
{
struct fb_cursor cursor;
struct fbcon_ops *ops = info->fbcon_par;
@@ -219,6 +219,15 @@
cursor.set = 0;
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
--- b/drivers/video/fbdev/core/fbcon_ud.c
+++ a/drivers/video/fbdev/core/fbcon_ud.c
@@ -249,7 +249,7 @@
}
static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg)
- int fg, int bg)
{
struct fb_cursor cursor;
struct fbcon_ops *ops = info->fbcon_par;
@@ -267,6 +267,15 @@
cursor.set = 0;
+ if (softback_lines) {
+ if (y + softback_lines >= vc->vc_rows) {
+ mode = CM_ERASE;
+ ops->cursor_flash = 0;
+ return;
+ } else
+ y += softback_lines;
+ }
+
c = scr_readw((u16 *) vc->vc_pos);
attribute = get_attribute(info, c);
src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
--- b/drivers/video/fbdev/core/tileblit.c
+++ a/drivers/video/fbdev/core/tileblit.c
@@ -80,7 +80,7 @@
}
static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ int softback_lines, int fg, int bg)
- int fg, int bg)
{
struct fb_tilecursor cursor;
int use_sw = (vc->vc_cursor_type & 0x10);

View File

@ -1,152 +0,0 @@
From: Manish Narani <manish.narani@xilinx.com>
Date: Tue, 18 Sep 2018 20:34:06 +0530
Subject: [PATCH 16/36] sdhci: arasan: Add runtime PM support
Add runtime PM support in Arasan SDHCI driver.
Signed-off-by: Manish Narani <manish.narani@xilinx.com>
---
drivers/mmc/host/sdhci-of-arasan.c | 88 +++++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 6a2e5a4..e08d6ef 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -19,6 +19,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/of.h>
@@ -27,6 +28,7 @@
#include "cqhci.h"
#include "sdhci-pltfm.h"
+#define SDHCI_ARASAN_AUTOSUSPEND_DELAY 2000 /* ms */
#define SDHCI_ARASAN_VENDOR_REGISTER 0x78
#define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8
@@ -472,6 +474,70 @@ static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = {
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
};
+#ifdef CONFIG_PM
+static int sdhci_arasan_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ if (sdhci_arasan->has_cqe) {
+ ret = cqhci_suspend(host->mmc);
+ if (ret)
+ return ret;
+ }
+
+ ret = sdhci_runtime_suspend_host(host);
+ if (ret)
+ return ret;
+
+ if (host->tuning_mode != SDHCI_TUNING_MODE_3)
+ mmc_retune_needed(host->mmc);
+
+ clk_disable(pltfm_host->clk);
+ clk_disable(sdhci_arasan->clk_ahb);
+
+ return 0;
+}
+
+static int sdhci_arasan_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+ int ret;
+
+ ret = clk_enable(sdhci_arasan->clk_ahb);
+ if (ret) {
+ dev_err(dev, "Cannot enable AHB clock.\n");
+ return ret;
+ }
+
+ ret = clk_enable(pltfm_host->clk);
+ if (ret) {
+ dev_err(dev, "Cannot enable SD clock.\n");
+ return ret;
+ }
+
+ ret = sdhci_runtime_resume_host(host, 0);
+ if (ret)
+ goto out;
+
+ if (sdhci_arasan->has_cqe)
+ return cqhci_resume(host->mmc);
+
+ return 0;
+out:
+ clk_disable(pltfm_host->clk);
+ clk_disable(sdhci_arasan->clk_ahb);
+
+ return ret;
+}
+#endif /* ! CONFIG_PM */
+
#ifdef CONFIG_PM_SLEEP
/**
* sdhci_arasan_suspend - Suspend method for the driver
@@ -568,8 +634,10 @@ static int sdhci_arasan_resume(struct device *dev)
}
#endif /* ! CONFIG_PM_SLEEP */
-static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend,
- sdhci_arasan_resume);
+static const struct dev_pm_ops sdhci_arasan_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_arasan_suspend, sdhci_arasan_resume)
+ SET_RUNTIME_PM_OPS(sdhci_arasan_runtime_suspend,
+ sdhci_arasan_runtime_resume, NULL) };
/**
* sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate
@@ -1708,13 +1776,25 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
}
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ SDHCI_ARASAN_AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+
ret = sdhci_arasan_add_host(sdhci_arasan);
if (ret)
goto err_add_host;
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return 0;
err_add_host:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
if (!IS_ERR(sdhci_arasan->phy))
phy_exit(sdhci_arasan->phy);
unreg_clk:
@@ -1742,6 +1822,10 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
phy_exit(sdhci_arasan->phy);
}
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
sdhci_arasan_unregister_sdclk(&pdev->dev);
ret = sdhci_pltfm_unregister(pdev);

View File

@ -1,37 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 22 Oct 2021 18:09:09 +0200
Subject: [PATCH 19/36] clk: rk3399: Export SCLK_CIF_OUT_SRC to device tree
So that it can be used in assigned-clock-parents.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/clk/rockchip/clk-rk3399.c | 2 +-
include/dt-bindings/clock/rk3399-cru.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 306910a..897581e 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -1259,7 +1259,7 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
RK3399_CLKGATE_CON(27), 6, GFLAGS),
/* cif */
- COMPOSITE_NODIV(0, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
+ COMPOSITE_NODIV(SCLK_CIF_OUT_SRC, "clk_cifout_src", mux_pll_src_cpll_gpll_npll_p, 0,
RK3399_CLKSEL_CON(56), 6, 2, MFLAGS,
RK3399_CLKGATE_CON(10), 7, GFLAGS),
diff --git a/include/dt-bindings/clock/rk3399-cru.h b/include/dt-bindings/clock/rk3399-cru.h
index 44e0a31..e83b3fb 100644
--- a/include/dt-bindings/clock/rk3399-cru.h
+++ b/include/dt-bindings/clock/rk3399-cru.h
@@ -125,6 +125,7 @@
#define SCLK_DDRC 168
#define SCLK_TESTCLKOUT1 169
#define SCLK_TESTCLKOUT2 170
+#define SCLK_CIF_OUT_SRC 171
#define DCLK_VOP0 180
#define DCLK_VOP1 181

View File

@ -1,31 +0,0 @@
--- b/drivers/video/fbdev/core/fbcon.c
+++ a/drivers/video/fbdev/core/fbcon.c
@@ -163,6 +163,8 @@
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
+static int fbcon_set_origin(struct vc_data *);
+
static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -2633,6 +2635,11 @@
}
}
+static int fbcon_set_origin(struct vc_data *vc)
+{
+ return 0;
+}
+
void fbcon_suspended(struct fb_info *info)
{
struct vc_data *vc = NULL;
@@ -3103,6 +3110,7 @@
.con_font_default = fbcon_set_def_font,
.con_font_copy = fbcon_copy_font,
.con_set_palette = fbcon_set_palette,
+ .con_set_origin = fbcon_set_origin,
.con_invert_region = fbcon_invert_region,
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,

View File

@ -1,39 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 21 Nov 2021 17:00:09 +0100
Subject: [PATCH 24/36] media: rockchip: rga: Fix probe bugs
The check for dst_mmu_pages allocation failure was inverted.
rga_parse_dt is missing a error return, so if some of the resources
return DEFER_PROBE, probe will succeed without these resources.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/platform/rockchip/rga/rga.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 4de5e8d..82cc0c0 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -815,8 +815,10 @@ static int rga_probe(struct platform_device *pdev)
mutex_init(&rga->mutex);
ret = rga_parse_dt(rga);
- if (ret)
+ if (ret) {
dev_err(&pdev->dev, "Unable to parse OF data\n");
+ return ret;
+ }
pm_runtime_enable(rga->dev);
@@ -892,7 +894,7 @@ static int rga_probe(struct platform_device *pdev)
}
rga->dst_mmu_pages =
(unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3);
- if (rga->dst_mmu_pages) {
+ if (!rga->dst_mmu_pages) {
ret = -ENOMEM;
goto free_src_pages;
}

View File

@ -1,500 +0,0 @@
--- b/drivers/video/fbdev/core/fbcon.c
+++ a/drivers/video/fbdev/core/fbcon.c
@@ -122,6 +122,12 @@
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
enums. */
static int logo_shown = FBCON_LOGO_CANSHOW;
+/* Software scrollback */
+static int fbcon_softback_size = 32768;
+static unsigned long softback_buf, softback_curr;
+static unsigned long softback_in;
+static unsigned long softback_top, softback_end;
+static int softback_lines;
/* console mappings */
static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1;
@@ -161,6 +167,8 @@
static const struct consw fb_con;
+#define CM_SOFTBACK (8)
+
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
static int fbcon_set_origin(struct vc_data *);
@@ -365,6 +373,18 @@
return color;
}
+static void fbcon_update_softback(struct vc_data *vc)
+{
+ int l = fbcon_softback_size / vc->vc_size_row;
+
+ if (l > 5)
+ softback_end = softback_buf + l * vc->vc_size_row;
+ else
+ /* Smaller scrollback makes no sense, and 0 would screw
+ the operation totally */
+ softback_top = 0;
+}
+
static void fb_flashcursor(struct work_struct *work)
{
struct fb_info *info = container_of(work, struct fb_info, queue);
@@ -394,7 +414,7 @@
c = scr_readw((u16 *) vc->vc_pos);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
CM_ERASE : CM_DRAW;
+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1),
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
console_unlock();
}
@@ -451,7 +471,13 @@
}
if (!strncmp(options, "scrollback:", 11)) {
+ options += 11;
+ if (*options) {
+ fbcon_softback_size = simple_strtoul(options, &options, 0);
+ if (*options == 'k' || *options == 'K') {
+ fbcon_softback_size *= 1024;
+ }
+ }
- pr_warn("Ignoring scrollback size option\n");
continue;
}
@@ -996,6 +1022,31 @@
set_blitting_type(vc, info);
+ if (info->fix.type != FB_TYPE_TEXT) {
+ if (fbcon_softback_size) {
+ if (!softback_buf) {
+ softback_buf =
+ (unsigned long)
+ kvmalloc(fbcon_softback_size,
+ GFP_KERNEL);
+ if (!softback_buf) {
+ fbcon_softback_size = 0;
+ softback_top = 0;
+ }
+ }
+ } else {
+ if (softback_buf) {
+ kvfree((void *) softback_buf);
+ softback_buf = 0;
+ softback_top = 0;
+ }
+ }
+ if (softback_buf)
+ softback_in = softback_top = softback_curr =
+ softback_buf;
+ softback_lines = 0;
+ }
+
/* Setup default font */
if (!p->fontdata && !vc->vc_font.data) {
if (!fontname[0] || !(font = find_font(fontname)))
@@ -1169,6 +1220,9 @@
if (logo)
fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
+ if (vc == svc && softback_buf)
+ fbcon_update_softback(vc);
+
if (ops->rotate_font && ops->rotate_font(info, vc)) {
ops->rotate = FB_ROTATE_UR;
set_blitting_type(vc, info);
@@ -1331,6 +1385,7 @@
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par;
+ int y;
int c = scr_readw((u16 *) vc->vc_pos);
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
@@ -1334,11 +1389,19 @@ static void fbcon_cursor(struct vc_data
fbcon_add_cursor_timer(info);
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+ if (mode & CM_SOFTBACK) {
+ mode &= ~CM_SOFTBACK;
+ y = softback_lines;
+ } else {
+ if (softback_lines)
+ fbcon_set_origin(vc);
+ y = 0;
+ }
if (!ops->cursor)
return;
- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1),
+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
}
@@ -1416,6 +1479,8 @@
if (con_is_visible(vc)) {
update_screen(vc);
+ if (softback_buf)
+ fbcon_update_softback(vc);
}
}
@@ -1553,6 +1618,99 @@
scrollback_current = 0;
}
+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p,
+ long delta)
+{
+ int count = vc->vc_rows;
+ unsigned short *d, *s;
+ unsigned long n;
+ int line = 0;
+
+ d = (u16 *) softback_curr;
+ if (d == (u16 *) softback_in)
+ d = (u16 *) vc->vc_origin;
+ n = softback_curr + delta * vc->vc_size_row;
+ softback_lines -= delta;
+ if (delta < 0) {
+ if (softback_curr < softback_top && n < softback_buf) {
+ n += softback_end - softback_buf;
+ if (n < softback_top) {
+ softback_lines -=
+ (softback_top - n) / vc->vc_size_row;
+ n = softback_top;
+ }
+ } else if (softback_curr >= softback_top
+ && n < softback_top) {
+ softback_lines -=
+ (softback_top - n) / vc->vc_size_row;
+ n = softback_top;
+ }
+ } else {
+ if (softback_curr > softback_in && n >= softback_end) {
+ n += softback_buf - softback_end;
+ if (n > softback_in) {
+ n = softback_in;
+ softback_lines = 0;
+ }
+ } else if (softback_curr <= softback_in && n > softback_in) {
+ n = softback_in;
+ softback_lines = 0;
+ }
+ }
+ if (n == softback_curr)
+ return;
+ softback_curr = n;
+ s = (u16 *) softback_curr;
+ if (s == (u16 *) softback_in)
+ s = (u16 *) vc->vc_origin;
+ while (count--) {
+ unsigned short *start;
+ unsigned short *le;
+ unsigned short c;
+ int x = 0;
+ unsigned short attr = 1;
+
+ start = s;
+ le = advance_row(s, 1);
+ do {
+ c = scr_readw(s);
+ if (attr != (c & 0xff00)) {
+ attr = c & 0xff00;
+ if (s > start) {
+ fbcon_putcs(vc, start, s - start,
+ line, x);
+ x += s - start;
+ start = s;
+ }
+ }
+ if (c == scr_readw(d)) {
+ if (s > start) {
+ fbcon_putcs(vc, start, s - start,
+ line, x);
+ x += s - start + 1;
+ start = s + 1;
+ } else {
+ x++;
+ start++;
+ }
+ }
+ s++;
+ d++;
+ } while (s < le);
+ if (s > start)
+ fbcon_putcs(vc, start, s - start, line, x);
+ line++;
+ if (d == (u16 *) softback_end)
+ d = (u16 *) softback_buf;
+ if (d == (u16 *) softback_in)
+ d = (u16 *) vc->vc_origin;
+ if (s == (u16 *) softback_end)
+ s = (u16 *) softback_buf;
+ if (s == (u16 *) softback_in)
+ s = (u16 *) vc->vc_origin;
+ }
+}
+
static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
int line, int count, int dy)
{
@@ -1692,6 +1850,31 @@
}
}
+static inline void fbcon_softback_note(struct vc_data *vc, int t,
+ int count)
+{
+ unsigned short *p;
+
+ if (vc->vc_num != fg_console)
+ return;
+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row);
+
+ while (count) {
+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row);
+ count--;
+ p = advance_row(p, 1);
+ softback_in += vc->vc_size_row;
+ if (softback_in == softback_end)
+ softback_in = softback_buf;
+ if (softback_in == softback_top) {
+ softback_top += vc->vc_size_row;
+ if (softback_top == softback_end)
+ softback_top = softback_buf;
+ }
+ }
+ softback_curr = softback_in;
+}
+
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int count)
{
@@ -1714,6 +1897,8 @@
case SM_UP:
if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows;
+ if (softback_top)
+ fbcon_softback_note(vc, t, count);
if (logo_shown >= 0)
goto redraw_up;
switch (p->scrollmode) {
@@ -2084,6 +2269,14 @@
info = registered_fb[con2fb_map[vc->vc_num]];
ops = info->fbcon_par;
+ if (softback_top) {
+ if (softback_lines)
+ fbcon_set_origin(vc);
+ softback_top = softback_curr = softback_in = softback_buf;
+ softback_lines = 0;
+ fbcon_update_softback(vc);
+ }
+
if (logo_shown >= 0) {
struct vc_data *conp2 = vc_cons[logo_shown].d;
@@ -2407,6 +2600,9 @@
int cnt;
char *old_data = NULL;
+ if (con_is_visible(vc) && softback_lines)
+ fbcon_set_origin(vc);
+
resize = (w != vc->vc_font.width) || (h != vc->vc_font.height);
if (p->userfont)
old_data = vc->vc_font.data;
@@ -2432,6 +2628,8 @@
cols /= w;
rows /= h;
vc_resize(vc, cols, rows);
+ if (con_is_visible(vc) && softback_buf)
+ fbcon_update_softback(vc);
} else if (con_is_visible(vc)
&& vc->vc_mode == KD_TEXT) {
fbcon_clear_margins(vc, 0);
@@ -2590,7 +2788,19 @@
static u16 *fbcon_screen_pos(struct vc_data *vc, int offset)
{
+ unsigned long p;
+ int line;
+
+ if (vc->vc_num != fg_console || !softback_lines)
+ return (u16 *) (vc->vc_origin + offset);
+ line = offset / vc->vc_size_row;
+ if (line >= softback_lines)
+ return (u16 *) (vc->vc_origin + offset -
+ softback_lines * vc->vc_size_row);
+ p = softback_curr + offset;
+ if (p >= softback_end)
+ p += softback_buf - softback_end;
+ return (u16 *) p;
- return (u16 *) (vc->vc_origin + offset);
}
static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos,
@@ -2604,7 +2814,22 @@
x = offset % vc->vc_cols;
y = offset / vc->vc_cols;
+ if (vc->vc_num == fg_console)
+ y += softback_lines;
ret = pos + (vc->vc_cols - x) * 2;
+ } else if (vc->vc_num == fg_console && softback_lines) {
+ unsigned long offset = pos - softback_curr;
+
+ if (pos < softback_curr)
+ offset += softback_end - softback_buf;
+ offset /= 2;
+ x = offset % vc->vc_cols;
+ y = offset / vc->vc_cols;
+ ret = pos + (vc->vc_cols - x) * 2;
+ if (ret == softback_end)
+ ret = softback_buf;
+ if (ret == softback_in)
+ ret = vc->vc_origin;
} else {
/* Should not happen */
x = y = 0;
@@ -2632,11 +2857,106 @@
a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) |
(((a) & 0x0700) << 4);
scr_writew(a, p++);
+ if (p == (u16 *) softback_end)
+ p = (u16 *) softback_buf;
+ if (p == (u16 *) softback_in)
+ p = (u16 *) vc->vc_origin;
+ }
+}
+
+static void fbcon_scrolldelta(struct vc_data *vc, int lines)
+{
+ struct fb_info *info = registered_fb[con2fb_map[fg_console]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_display *disp = &fb_display[fg_console];
+ int offset, limit, scrollback_old;
+
+ if (softback_top) {
+ if (vc->vc_num != fg_console)
+ return;
+ if (vc->vc_mode != KD_TEXT || !lines)
+ return;
+ if (logo_shown >= 0) {
+ struct vc_data *conp2 = vc_cons[logo_shown].d;
+
+ if (conp2->vc_top == logo_lines
+ && conp2->vc_bottom == conp2->vc_rows)
+ conp2->vc_top = 0;
+ if (logo_shown == vc->vc_num) {
+ unsigned long p, q;
+ int i;
+
+ p = softback_in;
+ q = vc->vc_origin +
+ logo_lines * vc->vc_size_row;
+ for (i = 0; i < logo_lines; i++) {
+ if (p == softback_top)
+ break;
+ if (p == softback_buf)
+ p = softback_end;
+ p -= vc->vc_size_row;
+ q -= vc->vc_size_row;
+ scr_memcpyw((u16 *) q, (u16 *) p,
+ vc->vc_size_row);
+ }
+ softback_in = softback_curr = p;
+ update_region(vc, vc->vc_origin,
+ logo_lines * vc->vc_cols);
+ }
+ logo_shown = FBCON_LOGO_CANSHOW;
+ }
+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK);
+ fbcon_redraw_softback(vc, disp, lines);
+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK);
+ return;
}
+
+ if (!scrollback_phys_max)
+ return;
+
+ scrollback_old = scrollback_current;
+ scrollback_current -= lines;
+ if (scrollback_current < 0)
+ scrollback_current = 0;
+ else if (scrollback_current > scrollback_max)
+ scrollback_current = scrollback_max;
+ if (scrollback_current == scrollback_old)
+ return;
+
+ if (fbcon_is_inactive(vc, info))
+ return;
+
+ fbcon_cursor(vc, CM_ERASE);
+
+ offset = disp->yscroll - scrollback_current;
+ limit = disp->vrows;
+ switch (disp->scrollmode) {
+ case SCROLL_WRAP_MOVE:
+ info->var.vmode |= FB_VMODE_YWRAP;
+ break;
+ case SCROLL_PAN_MOVE:
+ case SCROLL_PAN_REDRAW:
+ limit -= vc->vc_rows;
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+ break;
+ }
+ if (offset < 0)
+ offset += limit;
+ else if (offset >= limit)
+ offset -= limit;
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = offset * vc->vc_font.height;
+ ops->update_start(info);
+
+ if (!scrollback_current)
+ fbcon_cursor(vc, CM_DRAW);
}
static int fbcon_set_origin(struct vc_data *vc)
{
+ if (softback_lines)
+ fbcon_scrolldelta(vc, softback_lines);
return 0;
}
@@ -2700,6 +3020,8 @@
fbcon_set_palette(vc, color_table);
update_screen(vc);
+ if (softback_buf)
+ fbcon_update_softback(vc);
}
}
@@ -3110,6 +3432,7 @@
.con_font_default = fbcon_set_def_font,
.con_font_copy = fbcon_copy_font,
.con_set_palette = fbcon_set_palette,
+ .con_scrolldelta = fbcon_scrolldelta,
.con_set_origin = fbcon_set_origin,
.con_invert_region = fbcon_invert_region,
.con_screen_pos = fbcon_screen_pos,
@@ -3344,6 +3667,9 @@
}
#endif
+ kvfree((void *)softback_buf);
+ softback_buf = 0UL;
+
for_each_registered_fb(i) {
int pending = 0;

View File

@ -1,34 +0,0 @@
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
Date: Fri, 8 Jan 2021 00:19:23 +0100
Subject: [PATCH 02/36] drm: dw-mipi-dsi-rockchip: Ensure that lane is
properly configured
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
???
Signed-of-by: Kamil Trzciński <ayufan@ayufan.eu>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index a9acbcc..53c8b40 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -406,6 +406,14 @@ static int dw_mipi_dsi_phy_init(void *priv_data)
*/
vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
+ if (dsi->cdata->lanecfg1_grf_reg) {
+ regmap_write(dsi->grf_regmap, dsi->cdata->lanecfg1_grf_reg,
+ dsi->cdata->lanecfg1);
+
+ dev_info(dsi->dev, "dw_mipi_dsi_phy_init / dw_mipi_dsi_rockchip_config: %08x => set=%08x\n",
+ dsi->cdata->lanecfg1_grf_reg, dsi->cdata->lanecfg1);
+ }
+
i = max_mbps_to_parameter(dsi->lane_mbps);
if (i < 0) {
DRM_DEV_ERROR(dsi->dev,

View File

@ -1,48 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 17 Oct 2021 18:04:21 +0200
Subject: [PATCH 03/36] drm: rockchip: dw-mipi-dsi: Fix missing
clk_disable_unprepare for pllref_clk
In some error paths, clk_disable_unprepare function was not called.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 53c8b40..095d0f1 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -960,7 +960,7 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
ret = clk_prepare_enable(dsi->grf_clk);
if (ret) {
DRM_DEV_ERROR(dsi->dev, "Failed to enable grf_clk: %d\n", ret);
- return ret;
+ goto err_pllref_disable;
}
dw_mipi_dsi_rockchip_config(dsi);
@@ -972,16 +972,20 @@ static int dw_mipi_dsi_rockchip_bind(struct device *dev,
ret = rockchip_dsi_drm_create_encoder(dsi, drm_dev);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to create drm encoder\n");
- return ret;
+ goto err_pllref_disable;
}
ret = dw_mipi_dsi_bind(dsi->dmd, &dsi->encoder);
if (ret) {
DRM_DEV_ERROR(dev, "Failed to bind: %d\n", ret);
- return ret;
+ goto err_pllref_disable;
}
return 0;
+
+err_pllref_disable:
+ clk_disable_unprepare(dsi->pllref_clk);
+ return ret;
}
static void dw_mipi_dsi_rockchip_unbind(struct device *dev,

View File

@ -1,145 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 17 Oct 2021 20:14:25 +0200
Subject: [PATCH 04/36] drm: bridge: dw-mipi-dsi: Fix enable/disable of dsi
controller
The driver had it all wrong. mode_set is not for enabling the
DSI controller, that should be done in pre_enable so that
panel driver can initialize the panel (working dsi controller
is needed for that). Having dsi powerup in mode_set led to
all kind of fun, because disable would be called more often
than mode_set.
The whole panel/dsi enable/disable dance is such (for future
reference):
- dsi: mode set
- panel: prepare (we turn on panel power)
- dsi: pre enable (we enable and setup DSI)
- dsi: enable (we enable video data)
- panel: enable (we configure and turn on the display)
For disable:
- panel: disable (we turn off the display nicely)
- dsi: disable (we disable DSI)
- dsi: post disable
- panel: unprepare (we power off display power, panel should
be safely sleeping now)
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 45 +++++++++++++++++++--------
1 file changed, 32 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index e44e18a..9cce2ab 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -266,6 +266,7 @@ struct dw_mipi_dsi {
struct dw_mipi_dsi *master; /* dual-dsi master ptr */
struct dw_mipi_dsi *slave; /* dual-dsi slave ptr */
+ struct drm_display_mode mode;
const struct dw_mipi_dsi_plat_data *plat_data;
};
@@ -597,6 +598,8 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi,
{
u32 val;
+ dev_info(dsi->dev, "mode %d\n", (int)mode_flags);
+
dsi_write(dsi, DSI_PWR_UP, RESET);
if (mode_flags & MIPI_DSI_MODE_VIDEO) {
@@ -871,11 +874,20 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_INT_MSK1, 0);
}
+static void dw_mipi_dsi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+ dev_info(dsi->dev, "disable\n");
+}
+
static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
+ dev_info(dsi->dev, "post disable\n");
+
/*
* Switch to command mode before panel-bridge post_disable &
* panel unprepare.
@@ -884,15 +896,6 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge)
*/
dw_mipi_dsi_set_mode(dsi, 0);
- /*
- * TODO Only way found to call panel-bridge post_disable &
- * panel unprepare before the dsi "final" disable...
- * This needs to be fixed in the drm_bridge framework and the API
- * needs to be updated to manage our own call chains...
- */
- if (dsi->panel_bridge->funcs->post_disable)
- dsi->panel_bridge->funcs->post_disable(dsi->panel_bridge);
-
if (phy_ops->power_off)
phy_ops->power_off(dsi->plat_data->priv_data);
@@ -921,7 +924,7 @@ static unsigned int dw_mipi_dsi_get_lanes(struct dw_mipi_dsi *dsi)
return dsi->lanes;
}
-static void dw_mipi_dsi_mode_set(struct dw_mipi_dsi *dsi,
+static void dw_mipi_dsi_enable(struct dw_mipi_dsi *dsi,
const struct drm_display_mode *adjusted_mode)
{
const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops;
@@ -973,16 +976,30 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge,
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
- dw_mipi_dsi_mode_set(dsi, adjusted_mode);
+ dev_info(dsi->dev, "mode set\n");
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&dsi->mode, mode, sizeof(dsi->mode));
+}
+
+static void dw_mipi_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+{
+ struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
+
+ dev_info(dsi->dev, "pre enable\n");
+
+ /* power up the dsi ctl into a command mode */
+ dw_mipi_dsi_enable(dsi, &dsi->mode);
if (dsi->slave)
- dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode);
+ dw_mipi_dsi_enable(dsi->slave, &dsi->mode);
}
static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
- /* Switch to video mode for panel-bridge enable & panel enable */
+ dev_info(dsi->dev, "enable\n");
+
dw_mipi_dsi_set_mode(dsi, MIPI_DSI_MODE_VIDEO);
if (dsi->slave)
dw_mipi_dsi_set_mode(dsi->slave, MIPI_DSI_MODE_VIDEO);
@@ -1033,7 +1050,9 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
.mode_set = dw_mipi_dsi_bridge_mode_set,
+ .pre_enable = dw_mipi_dsi_bridge_pre_enable,
.enable = dw_mipi_dsi_bridge_enable,
+ .disable = dw_mipi_dsi_bridge_disable,
.post_disable = dw_mipi_dsi_bridge_post_disable,
.mode_valid = dw_mipi_dsi_bridge_mode_valid,
.attach = dw_mipi_dsi_bridge_attach,

View File

@ -1,28 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 16 Nov 2021 21:16:26 +0100
Subject: [PATCH 07/36] drm: dw-mipi-dsi-rockchip: Never allow lane bandwidth
to be less than requested
Bandwidth can be less than requested in some cases, because the search
for best values only checked for absolute difference from ideal value.
This is likely not intentional.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
index 095d0f1..bd488a8 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c
@@ -612,7 +612,7 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
continue;
delta = abs(fout - tmp);
- if (delta < min_delta) {
+ if (delta < min_delta && fout < tmp) {
best_prediv = _prediv;
best_fbdiv = _fbdiv;
min_delta = delta;

View File

@ -1,23 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sat, 20 Nov 2021 14:35:52 +0100
Subject: [PATCH 09/36] drm: rockchip: cdn-dp: Disable CDN DP on disconnect
Why not?
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/rockchip/cdn-dp-core.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 16497c3..f4dcd9e 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -934,6 +934,7 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n");
dp->connected = false;
+ cdn_dp_disable(dp);
/* Connected but not enabled, enable the block */
} else if (!dp->active) {
DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n");

View File

@ -1,69 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 17 Oct 2021 12:46:01 +0200
Subject: [PATCH 10/36] video: fbdev: Add events for early fb event support
This patch adds FB_EARLY_EVENT_BLANK and FB_R_EARLY_EVENT_BLANK
event mode supports. first, fb_notifier_call_chain() is called with
FB_EARLY_EVENT_BLANK and fb_blank() of specific fb driver is called
and then fb_notifier_call_chain() is called with FB_EVENT_BLANK again
at fb_blank(). and if fb_blank() was failed then fb_nitifier_call_chain()
would be called with FB_R_EARLY_EVENT_BLANK to revert the previous effects.
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/video/fbdev/core/fbmem.c | 12 +++++++++++-
include/linux/fb.h | 5 +++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 826175a..fb1651a 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1067,7 +1067,7 @@ int
fb_blank(struct fb_info *info, int blank)
{
struct fb_event event;
- int ret = -EINVAL;
+ int ret = -EINVAL, early_ret;
if (blank > FB_BLANK_POWERDOWN)
blank = FB_BLANK_POWERDOWN;
@@ -1075,11 +1075,21 @@ fb_blank(struct fb_info *info, int blank)
event.info = info;
event.data = &blank;
+ early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event);
+
if (info->fbops->fb_blank)
ret = info->fbops->fb_blank(blank, info);
if (!ret)
fb_notifier_call_chain(FB_EVENT_BLANK, &event);
+ else {
+ /*
+ * if fb_blank is failed then revert effects of
+ * the early blank event.
+ */
+ if (!early_ret)
+ fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event);
+ }
return ret;
}
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 6f3db99..ffef502a 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -137,6 +137,11 @@ struct fb_cursor_user {
/* A display blank is requested */
#define FB_EVENT_BLANK 0x09
+/* A hardware display blank early change occured */
+#define FB_EARLY_EVENT_BLANK 0x10
+/* A hardware display blank revert early change occured */
+#define FB_R_EARLY_EVENT_BLANK 0x11
+
struct fb_event {
struct fb_info *info;
void *data;

View File

@ -1,40 +0,0 @@
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
Date: Mon, 4 Jan 2021 17:57:49 +0100
Subject: [PATCH 11/36] power: rk818: Configure `rk808-clkout2` function
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
???
Signed-of-by: Kamil Trzciński <ayufan@ayufan.eu>
---
drivers/mfd/rk808.c | 1 +
include/linux/mfd/rk808.h | 2 ++
2 files changed, 3 insertions(+)
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index b181fe4..1a6857e 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -303,6 +303,7 @@ static const struct rk808_reg_data rk818_pre_init_reg[] = {
{ RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
{ RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
VB_LO_SEL_3500MV },
+ { RK808_CLK32OUT_REG, CLK32KOUT2_FUNC_MASK, CLK32KOUT2_FUNC },
};
static const struct regmap_irq rk805_irqs[] = {
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index a96e6d4..2ec0520 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -381,6 +381,8 @@ enum rk805_reg {
#define VOUT_LO_INT BIT(0)
#define CLK32KOUT2_EN BIT(0)
+#define CLK32KOUT2_FUNC (0 << 1)
+#define CLK32KOUT2_FUNC_MASK BIT(1)
#define TEMP115C 0x0c
#define TEMP_HOTDIE_MSK 0x0c

View File

@ -1,46 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:30:07 +0100
Subject: [PATCH 13/36] power: supply: rk818-battery: Use a more propper
compatible string
Prefix with vendor name.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/mfd/rk808.c | 2 +-
drivers/power/supply/rk818_battery.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 7d1f000..a99fec0 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -205,7 +205,7 @@ static const struct mfd_cell rk817s[] = {
static const struct mfd_cell rk818s[] = {
{ .name = "rk808-clkout", },
{ .name = "rk808-regulator", },
- { .name = "rk818-battery", .of_compatible = "rk818-battery", },
+ { .name = "rk818-battery", .of_compatible = "rockchip,rk818-battery", },
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c
index f09f456..665f043 100644
--- a/drivers/power/supply/rk818_battery.c
+++ b/drivers/power/supply/rk818_battery.c
@@ -3339,7 +3339,7 @@ static int rk818_bat_parse_dt(struct rk818_battery *di)
#endif
static const struct of_device_id rk818_battery_of_match[] = {
- {.compatible = "rk818-battery",},
+ { .compatible = "rockchip,rk818-battery", },
{ },
};
@@ -3565,4 +3565,4 @@ module_exit(battery_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:rk818-battery");
-MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");
\ No newline at end of file
+MODULE_AUTHOR("chenjh<chenjh@rock-chips.com>");

View File

@ -1,85 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 14 Nov 2021 21:24:05 +0100
Subject: [PATCH 14/36] power: supply: core: Don't ignore max_current of 0
when setting current limit
If we ignore current limit of 0, the dependent power source will not
set input current limit to that value when the supplier changes max
current to 0. This may happen when USB power is disconnected from the
device.
On next connection, the dependent power supply will start consuming
power at the previously set limit even before the PD/BC1.2 power
negotiation has a chance to complete.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/power/supply/power_supply_core.c | 47 ++++++++++++++------------------
1 file changed, 20 insertions(+), 27 deletions(-)
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index fc12a4f..f681372 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -375,41 +375,34 @@ int power_supply_is_system_supplied(void)
}
EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
-static int __power_supply_get_supplier_max_current(struct device *dev,
- void *data)
-{
- union power_supply_propval ret = {0,};
- struct power_supply *epsy = dev_get_drvdata(dev);
- struct power_supply *psy = data;
-
- if (__power_supply_is_supplied_by(epsy, psy))
- if (!epsy->desc->get_property(epsy,
- POWER_SUPPLY_PROP_CURRENT_MAX,
- &ret))
- return ret.intval;
-
- return 0;
-}
-
int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy)
{
union power_supply_propval val = {0,};
- int curr;
+ struct class_dev_iter iter;
+ struct power_supply *epsy;
+ struct device *dev;
+ int ret;
if (!psy->desc->set_property)
return -EINVAL;
- /*
- * This function is not intended for use with a supply with multiple
- * suppliers, we simply pick the first supply to report a non 0
- * max-current.
- */
- curr = class_for_each_device(power_supply_class, NULL, psy,
- __power_supply_get_supplier_max_current);
- if (curr <= 0)
- return (curr == 0) ? -ENODEV : curr;
+ class_dev_iter_init(&iter, power_supply_class, NULL, NULL);
+ while ((dev = class_dev_iter_next(&iter))) {
+ epsy = dev_get_drvdata(dev);
+
+ if (!__power_supply_is_supplied_by(epsy, psy))
+ continue;
- val.intval = curr;
+ ret = epsy->desc->get_property(epsy,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ &val);
+ if (!ret)
+ break;
+ }
+ class_dev_iter_exit(&iter);
+
+ if (ret)
+ return ret;
return psy->desc->set_property(psy,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);

View File

@ -1,699 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 20:09:02 +0100
Subject: [PATCH 15/36] power: supply: rk818-charger: Implement charger driver
for RK818 PMIC
For now this driver is just meant to watch Type-C power supply
and apply current limits to RK818, to not overload the Type-C
partner.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/mfd/rk808.c | 1 +
drivers/power/supply/Kconfig | 8 +
drivers/power/supply/Makefile | 1 +
drivers/power/supply/rk818_charger.c | 637 +++++++++++++++++++++++++++++++++++
4 files changed, 647 insertions(+)
create mode 100644 drivers/power/supply/rk818_charger.c
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index a99fec0..75d18de 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -206,6 +206,7 @@ static const struct mfd_cell rk818s[] = {
{ .name = "rk808-clkout", },
{ .name = "rk808-regulator", },
{ .name = "rk818-battery", .of_compatible = "rockchip,rk818-battery", },
+ { .name = "rk818-charger", .of_compatible = "rockchip,rk818-charger", },
{
.name = "rk808-rtc",
.num_resources = ARRAY_SIZE(rtc_resources),
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index f5d4434..6bf0834 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -862,4 +862,12 @@ config BATTERY_RK818
If you say yes here you will get support for the battery of RK818 PMIC.
This driver can give support for Rk818 Battery Charge Interface.
+config CHARGER_RK818
+ bool "RK818 Charger driver"
+ depends on MFD_RK808
+ default n
+ help
+ If you say yes here you will get support for the charger of RK818 PMIC.
+ This driver can give support for Rk818 Charger Interface.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 1c725ee..3a1526f 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -105,3 +105,4 @@ obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o
obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o
obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o
obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o
+obj-$(CONFIG_CHARGER_RK818) += rk818_charger.o
diff --git a/drivers/power/supply/rk818_charger.c b/drivers/power/supply/rk818_charger.c
new file mode 100644
index 00000000..7b67a0b
--- /dev/null
+++ b/drivers/power/supply/rk818_charger.c
@@ -0,0 +1,637 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * rk818 usb power driver
+ *
+ * Copyright (c) 2021 Ondřej Jirman <megi@xff.cz>
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/mfd/rk808.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+
+#define RK818_CHG_STS_MASK (7u << 4) /* charger status */
+#define RK818_CHG_STS_NONE (0u << 4)
+#define RK818_CHG_STS_WAKEUP_CUR (1u << 4)
+#define RK818_CHG_STS_TRICKLE_CUR (2u << 4)
+#define RK818_CHG_STS_CC_OR_CV (3u << 4)
+#define RK818_CHG_STS_TERMINATED (4u << 4)
+#define RK818_CHG_STS_USB_OV (5u << 4)
+#define RK818_CHG_STS_BAT_TEMP_FAULT (6u << 4)
+#define RK818_CHG_STS_TIMEOUT (7u << 4)
+
+/* RK818_SUP_STS_REG */
+#define RK818_SUP_STS_USB_VLIM_EN BIT(3) /* input voltage limit enable */
+#define RK818_SUP_STS_USB_ILIM_EN BIT(2) /* input current limit enable */
+#define RK818_SUP_STS_USB_EXS BIT(1) /* USB power connected */
+#define RK818_SUP_STS_USB_EFF BIT(0) /* USB fault */
+
+/* RK818_USB_CTRL_REG */
+#define RK818_USB_CTRL_USB_ILIM_MASK (0xfu)
+#define RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET 4
+#define RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK (0x7u << 4)
+
+/* RK818_CHRG_CTRL_REG1 */
+#define RK818_CHRG_CTRL_REG1_CHRG_EN BIT(7)
+#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET 4
+#define RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK (0x7u << 4)
+#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET 0
+#define RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK (0xfu << 0)
+
+/* RK818_CHRG_CTRL_REG3 */
+#define RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL BIT(5)
+
+struct rk818_charger {
+ struct device *dev;
+ struct rk808 *rk818;
+ struct regmap *regmap;
+
+ struct power_supply *usb_psy;
+ struct power_supply *charger_psy;
+};
+
+// {{{ USB supply
+
+static int rk818_usb_set_input_current_max(struct rk818_charger *cg,
+ int val)
+{
+ int ret;
+ unsigned reg;
+
+ if (val < 450000)
+ reg = 1;
+ else if (val < 850000)
+ reg = 0;
+ else if (val < 1000000)
+ reg = 2;
+ else if (val < 3000000)
+ reg = 3 + (val - 1000000) / 250000;
+ else
+ reg = 11;
+
+ ret = regmap_update_bits(cg->regmap, RK818_USB_CTRL_REG,
+ RK818_USB_CTRL_USB_ILIM_MASK, reg);
+ if (ret)
+ dev_err(cg->dev,
+ "USB input current limit setting failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int rk818_usb_get_input_current_max(struct rk818_charger *cg,
+ int *val)
+{
+ unsigned reg;
+ int ret;
+
+ ret = regmap_read(cg->regmap, RK818_USB_CTRL_REG, &reg);
+ if (ret) {
+ dev_err(cg->dev,
+ "USB input current limit getting failed (%d)\n", ret);
+ return ret;
+ }
+
+ reg &= RK818_USB_CTRL_USB_ILIM_MASK;
+ if (reg == 0)
+ *val = 450000;
+ else if (reg == 1)
+ *val = 80000;
+ else if (reg == 2)
+ *val = 850000;
+ else if (reg < 11)
+ *val = 1000000 + (reg - 3) * 250000;
+ else
+ *val = 3000000;
+
+ return 0;
+}
+
+static int rk818_usb_set_input_voltage_min(struct rk818_charger *cg,
+ int val)
+{
+ unsigned reg;
+ int ret;
+
+ if (val < 2780000)
+ reg = 0;
+ else if (val < 3270000)
+ reg = (val - 2780000) / 70000;
+ else
+ reg = 7;
+
+ ret = regmap_update_bits(cg->regmap, RK818_USB_CTRL_REG,
+ RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK,
+ reg << RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET);
+ if (ret)
+ dev_err(cg->dev,
+ "USB input voltage limit setting failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int rk818_usb_get_input_voltage_min(struct rk818_charger *cg,
+ int *val)
+{
+ unsigned reg;
+ int ret;
+
+ ret = regmap_read(cg->regmap, RK818_USB_CTRL_REG, &reg);
+ if (ret) {
+ dev_err(cg->dev,
+ "USB input voltage limit getting failed (%d)\n", ret);
+ return ret;
+ }
+
+ reg &= RK818_USB_CTRL_USB_CHG_SD_VSEL_MASK;
+ reg >>= RK818_USB_CTRL_USB_CHG_SD_VSEL_OFFSET;
+
+ *val = 2780000 + (reg * 70000);
+
+ return 0;
+}
+
+static int rk818_usb_power_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
+ unsigned reg;
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_PRESENT:
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, &reg);
+ if (ret)
+ return ret;
+
+ val->intval = !!(reg & RK818_SUP_STS_USB_EXS);
+ break;
+
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, &reg);
+ if (ret)
+ return ret;
+
+ if (!(reg & RK818_SUP_STS_USB_EXS)) {
+ val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
+ } else if (reg & RK818_SUP_STS_USB_EFF) {
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ } else {
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ }
+
+ break;
+
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rk818_usb_get_input_voltage_min(cg, &val->intval);
+
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return rk818_usb_get_input_current_max(cg, &val->intval);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rk818_usb_power_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return rk818_usb_set_input_voltage_min(cg, val->intval);
+
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ return rk818_usb_set_input_current_max(cg, val->intval);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rk818_usb_power_prop_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+ case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Sync the input-current-limit with our parent supply (if we have one) */
+static void rk818_usb_power_external_power_changed(struct power_supply *psy)
+{
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
+
+ power_supply_set_input_current_limit_from_supplier(cg->usb_psy);
+}
+
+static enum power_supply_property rk818_usb_power_props[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+ POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+};
+
+static const struct power_supply_desc rk818_usb_desc = {
+ .name = "rk818-usb",
+ .type = POWER_SUPPLY_TYPE_USB,
+ .properties = rk818_usb_power_props,
+ .num_properties = ARRAY_SIZE(rk818_usb_power_props),
+ .property_is_writeable = rk818_usb_power_prop_writeable,
+ .get_property = rk818_usb_power_get_property,
+ .set_property = rk818_usb_power_set_property,
+ .external_power_changed = rk818_usb_power_external_power_changed,
+};
+
+// }}}
+// {{{ Charger supply
+
+static int rk818_charger_set_current_max(struct rk818_charger *cg, int val)
+{
+ unsigned reg;
+ int ret;
+
+ if (val < 1000000)
+ reg = 0;
+ else if (val < 3000000)
+ reg = (val - 1000000) / 200000;
+ else
+ reg = 10;
+
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
+ RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK,
+ reg << RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET);
+ if (ret)
+ dev_err(cg->dev,
+ "Charging max current setting failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int rk818_charger_get_current_max(struct rk818_charger *cg, int *val)
+{
+ unsigned reg;
+ int ret;
+
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, &reg);
+ if (ret) {
+ dev_err(cg->dev,
+ "Charging max current getting failed (%d)\n", ret);
+ return ret;
+ }
+
+ reg &= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_MASK;
+ reg >>= RK818_CHRG_CTRL_REG1_CHRG_CUR_SEL_OFFSET;
+
+ *val = 1000000 + reg * 200000;
+
+ return 0;
+}
+
+static int rk818_charger_set_voltage_max(struct rk818_charger *cg, int val)
+{
+ unsigned reg;
+ int ret;
+
+ if (val < 4050000)
+ reg = 0;
+ else if (val < 4350000)
+ reg = (val - 4050000) / 50000;
+ else
+ reg = 6;
+
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
+ RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK,
+ reg << RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET);
+ if (ret)
+ dev_err(cg->dev,
+ "Charging end voltage setting failed (%d)\n", ret);
+
+ return ret;
+}
+
+static int rk818_charger_get_voltage_max(struct rk818_charger *cg, int *val)
+{
+ unsigned reg;
+ int ret;
+
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, &reg);
+ if (ret) {
+ dev_err(cg->dev,
+ "Charging end voltage getting failed (%d)\n", ret);
+ return ret;
+ }
+
+ reg &= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_MASK;
+ reg >>= RK818_CHRG_CTRL_REG1_CHRG_VOL_SEL_OFFSET;
+
+ *val = 4050000 + reg * 50000;
+
+ return 0;
+}
+
+static int rk818_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
+ unsigned reg;
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG1, &reg);
+ if (ret) {
+ dev_err(cg->dev, "failed to read the charger state (%d)\n", ret);
+ return ret;
+ }
+
+ val->intval = !!(reg & RK818_CHRG_CTRL_REG1_CHRG_EN);
+ break;
+
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, &reg);
+ if (ret)
+ return ret;
+
+ switch (reg & RK818_CHG_STS_MASK) {
+ case RK818_CHG_STS_WAKEUP_CUR:
+ case RK818_CHG_STS_TRICKLE_CUR:
+ case RK818_CHG_STS_CC_OR_CV:
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case RK818_CHG_STS_TERMINATED:
+ default:
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ }
+
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, &reg);
+ if (ret)
+ return ret;
+
+ switch (reg & RK818_CHG_STS_MASK) {
+ case RK818_CHG_STS_WAKEUP_CUR:
+ case RK818_CHG_STS_TRICKLE_CUR:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case RK818_CHG_STS_CC_OR_CV:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case RK818_CHG_STS_TERMINATED:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ break;
+ }
+
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+ ret = regmap_read(cg->regmap, RK818_CHRG_CTRL_REG2, &reg);
+ if (ret)
+ return ret;
+
+ val->intval = 100000 + ((reg >> 6) & 3) * 50000;
+ break;
+
+ case POWER_SUPPLY_PROP_HEALTH:
+ ret = regmap_read(cg->regmap, RK818_SUP_STS_REG, &reg);
+ if (ret)
+ return ret;
+
+ switch (reg & RK818_CHG_STS_MASK) {
+ case RK818_CHG_STS_USB_OV:
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ case RK818_CHG_STS_BAT_TEMP_FAULT:
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ break;
+ case RK818_CHG_STS_TIMEOUT:
+ val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ break;
+ default:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ }
+
+ break;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rk818_charger_get_voltage_max(cg, &val->intval);
+
+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+ ret = rk818_charger_get_current_max(cg, &val->intval);
+ val->intval /= 10;
+ return ret;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return rk818_charger_get_current_max(cg, &val->intval);
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+ val->intval = 4350000;
+ break;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+ val->intval = 3000000;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rk818_charger_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct rk818_charger *cg = power_supply_get_drvdata(psy);
+ int ret;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1,
+ RK818_CHRG_CTRL_REG1_CHRG_EN,
+ val->intval ? RK818_CHRG_CTRL_REG1_CHRG_EN : 0);
+ if (ret)
+ dev_err(cg->dev, "failed to setup the charger (%d)\n", ret);
+
+ return ret;
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ return rk818_charger_set_voltage_max(cg, val->intval);
+
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ return rk818_charger_set_current_max(cg, val->intval);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rk818_charger_prop_writeable(struct power_supply *psy,
+ enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+ case POWER_SUPPLY_PROP_ONLINE:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static enum power_supply_property rk818_charger_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+ POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+};
+
+/*
+ * TODO: This functionality should be in a battery driver/supply, but that one
+ * is such a mess, I don't want to touch it now. Let's have a separate supply
+ * for controlling the charger for now, and a prayer for the poor soul that
+ * will have to understand and clean up the battery driver.
+ */
+static const struct power_supply_desc rk818_charger_desc = {
+ .name = "rk818-charger",
+ .type = POWER_SUPPLY_TYPE_BATTERY,
+ .properties = rk818_charger_props,
+ .num_properties = ARRAY_SIZE(rk818_charger_props),
+ .property_is_writeable = rk818_charger_prop_writeable,
+ .get_property = rk818_charger_get_property,
+ .set_property = rk818_charger_set_property,
+};
+
+// }}}
+
+static int rk818_charger_probe(struct platform_device *pdev)
+{
+ struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent);
+ struct power_supply_config psy_cfg = { };
+ struct device *dev = &pdev->dev;
+ struct rk818_charger *cg;
+ int ret;
+
+ cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
+ if (!cg)
+ return -ENOMEM;
+
+ cg->rk818 = rk818;
+ cg->dev = dev;
+ cg->regmap = rk818->regmap;
+ platform_set_drvdata(pdev, cg);
+
+ psy_cfg.drv_data = cg;
+ psy_cfg.of_node = dev->of_node;
+
+ cg->usb_psy = devm_power_supply_register(dev, &rk818_usb_desc,
+ &psy_cfg);
+ if (IS_ERR(cg->usb_psy))
+ return dev_err_probe(dev, PTR_ERR(cg->usb_psy),
+ "register usb power supply fail\n");
+
+ cg->charger_psy = devm_power_supply_register(dev, &rk818_charger_desc,
+ &psy_cfg);
+ if (IS_ERR(cg->charger_psy))
+ return dev_err_probe(dev, PTR_ERR(cg->charger_psy),
+ "register charger power supply fail\n");
+
+ /* disable voltage limit and enable input current limit */
+ ret = regmap_update_bits(cg->regmap, RK818_SUP_STS_REG,
+ RK818_SUP_STS_USB_ILIM_EN | RK818_SUP_STS_USB_VLIM_EN,
+ RK818_SUP_STS_USB_ILIM_EN);
+ if (ret)
+ dev_warn(cg->dev, "failed to enable input current limit (%d)\n", ret);
+
+ /* make sure analog control loop is enabled */
+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG3,
+ RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL,
+ 0);
+ if (ret)
+ dev_warn(cg->dev, "failed to enable analog control loop (%d)\n", ret);
+
+ /* enable charger and set some reasonable limits on each boot */
+ ret = regmap_write(cg->regmap, RK818_CHRG_CTRL_REG1,
+ RK818_CHRG_CTRL_REG1_CHRG_EN
+ | (1) /* 1.2A */
+ | (5 << 4) /* 4.3V */);
+ if (ret)
+ dev_warn(cg->dev, "failed to enable charger (%d)\n", ret);
+
+ power_supply_set_input_current_limit_from_supplier(cg->usb_psy);
+
+ return 0;
+}
+
+static int rk818_charger_remove(struct platform_device *pdev)
+{
+ //struct rk818_charger *cg = platform_get_drvdata(pdev);
+
+ return 0;
+}
+
+static void rk818_charger_shutdown(struct platform_device *pdev)
+{
+}
+
+static int rk818_charger_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int rk818_charger_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id rk818_charger_of_match[] = {
+ { .compatible = "rockchip,rk818-charger", },
+ { },
+};
+
+static struct platform_driver rk818_charger_driver = {
+ .probe = rk818_charger_probe,
+ .remove = rk818_charger_remove,
+ .suspend = rk818_charger_suspend,
+ .resume = rk818_charger_resume,
+ .shutdown = rk818_charger_shutdown,
+ .driver = {
+ .name = "rk818-charger",
+ .of_match_table = rk818_charger_of_match,
+ },
+};
+
+module_platform_driver(rk818_charger_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rk818-charger");
+MODULE_AUTHOR("Ondřej Jirman <megi@xff.cz>");

View File

@ -1,47 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:28:27 +0100
Subject: [PATCH 26/36] usb: typec: fusb302: Set the current before enabling
pullups
This seems more reasonable and should avoid short period of incorrect
current setting being applied to CC pin.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 72f9001..776a949 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -635,6 +635,14 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
goto done;
}
+ /* adjust current for SRC */
+ ret = fusb302_set_src_current(chip, cc_src_current[cc]);
+ if (ret < 0) {
+ fusb302_log(chip, "cannot set src current %s, ret=%d",
+ typec_cc_status_name[cc], ret);
+ goto done;
+ }
+
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
switches0_mask, switches0_data);
if (ret < 0) {
@@ -645,14 +653,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc)
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
- /* adjust current for SRC */
- ret = fusb302_set_src_current(chip, cc_src_current[cc]);
- if (ret < 0) {
- fusb302_log(chip, "cannot set src current %s, ret=%d",
- typec_cc_status_name[cc], ret);
- goto done;
- }
-
/* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
switch (cc) {
case TYPEC_CC_RP_DEF:

View File

@ -1,108 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:29:06 +0100
Subject: [PATCH 27/36] usb: typec: fusb302: Extend debugging interface with
driver state dumps
This is useful for debugging.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 78 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 776a949..1a758e3 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -207,6 +207,81 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
}
DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
+static const char * const typec_cc_status_name[];
+static const char * const cc_polarity_name[];
+static const char * const toggling_mode_name[] = {
+ [TOGGLING_MODE_OFF] = "Off",
+ [TOGGLING_MODE_DRP] = "DRP",
+ [TOGGLING_MODE_SNK] = "SNK",
+ [TOGGLING_MODE_SRC] = "SRC",
+};
+static const char * const src_current_status_name[] = {
+ [SRC_CURRENT_DEFAULT] = "Default",
+ [SRC_CURRENT_MEDIUM] = "Medium",
+ [SRC_CURRENT_HIGH] = "High",
+};
+
+#define FUSB_REG(n) { n, #n },
+struct fusb_reg {
+ u8 addr;
+ const char* name;
+} fusb_regs[] = {
+ FUSB_REG(FUSB_REG_DEVICE_ID)
+ FUSB_REG(FUSB_REG_SWITCHES0)
+ FUSB_REG(FUSB_REG_SWITCHES1)
+ FUSB_REG(FUSB_REG_MEASURE)
+ FUSB_REG(FUSB_REG_CONTROL0)
+ FUSB_REG(FUSB_REG_CONTROL1)
+ FUSB_REG(FUSB_REG_CONTROL2)
+ FUSB_REG(FUSB_REG_CONTROL3)
+ FUSB_REG(FUSB_REG_MASK)
+ FUSB_REG(FUSB_REG_POWER)
+ FUSB_REG(FUSB_REG_RESET)
+ FUSB_REG(FUSB_REG_MASKA)
+ FUSB_REG(FUSB_REG_MASKB)
+ FUSB_REG(FUSB_REG_STATUS0A)
+ FUSB_REG(FUSB_REG_STATUS1A)
+ FUSB_REG(FUSB_REG_INTERRUPTA)
+ FUSB_REG(FUSB_REG_INTERRUPTB)
+ FUSB_REG(FUSB_REG_STATUS0)
+ FUSB_REG(FUSB_REG_STATUS1)
+ FUSB_REG(FUSB_REG_INTERRUPT)
+};
+
+static int fusb302_i2c_read(struct fusb302_chip *chip,
+ u8 address, u8 *data);
+
+static int fusb302_debug_regs_show(struct seq_file *s, void *v)
+{
+ struct fusb302_chip *chip = (struct fusb302_chip *)s->private;
+ int i, ret;
+
+ seq_printf(s, "chip->intr_togdone = %d\n", chip->intr_togdone);
+ seq_printf(s, "chip->intr_bc_lvl = %d\n", chip->intr_bc_lvl);
+ seq_printf(s, "chip->intr_comp_chng = %d\n", chip->intr_comp_chng);
+ seq_printf(s, "chip->vconn_on = %d\n", chip->vconn_on);
+ seq_printf(s, "chip->vbus_on = %d\n", chip->vbus_on);
+ seq_printf(s, "chip->charge_on = %d\n", chip->charge_on);
+ seq_printf(s, "chip->vbus_present = %d\n", chip->vbus_present);
+ seq_printf(s, "chip->cc_polarity = %s\n", cc_polarity_name[chip->cc_polarity]);
+ seq_printf(s, "chip->cc1 = %s\n", typec_cc_status_name[chip->cc1]);
+ seq_printf(s, "chip->cc2 = %s\n", typec_cc_status_name[chip->cc2]);
+ seq_printf(s, "chip->toggling_mode = %s\n", toggling_mode_name[chip->toggling_mode]);
+ seq_printf(s, "chip->src_current_status = %s\n", src_current_status_name[chip->src_current_status]);
+
+ seq_printf(s, "\nRegisters:\n");
+ for (i = 0; i < ARRAY_SIZE(fusb_regs); i++) {
+ u8 val = 0;
+
+ ret = fusb302_i2c_read(chip, fusb_regs[i].addr, &val);
+ if (ret >= 0)
+ seq_printf(s, "%s = %02hhx\n", fusb_regs[i].name, val);
+ }
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(fusb302_debug_regs);
+
static void fusb302_debugfs_init(struct fusb302_chip *chip)
{
char name[NAME_MAX];
@@ -216,6 +291,9 @@ static void fusb302_debugfs_init(struct fusb302_chip *chip)
chip->dentry = debugfs_create_dir(name, usb_debug_root);
debugfs_create_file("log", S_IFREG | 0444, chip->dentry, chip,
&fusb302_debug_fops);
+
+ debugfs_create_file("regs", S_IFREG | 0444, chip->dentry, chip,
+ &fusb302_debug_regs_fops);
}
static void fusb302_debugfs_exit(struct fusb302_chip *chip)

View File

@ -1,72 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 17:53:27 +0100
Subject: [PATCH 28/36] usb: typec: fusb302: Retry reading of CC pins status
if activity is detected
This is just for testing, to see if this ever happens. It should
also help when this happens.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 34 ++++++++++++++++++++++++++++++++--
1 file changed, 32 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 1a758e3..7386805 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1317,6 +1317,36 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip,
return ret;
}
+static int fusb302_get_status0_stable(struct fusb302_chip *chip, u8 *status0)
+{
+ int ret, tries = 0;
+ u8 reg;
+
+try_again:
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &reg);
+ if (ret < 0)
+ return ret;
+
+ if (reg & FUSB_REG_STATUS0_ACTIVITY) {
+ fusb302_log(chip, "activity reading CC status");
+ if (++tries == 5) {
+ fusb302_log(chip, "failed to read stable status0 value");
+
+ /*
+ * The best we can do is to return at least something.
+ */
+ *status0 = reg;
+ return 0;
+ }
+
+ usleep_range(50, 100);
+ goto try_again;
+ }
+
+ *status0 = reg;
+ return 0;
+}
+
/* On error returns < 0, otherwise a typec_cc_status value */
static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
enum typec_cc_polarity cc_polarity,
@@ -1344,7 +1374,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
return ret;
usleep_range(50, 100);
- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+ ret = fusb302_get_status0_stable(chip, &status0);
if (ret < 0)
return ret;
@@ -1360,7 +1390,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
return ret;
usleep_range(50, 100);
- ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+ ret = fusb302_get_status0_stable(chip, &status0);
if (ret < 0)
return ret;

View File

@ -1,186 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 17:55:34 +0100
Subject: [PATCH 29/36] usb: typec: fusb302: More useful of logging status on
interrupt
This is just for debugging. It prints more info that's useful to
see how hardware state changes in time.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 121 +++++++++++++++++++++++++++++++++------
1 file changed, 104 insertions(+), 17 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 7386805..70b0e15 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -68,7 +68,7 @@ static const u8 rd_mda_value[] = {
};
#define LOG_BUFFER_ENTRIES 1024
-#define LOG_BUFFER_ENTRY_SIZE 128
+#define LOG_BUFFER_ENTRY_SIZE 256
struct fusb302_chip {
struct device *dev;
@@ -1598,6 +1598,84 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void fusb302_print_state(struct fusb302_chip *chip)
+{
+ u8 ctl0, ctl2, measure, status0, status1a, sw0, mask;
+ int ret;
+
+ ret = fusb302_i2c_read(chip, FUSB_REG_CONTROL0, &ctl0);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_CONTROL2, &ctl2);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_MEASURE, &measure);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_STATUS1A, &status1a);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &sw0);
+ if (ret < 0)
+ return;
+ ret = fusb302_i2c_read(chip, FUSB_REG_MASK, &mask);
+ if (ret < 0)
+ return;
+
+ //FUSB_REG(FUSB_REG_POWER) // power control
+
+ const char* host_cur = "?";
+ switch ((ctl0 >> 2) & 3) {
+ case 0: host_cur = "none"; break;
+ case 1: host_cur = "80uA"; break;
+ case 2: host_cur = "160uA"; break;
+ case 3: host_cur = "330uA"; break;
+ }
+
+ const char* bc_lvl = "?";
+ switch (status0 & 3) {
+ case 0: bc_lvl = "0-200mV"; break;
+ case 1: bc_lvl = "200-660mV"; break;
+ case 2: bc_lvl = "660-1230mV"; break;
+ case 3: bc_lvl = ">1230mV"; break;
+ }
+
+ // status0
+ unsigned vbusok = !!(status0 & BIT(7));
+ unsigned activity = !!(status0 & BIT(6));
+ unsigned comp = !!(status0 & BIT(5));
+ unsigned wake = !!(status0 & BIT(2));
+
+ // measure
+ unsigned mdac = ((measure & 0x3f) + 1) * 42 * (measure & BIT(6) ? 10 : 1);
+
+ // status1a
+ unsigned togss = (status1a >> 3) & 7;
+ const char* togss_s = "?";
+ switch (togss) {
+ case 0: togss_s = "running"; break;
+ case 1: togss_s = "src1"; break;
+ case 2: togss_s = "src2"; break;
+ case 5: togss_s = "snk1"; break;
+ case 6: togss_s = "snk2"; break;
+ case 7: togss_s = "audio"; break;
+ }
+
+ // ctl2 print as is
+
+#define SW(n) (!!(sw0 & BIT(n)))
+
+ fusb302_log(chip, "state: cc(puen=%u%u vconn=%u%u meas=%u%u pdwn=%u%u) "
+ "host_cur=%s mdac=%umV comp=%u bc_lvl=%s vbusok=%u act=%u "
+ "wake=%u togss=%s ctl2=0x%02x mask=0x%02x",
+ SW(6), SW(7), SW(4), SW(5), SW(2), SW(3), SW(0), SW(1),
+ host_cur, mdac, comp, bc_lvl, vbusok, activity,
+ wake, togss_s, ctl2, mask);
+}
+
static void fusb302_irq_work(struct work_struct *work)
{
struct fusb302_chip *chip = container_of(work, struct fusb302_chip,
@@ -1607,6 +1685,7 @@ static void fusb302_irq_work(struct work_struct *work)
u8 interrupta;
u8 interruptb;
u8 status0;
+ u8 mda;
bool vbus_present;
bool comp_result;
bool intr_togdone;
@@ -1632,9 +1711,10 @@ static void fusb302_irq_work(struct work_struct *work)
ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
if (ret < 0)
goto done;
- fusb302_log(chip,
- "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x, status0: 0x%02x",
- interrupt, interrupta, interruptb, status0);
+ fusb302_log(chip, "IRQ: 0x%02x, a: 0x%02x, b: 0x%02x",
+ interrupt, interrupta, interruptb);
+
+ fusb302_print_state(chip);
if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) {
vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
@@ -1646,32 +1726,39 @@ static void fusb302_irq_work(struct work_struct *work)
}
}
- if ((interrupta & FUSB_REG_INTERRUPTA_TOGDONE) && intr_togdone) {
+ if (interrupta & FUSB_REG_INTERRUPTA_TOGDONE) {
fusb302_log(chip, "IRQ: TOGDONE");
- ret = fusb302_handle_togdone(chip);
- if (ret < 0) {
- fusb302_log(chip,
- "handle togdone error, ret=%d", ret);
- goto done;
+ if (intr_togdone) {
+ ret = fusb302_handle_togdone(chip);
+ if (ret < 0) {
+ fusb302_log(chip,
+ "handle togdone error, ret=%d", ret);
+ goto done;
+ }
}
}
- if ((interrupt & FUSB_REG_INTERRUPT_BC_LVL) && intr_bc_lvl) {
+ if (interrupt & FUSB_REG_INTERRUPT_BC_LVL) {
fusb302_log(chip, "IRQ: BC_LVL, handler pending");
/*
* as BC_LVL interrupt can be affected by PD activity,
* apply delay to for the handler to wait for the PD
* signaling to finish.
*/
- mod_delayed_work(chip->wq, &chip->bc_lvl_handler,
- msecs_to_jiffies(T_BC_LVL_DEBOUNCE_DELAY_MS));
+ if (intr_bc_lvl)
+ mod_delayed_work(chip->wq, &chip->bc_lvl_handler,
+ msecs_to_jiffies(T_BC_LVL_DEBOUNCE_DELAY_MS));
}
- if ((interrupt & FUSB_REG_INTERRUPT_COMP_CHNG) && intr_comp_chng) {
+ if (interrupt & FUSB_REG_INTERRUPT_COMP_CHNG) {
+ ret = fusb302_i2c_read(chip, FUSB_REG_MEASURE, &mda);
+ if (ret < 0)
+ goto done;
+
comp_result = !!(status0 & FUSB_REG_STATUS0_COMP);
- fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s",
- comp_result ? "true" : "false");
- if (comp_result) {
+ fusb302_log(chip, "IRQ: COMP_CHNG, cc* %s mdac (%u mV)",
+ comp_result ? ">" : "<", ((mda & 0x3f) + 1) * 42 * (mda & BIT(6) ? 10 : 1));
+ if (comp_result && intr_comp_chng) {
/* cc level > Rd_threshold, detach */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;

View File

@ -1,39 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 17:57:06 +0100
Subject: [PATCH 30/36] usb: typec: fusb302: Update VBUS state even if VBUS
interrupt is not triggered
This seems to improve robustness.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 70b0e15..1d5affa 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1716,14 +1716,16 @@ static void fusb302_irq_work(struct work_struct *work)
fusb302_print_state(chip);
- if (interrupt & FUSB_REG_INTERRUPT_VBUSOK) {
- vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
+ vbus_present = !!(status0 & FUSB_REG_STATUS0_VBUSOK);
+ if (interrupt & FUSB_REG_INTERRUPT_VBUSOK)
fusb302_log(chip, "IRQ: VBUS_OK, vbus=%s",
vbus_present ? "On" : "Off");
- if (vbus_present != chip->vbus_present) {
- chip->vbus_present = vbus_present;
- tcpm_vbus_change(chip->tcpm_port);
- }
+ if (vbus_present != chip->vbus_present) {
+ chip->vbus_present = vbus_present;
+ if (!(interrupt & FUSB_REG_INTERRUPT_VBUSOK))
+ fusb302_log(chip, "IRQ: VBUS changed without interrupt, vbus=%s",
+ vbus_present ? "On" : "Off");
+ tcpm_vbus_change(chip->tcpm_port);
}
if (interrupta & FUSB_REG_INTERRUPTA_TOGDONE) {

View File

@ -1,160 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 17:58:05 +0100
Subject: [PATCH 31/36] usb: typec: fusb302: Make tcpm/fusb302 logs less
polluted by PD comm stuff
This adds clarity to debugging.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 18 ++++++++++--------
drivers/usb/typec/tcpm/tcpm.c | 18 ++++++++++--------
2 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 1d5affa..ae3b930 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -787,7 +787,7 @@ static int tcpm_get_cc(struct tcpc_dev *dev, enum typec_cc_status *cc1,
mutex_lock(&chip->lock);
*cc1 = chip->cc1;
*cc2 = chip->cc2;
- fusb302_log(chip, "cc1=%s, cc2=%s", typec_cc_status_name[*cc1],
+ fusb302_log(chip, "tcpm_get_cc => cc1=%s, cc2=%s (cached)", typec_cc_status_name[*cc1],
typec_cc_status_name[*cc2]);
mutex_unlock(&chip->lock);
@@ -1073,8 +1073,8 @@ static int fusb302_pd_send_message(struct fusb302_chip *chip,
ret = fusb302_i2c_block_write(chip, FUSB_REG_FIFOS, pos, buf);
if (ret < 0)
return ret;
- fusb302_log(chip, "sending PD message header: %x", msg->header);
- fusb302_log(chip, "sending PD message len: %d", len);
+ //fusb302_log(chip, "sending PD message header: %x", msg->header);
+ //fusb302_log(chip, "sending PD message len: %d", len);
return ret;
}
@@ -1365,8 +1365,10 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
if (ret < 0)
return ret;
+ //XXX resolve activity conflicts while measuring
+
fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
- fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
+ //fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
/* Step 2: Set compararator volt to differentiate between Open and Rd */
ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
@@ -1378,7 +1380,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
if (ret < 0)
return ret;
- fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
+ //fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
if (status0 & FUSB_REG_STATUS0_COMP) {
*cc = TYPEC_CC_OPEN;
return 0;
@@ -1394,7 +1396,7 @@ static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
if (ret < 0)
return ret;
- fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
+ //fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
if (status0 & FUSB_REG_STATUS0_COMP)
*cc = TYPEC_CC_RD;
else
@@ -1559,8 +1561,8 @@ static int fusb302_pd_read_message(struct fusb302_chip *chip,
ret = fusb302_i2c_block_read(chip, FUSB_REG_FIFOS, 4, crc);
if (ret < 0)
return ret;
- fusb302_log(chip, "PD message header: %x", msg->header);
- fusb302_log(chip, "PD message len: %d", len);
+ //fusb302_log(chip, "PD message header: %x", msg->header);
+ //fusb302_log(chip, "PD message len: %d", len);
/*
* Check if we've read off a GoodCRC message. If so then indicate to
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 59d4fa2..0451441 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -776,7 +776,7 @@ static void tcpm_debugfs_exit(const struct tcpm_port *port) { }
static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc)
{
- tcpm_log(port, "cc:=%d", cc);
+ //tcpm_log(port, "cc:=%d", cc);
port->cc_req = cc;
port->tcpc->set_cc(port->tcpc, cc);
}
@@ -869,10 +869,12 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
unsigned long timeout;
int ret;
+ /*
if (msg)
tcpm_log(port, "PD TX, header: %#x", le16_to_cpu(msg->header));
else
tcpm_log(port, "PD TX, type: %#x", type);
+ */
reinit_completion(&port->tx_complete);
ret = port->tcpc->pd_transmit(port->tcpc, type, msg, port->negotiated_rev);
@@ -918,7 +920,7 @@ static int tcpm_pd_transmit(struct tcpm_port *port,
void tcpm_pd_transmit_complete(struct tcpm_port *port,
enum tcpm_transmit_status status)
{
- tcpm_log(port, "PD TX complete, status: %u", status);
+ //tcpm_log(port, "PD TX complete, status: %u", status);
port->tx_status = status;
complete(&port->tx_complete);
}
@@ -951,7 +953,7 @@ static int tcpm_set_polarity(struct tcpm_port *port,
{
int ret;
- tcpm_log(port, "polarity %d", polarity);
+ //tcpm_log(port, "polarity %d", polarity);
ret = port->tcpc->set_polarity(port->tcpc, polarity);
if (ret < 0)
@@ -966,7 +968,7 @@ static int tcpm_set_vconn(struct tcpm_port *port, bool enable)
{
int ret;
- tcpm_log(port, "vconn:=%d", enable);
+ //tcpm_log(port, "vconn:=%d", enable);
ret = port->tcpc->set_vconn(port->tcpc, enable);
if (!ret) {
@@ -2871,8 +2873,8 @@ static void tcpm_pd_rx_handler(struct kthread_work *work)
mutex_lock(&port->lock);
- tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
- port->attached);
+ //tcpm_log(port, "PD RX, header: %#x [%d]", le16_to_cpu(msg->header),
+ //port->attached);
if (port->attached) {
enum pd_ctrl_msg_type type = pd_header_type_le(msg->header);
@@ -5041,7 +5043,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1,
static void _tcpm_pd_vbus_on(struct tcpm_port *port)
{
- tcpm_log_force(port, "VBUS on");
+ tcpm_log_force(port, "VBUS event received: on");
port->vbus_present = true;
/*
* When vbus_present is true i.e. Voltage at VBUS is greater than VSAFE5V implicitly
@@ -5131,7 +5133,7 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port)
static void _tcpm_pd_vbus_off(struct tcpm_port *port)
{
- tcpm_log_force(port, "VBUS off");
+ tcpm_log_force(port, "VBUS event received: off");
port->vbus_present = false;
port->vbus_never_low = false;
switch (port->state) {

View File

@ -1,34 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 14 Nov 2021 01:14:25 +0100
Subject: [PATCH 32/36] usb: typec: fusb302: Add OF extcon support
It's possible to create a dependency cycle between fusb302 and
other drivers via extcon device, so we retrieve the device on
demand after probe and not during probe.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index ae3b930..0c5dd00 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -518,6 +518,16 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
int current_limit = 0;
unsigned long timeout;
+ /*
+ * To avoid cycles in OF dependencies, we get extcon when necessary
+ * outside of probe function.
+ */
+ if (of_property_read_bool(chip->dev->of_node, "extcon") && !chip->extcon) {
+ chip->extcon = extcon_get_edev_by_phandle(chip->dev, 0);
+ if (IS_ERR(chip->extcon))
+ chip->extcon = NULL;
+ }
+
if (!chip->extcon)
return 0;

View File

@ -1,45 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sat, 20 Nov 2021 14:33:58 +0100
Subject: [PATCH 33/36] usb: typec: fusb302: Fix register definitions
MEASURE_VBUS bit is at position 6. MDAC bits are also wrong.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302_reg.h | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/typec/tcpm/fusb302_reg.h b/drivers/usb/typec/tcpm/fusb302_reg.h
index edc0e4b..f37d226 100644
--- a/drivers/usb/typec/tcpm/fusb302_reg.h
+++ b/drivers/usb/typec/tcpm/fusb302_reg.h
@@ -27,14 +27,13 @@
#define FUSB_REG_SWITCHES1_TXCC2_EN BIT(1)
#define FUSB_REG_SWITCHES1_TXCC1_EN BIT(0)
#define FUSB_REG_MEASURE 0x04
-#define FUSB_REG_MEASURE_MDAC5 BIT(7)
-#define FUSB_REG_MEASURE_MDAC4 BIT(6)
-#define FUSB_REG_MEASURE_MDAC3 BIT(5)
-#define FUSB_REG_MEASURE_MDAC2 BIT(4)
-#define FUSB_REG_MEASURE_MDAC1 BIT(3)
-#define FUSB_REG_MEASURE_MDAC0 BIT(2)
-#define FUSB_REG_MEASURE_VBUS BIT(1)
-#define FUSB_REG_MEASURE_XXXX5 BIT(0)
+#define FUSB_REG_MEASURE_VBUS BIT(6)
+#define FUSB_REG_MEASURE_MDAC5 BIT(5)
+#define FUSB_REG_MEASURE_MDAC4 BIT(4)
+#define FUSB_REG_MEASURE_MDAC3 BIT(3)
+#define FUSB_REG_MEASURE_MDAC2 BIT(2)
+#define FUSB_REG_MEASURE_MDAC1 BIT(1)
+#define FUSB_REG_MEASURE_MDAC0 BIT(0)
#define FUSB_REG_CONTROL0 0x06
#define FUSB_REG_CONTROL0_TX_FLUSH BIT(6)
#define FUSB_REG_CONTROL0_INT_MASK BIT(5)
@@ -105,7 +104,6 @@
#define FUSB_REG_STATUS0A_RX_SOFT_RESET BIT(1)
#define FUSB_REG_STATUS0A_RX_HARD_RESET BIT(0)
#define FUSB_REG_STATUS1A 0x3D
-#define FUSB_REG_STATUS1A_TOGSS BIT(3)
#define FUSB_REG_STATUS1A_TOGSS_RUNNING 0x0
#define FUSB_REG_STATUS1A_TOGSS_SRC1 0x1
#define FUSB_REG_STATUS1A_TOGSS_SRC2 0x2

View File

@ -1,37 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sat, 20 Nov 2021 14:35:10 +0100
Subject: [PATCH 34/36] usb: typec: fusb302: Clear interrupts before we start
toggling
This is recommended by the datasheet.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/tcpm/fusb302.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 0c5dd00..011dce5 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -586,6 +586,7 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
enum toggling_mode mode)
{
int ret = 0;
+ u8 reg;
/* first disable toggling */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_CONTROL2,
@@ -644,6 +645,12 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
} else {
/* Datasheet says vconn MUST be off when toggling */
WARN(chip->vconn_on, "Vconn is on during toggle start");
+
+ /* clear interrupts */
+ ret = fusb302_i2c_read(chip, FUSB_REG_INTERRUPT, &reg);
+ if (ret < 0)
+ return ret;
+
/* unmask TOGDONE interrupt */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
FUSB_REG_MASKA_TOGDONE);

View File

@ -1,388 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:24:40 +0100
Subject: [PATCH 35/36] usb: typec: typec-extcon: Add typec -> extcon bridge
driver
This bridge connects standard Type C port interfaces for controling
muxes, switches and usb roles to muxes, switches and usb role
drivers controlled via extcon interface.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/usb/typec/Kconfig | 7 +
drivers/usb/typec/Makefile | 1 +
drivers/usb/typec/typec-extcon.c | 337 +++++++++++++++++++++++++++++++++++++++
3 files changed, 345 insertions(+)
create mode 100644 drivers/usb/typec/typec-extcon.c
diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig
index ab480f3..01ecc5e 100644
--- a/drivers/usb/typec/Kconfig
+++ b/drivers/usb/typec/Kconfig
@@ -88,6 +88,13 @@ config TYPEC_QCOM_PMIC
It will also enable the VBUS output to connected devices when a
DFP connection is made.
+config TYPEC_EXTCON
+ tristate "Type-C switch/mux -> extcon interface bridge driver"
+ depends on USB_ROLE_SWITCH
+ help
+ Say Y or M here if your system needs bridging between typec class
+ and extcon interfaces.
+
source "drivers/usb/typec/mux/Kconfig"
source "drivers/usb/typec/altmodes/Kconfig"
diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile
index a0adb89..d9d8293 100644
--- a/drivers/usb/typec/Makefile
+++ b/drivers/usb/typec/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_TYPEC_TPS6598X) += tipd/
obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o
obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom-pmic-typec.o
obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o
+obj-$(CONFIG_TYPEC_EXTCON) += typec-extcon.o
obj-$(CONFIG_TYPEC) += mux/
diff --git a/drivers/usb/typec/typec-extcon.c b/drivers/usb/typec/typec-extcon.c
new file mode 100644
index 00000000..143ff24
--- /dev/null
+++ b/drivers/usb/typec/typec-extcon.c
@@ -0,0 +1,337 @@
+/*
+ * typec -> extcon bridge
+ * Copyright (c) 2021 Ondřej Jirman <megi@xff.cz>
+ *
+ * This driver bridges standard type-c interfaces to drivers that
+ * expect extcon interface.
+ */
+
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/role.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/extcon-provider.h>
+
+struct typec_extcon {
+ struct device *dev;
+
+ /* consumers */
+ struct usb_role_switch *role_sw;
+ struct typec_switch *sw;
+ struct typec_mux *mux;
+
+ /* providers */
+ struct extcon_dev *extcon;
+ struct notifier_block extcon_nb;
+
+ /* cached state from typec controller */
+ enum usb_role role;
+ enum typec_orientation orientation;
+ struct typec_altmode alt;
+ unsigned long mode;
+ bool has_alt;
+ struct mutex lock;
+};
+
+static const unsigned int typec_extcon_cable[] = {
+ EXTCON_DISP_DP,
+
+ EXTCON_USB,
+ EXTCON_USB_HOST,
+
+ EXTCON_CHG_USB_SDP,
+ EXTCON_CHG_USB_CDP,
+ EXTCON_CHG_USB_DCP,
+ EXTCON_CHG_USB_ACA,
+
+ EXTCON_NONE,
+};
+
+static void typec_extcon_set_cable(struct typec_extcon *tce, int id, bool on,
+ union extcon_property_value prop_ss,
+ union extcon_property_value prop_or)
+{
+ union extcon_property_value cur_ss, cur_or;
+ bool prop_diff = false;
+ int ret;
+
+ ret = extcon_get_property(tce->extcon, id,
+ EXTCON_PROP_USB_SS, &cur_ss);
+ if (ret || cur_ss.intval != prop_ss.intval)
+ prop_diff = true;
+
+ ret = extcon_get_property(tce->extcon, id,
+ EXTCON_PROP_USB_TYPEC_POLARITY, &cur_or);
+ if (ret || cur_or.intval != prop_or.intval)
+ prop_diff = true;
+
+ if (!on && extcon_get_state(tce->extcon, id)) {
+ extcon_set_state_sync(tce->extcon, id, false);
+ } else if (on && (!extcon_get_state(tce->extcon, id) || prop_diff)) {
+ extcon_set_state(tce->extcon, id, true);
+ extcon_set_property(tce->extcon, id,
+ EXTCON_PROP_USB_SS, prop_ss);
+ extcon_set_property(tce->extcon, id,
+ EXTCON_PROP_USB_TYPEC_POLARITY, prop_or);
+ extcon_sync(tce->extcon, id);
+ }
+}
+
+static int typec_extcon_sync_extcon(struct typec_extcon *tce)
+{
+ union extcon_property_value prop_ss, prop_or;
+ bool has_dp = false;
+
+ mutex_lock(&tce->lock);
+
+ /* connector is disconnected */
+ if (tce->orientation == TYPEC_ORIENTATION_NONE) {
+ typec_extcon_set_cable(tce, EXTCON_USB, false, prop_ss, prop_or);
+ typec_extcon_set_cable(tce, EXTCON_USB_HOST, false, prop_ss, prop_or);
+ typec_extcon_set_cable(tce, EXTCON_DISP_DP, false, prop_ss, prop_or);
+
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_SDP, false);
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_DCP, false);
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_CDP, false);
+ extcon_set_state_sync(tce->extcon, EXTCON_CHG_USB_ACA, false);
+
+ goto out_unlock;
+ }
+
+ prop_or.intval = tce->orientation == TYPEC_ORIENTATION_NORMAL ? 0 : 1;
+ prop_ss.intval = 0;
+
+ if (tce->has_alt && tce->alt.svid == USB_TYPEC_DP_SID) {
+ switch (tce->mode) {
+ case TYPEC_STATE_SAFE:
+ break;
+ case TYPEC_DP_STATE_C:
+ case TYPEC_DP_STATE_E:
+ has_dp = true;
+ break;
+ case TYPEC_DP_STATE_D:
+ has_dp = true;
+ fallthrough;
+ case TYPEC_STATE_USB:
+ prop_ss.intval = 1;
+ break;
+ default:
+ dev_err(tce->dev, "unhandled mux mode=%lu\n", tce->mode);
+ break;
+ }
+ }
+
+ typec_extcon_set_cable(tce, EXTCON_USB,
+ tce->role == USB_ROLE_DEVICE, prop_ss, prop_or);
+ typec_extcon_set_cable(tce, EXTCON_USB_HOST,
+ tce->role == USB_ROLE_HOST, prop_ss, prop_or);
+
+ typec_extcon_set_cable(tce, EXTCON_DISP_DP, has_dp, prop_ss, prop_or);
+
+out_unlock:
+ mutex_unlock(&tce->lock);
+ return 0;
+}
+
+static int typec_extcon_sw_set(struct typec_switch *sw,
+ enum typec_orientation orientation)
+{
+ struct typec_extcon *tce = typec_switch_get_drvdata(sw);
+
+ dev_dbg(tce->dev, "SW SET: orientation=%d\n", orientation);
+
+ mutex_lock(&tce->lock);
+ tce->orientation = orientation;
+ mutex_unlock(&tce->lock);
+
+ typec_extcon_sync_extcon(tce);
+
+ return 0;
+}
+
+static int typec_extcon_mux_set(struct typec_mux *mux,
+ struct typec_mux_state *state)
+{
+ struct typec_extcon *tce = typec_mux_get_drvdata(mux);
+ struct typec_altmode *alt = state->alt;
+
+ dev_dbg(tce->dev, "MUX SET: state->mode=%lu\n", state->mode);
+ if (alt)
+ dev_dbg(tce->dev, " ...alt: svid=%04hx mode=%d vdo=%08x active=%u\n",
+ alt->svid, alt->mode, alt->vdo, alt->active);
+
+ mutex_lock(&tce->lock);
+ tce->mode = state->mode;
+ tce->has_alt = alt != NULL;
+ if (alt)
+ tce->alt = *alt;
+ mutex_unlock(&tce->lock);
+
+ typec_extcon_sync_extcon(tce);
+
+ return 0;
+}
+
+static int typec_extcon_usb_set_role(struct usb_role_switch *sw,
+ enum usb_role role)
+{
+ struct typec_extcon *tce = usb_role_switch_get_drvdata(sw);
+
+ dev_dbg(tce->dev, "ROLE SET: role=%d\n", role);
+
+ mutex_lock(&tce->lock);
+ tce->role = role;
+ mutex_unlock(&tce->lock);
+
+ typec_extcon_sync_extcon(tce);
+
+ return 0;
+}
+
+static int typec_extcon_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct typec_extcon *tce = container_of(nb, struct typec_extcon, extcon_nb);
+
+ bool sdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_SDP);
+ bool cdp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_CDP);
+ bool dcp = extcon_get_state(tce->extcon, EXTCON_CHG_USB_DCP);
+ bool usb = extcon_get_state(tce->extcon, EXTCON_USB);
+ bool usb_host = extcon_get_state(tce->extcon, EXTCON_USB_HOST);
+ bool dp = extcon_get_state(tce->extcon, EXTCON_DISP_DP);
+
+ dev_info(tce->dev, "extcon changed sdp=%d cdp=%d dcp=%d usb=%d usb_host=%d dp=%d\n",
+ sdp, cdp, dcp, usb, usb_host, dp);
+
+ return NOTIFY_OK;
+}
+
+static int typec_extcon_probe(struct platform_device *pdev)
+{
+ struct typec_switch_desc sw_desc = { };
+ struct typec_mux_desc mux_desc = { };
+ struct usb_role_switch_desc role_desc = { };
+ struct device *dev = &pdev->dev;
+ struct typec_extcon *tce;
+ int ret = 0;
+
+ tce = devm_kzalloc(dev, sizeof(*tce), GFP_KERNEL);
+ if (!tce)
+ return -ENOMEM;
+
+ tce->dev = &pdev->dev;
+ mutex_init(&tce->lock);
+ tce->mode = TYPEC_STATE_SAFE;
+
+ sw_desc.drvdata = tce;
+ sw_desc.fwnode = dev->fwnode;
+ sw_desc.set = typec_extcon_sw_set;
+
+ tce->sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(tce->sw))
+ return dev_err_probe(dev, PTR_ERR(tce->sw),
+ "Error registering typec switch\n");
+
+ mux_desc.drvdata = tce;
+ mux_desc.fwnode = dev->fwnode;
+ mux_desc.set = typec_extcon_mux_set;
+
+ tce->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(tce->mux)) {
+ ret = dev_err_probe(dev, PTR_ERR(tce->mux),
+ "Error registering typec mux\n");
+ goto err_sw;
+ }
+
+ role_desc.driver_data = tce;
+ role_desc.fwnode = dev->fwnode;
+ role_desc.name = fwnode_get_name(dev->fwnode);
+ role_desc.set = typec_extcon_usb_set_role;
+
+ tce->role_sw = usb_role_switch_register(dev, &role_desc);
+ if (IS_ERR(tce->role_sw)) {
+ ret = dev_err_probe(dev, PTR_ERR(tce->role_sw),
+ "Error registering USB role switch\n");
+ goto err_mux;
+ }
+
+ tce->extcon = devm_extcon_dev_allocate(dev, typec_extcon_cable);
+ if (IS_ERR(tce->extcon)) {
+ ret = PTR_ERR(tce->extcon);
+ goto err_role;
+ }
+
+ ret = devm_extcon_dev_register(dev, tce->extcon);
+ if (ret) {
+ ret = dev_err_probe(dev, ret, "failed to register extcon device\n");
+ goto err_role;
+ }
+
+ extcon_set_property_capability(tce->extcon, EXTCON_USB,
+ EXTCON_PROP_USB_SS);
+ extcon_set_property_capability(tce->extcon, EXTCON_USB,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+ extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_SS);
+ extcon_set_property_capability(tce->extcon, EXTCON_USB_HOST,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+ extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
+ EXTCON_PROP_USB_SS);
+ extcon_set_property_capability(tce->extcon, EXTCON_DISP_DP,
+ EXTCON_PROP_USB_TYPEC_POLARITY);
+
+ tce->extcon_nb.notifier_call = typec_extcon_notifier;
+ ret = devm_extcon_register_notifier_all(dev, tce->extcon, &tce->extcon_nb);
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to register extcon notifier\n");
+ goto err_role;
+ }
+
+ return 0;
+
+err_role:
+ usb_role_switch_unregister(tce->role_sw);
+err_mux:
+ typec_mux_unregister(tce->mux);
+err_sw:
+ typec_switch_unregister(tce->sw);
+ return ret;
+}
+
+static int typec_extcon_remove(struct platform_device *pdev)
+{
+ struct typec_extcon *tce = platform_get_drvdata(pdev);
+
+ usb_role_switch_unregister(tce->role_sw);
+ typec_mux_unregister(tce->mux);
+ typec_switch_unregister(tce->sw);
+
+ return 0;
+}
+
+static struct of_device_id typec_extcon_of_match_table[] = {
+ { .compatible = "linux,typec-extcon-bridge" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, typec_extcon_of_match_table);
+
+static struct platform_driver typec_extcon_driver = {
+ .driver = {
+ .name = "typec-extcon",
+ .of_match_table = typec_extcon_of_match_table,
+ },
+ .probe = typec_extcon_probe,
+ .remove = typec_extcon_remove,
+};
+
+module_platform_driver(typec_extcon_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ondrej Jirman <megous@megous.com>");
+MODULE_DESCRIPTION("typec -> extcon bridge driver");

View File

@ -1,64 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 17:32:18 +0100
Subject: [PATCH 36/36] phy: rockchip-typec: Make sure the plug orientation is
respected
RK3399 TRM says about bit 8:
typec_conn_dir_sel: TypeC connect direction select
- 0: select typec_conn_dir (bit0 of this register) to TypeC PHY
- 1: select TCPC ouput typec_con_dir to TypeC PHY (default value)
This means that by default, typec_conn_dir bit is not respected.
Fix setting of typec_conn_dir by setting typec_conn_dir to 0 first.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/phy/rockchip/phy-rockchip-typec.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index d2bbdc9..fa10ee9 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -350,6 +350,7 @@ struct usb3phy_reg {
* struct rockchip_usb3phy_port_cfg - usb3-phy port configuration.
* @reg: the base address for usb3-phy config.
* @typec_conn_dir: the register of type-c connector direction.
+ * @typec_conn_dir_sel: the register of type-c connector direction source.
* @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
* @external_psm: the register of type-c phy external psm clock.
* @pipe_status: the register of type-c phy pipe status.
@@ -360,6 +361,7 @@ struct usb3phy_reg {
struct rockchip_usb3phy_port_cfg {
unsigned int reg;
struct usb3phy_reg typec_conn_dir;
+ struct usb3phy_reg typec_conn_dir_sel;
struct usb3phy_reg usb3tousb2_en;
struct usb3phy_reg external_psm;
struct usb3phy_reg pipe_status;
@@ -434,6 +436,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
{
.reg = 0xff7c0000,
.typec_conn_dir = { 0xe580, 0, 16 },
+ .typec_conn_dir_sel = { 0xe580, 8, 16+8 },
.usb3tousb2_en = { 0xe580, 3, 19 },
.external_psm = { 0xe588, 14, 30 },
.pipe_status = { 0xe5c0, 0, 0 },
@@ -444,6 +447,7 @@ static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
{
.reg = 0xff800000,
.typec_conn_dir = { 0xe58c, 0, 16 },
+ .typec_conn_dir_sel = { 0xe58c, 8, 16+8 },
.usb3tousb2_en = { 0xe58c, 3, 19 },
.external_psm = { 0xe594, 14, 30 },
.pipe_status = { 0xe5c0, 16, 16 },
@@ -739,6 +743,7 @@ static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
reset_control_deassert(tcphy->tcphy_rst);
+ property_enable(tcphy, &cfg->typec_conn_dir_sel, 0);
property_enable(tcphy, &cfg->typec_conn_dir, tcphy->flip);
tcphy_dp_aux_set_flip(tcphy);

View File

@ -1,56 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 22 Oct 2021 18:10:18 +0200
Subject: [PATCH 20/36] media: i2c: imx258: Add support for powerdown gpio
On some boards powerdown signal needs to be deasserted for this
sensor to be enabled.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/imx258.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index c249507..be5adcc 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -612,6 +612,8 @@ struct imx258 {
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ struct gpio_desc *pwdn_gpio;
+
/* Current mode */
const struct imx258_mode *cur_mode;
@@ -1010,6 +1012,8 @@ static int imx258_power_on(struct device *dev)
struct imx258 *imx258 = to_imx258(sd);
int ret;
+ gpiod_set_value_cansleep(imx258->pwdn_gpio, 0);
+
ret = clk_prepare_enable(imx258->clk);
if (ret)
dev_err(dev, "failed to enable clock\n");
@@ -1024,6 +1028,8 @@ static int imx258_power_off(struct device *dev)
clk_disable_unprepare(imx258->clk);
+ gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
+
return 0;
}
@@ -1284,6 +1290,12 @@ static int imx258_probe(struct i2c_client *client)
if (ret || val != 180)
return -EINVAL;
+ /* request optional power down pin */
+ imx258->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(imx258->pwdn_gpio))
+ return PTR_ERR(imx258->pwdn_gpio);
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);

View File

@ -1,41 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 22 Oct 2021 18:11:26 +0200
Subject: [PATCH 21/36] media: i2c: imx258: Don't be too strict about clock
rate
On Pinephone Pro, we are not able to set 19.2MHz precisely.
Allow some slack in clock rate.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/imx258.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index be5adcc..e64fadc 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -79,7 +79,9 @@
#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
/* Input clock frequency in Hz */
+#define IMX258_INPUT_CLOCK_FREQ_MIN 19000000
#define IMX258_INPUT_CLOCK_FREQ 19200000
+#define IMX258_INPUT_CLOCK_FREQ_MAX 19400000
struct imx258_reg {
u16 address;
@@ -1277,8 +1279,11 @@ static int imx258_probe(struct i2c_client *client)
} else {
val = clk_get_rate(imx258->clk);
}
- if (val != IMX258_INPUT_CLOCK_FREQ) {
- dev_err(&client->dev, "input clock frequency not supported\n");
+
+ if (val < IMX258_INPUT_CLOCK_FREQ_MIN
+ || val > IMX258_INPUT_CLOCK_FREQ_MAX) {
+ dev_err(&client->dev, "input clock frequency %u not supported\n",
+ val);
return -EINVAL;
}

View File

@ -1,57 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 22 Oct 2021 21:44:13 +0200
Subject: [PATCH 22/36] media: i2c: imx258: Add support for reset gpio
It was documented in DT, but not implemented.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/imx258.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index e64fadc..ec6e919 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -615,6 +615,7 @@ struct imx258 {
struct v4l2_ctrl *exposure;
struct gpio_desc *pwdn_gpio;
+ struct gpio_desc *reset_gpio;
/* Current mode */
const struct imx258_mode *cur_mode;
@@ -1020,7 +1021,11 @@ static int imx258_power_on(struct device *dev)
if (ret)
dev_err(dev, "failed to enable clock\n");
- return ret;
+ gpiod_set_value_cansleep(imx258->reset_gpio, 0);
+
+ usleep_range(400, 500);
+
+ return 0;
}
static int imx258_power_off(struct device *dev)
@@ -1030,6 +1035,7 @@ static int imx258_power_off(struct device *dev)
clk_disable_unprepare(imx258->clk);
+ gpiod_set_value_cansleep(imx258->reset_gpio, 1);
gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
return 0;
@@ -1301,6 +1307,12 @@ static int imx258_probe(struct i2c_client *client)
if (IS_ERR(imx258->pwdn_gpio))
return PTR_ERR(imx258->pwdn_gpio);
+ /* request optional reset pin */
+ imx258->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(imx258->reset_gpio))
+ return PTR_ERR(imx258->reset_gpio);
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);

View File

@ -1,100 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 22 Oct 2021 21:44:30 +0200
Subject: [PATCH 23/36] media: i2c: imx258: Add support for power supplies
They were documented in DT, but not implemented.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/imx258.c | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index ec6e919..2570b51 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -602,6 +602,15 @@ static const struct imx258_mode supported_modes[] = {
},
};
+/* regulator supplies */
+static const char * const imx258_supply_names[] = {
+ "vana", /* Analog (2.8V) supply */
+ "vdig", /* Digital Core (1.5V) supply */
+ "vif", /* Digital I/O (1.8V) supply */
+};
+
+#define IMX258_SUPPLY_COUNT ARRAY_SIZE(imx258_supply_names)
+
struct imx258 {
struct v4l2_subdev sd;
struct media_pad pad;
@@ -616,6 +625,7 @@ struct imx258 {
struct gpio_desc *pwdn_gpio;
struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[IMX258_SUPPLY_COUNT];
/* Current mode */
const struct imx258_mode *cur_mode;
@@ -1015,11 +1025,26 @@ static int imx258_power_on(struct device *dev)
struct imx258 *imx258 = to_imx258(sd);
int ret;
+ ret = regulator_bulk_enable(IMX258_SUPPLY_COUNT, imx258->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable regulators\n");
+ return ret;
+ }
+
+ mdelay(20);
+
gpiod_set_value_cansleep(imx258->pwdn_gpio, 0);
+ mdelay(5);
+
ret = clk_prepare_enable(imx258->clk);
- if (ret)
+ if (ret) {
dev_err(dev, "failed to enable clock\n");
+ regulator_bulk_disable(IMX258_SUPPLY_COUNT, imx258->supplies);
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
gpiod_set_value_cansleep(imx258->reset_gpio, 0);
@@ -1038,6 +1063,8 @@ static int imx258_power_off(struct device *dev)
gpiod_set_value_cansleep(imx258->reset_gpio, 1);
gpiod_set_value_cansleep(imx258->pwdn_gpio, 1);
+ regulator_bulk_disable(IMX258_SUPPLY_COUNT, imx258->supplies);
+
return 0;
}
@@ -1266,7 +1293,7 @@ static void imx258_free_controls(struct imx258 *imx258)
static int imx258_probe(struct i2c_client *client)
{
struct imx258 *imx258;
- int ret;
+ int ret, i;
u32 val = 0;
imx258 = devm_kzalloc(&client->dev, sizeof(*imx258), GFP_KERNEL);
@@ -1301,6 +1328,14 @@ static int imx258_probe(struct i2c_client *client)
if (ret || val != 180)
return -EINVAL;
+ for (i = 0; i < IMX258_SUPPLY_COUNT; i++)
+ imx258->supplies[i].supply = imx258_supply_names[i];
+ ret = devm_regulator_bulk_get(&client->dev,
+ IMX258_SUPPLY_COUNT,
+ imx258->supplies);
+ if (ret)
+ return dev_err_probe(&client->dev, ret, "Failed to get supplies\n");
+
/* request optional power down pin */
imx258->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
GPIOD_OUT_HIGH);

View File

@ -1,52 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 24 Jan 2020 18:25:12 +0100
Subject: [PATCH 091/194] media: ov5640: Add more framerates to the driver
(some of them even work!)
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/ov5640.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index ddbd713..624a3c0 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -112,7 +112,11 @@ enum ov5640_mode_id {
};
enum ov5640_frame_rate {
- OV5640_15_FPS = 0,
+ OV5640_2_FPS = 0,
+ OV5640_3_FPS,
+ OV5640_5_FPS,
+ OV5640_7_FPS,
+ OV5640_15_FPS,
OV5640_30_FPS,
OV5640_60_FPS,
OV5640_NUM_FRAMERATES,
@@ -156,6 +160,10 @@ MODULE_PARM_DESC(virtual_channel,
"MIPI CSI-2 virtual channel (0..3), default 0");
static const int ov5640_framerates[] = {
+ [OV5640_2_FPS] = 2,
+ [OV5640_3_FPS] = 3,
+ [OV5640_5_FPS] = 5,
+ [OV5640_7_FPS] = 7,
[OV5640_15_FPS] = 15,
[OV5640_30_FPS] = 30,
[OV5640_60_FPS] = 60,
@@ -2193,11 +2201,11 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
u32 width, u32 height)
{
const struct ov5640_mode_info *mode;
- enum ov5640_frame_rate rate = OV5640_15_FPS;
+ enum ov5640_frame_rate rate = OV5640_2_FPS;
int minfps, maxfps, best_fps, fps;
int i;
- minfps = ov5640_framerates[OV5640_15_FPS];
+ minfps = ov5640_framerates[OV5640_2_FPS];
maxfps = ov5640_framerates[OV5640_60_FPS];
if (fi->numerator == 0) {

View File

@ -1,47 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Fri, 24 Jan 2020 18:25:59 +0100
Subject: [PATCH 158/465] media: ov5640: [Experiment] Try to disable
denoising/sharpening
Not sure how this works exactly. More tests are needed.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/ov5640.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 624a3c0..2f6f97e 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -1772,6 +1772,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
unsigned long rate;
int ret;
+ u8 tmp;
dn_mode = mode->dn_mode;
orig_dn_mode = orig_mode->dn_mode;
@@ -1844,6 +1845,22 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
if (ret < 0)
return ret;
+ ret = ov5640_read_reg(sensor, 0x5308, &tmp);
+ if (ret)
+ return ret;
+
+ ret = ov5640_write_reg(sensor, 0x5308, tmp | 0x10 | 0x40);
+ if (ret)
+ return ret;
+
+ ret = ov5640_write_reg(sensor, 0x5306, 0);
+ if (ret)
+ return ret;
+
+ ret = ov5640_write_reg(sensor, 0x5302, 0);
+ if (ret)
+ return ret;
+
sensor->pending_mode_change = false;
sensor->last_mode = mode;

View File

@ -1,25 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 26 Jan 2020 00:19:40 +0100
Subject: [PATCH 093/194] media: ov5640: Sleep after poweroff to ensure next
poweron is not too early
It's easy to use v4l2 userspace api in such a way that user can trigger
a brownout on the sensor instead of a proper powerdown and powerup.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/ov5640.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 2f6f97e..8a53c0c 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -1971,6 +1971,7 @@ static void ov5640_set_power_off(struct ov5640_dev *sensor)
ov5640_power(sensor, false);
regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies);
clk_disable_unprepare(sensor->xclk);
+ msleep(100);
}
static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)

View File

@ -1,86 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 26 Jan 2020 00:28:10 +0100
Subject: [PATCH 094/194] media: ov5640: Don't powerup the sensor during
driver probe
It causes autofocus clicking during boot on some devices, and
it's enough to do it when turning on the sensor power by media
pipeline via s_power callback, later on.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/media/i2c/ov5640.c | 40 ++++++++--------------------------------
1 file changed, 8 insertions(+), 32 deletions(-)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 8a53c0c..75f71e6 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -1932,6 +1932,7 @@ static void ov5640_reset(struct ov5640_dev *sensor)
static int ov5640_set_power_on(struct ov5640_dev *sensor)
{
struct i2c_client *client = sensor->i2c_client;
+ u16 chip_id;
int ret;
ret = clk_prepare_enable(sensor->xclk);
@@ -1956,6 +1957,13 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
if (ret)
goto power_off;
+ ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
+ if (ret) {
+ dev_err(&client->dev, "%s: failed to read chip identifier\n",
+ __func__);
+ goto power_off;
+ }
+
return 0;
power_off:
@@ -3039,34 +3047,6 @@ static int ov5640_get_regulators(struct ov5640_dev *sensor)
sensor->supplies);
}
-static int ov5640_check_chip_id(struct ov5640_dev *sensor)
-{
- struct i2c_client *client = sensor->i2c_client;
- int ret = 0;
- u16 chip_id;
-
- ret = ov5640_set_power_on(sensor);
- if (ret)
- return ret;
-
- ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id);
- if (ret) {
- dev_err(&client->dev, "%s: failed to read chip identifier\n",
- __func__);
- goto power_off;
- }
-
- if (chip_id != 0x5640) {
- dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n",
- __func__, chip_id);
- ret = -ENXIO;
- }
-
-power_off:
- ov5640_set_power_off(sensor);
- return ret;
-}
-
static int ov5640_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -3184,10 +3164,6 @@ static int ov5640_probe(struct i2c_client *client)
mutex_init(&sensor->lock);
- ret = ov5640_check_chip_id(sensor);
- if (ret)
- goto entity_cleanup;
-
ret = ov5640_init_controls(sensor);
if (ret)
goto entity_cleanup;

View File

@ -1,405 +0,0 @@
From: Martijn Braam <martijn@brixit.nl>
Date: Mon, 28 Sep 2020 14:26:11 +0200
Subject: [PATCH 120/194] media: ov5640: Implement autofocus
The autofocus functionality needs a firmware blob loaded into the
internal microcontroller.
V4L2 doesn't have an api to control all autofocus functionality, but
this at least makes it possible to focus on the center of the sensor.
Signed-off-by: Martijn Braam <martijn@brixit.nl>
---
drivers/media/i2c/ov5640.c | 273 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 273 insertions(+)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 75f71e6..246563e 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -9,6 +9,7 @@
#include <linux/clkdev.h>
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -31,7 +32,11 @@
#define OV5640_DEFAULT_SLAVE_ID 0x3c
+#define OV5640_REG_SYS_RESET00 0x3000
+#define OV5640_REG_SYS_RESET01 0x3001
#define OV5640_REG_SYS_RESET02 0x3002
+#define OV5640_REG_SYS_CLOCK_ENABLE00 0x3004
+#define OV5640_REG_SYS_CLOCK_ENABLE01 0x3005
#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
#define OV5640_REG_SYS_CTRL0 0x3008
#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
@@ -41,6 +46,14 @@
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018
#define OV5640_REG_PAD_OUTPUT00 0x3019
+#define OV5640_REG_FW_CMD_MAIN 0x3022
+#define OV5640_REG_FW_CMD_ACK 0x3023
+#define OV5640_REG_FW_CMD_PARA0 0x3024
+#define OV5640_REG_FW_CMD_PARA1 0x3025
+#define OV5640_REG_FW_CMD_PARA2 0x3026
+#define OV5640_REG_FW_CMD_PARA3 0x3027
+#define OV5640_REG_FW_CMD_PARA4 0x3028
+#define OV5640_REG_FW_STATUS 0x3029
#define OV5640_REG_SYSTEM_CONTROL1 0x302e
#define OV5640_REG_SC_PLL_CTRL0 0x3034
#define OV5640_REG_SC_PLL_CTRL1 0x3035
@@ -59,6 +72,7 @@
#define OV5640_REG_AEC_PK_MANUAL 0x3503
#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
#define OV5640_REG_AEC_PK_VTS 0x350c
+#define OV5640_REG_VCM_CONTROL4 0x3606
#define OV5640_REG_TIMING_DVPHO 0x3808
#define OV5640_REG_TIMING_DVPVO 0x380a
#define OV5640_REG_TIMING_HTS 0x380c
@@ -96,6 +110,20 @@
#define OV5640_REG_SDE_CTRL4 0x5584
#define OV5640_REG_SDE_CTRL5 0x5585
#define OV5640_REG_AVG_READOUT 0x56a1
+#define OV5640_REG_FIRMWARE_BASE 0x8000
+
+#define OV5640_FW_STATUS_S_FIRMWARE 0x7f
+#define OV5640_FW_STATUS_S_STARTUP 0x7e
+#define OV5640_FW_STATUS_S_IDLE 0x70
+#define OV5640_FW_STATUS_S_FOCUSING 0x00
+#define OV5640_FW_STATUS_S_FOCUSED 0x10
+
+#define OV5640_FW_CMD_TRIGGER_FOCUS 0x03
+#define OV5640_FW_CMD_CONTINUOUS_FOCUS 0x04
+#define OV5640_FW_CMD_GET_FOCUS_RESULT 0x07
+#define OV5640_FW_CMD_RELEASE_FOCUS 0x08
+#define OV5640_FW_CMD_ZONE_CONFIG 0x12
+#define OV5640_FW_CMD_DEFAULT_ZONES 0x80
enum ov5640_mode_id {
OV5640_MODE_QQVGA_160_120 = 0,
@@ -222,6 +250,12 @@ struct ov5640_ctrls {
struct v4l2_ctrl *auto_gain;
struct v4l2_ctrl *gain;
};
+ struct {
+ struct v4l2_ctrl *focus_auto;
+ struct v4l2_ctrl *af_start;
+ struct v4l2_ctrl *af_stop;
+ struct v4l2_ctrl *af_status;
+ };
struct v4l2_ctrl *brightness;
struct v4l2_ctrl *light_freq;
struct v4l2_ctrl *saturation;
@@ -265,6 +299,8 @@ struct ov5640_dev {
bool pending_mode_change;
bool streaming;
+
+ bool af_initialized;
};
static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd)
@@ -1929,6 +1965,118 @@ static void ov5640_reset(struct ov5640_dev *sensor)
usleep_range(20000, 25000);
}
+static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor,
+ const struct firmware *fw)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ const u8 *data = (const u8 *)fw->data;
+ u8 fw_status;
+ int i;
+ int ret;
+
+ // Putting MCU in reset state
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20);
+ if (ret)
+ return ret;
+
+ // Write firmware
+ for (i = 0; i < fw->size / sizeof(u8); i++)
+ ov5640_write_reg(sensor,
+ OV5640_REG_FIRMWARE_BASE + i,
+ data[i]);
+
+ // Reset MCU state
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA0, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA1, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA2, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA3, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA4, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_FW_STATUS, 0x7f);
+
+ // Start AF MCU
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00);
+ if (ret)
+ return ret;
+
+ dev_info(&client->dev, "firmware upload success\n");
+
+ // Wait for firmware to be ready
+ for (i = 0; i < 5; i++) {
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
+ if (fw_status == OV5640_FW_STATUS_S_IDLE) {
+ dev_info(&client->dev, "fw started after %d ms\n", i * 50);
+ return ret;
+ }
+ msleep(50);
+ }
+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x, retrying...\n", fw_status);
+
+ // Putting MCU in reset state
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20);
+ if (ret)
+ return ret;
+ // Start AF MCU
+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00);
+ if (ret)
+ return ret;
+ // Wait for firmware to be ready
+ for (i = 0; i < 5; i++) {
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
+ if (fw_status == OV5640_FW_STATUS_S_IDLE) {
+ dev_info(&client->dev, "fw started after %d ms\n", i * 50);
+ return ret;
+ }
+ msleep(50);
+ }
+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x\n", fw_status);
+ return -ETIMEDOUT;
+}
+
+static int ov5640_af_init(struct ov5640_dev *sensor)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ const char* fwname = "ov5640_af.bin";
+ const struct firmware *fw;
+ int ret;
+
+ if (sensor->af_initialized) {
+ return 0;
+ }
+
+ if (firmware_request_nowarn(&fw, fwname, &client->dev) == 0) {
+ ret = ov5640_copy_fw_to_device(sensor, fw);
+ if (ret == 0)
+ sensor->af_initialized = 1;
+ } else {
+ dev_warn(&client->dev, "%s: no autofocus firmware available (%s)\n",
+ __func__, fwname);
+ ret = -1;
+ }
+ release_firmware(fw);
+
+ if (ret)
+ return ret;
+
+ // Enable AF systems
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE00,
+ (BIT(6) | BIT(5)), (BIT(6) | BIT(5)));
+ if (ret)
+ return ret;
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE01,
+ BIT(6), BIT(6));
+ if (ret)
+ return ret;
+
+ // Set lens focus driver on
+ ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
static int ov5640_set_power_on(struct ov5640_dev *sensor)
{
struct i2c_client *client = sensor->i2c_client;
@@ -1950,6 +2098,8 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor)
goto xclk_off;
}
+ sensor->af_initialized = 0;
+
ov5640_reset(sensor);
ov5640_power(sensor, true);
@@ -2467,6 +2617,35 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor,
is_jpeg ? (BIT(5) | BIT(3)) : 0);
}
+static int ov5640_fw_command(struct ov5640_dev *sensor, int command)
+{
+ u8 fw_ack;
+ int i;
+ int ret;
+
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x01);
+ if(ret)
+ return ret;
+
+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, command);
+ if(ret)
+ return ret;
+
+ for (i = 0; i < 100; i++) {
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_CMD_ACK, &fw_ack);
+ if (ret)
+ return ret;
+
+ if (fw_ack == 0){
+ return ret;
+ }
+
+ msleep(50);
+ }
+ return -ETIMEDOUT;
+}
+
+
/*
* Sensor Controls.
*/
@@ -2583,6 +2762,41 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor,
return ret;
}
+static int ov5640_set_ctrl_focus(struct ov5640_dev *sensor, int command)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ int ret;
+
+ ret = ov5640_af_init(sensor);
+ if (ret) {
+ dev_err(&client->dev, "%s: no autofocus firmware loaded\n",
+ __func__);
+ return 0;
+ }
+
+ if (command == OV5640_FW_CMD_RELEASE_FOCUS) {
+ dev_dbg(&client->dev, "%s: Releasing autofocus\n",
+ __func__);
+ return ov5640_fw_command(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
+ }
+
+ // Restart zone config
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_ZONE_CONFIG);
+ if (ret)
+ return ret;
+
+ // Set default focus zones
+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_DEFAULT_ZONES);
+ if (ret)
+ return ret;
+
+ dev_dbg(&client->dev, "%s: Triggering autofocus\n",
+ __func__);
+
+ // Start focussing
+ return ov5640_fw_command(sensor, command);
+}
+
static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain)
{
struct ov5640_ctrls *ctrls = &sensor->ctrls;
@@ -2689,6 +2903,32 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
(BIT(2) | BIT(1)) : 0);
}
+static int ov5640_get_af_status(struct ov5640_dev *sensor)
+{
+ u8 fw_status;
+ int ret;
+
+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status);
+ if (ret)
+ return ret;
+
+ switch (fw_status) {
+ case OV5640_FW_STATUS_S_FIRMWARE:
+ case OV5640_FW_STATUS_S_STARTUP:
+ return V4L2_AUTO_FOCUS_STATUS_FAILED;
+ break;
+ case OV5640_FW_STATUS_S_IDLE:
+ return V4L2_AUTO_FOCUS_STATUS_IDLE;
+ break;
+ case OV5640_FW_STATUS_S_FOCUSED:
+ return V4L2_AUTO_FOCUS_STATUS_REACHED;
+ break;
+ default:
+ return V4L2_AUTO_FOCUS_STATUS_BUSY;
+ break;
+ }
+}
+
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
@@ -2710,6 +2950,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
return val;
sensor->ctrls.exposure->val = val;
break;
+ case V4L2_CID_FOCUS_AUTO:
+ val = ov5640_get_af_status(sensor);
+ if (val < 0)
+ return val;
+ sensor->ctrls.af_status->val = val;
+ break;
}
return 0;
@@ -2741,6 +2987,18 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_AUTO_WHITE_BALANCE:
ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val);
break;
+ case V4L2_CID_FOCUS_AUTO:
+ if (ctrl->val)
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_CONTINUOUS_FOCUS);
+ else
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
+ break;
+ case V4L2_CID_AUTO_FOCUS_START:
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_TRIGGER_FOCUS);
+ break;
+ case V4L2_CID_AUTO_FOCUS_STOP:
+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS);
+ break;
case V4L2_CID_HUE:
ret = ov5640_set_ctrl_hue(sensor, ctrl->val);
break;
@@ -2813,6 +3071,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
0, 1023, 1, 0);
+ /* Autofocus */
+ ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_AUTO,
+ 0, 1, 1, 0);
+ ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_START,
+ 0, 1, 1, 0);
+ ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_STOP,
+ 0, 1, 1, 0);
+ ctrls->af_status = v4l2_ctrl_new_std(hdl, ops,
+ V4L2_CID_AUTO_FOCUS_STATUS, 0,
+ (V4L2_AUTO_FOCUS_STATUS_BUSY |
+ V4L2_AUTO_FOCUS_STATUS_REACHED |
+ V4L2_AUTO_FOCUS_STATUS_FAILED),
+ 0, V4L2_AUTO_FOCUS_STATUS_IDLE);
+
ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION,
0, 255, 1, 64);
ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE,
@@ -2846,6 +3118,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);
v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);
v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);
+ v4l2_ctrl_cluster(4, &ctrls->focus_auto);
sensor->sd.ctrl_handler = hdl;
return 0;

View File

@ -1,23 +0,0 @@
From: Martijn Braam <martijn@brixit.nl>
Date: Wed, 7 Oct 2020 17:33:43 +0200
Subject: [PATCH 121/194] media: ov5640: set default ae target lower
The OV5640 tries to overexpose all photos by about 1 stop. This makes
the exposure target one stop lower.
---
drivers/media/i2c/ov5640.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 246563e..f01bf29 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -3355,7 +3355,7 @@ static int ov5640_probe(struct i2c_client *client)
&ov5640_mode_data[OV5640_MODE_VGA_640_480];
sensor->last_mode = sensor->current_mode;
- sensor->ae_target = 52;
+ sensor->ae_target = 28;
/* optional indication of physical rotation of sensor */
ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",

View File

@ -1,464 +0,0 @@
From: =?utf-8?q?Kamil_Trzci=C5=84ski?= <ayufan@ayufan.eu>
Date: Wed, 8 Sep 2021 13:50:04 +0200
Subject: [PATCH 05/36] drm: panel: hx8394: Add driver for HX8394 based
HannStar HSD060BHW4 panel
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
...
Signed-off-by: Kamil Trzciński <ayufan@ayufan.eu>
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/panel/Kconfig | 9 +
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-himax-hx8394.c | 410 +++++++++++++++++++++++++++++
3 files changed, 420 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-himax-hx8394.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index cfc8d64..166bd4a 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -129,6 +129,15 @@ config DRM_PANEL_FEIYANG_FY07024DI26A30D
Say Y if you want to enable support for panels based on the
Feiyang FY07024DI26A30-D MIPI-DSI interface.
+config DRM_PANEL_HIMAX_HX8394
+ tristate "HIMAX HX8394 MIPI-DSI LCD panel"
+ depends on OF
+ depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
+ help
+ Say Y if you want to enable support for panels based on the
+ HIMAX HX8394 MIPI-DSI interface.
+
config DRM_PANEL_ILITEK_IL9322
tristate "Ilitek ILI9322 320x240 QVGA panels"
depends on OF && SPI
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index bca4cc1..486926c 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_DRM_PANEL_TRULY_NT35597_WQXGA) += panel-truly-nt35597.o
obj-$(CONFIG_DRM_PANEL_VISIONOX_RM69299) += panel-visionox-rm69299.o
obj-$(CONFIG_DRM_PANEL_WIDECHIPS_WS2401) += panel-widechips-ws2401.o
obj-$(CONFIG_DRM_PANEL_XINPENG_XPP055C272) += panel-xinpeng-xpp055c272.o
+obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
new file mode 100644
index 00000000..14659cb
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
@@ -0,0 +1,410 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for panels based on Himax HX8394 controller, souch as:
+ *
+ * - HannStar HSD060BHW4 5.99" MIPI-DSI panel
+ *
+ * Copyright (C) Kamil Trzciński
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/display_timing.h>
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+
+#define DRV_NAME "panel-himax-hx8394"
+
+struct hx8394 {
+ struct device *dev;
+ struct drm_panel panel;
+ struct gpio_desc *reset_gpio;
+ struct regulator *vcc;
+ struct regulator *iovcc;
+ bool prepared;
+
+ struct dentry *debugfs;
+ const struct hx8394_panel_desc *desc;
+};
+
+struct hx8394_panel_desc {
+ const struct drm_display_mode *mode;
+ unsigned int lanes;
+ unsigned long mode_flags;
+ enum mipi_dsi_pixel_format format;
+ int (*init_sequence)(struct hx8394 *ctx);
+};
+
+static inline struct hx8394 *panel_to_hx8394(struct drm_panel *panel)
+{
+ return container_of(panel, struct hx8394, panel);
+}
+
+#define dsi_generic_write_seq(dsi, seq...) do { \
+ static const u8 d[] = { seq }; \
+ int ret; \
+ ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+#define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
+ static const u8 d[] = { seq }; \
+ int ret; \
+ ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
+ if (ret < 0) \
+ return ret; \
+ } while (0)
+
+
+static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
+{
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+ dsi_dcs_write_seq(dsi, 0xb9, 0xff, 0x83, 0x94);
+ dsi_dcs_write_seq(dsi, 0xb1, 0x48, 0x11, 0x71, 0x09, 0x32, 0x24, 0x71, 0x31, 0x55, 0x30);
+ dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0);
+ dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x78, 0x0c, 0x07);
+ dsi_dcs_write_seq(dsi, 0xb4, 0x12, 0x63, 0x12, 0x63, 0x12, 0x63, 0x01, 0x0c, 0x7c, 0x55, 0x00, 0x3f, 0x12, 0x6b, 0x12, 0x6b, 0x12, 0x6b, 0x01, 0x0c, 0x7c);
+ dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x00, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, 0x15, 0xad, 0x05, 0xad, 0x32, 0x00, 0x00, 0x00, 0x00, 0x37, 0x03, 0x0b, 0x0b, 0x37, 0x00, 0x00, 0x00, 0x0c, 0x40);
+ dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, 0x1a, 0x1a, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x20, 0x21, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x24, 0x25, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
+ dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, 0x1a, 0x1a, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x25, 0x24, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18);
+ dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x04, 0x0c, 0x12, 0x14, 0x18, 0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f, 0x00, 0x04, 0x0c, 0x11, 0x13, 0x17, 0x1a, 0x18, 0x31, 0x3f, 0x4d, 0x4c, 0x54, 0x65, 0x6b, 0x70, 0x7f, 0x82, 0x7e, 0x8a, 0x99, 0x4a, 0x48, 0x49, 0x4b, 0x4a, 0x4c, 0x4b, 0x7f);
+ dsi_dcs_write_seq(dsi, 0xcc, 0x0b);
+ dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31);
+ dsi_dcs_write_seq(dsi, 0xb6, 0x7d, 0x7d);
+ dsi_dcs_write_seq(dsi, 0xd4, 0x02);
+ dsi_dcs_write_seq(dsi, 0xbd, 0x01);
+ dsi_dcs_write_seq(dsi, 0xb1, 0x00);
+ dsi_dcs_write_seq(dsi, 0xbd, 0x00);
+ dsi_dcs_write_seq(dsi, 0xc6, 0xed);
+
+ // msleep(0xfa);
+ // dsi_dcs_write_seq(dsi, 0x11);
+ // msleep(0x32);
+ // dsi_dcs_write_seq(dsi, 0x29);
+
+ return 0;
+}
+
+static const struct drm_display_mode hsd060bhw4_mode = {
+ .hdisplay = 720,
+ .hsync_start = 720 + 40,
+ .hsync_end = 720 + 40 + 40,
+ .htotal = 720 + 40 + 40 + 40,
+ .vdisplay = 1440,
+ .vsync_start = 1440 + 18,
+ .vsync_end = 1440 + 18 + 10,
+ .vtotal = 1440 + 18 + 10 + 17,
+ .clock = 69000,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ .width_mm = 68,
+ .height_mm = 136,
+};
+
+static const struct drm_display_mode hsd060bhw4_mode2 = {
+ .hdisplay = 720,
+ .hsync_start = 720 + 50,
+ .hsync_end = 720 + 50 + 10,
+ .htotal = 720 + 50 + 10 + 50,
+ .vdisplay = 1440,
+ .vsync_start = 1440 + 17,
+ .vsync_end = 1440 + 17 + 4,
+ .vtotal = 1440 + 17 + 4 + 10,
+ .clock = 60000,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+ .width_mm = 68,
+ .height_mm = 136,
+};
+
+static const struct hx8394_panel_desc hsd060bhw4_desc = {
+ .mode = &hsd060bhw4_mode,
+ .lanes = 4,
+ .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST,// | MIPI_DSI_MODE_LPM,//, // 0x843
+ .format = MIPI_DSI_FMT_RGB888,
+ .init_sequence = hsd060bhw4_init_sequence,
+};
+
+static int hx8394_enable(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = ctx->desc->init_sequence(ctx);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
+ return ret;
+ }
+
+ msleep(20);
+
+ ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ /* Panel is operational 120 msec after reset */
+ msleep(60);
+
+ ret = mipi_dsi_dcs_set_display_on(dsi);
+ if (ret)
+ return ret;
+
+ dev_dbg(ctx->dev, "Panel init sequence done\n");
+
+ return 0;
+}
+
+static int hx8394_disable(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ int ret;
+
+ ret = mipi_dsi_dcs_set_display_off(dsi);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
+
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (ret < 0)
+ dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
+
+ return 0;
+}
+
+static int hx8394_unprepare(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+
+ if (!ctx->prepared)
+ return 0;
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ regulator_disable(ctx->iovcc);
+ regulator_disable(ctx->vcc);
+ ctx->prepared = false;
+
+ return 0;
+}
+
+static int hx8394_prepare(struct drm_panel *panel)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ int ret;
+
+ if (ctx->prepared)
+ return 0;
+
+ dev_dbg(ctx->dev, "Resetting the panel\n");
+ ret = regulator_enable(ctx->vcc);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
+ return ret;
+ }
+ ret = regulator_enable(ctx->iovcc);
+ if (ret < 0) {
+ dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
+ goto disable_vcc;
+ }
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+ mdelay(0x32);
+ gpiod_set_value_cansleep(ctx->reset_gpio, 0);
+ msleep(0x64);
+
+ ctx->prepared = true;
+
+ return 0;
+
+disable_vcc:
+ regulator_disable(ctx->vcc);
+ return ret;
+}
+
+static int hx8394_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ struct hx8394 *ctx = panel_to_hx8394(panel);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
+ if (!mode) {
+ dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode));
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs hx8394_drm_funcs = {
+ .disable = hx8394_disable,
+ .unprepare = hx8394_unprepare,
+ .prepare = hx8394_prepare,
+ .enable = hx8394_enable,
+ .get_modes = hx8394_get_modes,
+};
+
+static int allpixelson_set(void *data, u64 val)
+{
+ struct hx8394 *ctx = data;
+ struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+
+ dev_dbg(ctx->dev, "Setting all pixels on\n");
+ dsi_generic_write_seq(dsi, 0x23);
+ msleep(val * 1000);
+ /* Reset the panel to get video back */
+ drm_panel_disable(&ctx->panel);
+ drm_panel_unprepare(&ctx->panel);
+ drm_panel_prepare(&ctx->panel);
+ drm_panel_enable(&ctx->panel);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
+ allpixelson_set, "%llu\n");
+
+static void hx8394_debugfs_init(struct hx8394 *ctx)
+{
+ ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
+
+ debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
+ &allpixelson_fops);
+}
+
+static void hx8394_debugfs_remove(struct hx8394 *ctx)
+{
+ debugfs_remove_recursive(ctx->debugfs);
+ ctx->debugfs = NULL;
+}
+
+static int hx8394_probe(struct mipi_dsi_device *dsi)
+{
+ struct device *dev = &dsi->dev;
+ struct hx8394 *ctx;
+ int ret;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(ctx->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
+
+ mipi_dsi_set_drvdata(dsi, ctx);
+
+ ctx->dev = dev;
+ ctx->desc = of_device_get_match_data(dev);
+
+ dsi->mode_flags = ctx->desc->mode_flags;
+ dsi->format = ctx->desc->format;
+ dsi->lanes = ctx->desc->lanes;
+
+ ctx->vcc = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(ctx->vcc))
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
+
+ ctx->iovcc = devm_regulator_get(dev, "iovcc");
+ if (IS_ERR(ctx->iovcc))
+ return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
+ "Failed to request iovcc regulator\n");
+
+ drm_panel_init(&ctx->panel, dev, &hx8394_drm_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&ctx->panel);
+ if (ret)
+ return ret;
+
+ drm_panel_add(&ctx->panel);
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
+ drm_panel_remove(&ctx->panel);
+ return ret;
+ }
+
+ dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
+ ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
+ drm_mode_vrefresh(ctx->desc->mode),
+ mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
+
+ hx8394_debugfs_init(ctx);
+ return 0;
+}
+
+static void hx8394_shutdown(struct mipi_dsi_device *dsi)
+{
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ ret = drm_panel_unprepare(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
+
+ ret = drm_panel_disable(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
+}
+
+static int hx8394_remove(struct mipi_dsi_device *dsi)
+{
+ struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
+ int ret;
+
+ hx8394_shutdown(dsi);
+
+ ret = mipi_dsi_detach(dsi);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&ctx->panel);
+
+ hx8394_debugfs_remove(ctx);
+
+ return 0;
+}
+
+static const struct of_device_id hx8394_of_match[] = {
+ { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hx8394_of_match);
+
+static struct mipi_dsi_driver hx8394_driver = {
+ .probe = hx8394_probe,
+ .remove = hx8394_remove,
+ .shutdown = hx8394_shutdown,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = hx8394_of_match,
+ },
+};
+module_mipi_dsi_driver(hx8394_driver);
+
+MODULE_AUTHOR("Kamil Trzciński <ayufan@ayufan.eu>");
+MODULE_DESCRIPTION("DRM driver for Himax HX8394 based MIPI DSI panels");
+MODULE_LICENSE("GPL v2");

View File

@ -1,226 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 17 Oct 2021 18:03:05 +0200
Subject: [PATCH 06/36] drm: panel: hx8394: Improve the panel driver (make it
work with DSI fixes)
Powerup/down should be done in prepare/unprepare. Enable/disable is just
for initialization. Fix timings and reset order according to datasheet.
Reset panel on probe.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/panel/panel-himax-hx8394.c | 84 ++++++++++++++++++------------
1 file changed, 52 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
index 14659cb..2f69b94 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
@@ -89,11 +89,6 @@ static int hsd060bhw4_init_sequence(struct hx8394 *ctx)
dsi_dcs_write_seq(dsi, 0xbd, 0x00);
dsi_dcs_write_seq(dsi, 0xc6, 0xed);
- // msleep(0xfa);
- // dsi_dcs_write_seq(dsi, 0x11);
- // msleep(0x32);
- // dsi_dcs_write_seq(dsi, 0x29);
-
return 0;
}
@@ -141,30 +136,38 @@ static int hx8394_enable(struct drm_panel *panel)
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
+ dev_info(ctx->dev, "enable\n");
+
ret = ctx->desc->init_sequence(ctx);
- if (ret < 0) {
+ if (ret) {
dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
return ret;
}
- msleep(20);
-
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
- if (ret < 0) {
+ if (ret) {
dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
/* Panel is operational 120 msec after reset */
- msleep(60);
+ msleep(120);
ret = mipi_dsi_dcs_set_display_on(dsi);
- if (ret)
- return ret;
-
- dev_dbg(ctx->dev, "Panel init sequence done\n");
+ if (ret) {
+ dev_err(ctx->dev, "Failed to turn on the display: %d\n", ret);
+ goto sleep_in;
+ }
return 0;
+
+sleep_in:
+ /* This will probably fail, but let's try orderly power off anyway. */
+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
+ if (!ret)
+ msleep(50);
+
+ return ret;
}
static int hx8394_disable(struct drm_panel *panel)
@@ -173,13 +176,15 @@ static int hx8394_disable(struct drm_panel *panel)
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
- ret = mipi_dsi_dcs_set_display_off(dsi);
- if (ret < 0)
- dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
+ dev_info(ctx->dev, "disable\n");
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
- if (ret < 0)
+ if (ret) {
dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
+ return ret;
+ }
+
+ msleep(50); /* about 3 frames */
return 0;
}
@@ -187,13 +192,19 @@ static int hx8394_disable(struct drm_panel *panel)
static int hx8394_unprepare(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
+ //struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+ //int ret;
if (!ctx->prepared)
return 0;
+ dev_info(ctx->dev, "unprepare\n");
+
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
regulator_disable(ctx->iovcc);
regulator_disable(ctx->vcc);
+
ctx->prepared = false;
return 0;
@@ -202,33 +213,38 @@ static int hx8394_unprepare(struct drm_panel *panel)
static int hx8394_prepare(struct drm_panel *panel)
{
struct hx8394 *ctx = panel_to_hx8394(panel);
+ //struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
if (ctx->prepared)
return 0;
- dev_dbg(ctx->dev, "Resetting the panel\n");
+ dev_info(ctx->dev, "prepare\n");
+
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
+
ret = regulator_enable(ctx->vcc);
- if (ret < 0) {
+ if (ret) {
dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
return ret;
}
+
ret = regulator_enable(ctx->iovcc);
- if (ret < 0) {
+ if (ret) {
dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
goto disable_vcc;
}
- gpiod_set_value_cansleep(ctx->reset_gpio, 1);
- mdelay(0x32);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
- msleep(0x64);
+
+ msleep(180);
ctx->prepared = true;
return 0;
disable_vcc:
+ gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->vcc);
return ret;
}
@@ -273,9 +289,11 @@ static int allpixelson_set(void *data, u64 val)
dev_dbg(ctx->dev, "Setting all pixels on\n");
dsi_generic_write_seq(dsi, 0x23);
msleep(val * 1000);
+
/* Reset the panel to get video back */
drm_panel_disable(&ctx->panel);
drm_panel_unprepare(&ctx->panel);
+
drm_panel_prepare(&ctx->panel);
drm_panel_enable(&ctx->panel);
@@ -309,9 +327,10 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
if (!ctx)
return -ENOMEM;
- ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
- return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
+ return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
+ "Failed to get reset gpio\n");
mipi_dsi_set_drvdata(dsi, ctx);
@@ -324,7 +343,8 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
ctx->vcc = devm_regulator_get(dev, "vcc");
if (IS_ERR(ctx->vcc))
- return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
+ return dev_err_probe(dev, PTR_ERR(ctx->vcc),
+ "Failed to request vcc regulator\n");
ctx->iovcc = devm_regulator_get(dev, "iovcc");
if (IS_ERR(ctx->iovcc))
@@ -342,7 +362,7 @@ static int hx8394_probe(struct mipi_dsi_device *dsi)
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
- dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
+ dev_err_probe(dev, ret, "mipi_dsi_attach failed\n");
drm_panel_remove(&ctx->panel);
return ret;
}
@@ -361,13 +381,13 @@ static void hx8394_shutdown(struct mipi_dsi_device *dsi)
struct hx8394 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
- ret = drm_panel_unprepare(&ctx->panel);
- if (ret < 0)
- dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
-
ret = drm_panel_disable(&ctx->panel);
if (ret < 0)
dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
+
+ ret = drm_panel_unprepare(&ctx->panel);
+ if (ret < 0)
+ dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
}
static int hx8394_remove(struct mipi_dsi_device *dsi)

View File

@ -1,29 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 16 Nov 2021 21:19:42 +0100
Subject: [PATCH 08/36] drm: panel: hx8394: Fix mode clock for the pinephone
pro panel
The actual rate that was set by CRU was 66.333 MHz The panel does
not actually work at 69 MHz, now that CRU can generate the requested
clock rate precisely.
Change the clock rate.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/gpu/drm/panel/panel-himax-hx8394.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c
index 2f69b94..7a2f74a 100644
--- a/drivers/gpu/drm/panel/panel-himax-hx8394.c
+++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c
@@ -101,7 +101,7 @@ static const struct drm_display_mode hsd060bhw4_mode = {
.vsync_start = 1440 + 18,
.vsync_end = 1440 + 18 + 10,
.vtotal = 1440 + 18 + 10 + 17,
- .clock = 69000,
+ .clock = 66000, /*XXX: only 66MHz works */
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.width_mm = 68,
.height_mm = 136,

View File

@ -1,97 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 25 Apr 2021 03:16:42 +0200
Subject: input: goodix: Add option to power off the controller during suspend
For whatever reason the controller is not suspended on Pinephone
by the default procedure. It consumes quite a bit of power (~40mW)
during system sleep, and more when the screen is touched.
Let's power off the controller during system sleep instead.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/input/touchscreen/goodix.c | 37 +++++++++++++++++++++++++++++++++++++
drivers/input/touchscreen/goodix.h | 1 +
2 files changed, 38 insertions(+)
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index b5cc917..90a3584 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1133,6 +1133,7 @@ static void goodix_disable_regulators(void *arg)
static int goodix_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device_node *np = client->dev.of_node;
struct goodix_ts_data *ts;
const char *cfg_name;
int error;
@@ -1152,6 +1153,7 @@ static int goodix_ts_probe(struct i2c_client *client,
i2c_set_clientdata(client, ts);
init_completion(&ts->firmware_loading_complete);
ts->contact_size = GOODIX_CONTACT_SIZE;
+ ts->poweroff_in_suspend = of_property_read_bool(np, "poweroff-in-suspend");
error = goodix_get_gpio_config(ts);
if (error)
@@ -1261,6 +1263,15 @@ static int __maybe_unused goodix_suspend(struct device *dev)
if (ts->load_cfg_from_disk)
wait_for_completion(&ts->firmware_loading_complete);
+ if (ts->poweroff_in_suspend) {
+ goodix_free_irq(ts);
+ goodix_irq_direction_output(ts, 0);
+ gpiod_direction_output(ts->gpiod_rst, 0);
+ regulator_disable(ts->avdd28);
+ regulator_disable(ts->vddio);
+ return 0;
+ }
+
/* We need gpio pins to suspend/resume */
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
disable_irq(client->irq);
@@ -1306,6 +1317,32 @@ static int __maybe_unused goodix_resume(struct device *dev)
u8 config_ver;
int error;
+ if (ts->poweroff_in_suspend) {
+ error = regulator_enable(ts->avdd28);
+ if (error) {
+ dev_err(dev, "Regulator avdd28 enable failed.\n");
+ return error;
+ }
+
+ error = regulator_enable(ts->vddio);
+ if (error) {
+ dev_err(dev, "Regulator vddio enable failed.\n");
+ return error;
+ }
+
+ error = goodix_reset(ts);
+ if (error) {
+ dev_err(dev, "Controller reset failed.\n");
+ return error;
+ }
+
+ error = goodix_request_irq(ts);
+ if (error)
+ return error;
+
+ return 0;
+ }
+
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
enable_irq(client->irq);
return 0;
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 62138f9..3bb51ea 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -101,6 +101,7 @@ struct goodix_ts_data {
u8 main_clk[GOODIX_MAIN_CLK_LEN];
int bak_ref_len;
u8 *bak_ref;
+ bool poweroff_in_suspend;
};
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);

View File

@ -1,49 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sat, 1 May 2021 01:28:07 +0200
Subject: input: goodix: Don't disable regulators during suspend
It does no harm to disable them, but on Pinephone we have other
peripherals attached to the same power supplies, whose drivers
will not reference the regulator, so powering down the regulators
from Goodix driver will break those other devices.
Until those drivers gain the regulator support, don't disable
the regulators in Goodix driver.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/input/touchscreen/goodix.c | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 90a3584..5f78dc1 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1267,8 +1267,6 @@ static int __maybe_unused goodix_suspend(struct device *dev)
goodix_free_irq(ts);
goodix_irq_direction_output(ts, 0);
gpiod_direction_output(ts->gpiod_rst, 0);
- regulator_disable(ts->avdd28);
- regulator_disable(ts->vddio);
return 0;
}
@@ -1318,18 +1316,6 @@ static int __maybe_unused goodix_resume(struct device *dev)
int error;
if (ts->poweroff_in_suspend) {
- error = regulator_enable(ts->avdd28);
- if (error) {
- dev_err(dev, "Regulator avdd28 enable failed.\n");
- return error;
- }
-
- error = regulator_enable(ts->vddio);
- if (error) {
- dev_err(dev, "Regulator vddio enable failed.\n");
- return error;
- }
-
error = goodix_reset(ts);
if (error) {
dev_err(dev, "Controller reset failed.\n");

View File

@ -1,53 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 18 Oct 2021 03:56:14 +0200
Subject: [PATCH 17/36] input: touchscreen: goodix: Respect IRQ flags from DT
when asked to
Sometimes the IRQ flags determined from toucschreen config don't
work well.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/input/touchscreen/goodix.c | 7 ++++++-
drivers/input/touchscreen/goodix.h | 1 +
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 5f78dc1..91836019 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -400,9 +400,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts)
static int goodix_request_irq(struct goodix_ts_data *ts)
{
+ unsigned long irq_flags = ts->irq_flags;
+ if (ts->use_dt_irqflags)
+ irq_flags = IRQF_ONESHOT;
+
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
- ts->irq_flags, ts->client->name, ts);
+ irq_flags, ts->client->name, ts);
}
static int goodix_check_cfg_8(struct goodix_ts_data *ts, const u8 *cfg, int len)
@@ -1149,6 +1153,7 @@ static int goodix_ts_probe(struct i2c_client *client,
if (!ts)
return -ENOMEM;
+ ts->use_dt_irqflags = of_property_read_bool(np, "use-dt-irq-flags");
ts->client = client;
i2c_set_clientdata(client, ts);
init_completion(&ts->firmware_loading_complete);
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 3bb51ea..0e992a8 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -80,6 +80,7 @@ struct goodix_ts_data {
const char *firmware_name;
struct touchscreen_properties prop;
unsigned int max_touch_num;
+ bool use_dt_irqflags;
unsigned int int_trigger_type;
struct regulator *avdd28;
struct regulator *vddio;

View File

@ -1,23 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Thu, 11 Nov 2021 14:28:41 +0100
Subject: [PATCH 18/36] input: touchscreen: goodix: Add support for GT1158
This controller is used by Pinephone Pro.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
drivers/input/touchscreen/goodix.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 91836019..e2167d8 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -94,6 +94,7 @@ static const struct goodix_chip_data gt9x_chip_data = {
static const struct goodix_chip_id goodix_chip_ids[] = {
{ .id = "1151", .data = &gt1x_chip_data },
+ { .id = "1158", .data = &gt1x_chip_data },
{ .id = "5663", .data = &gt1x_chip_data },
{ .id = "5688", .data = &gt1x_chip_data },
{ .id = "917S", .data = &gt1x_chip_data },

View File

@ -1,101 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Wed, 22 Sep 2021 19:30:39 +0200
Subject: [PATCH 02/18] arm64: dts: rk3399-pinephone-pro: Fixup DT validation
issues
Fixes:
rk3399-pinephone-pro.dts:751.4-14: Warning (reg_format): /mipi@ff960000/panel/port:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
rk3399-pinephone-pro.dtb: Warning (pci_device_reg): Failed prerequisite 'reg_format'
rk3399-pinephone-pro.dtb: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
rk3399-pinephone-pro.dtb: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
rk3399-pinephone-pro.dtb: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
rk3399-pinephone-pro.dts:747.8-756.5: Warning (avoid_default_addr_size): /mipi@ff960000/panel/port: Relying on default #address-cells value
rk3399-pinephone-pro.dts:747.8-756.5: Warning (avoid_default_addr_size): /mipi@ff960000/panel/port: Relying on default #size-cells value
rk3399-pinephone-pro.dts:747.8-756.5: Warning (graph_port): /mipi@ff960000/panel/port: graph node unit address error, expected "0"
rk3399-pinephone-pro.dts:748.4-25: Warning (graph_port): /mipi@ff960000/panel/port:#address-cells: graph node '#address-cells' is -1, must be 1
rk3399-pinephone-pro.dts:749.4-22: Warning (graph_port): /mipi@ff960000/panel/port:#size-cells: graph node '#size-cells' is -1, must be 0
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index b53df0d..de8a1f3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -626,7 +626,6 @@ fusb0: typec-portc@22 {
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int>;
vbus-supply = <&vcc5v0_typec>;
- status = "okay";
connector {
compatible = "usb-c-connector";
@@ -691,23 +690,25 @@ accelerometer@68 {
"0", "0", "1";
};
- lis3mdl: magnetometer@1e {
+ lis3mdl: magnetometer@1c {
compatible = "st,lis3mdl-magn";
reg = <0x1c>;
interrupt-parent = <&gpio1>;
interrupts = <RK_PA1 IRQ_TYPE_LEVEL_LOW>;
vdd-supply = <&vcc3v3_sys>;
vddio-supply = <&vcc_1v8>;
+ status = "disabled";
};
// not populated currently
- ak09911: compass@0c {
+ ak09911: compass@c {
compatible = "asahi-kasei,ak09911";
reg = <0x0c>;
interrupt-parent = <&gpio1>;
interrupts = <RK_PA1 IRQ_TYPE_LEVEL_LOW>;
vdd-supply = <&vcc_3v0>;
vid-supply = <&vcc_1v8>;
+ status = "disabled";
};
};
@@ -726,6 +727,8 @@ &mipi_dsi {
ports {
mipi_out: port@1 {
+ #address-cells = <0>;
+ #size-cells = <0>;
reg = <1>;
mipi_out_panel: endpoint {
@@ -734,7 +737,7 @@ mipi_out_panel: endpoint {
};
};
- panel {
+ panel@0 {
compatible = "hannstar,hsd060bhw4";
reg = <0>;
backlight = <&backlight>;
@@ -745,11 +748,6 @@ panel {
pinctrl-0 = <&display_rst_l>;
port {
- #address-cells = <1>;
- #size-cells = <0>;
-
- reg = <0>;
-
mipi_in_panel: endpoint {
remote-endpoint = <&mipi_out_panel>;
};
@@ -757,7 +755,6 @@ mipi_in_panel: endpoint {
};
};
-
&pmu_io_domains {
pmu1830-supply = <&vcc_3v0>;
status = "okay";

View File

@ -1,34 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 11 Oct 2021 17:32:31 +0200
Subject: [PATCH 03/18] arm64: dts: rk3399-pinephone-pro: Make charging and
peripheral mode work
Signed-of-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index de8a1f3..eb2d15e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -511,8 +511,8 @@ otg_switch: OTG_SWITCH {
regulator-name = "otg_switch";
// TODO: This requires a proper rk818-charger implementation
// without this always-on the type-c is not powered on
- regulator-always-on;
- regulator-boot-on;
+ //regulator-always-on;
+ //regulator-boot-on;
};
};
@@ -1013,7 +1013,7 @@ &usbdrd3_0 {
};
&usbdrd_dwc3_0 {
- dr_mode = "host";
+ dr_mode = "peripheral";
status = "okay";
};

View File

@ -1,30 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 18 Oct 2021 03:55:15 +0200
Subject: [PATCH 04/18] arm64: dts: rk3399-pinephone-pro: Fix goodix
toucscreen interrupts
The interrupt type read from the screen does not work well. It generates
constant stream of interrupts.
Change to rising edge interrupt, and enforce it in the driver via
'use-dt-irq-flags'.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index eb2d15e..83eb683 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -594,7 +594,8 @@ touchscreen@14 {
compatible = "goodix,gt917s";
reg = <0x14>;
interrupt-parent = <&gpio3>;
- interrupts = <RK_PB5 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <RK_PB5 IRQ_TYPE_EDGE_RISING>;
+ use-dt-irq-flags;
irq-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;
AVDD28-supply = <&vcc3v0_touch>;

View File

@ -1,26 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 18 Oct 2021 03:57:56 +0200
Subject: [PATCH 05/18] arm64: dts: rk3399-pinephone-pro: Correct the pmu1830
io-domain supply
It's connected to vcc_1v8 according to datasheet. Credits to carlos
for noticing!
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 83eb683..59733033 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -757,7 +757,7 @@ mipi_in_panel: endpoint {
};
&pmu_io_domains {
- pmu1830-supply = <&vcc_3v0>;
+ pmu1830-supply = <&vcc_1v8>;
status = "okay";
};

View File

@ -1,25 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 18 Oct 2021 03:58:56 +0200
Subject: [PATCH 06/18] arm64: dts: rk3399-pinephone-pro: Power off goodix
touchscreen in sleep
Otherwise it consumes 200mW of power when touched during system sleep.
It can't wake up the phone anyway.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 59733033..96b5170 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -602,6 +602,7 @@ touchscreen@14 {
VDDIO-supply = <&vcc3v0_touch>;
touchscreen-size-x = <720>;
touchscreen-size-y = <1440>;
+ poweroff-in-suspend;
};
light-sensor@48 {

View File

@ -1,198 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Thu, 21 Oct 2021 20:25:35 +0200
Subject: [PATCH 07/18] arm64: dts: rk3399-pinephone-pro: Add support for both
cameras
IMX258 + OV5640.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 146 ++++++++++++++++++++-
1 file changed, 142 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 96b5170..3e9aa7b 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -456,8 +456,6 @@ regulator-state-mem {
vcc1v8_dvp: LDO_REG7 {
regulator-name = "vcc1v8_dvp";
- regulator-always-on;
- regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-state-mem {
@@ -579,10 +577,92 @@ regulator-state-mem {
};
};
+/*
+ * Cameras:
+ *
+ * cif clk out = gpio2 B3 / CIF_CLKOUTA_u
+ *
+ * both on i2c1 GPIO4_A1 (SDA) / GPIO4_A2 (SCL)
+ *
+ * both share power:
+ * VCC1V8_DVP - LDO7 - supplied by VCC7 (VCC3V3_SYS)
+ * DVDD_DVP 1.5V - autoenabled by VCC2V8_DVP depends on VCC1V8_S3 (U118 supplies 1.2V, though, not 1.5V)
+ * VCC2V8_DVP af - autoenabled by VCC1V8_DVP depends on VCC3V3_SYS
+ * AVDD2V8_DVP - autoenabled by VCC1V8_DVP depends on VCC3V3_SYS
+ *
+ * mipi0 = imx258
+ * reset = gpio1 A0
+ * powerdown = GPIO2_B4
+ *
+ * mipi1 = OV5640
+ * powerdown = GPIO2_D4
+ *
+ * bt656-supply = <&vcc1v8_dvp>;
+ */
&i2c1 {
+ status = "okay";
+
+ clock-frequency = <400000>;
i2c-scl-rising-time-ns = <300>;
i2c-scl-falling-time-ns = <15>;
- status = "okay";
+
+ pinctrl-0 = <&i2c1_xfer &cif_clkouta>;
+
+ assigned-clocks = <&cru SCLK_CIF_OUT &cru SCLK_CIF_OUT_SRC>;
+ assigned-clock-parents = <&cru SCLK_CIF_OUT_SRC &cru PLL_GPLL>;
+ assigned-clock-rates = <19200000 0>;
+
+ /* Rear-facing camera */
+ wcam: camera@1a {
+ compatible = "sony,imx258";
+ reg = <0x1a>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcam_rst &wcam_pdn>;
+
+ clocks = <&cru SCLK_CIF_OUT>;
+ clock-names = "xvclk";
+
+ vif-supply = <&vcc1v8_dvp>;
+ /*XXX: also depends on vcca1v8_codec for I2C bus power */
+
+ reset-gpios = <&gpio1 RK_PA0 GPIO_ACTIVE_LOW>;
+ powerdown-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>;
+ rotation = <180>;
+
+ port {
+ wcam_out: endpoint {
+ remote-endpoint = <&mipi_in_wcam>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <320000000>;
+ //link-frequencies = /bits/ 64 <633600000>;
+ };
+ };
+ };
+
+ /* Front-facing camera */
+ ucam: camera@3c {
+ compatible = "ovti,ov5640";
+ reg = <0x3c>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ucam_pdn>;
+
+ clocks = <&cru SCLK_CIF_OUT>;
+ clock-names = "xclk";
+
+ DOVDD-supply = <&vcc1v8_dvp>;
+ /*XXX: also depends on vcca1v8_codec for I2C bus power */
+
+ powerdown-gpios = <&gpio2 RK_PD4 GPIO_ACTIVE_HIGH>;
+ rotation = <180>;
+
+ port {
+ ucam_out: endpoint {
+ remote-endpoint = <&mipi_in_ucam>;
+ data-lanes = <1 2>;
+ clock-lanes = <0>;
+ };
+ };
+ };
};
&i2c3 {
@@ -723,6 +803,50 @@ &io_domains {
gpio1830-supply = <&vcc_3v0>;
};
+&isp0 {
+ status = "okay";
+
+ ports {
+ port@0 {
+ mipi_in_wcam: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&wcam_out>;
+ data-lanes = <1 2 3 4>;
+ };
+ };
+ };
+};
+
+&mipi_dphy_rx0 {
+ status = "okay";
+};
+
+&isp1 {
+ status = "okay";
+
+ ports {
+ port@0 {
+ mipi_in_ucam: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ucam_out>;
+ data-lanes = <1 2>;
+ };
+ };
+ };
+};
+
+&isp0_mmu {
+ status = "okay";
+};
+
+&isp1_mmu {
+ status = "okay";
+};
+
+&mipi_dsi1 {
+ status = "okay";
+};
+
&mipi_dsi {
status = "okay";
clock-master;
@@ -783,6 +907,20 @@ pwrbtn_pin: pwrbtn-pin {
};
};
+ camera {
+ wcam_rst: wcam-rst {
+ rockchip,pins = <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ wcam_pdn: wcam-pdn {
+ rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ ucam_pdn: ucam-pdn {
+ rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
fusb302x {
fusb0_int: fusb0-int {
rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -1033,4 +1171,4 @@ &vopl {
&vopl_mmu {
status = "okay";
-};
\ No newline at end of file
+};

View File

@ -1,71 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Wed, 20 Oct 2021 22:41:43 +0200
Subject: [PATCH 08/18] arm64: dts: rk3399-pinephone-pro: Fix SD card power
supply definition
GPIO0_A1 is used for modem's RI. SD card power supply is not changeable.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 27 ++++------------------
1 file changed, 5 insertions(+), 22 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 3e9aa7b..e6aac03 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -215,23 +215,6 @@ vcc1v8_codec: vcc1v8-codec-regulator {
vin-supply = <&vcc3v3_sys>;
};
- /* micro SD card power */
- vcc3v0_sd: vcc3v0-sd {
- compatible = "regulator-fixed";
- enable-active-high;
- gpio = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc0_pwr_h>;
- regulator-name = "vcc3v0_sd";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- vin-supply = <&vcc3v3_sys>;
-
- regulator-state-mem {
- regulator-off-in-suspend;
- };
- };
-
/* MIPI DSI panel 1.8v supply */
vcc1v8_lcd: vcc1v8-lcd {
compatible = "regulator-fixed";
@@ -474,8 +457,8 @@ regulator-state-mem {
};
};
- vcc_sd: LDO_REG9 {
- regulator-name = "vcc_sd";
+ vccio_sd: LDO_REG9 {
+ regulator-name = "vccio_sd";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-state-mem {
@@ -799,7 +782,7 @@ &io_domains {
bt656-supply = <&vcc1v8_dvp>;
audio-supply = <&vcca1v8_codec>;
- sdmmc-supply = <&vcc_sd>;
+ sdmmc-supply = <&vccio_sd>;
gpio1830-supply = <&vcc_3v0>;
};
@@ -1034,8 +1017,8 @@ &sdmmc {
max-frequency = <150000000>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
- vmmc-supply = <&vcc3v0_sd>;
- vqmmc-supply = <&vcc_sd>;
+ vmmc-supply = <&vcc3v3_sys>;
+ vqmmc-supply = <&vccio_sd>;
status = "okay";
};

View File

@ -1,44 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 25 Oct 2021 17:49:41 +0200
Subject: [PATCH 09/18] arm64: dts: rk3399-pinephone-pro: Correct the battery
specification
MIME-Version: 1.0
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit
XLS with ZCV measurements from the manufacturer say that at 25°C,
ZCV is ~200 mOhm. At 50°C it's at ~100 mOhm. Set some value in between.
Lower the charging current to something less aggressive.
Fix the current sensing resitor value (it's 10 mOhm in the schematic).
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index e6aac03..ffdaaa6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -504,16 +504,16 @@ battery {
4110 4161 4217 4308>;
design_capacity = <2916>;
design_qmax = <2708>;
- bat_res = <65>;
+ bat_res = <150>;
max_input_current = <3000>;
- max_chrg_current = <3000>;
+ max_chrg_current = <2000>;
max_chrg_voltage = <4350>;
sleep_enter_current = <300>;
sleep_exit_current = <300>;
power_off_thresd = <3400>;
zero_algorithm_vol = <3950>;
fb_temperature = <105>;
- sample_res = <20>;
+ sample_res = <10>;
max_soc_offset = <60>;
energy_mode = <0>;
monitor_sec = <5>;

View File

@ -1,32 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 26 Oct 2021 01:29:50 +0200
Subject: [PATCH 10/18] arm64: dts: rk3399-pinephone-pro: Cleanup some USB
nodes whitespace
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index ffdaaa6..d9159d4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -1067,7 +1067,7 @@ u2phy0_otg: otg-port {
u2phy0_host: host-port {
status = "okay";
- phy-supply = <&vcc5v0_sys>;
+ phy-supply = <&vcc5v0_sys>;
};
port {
@@ -1086,7 +1086,7 @@ u2phy1_otg: otg-port {
u2phy1_host: host-port {
status = "okay";
- phy-supply = <&vcc5v0_sys>;
+ phy-supply = <&vcc5v0_sys>;
};
};

View File

@ -1,33 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 26 Oct 2021 01:30:14 +0200
Subject: [PATCH 11/18] arm64: dts: rk3399-pinephone-pro: Fix PDOs to be more
reasonable
Let's not overtax the battery and provide only 4.5W to external devices.
Even that may be too much, given what PPP can consume by itself.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index d9159d4..9493672 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -696,12 +696,10 @@ connector {
compatible = "usb-c-connector";
data-role = "dual";
label = "USB-C";
- op-sink-microwatt = <1000000>;
+ op-sink-microwatt = <2500000>;
power-role = "dual";
- sink-pdos =
- <PDO_FIXED(5000, 2500, PDO_FIXED_USB_COMM)>;
- source-pdos =
- <PDO_FIXED(5000, 1400, PDO_FIXED_USB_COMM)>;
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
+ source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM)>;
try-power-role = "sink";
extcon-cables = <1 2 5 6 9 10 12 44>;

View File

@ -1,24 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 2 Nov 2021 13:28:24 +0100
Subject: [PATCH 12/18] arm64: dts: rk3399-pinephone-pro: Add chassis-type =
"handset" to DT
This way, desktop environment can pick up device type from DT.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 9493672..3f944af 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -17,6 +17,7 @@
/ {
model = "Pine64 PinePhonePro";
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
+ chassis-type = "handset";
chosen {
bootargs = "earlycon=uart8250,mmio32,0xff1a0000";

View File

@ -1,29 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 2 Nov 2021 13:29:29 +0100
Subject: [PATCH 13/18] arm64: dts: rk3399-pinephone-pro: Add mmc aliases to
get stable numbering
It's better to have stable meanings for /dev/mmcblk* device files.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 3f944af..58710a6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -19,6 +19,12 @@ / {
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
chassis-type = "handset";
+ aliases {
+ mmc0 = &sdio0;
+ mmc1 = &sdmmc;
+ mmc2 = &sdhci;
+ };
+
chosen {
bootargs = "earlycon=uart8250,mmio32,0xff1a0000";
stdout-path = "serial2:1500000n8";

View File

@ -1,23 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:30:46 +0100
Subject: [PATCH 14/18] arm64: dts: rk3399-pinephone-pro: Use a new
rk818-battery compatible
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 58710a6..1b4eb26 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -505,7 +505,7 @@ otg_switch: OTG_SWITCH {
};
battery {
- compatible = "rk818-battery";
+ compatible = "rockchip,rk818-battery";
ocv_table = <3400 3675 3689 3716 3740 3756 3768 3780
3793 3807 3827 3853 3896 3937 3974 4007 4066
4110 4161 4217 4308>;

View File

@ -1,294 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Sun, 7 Nov 2021 19:39:20 +0100
Subject: [PATCH 15/18] arm64: dts: rk3399-pinephone-pro: Full support for
Type-C port
Connect various devices to a extcon bridge. Fix some incorrectly
specified regulators. With this patch, this is now supported:
- PD charger / current limiting
- Alt-DisplayPort mode
- OTG - host/peripheral USB
- B1.2 detection
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 142 +++++++++++++++------
1 file changed, 103 insertions(+), 39 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 1b4eb26..f6eac416 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -12,8 +12,6 @@
#include "rk3399.dtsi"
#include "rk3399-opp.dtsi"
-#define WITHOUT_CDN_DP // TODO: everything works, but it is simpler to test mipi
-
/ {
model = "Pine64 PinePhonePro";
compatible = "pine64,pinephone-pro", "rockchip,rk3399";
@@ -50,6 +48,43 @@ button-down {
};
};
+ bat: battery {
+ compatible = "simple-battery";
+ voltage-min-design-microvolt = <3400000>;
+ voltage-max-design-microvolt = <4350000>;
+ energy-full-design-microwatt-hours = <11400000>;
+ charge-full-design-microamp-hours = <3000000>;
+ precharge-current-microamp = <120000>;
+ charge-term-current-microamp = <150000>;
+ constant-charge-current-max-microamp = <1500000>;
+ constant-charge-voltage-max-microvolt = <4350000>;
+ factory-internal-resistance-micro-ohms = <150000>;
+ resistance-temp-table = <20 150>;
+ ocv-capacity-celsius = <20>;
+ ocv-capacity-table-0 =
+ <4308000 100>,
+ <4217000 95>,
+ <4161000 90>,
+ <4110000 85>,
+ <4066000 80>,
+ <4007000 75>,
+ <3974000 70>,
+ <3937000 65>,
+ <3896000 60>,
+ <3853000 55>,
+ <3827000 50>,
+ <3807000 45>,
+ <3793000 40>,
+ <3780000 35>,
+ <3768000 30>,
+ <3756000 25>,
+ <3740000 20>,
+ <3716000 15>,
+ <3689000 10>,
+ <3675000 5>,
+ <3400000 0>;
+ };
+
cluster1_opp_ppp: opp-table1b {
compatible = "operating-points-v2";
opp-shared;
@@ -168,25 +203,35 @@ vcc5v0_sys: vcc5v0-host-regulator {
regulator-max-microvolt = <5000000>;
regulator-always-on;
regulator-boot-on;
- vin-supply = <&vcc_sysin>;
+ vin-supply = <&boost_otg>;
regulator-state-mem {
regulator-on-in-suspend;
};
};
+ /*
+ * This is not a regulator, but GPIO0_A6 is used to disable
+ * VCC_SYS -> VBAT+ switch that helps boost that power path's
+ * current carrying capacity.
+ *
+ * GPIO0_A6 high: path is disabled no matter what
+ * GPIO0_A6 low: path is enabled if there's 5V voltage on
+ * VBUS_TYPEC
+ *
+ * GPIO0_A6 must be high when the phone is providing VBUS_TYPEC
+ * power.
+ */
vcc5v0_typec: vcc5v0-typec-regulator {
compatible = "regulator-fixed";
- //enable-active-high;
+ enable-active-high;
gpio = <&gpio0 RK_PA6 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&vcc5v0_typec_en>;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-name = "vcc5v0_typec";
- vin-supply = <&vcc5v0_sys>;
- regulator-always-on;
- regulator-boot-on;
+ vin-supply = <&boost_otg>;
regulator-state-mem {
regulator-on-in-suspend;
@@ -257,6 +302,14 @@ vcca1v8_s3: vcc1v8-s3 {
regulator-always-on;
regulator-boot-on;
};
+
+ typec_extcon_bridge: typec-extcon {
+ compatible = "linux,typec-extcon-bridge";
+ usb-role-switch;
+ orientation-switch;
+ mode-switch;
+ svid = /bits/ 16 <0xff01>;
+ };
};
&cpu_l0 {
@@ -285,12 +338,11 @@ &cpu_b1 {
operating-points-v2 = <&cluster1_opp_ppp>;
};
-#ifndef WITHOUT_CDN_DP
&cdn_dp {
status = "okay";
- extcon = <&fusb0>;
+ extcon = <&typec_extcon_bridge>;
+ phys = <&tcphy0_dp>;
};
-#endif
&emmc_phy {
status = "okay";
@@ -318,7 +370,6 @@ rk818: pmic@1c {
pinctrl-0 = <&pmic_int_l>;
rockchip,system-power-controller;
wakeup-source;
- extcon = <&fusb0>;
vcc1-supply = <&vcc_sysin>;
vcc2-supply = <&vcc_sysin>;
@@ -328,6 +379,7 @@ rk818: pmic@1c {
vcc7-supply = <&vcc3v3_sys>;
vcc8-supply = <&vcc_sysin>;
vcc9-supply = <&vcc3v3_sys>;
+ usb-supply = <&vcc5v0_typec>;
regulators {
vdd_cpu_l: DCDC_REG1 {
@@ -497,13 +549,13 @@ regulator-state-mem {
otg_switch: OTG_SWITCH {
regulator-name = "otg_switch";
- // TODO: This requires a proper rk818-charger implementation
- // without this always-on the type-c is not powered on
- //regulator-always-on;
- //regulator-boot-on;
};
};
+ /*
+ * XXX: Backported BSP stuff, drop this. Use standard
+ * "monitored-battery" property.
+ */
battery {
compatible = "rockchip,rk818-battery";
ocv_table = <3400 3675 3689 3716 3740 3756 3768 3780
@@ -528,6 +580,12 @@ battery {
power_dc2otg = <0>;
otg5v_suspend_enable = <1>;
};
+
+ charger {
+ compatible = "rockchip,rk818-charger";
+ power-supplies = <&fusb0>;
+ monitored-battery = <&bat>;
+ };
};
vdd_cpu_b: regulator@40 {
@@ -697,7 +755,9 @@ fusb0: typec-portc@22 {
interrupts = <RK_PA2 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&fusb0_int>;
- vbus-supply = <&vcc5v0_typec>;
+ extcon = <&typec_extcon_bridge>;
+ usb-role-switch = <&typec_extcon_bridge>;
+ vbus-supply = <&otg_switch>;
connector {
compatible = "usb-c-connector";
@@ -705,12 +765,18 @@ connector {
label = "USB-C";
op-sink-microwatt = <2500000>;
power-role = "dual";
- sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
- source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM)>;
+ sink-pdos = <PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+ source-pdos = <PDO_FIXED(5000, 900, PDO_FIXED_USB_COMM | PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
try-power-role = "sink";
+ mode-switch = <&typec_extcon_bridge>;
+ orientation-switch = <&typec_extcon_bridge>;
- extcon-cables = <1 2 5 6 9 10 12 44>;
- typec-altmodes = <0xff01 1 0x001c0c00 1>;
+ altmodes {
+ dp {
+ svid = <0xff01>;
+ vdo = <0x0c0046>;
+ };
+ };
ports {
#address-cells = <1>;
@@ -1035,7 +1101,7 @@ &sdhci {
};
&tcphy0 {
- extcon = <&fusb0>;
+ extcon = <&typec_extcon_bridge>;
status = "okay";
};
@@ -1065,15 +1131,7 @@ &tsadc {
&u2phy0 {
status = "okay";
-
- u2phy0_otg: otg-port {
- status = "okay";
- };
-
- u2phy0_host: host-port {
- status = "okay";
- phy-supply = <&vcc5v0_sys>;
- };
+ extcon = <&typec_extcon_bridge>;
port {
u2phy0_typec_hs: endpoint {
@@ -1082,17 +1140,22 @@ u2phy0_typec_hs: endpoint {
};
};
-&u2phy1 {
+&u2phy0_otg {
status = "okay";
+};
- u2phy1_otg: otg-port {
- status = "okay";
- };
+&u2phy0_host {
+ status = "okay";
+ phy-supply = <&vcc5v0_sys>;
+};
- u2phy1_host: host-port {
- status = "okay";
- phy-supply = <&vcc5v0_sys>;
- };
+&u2phy1 {
+ status = "okay";
+};
+
+&u2phy1_host {
+ status = "okay";
+ phy-supply = <&vcc5v0_sys>;
};
&uart0 {
@@ -1141,7 +1204,8 @@ &usbdrd3_0 {
};
&usbdrd_dwc3_0 {
- dr_mode = "peripheral";
+ dr_mode = "otg";
+ extcon = <&typec_extcon_bridge>;
status = "okay";
};

View File

@ -1,37 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Mon, 15 Nov 2021 23:52:40 +0100
Subject: [PATCH 16/18] arm64: dts: rk3399-pinephone-pro: Use DCLK_VOP*_FRAC
to achieve precise rates
By setting parents of DCLK_VOP1_DIV to frac/cpll we can achieve
various clock rates needed by display engine precisely.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index f6eac416..4603788 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -1211,6 +1211,9 @@ &usbdrd_dwc3_0 {
&vopb {
status = "okay";
+ assigned-clocks = <&cru DCLK_VOP0_DIV>, <&cru DCLK_VOP0>, <&cru ACLK_VOP0>, <&cru HCLK_VOP0>;
+ assigned-clock-rates = <0>, <0>, <400000000>, <100000000>;
+ assigned-clock-parents = <&cru PLL_CPLL>, <&cru DCLK_VOP0_FRAC>;
};
&vopb_mmu {
@@ -1219,6 +1222,9 @@ &vopb_mmu {
&vopl {
status = "okay";
+ assigned-clocks = <&cru DCLK_VOP1_DIV>, <&cru DCLK_VOP1>, <&cru ACLK_VOP1>, <&cru HCLK_VOP1>;
+ assigned-clock-rates = <0>, <0>, <400000000>, <100000000>;
+ assigned-clock-parents = <&cru PLL_CPLL>, <&cru DCLK_VOP1_FRAC>;
};
&vopl_mmu {

View File

@ -1,78 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Tue, 23 Nov 2021 23:26:26 +0100
Subject: [PATCH 17/18] arm64: dts: rk3399-pinephone-pro: Add support for
powering up the modem
Pinephone Pro has the same modem that's already supported by modem-power.
Add support for it do DT.
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 40 ++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 4603788..65cb701 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -253,6 +253,32 @@ regulator-state-mem {
};
};
+ vcc_4g_5v: vcc-4g-5v {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc_4g_5v_en>;
+ regulator-name = "vcc_4g_5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ vin-supply = <&vcc5v0_sys>;
+ regulator-always-on;
+ };
+
+ vcc_4g: vcc-4g {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio4 RK_PC7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc_4g_en>;
+ regulator-name = "vcc_4g";
+ regulator-min-microvolt = <3800000>;
+ regulator-max-microvolt = <3800000>;
+ vin-supply = <&vcc_sysin>;
+ regulator-always-on;
+ };
+
vcc1v8_codec: vcc1v8-codec-regulator {
compatible = "regulator-fixed";
enable-active-high;
@@ -935,6 +961,10 @@ mipi_in_panel: endpoint {
};
};
+&uart3 {
+ status = "okay";
+};
+
&pmu_io_domains {
pmu1830-supply = <&vcc_1v8>;
status = "okay";
@@ -995,6 +1025,16 @@ blue_led_pin: blue-led-pin {
};
};
+ modem {
+ vcc_4g_5v_en: vcc-4g-5v-en-pin {
+ rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ vcc_4g_en: vcc-4g-en-pin {
+ rockchip,pins = <4 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
pmic {
pmic_int_l: pmic-int-l {
rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>;

View File

@ -1,139 +0,0 @@
From: Ondrej Jirman <megous@megous.com>
Date: Wed, 24 Nov 2021 01:58:45 +0100
Subject: [PATCH 18/18] arm64: dts: rk3399-pinephone-pro: Add audio support
The codec is complicated, good luck! :D
Signed-off-by: Ondrej Jirman <megous@megous.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 96 ++++++++++++++++++++++
1 file changed, 96 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 65cb701..4afed92 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -168,6 +168,69 @@ power {
};
};
+ // in1 - digital mic daughhterboard
+ // in2 - headset mic
+ // in3 - modem output (muxed with mono)
+ // spol - earphone
+ // hpo - heaphones
+ // lout - modem input
+ // spaker - amp enabled by SPK_CTL_H
+ //
+ // mclk - GPIO4_A0/I2S_CLK
+ //
+ // some gpio-jack-detection driver?
+ //pinctrl-0 = <&hp_det>; // GPIO4_D4
+
+ rt5640-sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "rockchip,rt5640-codec";
+ simple-audio-card,aux-devs = <&speaker_amp>;
+ simple-audio-card,format = "i2s";
+ simple-audio-card,mclk-fs = <256>;
+
+ simple-audio-card,widgets =
+ "Microphone", "Headset Microphone",
+ "Microphone", "Internal Microphone",
+ "Headphone", "Headphone Jack",
+ "Speaker", "Internal Earpiece",
+ "Speaker", "Internal Speaker",
+ "Line", "Line In Modem",
+ "Line", "Line Out Modem";
+
+ simple-audio-card,routing =
+ "Headphone Jack", "HPOL",
+ "Headphone Jack", "HPOR",
+ "Internal Earpiece", "SPOLP",
+ "Internal Earpiece", "SPOLN",
+ "Internal Speaker", "Speaker Amp OUTL",
+ "Internal Speaker", "Speaker Amp OUTR",
+ "Speaker Amp INL", "HPOL",
+ "Speaker Amp INR", "HPOR",
+ "DMIC1", "Internal Microphone",
+ "Headset Microphone", "MICBIAS1",
+ "IN2P", "Headset Microphone",
+ "Line Out Modem", "LOUTL",
+ "Line Out Modem", "LOUTR",
+ "IN3P", "Line In Modem",
+ "IN3N", "Line In Modem";
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s0>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&rt5640>;
+ };
+ };
+
+ speaker_amp: audio-amplifier {
+ compatible = "simple-audio-amplifier";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spk_en>;
+ enable-gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>;
+ sound-name-prefix = "Speaker Amp";
+ };
+
sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&rk818 1>;
@@ -737,6 +800,24 @@ ucam_out: endpoint {
};
};
};
+
+ // XXX: modem codec supplies:
+ // - vcc1v8_codec
+ // - vcca3v0_codec
+
+ // supplies: (always on currently)
+ // - vcca3v0_codec
+ // - vcca1v8_codec
+ // - vcc5v0_sys - spk_vcc
+ rt5640: rt5640@1c {
+ compatible = "realtek,rt5640";
+ reg = <0x1c>;
+ clocks = <&cru SCLK_I2S_8CH_OUT>;
+ clock-names = "mclk";
+ realtek,dmic1-data-pin = <1>;
+ realtek,in3-differential;
+ #sound-dai-cells = <0>;
+ };
};
&i2c3 {
@@ -874,6 +955,13 @@ ak09911: compass@c {
};
};
+&i2s0 {
+ rockchip,playback-channels = <2>;
+ rockchip,capture-channels = <2>;
+ pinctrl-0 = <&i2s0_2ch_bus>;
+ status = "okay";
+};
+
&io_domains {
status = "okay";
@@ -1086,6 +1174,14 @@ sound {
vcc1v8_codec_en: vcc1v8-codec-en {
rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_down>;
};
+
+ hp_det: hp-det {
+ rockchip,pins = <4 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ spk_en: spk-en {
+ rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
};
};

View File

@ -1,105 +0,0 @@
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Date: Wed, 1 Dec 2021 20:48:51 +0100
Subject: arm64: dts: rk3399-pinephone-pro: Add flash and fix leds
The PinePhone Pro has a similar device to the SGM3140 used in the OG
PinePhone. This commit adds the corresponding device-tree node so the
flash/torch can work on this device.
Moreover, existing LEDs use different names and functions than what
we're used to, change them all to the same names we use on the OG
PinePhone.
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 47 +++++++++++++---------
1 file changed, 28 insertions(+), 19 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index 4afed92..e305955 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -127,30 +127,22 @@ leds {
pinctrl-names = "default";
pinctrl-0 = <&red_led_pin &green_led_pin &blue_led_pin>;
- led-standby {
+ led-red {
color = <LED_COLOR_ID_RED>;
- default-state = "off";
- function = LED_FUNCTION_STANDBY;
+ function = LED_FUNCTION_INDICATOR;
gpios = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
- label = "red:standby";
- panic-indicator;
- retain-state-suspended;
};
- led-pwr {
+ led-green {
color = <LED_COLOR_ID_GREEN>;
- default-state = "on";
- function = LED_FUNCTION_POWER;
+ function = LED_FUNCTION_INDICATOR;
gpios = <&gpio4 RK_PD5 GPIO_ACTIVE_HIGH>;
- label = "green:disk-activity";
};
- blue-charging {
+ led-blue {
color = <LED_COLOR_ID_BLUE>;
- default-state = "off";
- function = LED_FUNCTION_CHARGING;
- gpios = <&gpio0 RK_PD6 GPIO_ACTIVE_HIGH>;
- label = "blue:charging";
+ function = LED_FUNCTION_INDICATOR;
+ gpios = <&gpio4 RK_PD6 GPIO_ACTIVE_HIGH>;
};
};
@@ -399,6 +391,21 @@ typec_extcon_bridge: typec-extcon {
mode-switch;
svid = /bits/ 16 <0xff01>;
};
+
+ sgm3140: led-controller {
+ compatible = "sgmicro,sgm3140";
+ vin-supply = <&vcc3v3_sys>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&flash_pins>;
+ enable-gpios = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>;
+ flash-gpios = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
+
+ sgm3140_flash: led {
+ function = LED_FUNCTION_FLASH;
+ color = <LED_COLOR_ID_WHITE>;
+ flash-max-timeout-us = <250000>;
+ };
+ };
};
&cpu_l0 {
@@ -1111,6 +1118,12 @@ green_led_pin: green-led-pin {
blue_led_pin: blue-led-pin {
rockchip,pins = <4 RK_PD6 RK_FUNC_GPIO &pcfg_pull_none>;
};
+
+ flash_pins: flash-pins {
+ rockchip,pins =
+ <1 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>,
+ <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
};
modem {
@@ -1189,10 +1202,6 @@ &pwm0 {
status = "okay";
};
-&pwm1 {
- status = "okay";
-};
-
&pwm2 {
status = "okay";
};

View File

@ -1,48 +0,0 @@
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Date: Wed, 8 Dec 2021 23:43:08 +0100
Subject: arm64: dts: rk3399-pinephone-pro: add modem RI pin
Taht way the modem can wake the phone on incoming calls/messages.
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
---
arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index e305955..ef5a58c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -160,6 +160,21 @@ power {
};
};
+ gpio-key-ri {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&ri_pin>;
+
+ ring_indicator: ring-indicator {
+ label = "ring-indicator";
+ linux,can-disable;
+ linux,code = <KEY_WAKEUP>;
+ gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_LOW>;
+ wakeup-event-action = <EV_ACT_ASSERTED>;
+ wakeup-source;
+ };
+ };
+
// in1 - digital mic daughhterboard
// in2 - headset mic
// in3 - modem output (muxed with mono)
@@ -1127,6 +1142,10 @@ flash_pins: flash-pins {
};
modem {
+ ri_pin: ri-pin {
+ rockchip,pins = <0 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+
vcc_4g_5v_en: vcc-4g-5v-en-pin {
rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>;
};

View File

@ -1,90 +0,0 @@
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Date: Thu, 9 Dec 2021 16:52:29 +0100
Subject: arm64: dts: rk3399-pinephone-pro: improve sound device definition
This commit renames the sound card and the "Headphone" widget so they
match the names used by the ALSA UCM profiles.
It also adds a jack detection GPIO to the sound card definition, and
creates a new set of ADC keys for handling headset buttons.
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 41 ++++++++++++++++++----
1 file changed, 34 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index ef5a58c..e46f36f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -48,6 +48,32 @@ button-down {
};
};
+ headset-keys {
+ compatible = "adc-keys";
+ io-channels = <&saradc 2>;
+ io-channel-names = "buttons";
+ keyup-threshold-microvolt = <900000>;
+ poll-interval = <100>;
+
+ headset-play {
+ label = "Play";
+ linux,code = <KEY_PLAYPAUSE>;
+ press-threshold-microvolt = <650000>;
+ };
+
+ headset-up {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ press-threshold-microvolt = <750000>;
+ };
+
+ headset-down {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ press-threshold-microvolt = <850000>;
+ };
+ };
+
bat: battery {
compatible = "simple-battery";
voltage-min-design-microvolt = <3400000>;
@@ -184,29 +210,30 @@ ring_indicator: ring-indicator {
// spaker - amp enabled by SPK_CTL_H
//
// mclk - GPIO4_A0/I2S_CLK
- //
- // some gpio-jack-detection driver?
- //pinctrl-0 = <&hp_det>; // GPIO4_D4
rt5640-sound {
compatible = "simple-audio-card";
- simple-audio-card,name = "rockchip,rt5640-codec";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hp_det>;
+ simple-audio-card,name = "PinePhonePro";
simple-audio-card,aux-devs = <&speaker_amp>;
simple-audio-card,format = "i2s";
simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,hp-det-gpio = <&gpio4 RK_PD4 GPIO_ACTIVE_LOW>;
+ simple-audio-card,pin-switches = "Internal Speaker";
simple-audio-card,widgets =
"Microphone", "Headset Microphone",
"Microphone", "Internal Microphone",
- "Headphone", "Headphone Jack",
+ "Headphone", "Headphones",
"Speaker", "Internal Earpiece",
"Speaker", "Internal Speaker",
"Line", "Line In Modem",
"Line", "Line Out Modem";
simple-audio-card,routing =
- "Headphone Jack", "HPOL",
- "Headphone Jack", "HPOR",
+ "Headphones", "HPOL",
+ "Headphones", "HPOR",
"Internal Earpiece", "SPOLP",
"Internal Earpiece", "SPOLN",
"Internal Speaker", "Speaker Amp OUTL",

View File

@ -22,70 +22,7 @@ SRC_URI="${KERNEL_URI} ${MEGI_PATCH_URI} -> all-${PV}.patch"
PATCHES=( PATCHES=(
${DISTDIR}/all-${PV}.patch ${DISTDIR}/all-${PV}.patch
${FILESDIR}/0001-base-property-Swap-order-of-search-for-connection-to.patch
${FILESDIR}/0002-sdhci-arasan-Add-runtime-PM-support.patch
${FILESDIR}/0003-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch
${FILESDIR}/0004-media-rockchip-rga-Fix-probe-bugs.patch
${FILESDIR}/0005-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch
${FILESDIR}/0006-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch
${FILESDIR}/0007-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch
${FILESDIR}/0008-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch
${FILESDIR}/0009-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch
${FILESDIR}/0010-video-fbdev-Add-events-for-early-fb-event-support.patch
${FILESDIR}/0011-power-rk818-Configure-rk808-clkout2-function.patch
${FILESDIR}/0012-power-rk818-battery-Add-battery-driver-for-RK818.patch
${FILESDIR}/0013-power-supply-rk818-battery-Use-a-more-propper-compat.patch
${FILESDIR}/0014-power-supply-core-Don-t-ignore-max_current-of-0-when.patch
${FILESDIR}/0015-power-supply-rk818-charger-Implement-charger-driver-.patch
${FILESDIR}/0016-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch
${FILESDIR}/0017-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch
${FILESDIR}/0018-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch
${FILESDIR}/0019-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch
${FILESDIR}/0020-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch
${FILESDIR}/0021-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch
${FILESDIR}/0022-usb-typec-fusb302-Add-OF-extcon-support.patch
${FILESDIR}/0023-usb-typec-fusb302-Fix-register-definitions.patch
${FILESDIR}/0024-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch
${FILESDIR}/0025-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch
${FILESDIR}/0026-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch
${FILESDIR}/0027-media-i2c-imx258-Add-support-for-powerdown-gpio.patch
${FILESDIR}/0028-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch
${FILESDIR}/0029-media-i2c-imx258-Add-support-for-reset-gpio.patch
${FILESDIR}/0030-media-i2c-imx258-Add-support-for-power-supplies.patch
${FILESDIR}/0031-media-ov5640-Add-more-framerates-to-the-driver-some-.patch
${FILESDIR}/0032-media-ov5640-Experiment-Try-to-disable-denoising-sha.patch
${FILESDIR}/0033-media-ov5640-Sleep-after-poweroff-to-ensure-next-pow.patch
${FILESDIR}/0034-media-ov5640-Don-t-powerup-the-sensor-during-driver-.patch
${FILESDIR}/0035-media-ov5640-Implement-autofocus.patch
${FILESDIR}/0036-media-ov5640-set-default-ae-target-lower.patch
${FILESDIR}/0037-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch
${FILESDIR}/0038-drm-panel-hx8394-Improve-the-panel-driver-make-it-wo.patch
${FILESDIR}/0039-drm-panel-hx8394-Fix-mode-clock-for-the-pinephone-pr.patch
${FILESDIR}/0040-input-goodix-Add-option-to-power-off-the-controller-.patch
${FILESDIR}/0041-input-goodix-Don-t-disable-regulators-during-suspend.patch
${FILESDIR}/0042-input-touchscreen-goodix-Respect-IRQ-flags-from-DT-w.patch
${FILESDIR}/0043-input-touchscreen-goodix-Add-support-for-GT1158.patch
${FILESDIR}/0044-arm64-dts-rk3399-pinephone-pro-Add-support-for-Pinep.patch
${FILESDIR}/0045-arm64-dts-rk3399-pinephone-pro-Fixup-DT-validation-i.patch
${FILESDIR}/0046-arm64-dts-rk3399-pinephone-pro-Make-charging-and-per.patch
${FILESDIR}/0047-arm64-dts-rk3399-pinephone-pro-Fix-goodix-toucscreen.patch
${FILESDIR}/0048-arm64-dts-rk3399-pinephone-pro-Correct-the-pmu1830-i.patch
${FILESDIR}/0049-arm64-dts-rk3399-pinephone-pro-Power-off-goodix-touc.patch
${FILESDIR}/0050-arm64-dts-rk3399-pinephone-pro-Add-support-for-both-.patch
${FILESDIR}/0051-arm64-dts-rk3399-pinephone-pro-Fix-SD-card-power-sup.patch
${FILESDIR}/0052-arm64-dts-rk3399-pinephone-pro-Correct-the-battery-s.patch
${FILESDIR}/0053-arm64-dts-rk3399-pinephone-pro-Cleanup-some-USB-node.patch
${FILESDIR}/0054-arm64-dts-rk3399-pinephone-pro-Fix-PDOs-to-be-more-r.patch
${FILESDIR}/0055-arm64-dts-rk3399-pinephone-pro-Add-chassis-type-hand.patch
${FILESDIR}/0056-arm64-dts-rk3399-pinephone-pro-Add-mmc-aliases-to-ge.patch
${FILESDIR}/0057-arm64-dts-rk3399-pinephone-pro-Use-a-new-rk818-batte.patch
${FILESDIR}/0058-arm64-dts-rk3399-pinephone-pro-Full-support-for-Type.patch
${FILESDIR}/0059-arm64-dts-rk3399-pinephone-pro-Use-DCLK_VOP-_FRAC-to.patch
${FILESDIR}/0060-arm64-dts-rk3399-pinephone-pro-Add-support-for-power.patch
${FILESDIR}/0061-arm64-dts-rk3399-pinephone-pro-Add-audio-support.patch
${FILESDIR}/0062-arm64-dts-rk3399-pinephone-pro-Add-flash-and-fix-led.patch
${FILESDIR}/0063-arm64-dts-rk3399-pinephone-pro-add-modem-RI-pin.patch
${FILESDIR}/0064-arm64-dts-rk3399-pinephone-pro-improve-sound-device.patch
# Pinephone Keyboard # Pinephone Keyboard
${FILESDIR}/d1d849cae12db71aa81ceedaedc1b17a34790367.patch ${FILESDIR}/d1d849cae12db71aa81ceedaedc1b17a34790367.patch
${FILESDIR}/2423aac2d6f5db55da99e11fd799ee66fe6f54c6.patch ${FILESDIR}/2423aac2d6f5db55da99e11fd799ee66fe6f54c6.patch