Changed ebuild

This commit is contained in:
Gerben Jan Dijkman 2022-01-15 02:12:55 +01:00
parent b5076efe59
commit 4b1427b69b
65 changed files with 10579 additions and 289 deletions

View File

@ -1,38 +1,14 @@
### Generic CI Template for chrootbuild
#
#
# Usage: chrootbuild [options]
#
# -b <branch> Branch to use:
# (unstable/testing/stable-staging/stable;
# arm-unstable/arm-testing/arm-stable)
# default: unstable / arm-unstable
# -c Start with clean chroot fs
# -h This help
# -i <pkg> Install package(s) to chroot fs
# (for multiple packages repeat -i flag)
# -l <list> List(s) to build
# (for multiple lists repeat -l flag)
# -n Install built pkg to chroot fs
# -p <pkg> Package(s) to build
# (for multiple packages repeat -p flag)
# -r Remove previously built packages in $PKGDEST
# -s Sign package(s)
build-package: build-package:
tags: tags:
# change the tag to your gitlab-runner
- bigbuilds - bigbuilds
- aarch64 - aarch64
- fosshost - fosshost
- xlarge - xlarge
script: script:
# build pkg via chrootbuild
- export PKG=${PWD##*/} - export PKG=${PWD##*/}
- cd .. - cd ..
- sudo chrootbuild -b arm-unstable -cp $PKG - sudo chrootbuild -b arm-unstable -cp $PKG
- mv -v ./*.pkg.tar.* $PKG - mv -v ./*.pkg.tar.* $PKG
#- sudo pacman -Syy && makepkg -scr --noconfirm
artifacts: artifacts:
paths: paths:
- ./*.pkg.tar.* - ./*.pkg.tar.*

View File

@ -0,0 +1,35 @@
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

@ -0,0 +1,37 @@
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

@ -0,0 +1,39 @@
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

@ -0,0 +1,34 @@
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

@ -0,0 +1,48 @@
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

@ -0,0 +1,145 @@
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

@ -0,0 +1,28 @@
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

@ -0,0 +1,23 @@
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

@ -0,0 +1,69 @@
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 0fa7ede..71d9d4a 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 3da9584..5ac24d0 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

@ -0,0 +1,40 @@
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

@ -0,0 +1,46 @@
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

@ -0,0 +1,85 @@
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 6093754..1c5be0d 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

@ -0,0 +1,699 @@
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..097f30b
--- /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_MAINS,
+ .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

@ -0,0 +1,47 @@
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

@ -0,0 +1,108 @@
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

@ -0,0 +1,72 @@
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

@ -0,0 +1,186 @@
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

@ -0,0 +1,39 @@
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

@ -0,0 +1,160 @@
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

@ -0,0 +1,34 @@
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

@ -0,0 +1,45 @@
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

@ -0,0 +1,37 @@
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

@ -0,0 +1,388 @@
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

@ -0,0 +1,64 @@
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

@ -0,0 +1,56 @@
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

@ -0,0 +1,41 @@
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

@ -0,0 +1,57 @@
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

@ -0,0 +1,100 @@
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

@ -0,0 +1,464 @@
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

@ -0,0 +1,226 @@
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

@ -0,0 +1,29 @@
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

@ -0,0 +1,97 @@
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 aaa3c45..81a9bca 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1154,6 +1154,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;
@@ -1173,6 +1174,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)
@@ -1282,6 +1284,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);
@@ -1327,6 +1338,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 02065d1..e265695 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -102,6 +102,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

@ -0,0 +1,49 @@
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 81a9bca..06cdb78 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1288,8 +1288,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;
}
@@ -1339,18 +1337,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

@ -0,0 +1,53 @@
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 06cdb78..d087fc9 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -401,9 +401,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)
@@ -1170,6 +1174,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 e265695..8aaec23 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

@ -0,0 +1,23 @@
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 d087fc9..fbefdc1 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

@ -0,0 +1,101 @@
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

@ -0,0 +1,34 @@
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

@ -0,0 +1,30 @@
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

@ -0,0 +1,26 @@
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

@ -0,0 +1,25 @@
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

@ -0,0 +1,198 @@
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..3bd36ef 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_PD4 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_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ ucam_pdn: ucam-pdn {
+ rockchip,pins = <2 RK_PB4 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

@ -0,0 +1,71 @@
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 3bd36ef..3e6fde7 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

@ -0,0 +1,44 @@
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 3e6fde7..1bd4304 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

@ -0,0 +1,32 @@
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 1bd4304..31840a9 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

@ -0,0 +1,33 @@
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 31840a9..0cc6391e 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

@ -0,0 +1,24 @@
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 0cc6391e..7e52219 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

@ -0,0 +1,29 @@
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 7e52219..4589433c3 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

@ -0,0 +1,23 @@
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 4589433c3..40a9fb8 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

@ -0,0 +1,294 @@
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 40a9fb8..69a9cd4 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

@ -0,0 +1,37 @@
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 69a9cd4..680eb49 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

@ -0,0 +1,78 @@
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 680eb49..88601c9 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

@ -0,0 +1,139 @@
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 88601c9..b2709ae 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

@ -0,0 +1,105 @@
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 b2709ae..de07518 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

@ -0,0 +1,48 @@
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 de07518..91687f6 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

@ -0,0 +1,90 @@
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 91687f6..b63a153 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

@ -0,0 +1,91 @@
From: Arnaud Ferraris <arnaud.ferraris@gmail.com>
Date: Mon, 3 Jan 2022 19:38:36 +0100
Subject: arm64: dts: rk3399-pinephone-pro: remove front camera nodes
We don't have a driver for it yet.
Signed-off-by: Arnaud Ferraris <arnaud.ferraris@gmail.com>
---
.../boot/dts/rockchip/rk3399-pinephone-pro.dts | 51 ----------------------
1 file changed, 51 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
index b63a153..8c9661a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -825,31 +825,6 @@ wcam_out: endpoint {
};
};
- /* 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>;
- };
- };
- };
-
// XXX: modem codec supplies:
// - vcc1v8_codec
// - vcca3v0_codec
@@ -1038,32 +1013,10 @@ &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;
@@ -1136,10 +1089,6 @@ wcam_rst: wcam-rst {
wcam_pdn: wcam-pdn {
rockchip,pins = <2 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>;
};
-
- ucam_pdn: ucam-pdn {
- rockchip,pins = <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
- };
};
fusb302x {

View File

@ -1,172 +0,0 @@
From 2423aac2d6f5db55da99e11fd799ee66fe6f54c6 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Mon, 9 Aug 2021 19:30:18 -0500
Subject: [PATCH] Input: kb151 - Add support for the FN layer
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
.../dts/allwinner/sun50i-a64-pinephone.dtsi | 34 +++++++++++++++++--
drivers/input/keyboard/kb151.c | 33 ++++++++++--------
2 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
index 0bdc6eceec6099..68f5730cf164c7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
@@ -557,7 +557,7 @@
reg = <0x15>;
interrupt-parent = <&r_pio>;
interrupts = <0 12 IRQ_TYPE_EDGE_FALLING>; /* PL12 */
- keypad,num-rows = <6>;
+ keypad,num-rows = <12>;
keypad,num-columns = <12>;
linux,keymap = <MATRIX_KEY(0, 0, KEY_ESC)
MATRIX_KEY(0, 1, KEY_1)
@@ -612,7 +612,37 @@
MATRIX_KEY(4, 9, KEY_LEFTBRACE)
MATRIX_KEY(5, 2, KEY_FN)
MATRIX_KEY(5, 3, KEY_LEFTALT)
- MATRIX_KEY(5, 5, KEY_RIGHTALT)>;
+ MATRIX_KEY(5, 5, KEY_RIGHTALT)
+
+ /* FN layer */
+ MATRIX_KEY(6, 1, KEY_BACKSLASH)
+ MATRIX_KEY(6, 2, KEY_BACKSLASH)
+ MATRIX_KEY(6, 3, KEY_DOLLAR)
+ MATRIX_KEY(6, 4, KEY_EURO)
+ MATRIX_KEY(6, 5, KEY_GRAVE)
+ MATRIX_KEY(6, 6, KEY_GRAVE)
+ MATRIX_KEY(6, 7, KEY_MINUS)
+ MATRIX_KEY(6, 8, KEY_EQUAL)
+ MATRIX_KEY(6, 9, KEY_MINUS)
+ MATRIX_KEY(6, 10, KEY_EQUAL)
+ MATRIX_KEY(6, 11, KEY_DELETE)
+
+ MATRIX_KEY(8, 0, KEY_SYSRQ)
+ MATRIX_KEY(8, 10, KEY_INSERT)
+
+ MATRIX_KEY(9, 0, KEY_LEFTSHIFT)
+ MATRIX_KEY(9, 8, KEY_HOME)
+ MATRIX_KEY(9, 9, KEY_UP)
+ MATRIX_KEY(9, 10, KEY_END)
+
+ MATRIX_KEY(10, 1, KEY_LEFTCTRL)
+ MATRIX_KEY(10, 6, KEY_LEFT)
+ MATRIX_KEY(10, 8, KEY_RIGHT)
+ MATRIX_KEY(10, 9, KEY_DOWN)
+
+ MATRIX_KEY(11, 2, KEY_FN)
+ MATRIX_KEY(11, 3, KEY_LEFTALT)
+ MATRIX_KEY(11, 5, KEY_RIGHTALT)>;
wakeup-source;
};
};
diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c
index 595275d4f9d96f..bb6250efe93419 100644
--- a/drivers/input/keyboard/kb151.c
+++ b/drivers/input/keyboard/kb151.c
@@ -29,6 +29,7 @@ struct kb151 {
u8 row_shift;
u8 rows;
u8 cols;
+ u8 fn_state;
u8 buf_swap;
u8 buf[];
};
@@ -55,7 +56,7 @@ static void kb151_update(struct i2c_client *client)
return;
}
- dev_info(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ dev_dbg(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
new_buf[0], new_buf[1], new_buf[2], new_buf[3], new_buf[4], new_buf[5],
new_buf[6], new_buf[7], new_buf[8], new_buf[9], new_buf[10], new_buf[11],
new_buf[12]);
@@ -65,8 +66,6 @@ static void kb151_update(struct i2c_client *client)
crc, new_buf[0]);
return;
}
- dev_info(dev, "Good scan data (%02x == %02x)\n",
- crc, new_buf[0]);
for (col = 0; col < kb151->cols; ++col) {
u8 old = *(++old_buf);
@@ -74,14 +73,20 @@ static void kb151_update(struct i2c_client *client)
u8 changed = old ^ new;
for (row = 0; row < kb151->rows; ++row) {
- int code = MATRIX_SCAN_CODE(row, col, kb151->row_shift);
u8 pressed = new & BIT(row);
+ u8 map_row = row + (kb151->fn_state ? kb151->rows : 0);
+ int code = MATRIX_SCAN_CODE(map_row, col, kb151->row_shift);
if (!(changed & BIT(row)))
continue;
dev_dbg(&client->dev, "row %u col %u %sed\n",
- row, col, pressed ? "press" : "releas");
+ map_row, col, pressed ? "press" : "releas");
+ if (keymap[code] == KEY_FN) {
+ dev_dbg(&client->dev, "FN is now %s\n",
+ pressed ? "pressed" : "released");
+ kb151->fn_state = pressed;
+ } else
input_report_key(kb151->input, keymap[code], pressed);
}
}
@@ -151,7 +156,7 @@ static int kb151_probe(struct i2c_client *client)
struct device *dev = &client->dev;
u8 info[KB151_MATRIX_SIZE + 1];
unsigned int kb_rows, kb_cols;
- unsigned int rows, cols;
+ unsigned int map_rows, map_cols;
struct kb151 *kb151;
int ret;
@@ -168,20 +173,20 @@ static int kb151_probe(struct i2c_client *client)
info[KB151_FW_REVISION] & 0xf,
info[KB151_FW_FEATURES]);
- ret = matrix_keypad_parse_properties(dev, &rows, &cols);
+ ret = matrix_keypad_parse_properties(dev, &map_rows, &map_cols);
if (ret)
return ret;
kb_rows = info[KB151_MATRIX_SIZE] & 0xf;
kb_cols = info[KB151_MATRIX_SIZE] >> 4;
- if (rows > kb_rows || cols != kb_cols) {
+ if (map_rows != 2 * kb_rows || map_cols != kb_cols) {
dev_err(dev, "Keyboard matrix is %ux%u, but key map is %ux%u\n",
- kb_rows, kb_cols, rows, cols);
+ kb_rows, kb_cols, map_rows, map_cols);
return -EINVAL;
}
/* Allocate two buffers, and include space for the CRC. */
- kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (cols + 1)), GFP_KERNEL);
+ kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (kb_cols + 1)), GFP_KERNEL);
if (!kb151)
return -ENOMEM;
@@ -189,9 +194,9 @@ static int kb151_probe(struct i2c_client *client)
crc8_populate_msb(kb151->crc_table, KB151_CRC8_POLYNOMIAL);
- kb151->row_shift = get_count_order(cols);
- kb151->rows = rows;
- kb151->cols = cols;
+ kb151->row_shift = get_count_order(kb_cols);
+ kb151->rows = kb_rows;
+ kb151->cols = kb_cols;
kb151->input = devm_input_allocate_device(dev);
if (!kb151->input)
@@ -207,7 +212,7 @@ static int kb151_probe(struct i2c_client *client)
__set_bit(EV_REP, kb151->input->evbit);
- ret = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
+ ret = matrix_keypad_build_keymap(NULL, NULL, map_rows, map_cols,
NULL, kb151->input);
if (ret)
return dev_err_probe(dev, ret, "Failed to build keymap\n");

View File

@ -1,6 +1,6 @@
# #
# Automatically generated file; DO NOT EDIT. # Automatically generated file; DO NOT EDIT.
# Linux/arm64 5.16.0-2 Kernel Configuration # Linux/arm64 5.16.0-4 Kernel Configuration
# #
CONFIG_CC_VERSION_TEXT="gcc (GCC) 10.2.0" CONFIG_CC_VERSION_TEXT="gcc (GCC) 10.2.0"
CONFIG_CC_IS_GCC=y CONFIG_CC_IS_GCC=y
@ -26,7 +26,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_INIT_ENV_ARG_LIMIT=32
# CONFIG_COMPILE_TEST is not set # CONFIG_COMPILE_TEST is not set
# CONFIG_WERROR is not set # CONFIG_WERROR is not set
CONFIG_LOCALVERSION="-gentoo-arm64" CONFIG_LOCALVERSION="-MANJARO-ARM"
# CONFIG_LOCALVERSION_AUTO is not set # CONFIG_LOCALVERSION_AUTO is not set
CONFIG_BUILD_SALT="" CONFIG_BUILD_SALT=""
CONFIG_DEFAULT_INIT="" CONFIG_DEFAULT_INIT=""
@ -2147,7 +2147,7 @@ CONFIG_KEYBOARD_GPIO_POLLED=y
# CONFIG_KEYBOARD_TCA6416 is not set # CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_TCA8418 is not set # CONFIG_KEYBOARD_TCA8418 is not set
# CONFIG_KEYBOARD_MATRIX is not set # CONFIG_KEYBOARD_MATRIX is not set
# CONFIG_KEYBOARD_KB151 is not set CONFIG_KEYBOARD_KB151=y
# CONFIG_KEYBOARD_LM8323 is not set # CONFIG_KEYBOARD_LM8323 is not set
# CONFIG_KEYBOARD_LM8333 is not set # CONFIG_KEYBOARD_LM8333 is not set
# CONFIG_KEYBOARD_MAX7359 is not set # CONFIG_KEYBOARD_MAX7359 is not set
@ -3086,6 +3086,7 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set # CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_USERSPACE_CONSUMER_OF is not set
# CONFIG_REGULATOR_88PG86X is not set # CONFIG_REGULATOR_88PG86X is not set
# CONFIG_REGULATOR_ACT8865 is not set # CONFIG_REGULATOR_ACT8865 is not set
# CONFIG_REGULATOR_AD5398 is not set # CONFIG_REGULATOR_AD5398 is not set
@ -3156,6 +3157,7 @@ CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_VCTRL=m CONFIG_REGULATOR_VCTRL=m
# CONFIG_REGULATOR_VEXPRESS is not set # CONFIG_REGULATOR_VEXPRESS is not set
# CONFIG_REGULATOR_QCOM_LABIBB is not set # CONFIG_REGULATOR_QCOM_LABIBB is not set
# CONFIG_REGULATOR_TP65185X is not set
CONFIG_RC_CORE=m CONFIG_RC_CORE=m
# CONFIG_RC_MAP is not set # CONFIG_RC_MAP is not set
# CONFIG_LIRC is not set # CONFIG_LIRC is not set
@ -3472,6 +3474,8 @@ CONFIG_VIDEO_OV5640=y
# CONFIG_VIDEO_CCS is not set # CONFIG_VIDEO_CCS is not set
# CONFIG_VIDEO_ET8EK8 is not set # CONFIG_VIDEO_ET8EK8 is not set
# CONFIG_VIDEO_S5C73M3 is not set # CONFIG_VIDEO_S5C73M3 is not set
# CONFIG_VIDEO_HM5065 is not set
# CONFIG_VIDEO_GC2145 is not set
# end of Camera sensor devices # end of Camera sensor devices
# #
@ -3724,6 +3728,7 @@ CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_ARMCLCD=y CONFIG_FB_ARMCLCD=y
# CONFIG_FB_OPENCORES is not set # CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set # CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_SUN5I_EINK is not set
# CONFIG_FB_SMSCUFX is not set # CONFIG_FB_SMSCUFX is not set
CONFIG_FB_UDL=m CONFIG_FB_UDL=m
# CONFIG_FB_IBM_GXT4500 is not set # CONFIG_FB_IBM_GXT4500 is not set
@ -3944,6 +3949,7 @@ CONFIG_SND_SOC_BT_SCO=m
CONFIG_SND_SOC_DA7219=m CONFIG_SND_SOC_DA7219=m
CONFIG_SND_SOC_DMIC=m CONFIG_SND_SOC_DMIC=m
CONFIG_SND_SOC_HDMI_CODEC=m CONFIG_SND_SOC_HDMI_CODEC=m
# CONFIG_SND_SOC_EC25 is not set
# CONFIG_SND_SOC_ES7134 is not set # CONFIG_SND_SOC_ES7134 is not set
# CONFIG_SND_SOC_ES7241 is not set # CONFIG_SND_SOC_ES7241 is not set
CONFIG_SND_SOC_ES8316=m CONFIG_SND_SOC_ES8316=m
@ -4527,6 +4533,7 @@ CONFIG_TYPEC_FUSB302=y
CONFIG_TYPEC_UCSI=y CONFIG_TYPEC_UCSI=y
# CONFIG_UCSI_CCG is not set # CONFIG_UCSI_CCG is not set
# CONFIG_TYPEC_TPS6598X is not set # CONFIG_TYPEC_TPS6598X is not set
# CONFIG_TYPEC_ANX7688 is not set
# CONFIG_TYPEC_HD3SS3220 is not set # CONFIG_TYPEC_HD3SS3220 is not set
# CONFIG_TYPEC_STUSB160X is not set # CONFIG_TYPEC_STUSB160X is not set
CONFIG_TYPEC_EXTCON=y CONFIG_TYPEC_EXTCON=y
@ -4637,6 +4644,8 @@ CONFIG_LEDS_SYSCON=y
# CONFIG_LEDS_USER is not set # CONFIG_LEDS_USER is not set
# CONFIG_LEDS_SPI_BYTE is not set # CONFIG_LEDS_SPI_BYTE is not set
# CONFIG_LEDS_TI_LMU_COMMON is not set # CONFIG_LEDS_TI_LMU_COMMON is not set
CONFIG_LEDS_SGM3140=m
# CONFIG_LEDS_AXP20X is not set
# #
# Flash and Torch LED drivers # Flash and Torch LED drivers
@ -4647,7 +4656,6 @@ CONFIG_LEDS_SYSCON=y
# CONFIG_LEDS_LM3601X is not set # CONFIG_LEDS_LM3601X is not set
# CONFIG_LEDS_RT4505 is not set # CONFIG_LEDS_RT4505 is not set
# CONFIG_LEDS_RT8515 is not set # CONFIG_LEDS_RT8515 is not set
CONFIG_LEDS_SGM3140=m
# #
# LED Triggers # LED Triggers
@ -4978,6 +4986,7 @@ CONFIG_BCM_VIDEOCORE=y
# CONFIG_XIL_AXIS_FIFO is not set # CONFIG_XIL_AXIS_FIFO is not set
# CONFIG_FIELDBUS_DEV is not set # CONFIG_FIELDBUS_DEV is not set
# CONFIG_WFX is not set # CONFIG_WFX is not set
# CONFIG_RTL8723CS is not set
# CONFIG_GOLDFISH is not set # CONFIG_GOLDFISH is not set
CONFIG_CHROME_PLATFORMS=y CONFIG_CHROME_PLATFORMS=y
CONFIG_CROS_EC=y CONFIG_CROS_EC=y
@ -5760,6 +5769,7 @@ CONFIG_PHY_ROCKCHIP_INNO_HDMI=y
CONFIG_PHY_ROCKCHIP_INNO_USB2=y CONFIG_PHY_ROCKCHIP_INNO_USB2=y
CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY=y CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY=y
CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=y CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY=y
# CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY is not set
CONFIG_PHY_ROCKCHIP_PCIE=y CONFIG_PHY_ROCKCHIP_PCIE=y
CONFIG_PHY_ROCKCHIP_TYPEC=y CONFIG_PHY_ROCKCHIP_TYPEC=y
CONFIG_PHY_ROCKCHIP_USB=m CONFIG_PHY_ROCKCHIP_USB=m

View File

@ -0,0 +1,10 @@
# mkinitcpio preset file for the '%PKGBASE%' package
ALL_config="/etc/mkinitcpio.conf"
ALL_kver="%KERNVER%"
PRESETS=('default')
#default_config="/etc/mkinitcpio.conf"
default_image="/boot/initramfs-linux.img"
#default_options=""

View File

@ -16,7 +16,7 @@ Signed-off-by: Samuel Holland <samuel@sholland.org>
create mode 100644 drivers/input/keyboard/kb151.c create mode 100644 drivers/input/keyboard/kb151.c
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
index 4ede9fe66020c9..0bdc6eceec6099 100644 index 4ede9fe66020c..0bdc6eceec609 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
@@ -551,6 +551,70 @@ @@ -551,6 +551,70 @@
@ -91,7 +91,7 @@ index 4ede9fe66020c9..0bdc6eceec6099 100644
&i2s2 { &i2s2 {
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 40a070a2e7f5b7..0259e9133f4692 100644 index 40a070a2e7f5b..0259e9133f469 100644
--- a/drivers/input/keyboard/Kconfig --- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig
@@ -353,6 +353,16 @@ config KEYBOARD_HP7XX @@ -353,6 +353,16 @@ config KEYBOARD_HP7XX
@ -112,7 +112,7 @@ index 40a070a2e7f5b7..0259e9133f4692 100644
tristate "LM8323 keypad chip" tristate "LM8323 keypad chip"
depends on I2C depends on I2C
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 1d689fdd5c00f9..87fda7b961913a 100644 index 1d689fdd5c00f..87fda7b961913 100644
--- a/drivers/input/keyboard/Makefile --- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o @@ -33,6 +33,7 @@ obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
@ -125,7 +125,7 @@ index 1d689fdd5c00f9..87fda7b961913a 100644
obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o
diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c
new file mode 100644 new file mode 100644
index 00000000000000..595275d4f9d96f index 0000000000000..595275d4f9d96
--- /dev/null --- /dev/null
+++ b/drivers/input/keyboard/kb151.c +++ b/drivers/input/keyboard/kb151.c
@@ -0,0 +1,246 @@ @@ -0,0 +1,246 @@
@ -375,3 +375,175 @@ index 00000000000000..595275d4f9d96f
+MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>"); +MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
+MODULE_DESCRIPTION("Pine64 KB151 keyboard driver"); +MODULE_DESCRIPTION("Pine64 KB151 keyboard driver");
+MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL");
From 2423aac2d6f5db55da99e11fd799ee66fe6f54c6 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Mon, 9 Aug 2021 19:30:18 -0500
Subject: [PATCH] Input: kb151 - Add support for the FN layer
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
.../dts/allwinner/sun50i-a64-pinephone.dtsi | 34 +++++++++++++++++--
drivers/input/keyboard/kb151.c | 33 ++++++++++--------
2 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
index 0bdc6eceec609..68f5730cf164c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi
@@ -557,7 +557,7 @@
reg = <0x15>;
interrupt-parent = <&r_pio>;
interrupts = <0 12 IRQ_TYPE_EDGE_FALLING>; /* PL12 */
- keypad,num-rows = <6>;
+ keypad,num-rows = <12>;
keypad,num-columns = <12>;
linux,keymap = <MATRIX_KEY(0, 0, KEY_ESC)
MATRIX_KEY(0, 1, KEY_1)
@@ -612,7 +612,37 @@
MATRIX_KEY(4, 9, KEY_LEFTBRACE)
MATRIX_KEY(5, 2, KEY_FN)
MATRIX_KEY(5, 3, KEY_LEFTALT)
- MATRIX_KEY(5, 5, KEY_RIGHTALT)>;
+ MATRIX_KEY(5, 5, KEY_RIGHTALT)
+
+ /* FN layer */
+ MATRIX_KEY(6, 1, KEY_BACKSLASH)
+ MATRIX_KEY(6, 2, KEY_BACKSLASH)
+ MATRIX_KEY(6, 3, KEY_DOLLAR)
+ MATRIX_KEY(6, 4, KEY_EURO)
+ MATRIX_KEY(6, 5, KEY_GRAVE)
+ MATRIX_KEY(6, 6, KEY_GRAVE)
+ MATRIX_KEY(6, 7, KEY_MINUS)
+ MATRIX_KEY(6, 8, KEY_EQUAL)
+ MATRIX_KEY(6, 9, KEY_MINUS)
+ MATRIX_KEY(6, 10, KEY_EQUAL)
+ MATRIX_KEY(6, 11, KEY_DELETE)
+
+ MATRIX_KEY(8, 0, KEY_SYSRQ)
+ MATRIX_KEY(8, 10, KEY_INSERT)
+
+ MATRIX_KEY(9, 0, KEY_LEFTSHIFT)
+ MATRIX_KEY(9, 8, KEY_HOME)
+ MATRIX_KEY(9, 9, KEY_UP)
+ MATRIX_KEY(9, 10, KEY_END)
+
+ MATRIX_KEY(10, 1, KEY_LEFTCTRL)
+ MATRIX_KEY(10, 6, KEY_LEFT)
+ MATRIX_KEY(10, 8, KEY_RIGHT)
+ MATRIX_KEY(10, 9, KEY_DOWN)
+
+ MATRIX_KEY(11, 2, KEY_FN)
+ MATRIX_KEY(11, 3, KEY_LEFTALT)
+ MATRIX_KEY(11, 5, KEY_RIGHTALT)>;
wakeup-source;
};
};
diff --git a/drivers/input/keyboard/kb151.c b/drivers/input/keyboard/kb151.c
index 595275d4f9d96..bb6250efe9341 100644
--- a/drivers/input/keyboard/kb151.c
+++ b/drivers/input/keyboard/kb151.c
@@ -29,6 +29,7 @@ struct kb151 {
u8 row_shift;
u8 rows;
u8 cols;
+ u8 fn_state;
u8 buf_swap;
u8 buf[];
};
@@ -55,7 +56,7 @@ static void kb151_update(struct i2c_client *client)
return;
}
- dev_info(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+ dev_dbg(dev, "%02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
new_buf[0], new_buf[1], new_buf[2], new_buf[3], new_buf[4], new_buf[5],
new_buf[6], new_buf[7], new_buf[8], new_buf[9], new_buf[10], new_buf[11],
new_buf[12]);
@@ -65,8 +66,6 @@ static void kb151_update(struct i2c_client *client)
crc, new_buf[0]);
return;
}
- dev_info(dev, "Good scan data (%02x == %02x)\n",
- crc, new_buf[0]);
for (col = 0; col < kb151->cols; ++col) {
u8 old = *(++old_buf);
@@ -74,14 +73,20 @@ static void kb151_update(struct i2c_client *client)
u8 changed = old ^ new;
for (row = 0; row < kb151->rows; ++row) {
- int code = MATRIX_SCAN_CODE(row, col, kb151->row_shift);
u8 pressed = new & BIT(row);
+ u8 map_row = row + (kb151->fn_state ? kb151->rows : 0);
+ int code = MATRIX_SCAN_CODE(map_row, col, kb151->row_shift);
if (!(changed & BIT(row)))
continue;
dev_dbg(&client->dev, "row %u col %u %sed\n",
- row, col, pressed ? "press" : "releas");
+ map_row, col, pressed ? "press" : "releas");
+ if (keymap[code] == KEY_FN) {
+ dev_dbg(&client->dev, "FN is now %s\n",
+ pressed ? "pressed" : "released");
+ kb151->fn_state = pressed;
+ } else
input_report_key(kb151->input, keymap[code], pressed);
}
}
@@ -151,7 +156,7 @@ static int kb151_probe(struct i2c_client *client)
struct device *dev = &client->dev;
u8 info[KB151_MATRIX_SIZE + 1];
unsigned int kb_rows, kb_cols;
- unsigned int rows, cols;
+ unsigned int map_rows, map_cols;
struct kb151 *kb151;
int ret;
@@ -168,20 +173,20 @@ static int kb151_probe(struct i2c_client *client)
info[KB151_FW_REVISION] & 0xf,
info[KB151_FW_FEATURES]);
- ret = matrix_keypad_parse_properties(dev, &rows, &cols);
+ ret = matrix_keypad_parse_properties(dev, &map_rows, &map_cols);
if (ret)
return ret;
kb_rows = info[KB151_MATRIX_SIZE] & 0xf;
kb_cols = info[KB151_MATRIX_SIZE] >> 4;
- if (rows > kb_rows || cols != kb_cols) {
+ if (map_rows != 2 * kb_rows || map_cols != kb_cols) {
dev_err(dev, "Keyboard matrix is %ux%u, but key map is %ux%u\n",
- kb_rows, kb_cols, rows, cols);
+ kb_rows, kb_cols, map_rows, map_cols);
return -EINVAL;
}
/* Allocate two buffers, and include space for the CRC. */
- kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (cols + 1)), GFP_KERNEL);
+ kb151 = devm_kzalloc(dev, struct_size(kb151, buf, 2 * (kb_cols + 1)), GFP_KERNEL);
if (!kb151)
return -ENOMEM;
@@ -189,9 +194,9 @@ static int kb151_probe(struct i2c_client *client)
crc8_populate_msb(kb151->crc_table, KB151_CRC8_POLYNOMIAL);
- kb151->row_shift = get_count_order(cols);
- kb151->rows = rows;
- kb151->cols = cols;
+ kb151->row_shift = get_count_order(kb_cols);
+ kb151->rows = kb_rows;
+ kb151->cols = kb_cols;
kb151->input = devm_input_allocate_device(dev);
if (!kb151->input)
@@ -207,7 +212,7 @@ static int kb151_probe(struct i2c_client *client)
__set_bit(EV_REP, kb151->input->evbit);
- ret = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
+ ret = matrix_keypad_build_keymap(NULL, NULL, map_rows, map_cols,
NULL, kb151->input);
if (ret)
return dev_err_probe(dev, ret, "Failed to build keymap\n");

View File

@ -1,54 +0,0 @@
--- b/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
+++ a/arch/arm64/boot/dts/rockchip/rk3399-pinephone-pro.dts
@@ -260,6 +260,7 @@
pinctrl-names = "default";
pinctrl-0 = <&vcc_4g_5v_en>;
regulator-name = "vcc_4g_5v";
+ regulator-always-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
vin-supply = <&vcc5v0_sys>;
@@ -272,6 +273,7 @@
pinctrl-names = "default";
pinctrl-0 = <&vcc_4g_en>;
regulator-name = "vcc_4g";
+ regulator-always-on;
regulator-min-microvolt = <3800000>;
regulator-max-microvolt = <3800000>;
vin-supply = <&vcc_sysin>;
@@ -959,35 +961,6 @@
};
};
-&uart3 {
- status = "okay";
-
- modem {
- compatible = "quectel,eg25";
- char-device-name = "modem-power";
-
- pinctrl-names = "default";
- pinctrl-0 = <&modem_control_pins>;
-
- power-supply = <&vcc_4g>;
- vbus-supply = <&vcc_4g_5v>;
-
- enable-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; // W_DISABLE#
- reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
- status-gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;
- pwrkey-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>;
-
- host-ready-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; // apready
- wakeup-gpios = <&gpio0 RK_PA1 GPIO_ACTIVE_HIGH>; // ri
-
- dtr-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_HIGH>;
- cts-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>;
- rts-gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>;
-
- quectel,qdai = "3,0,0,4,0,0,1,1";
- };
-};
-
&pmu_io_domains {
pmu1830-supply = <&vcc_1v8>;
status = "okay";

View File

@ -3,38 +3,95 @@
EAPI="8" EAPI="8"
UNIPATCH_STRICTORDER="yes"
K_NOUSENAME="yes"
K_NOSETEXTRAVERSION="yes"
K_NOUSEPR="yes"
K_SECURITY_UNSUPPORTED="1"
K_BASE_VER="5.16"
K_EXP_GENPATCHES_NOUSE="1"
K_FROM_GIT="yes"
ETYPE="sources" ETYPE="sources"
K_WANT_GENPATCHES="base extras experimental"
K_GENPATCHES_VER="1"
inherit kernel-2 inherit kernel-2
detect_version detect_version
detect_arch
KEYWORDS="~arm64" KEYWORDS="~arm64"
DEPEND="${RDEPEND} DEPEND="${RDEPEND}
>=sys-devel/patch-2.7.5" >=sys-devel/patch-2.7.5"
DESCRIPTION="Full sources for the Linux kernel, with megi's patch for Pinephone Pro" DESCRIPTION="Full sources for the Linux kernel with gentoo patchset and with megi's patch for Pinephone (Pro)"
MEGI_PATCH_COMMIT="382509700d5a3ea447b44f002e9d928fd0a14ad5" SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}"
MEGI_PATCH_URI="orange-pi-5.16-20220110-0757"
SRC_URI="https://github.com/megous/linux/archive/${MEGI_PATCH_URI}.tar.gz -> ${P}.tar.gz"
PATCHES=( PATCHES=(
${FILESDIR}/0001-bootsplash.patch # Mobian Patches
${FILESDIR}/0001-base-property-Swap-order-of-search-for-connection-to.patch
${FILESDIR}/0002-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch
${FILESDIR}/0003-media-rockchip-rga-Fix-probe-bugs.patch
${FILESDIR}/0004-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch
${FILESDIR}/0005-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch
${FILESDIR}/0006-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch
${FILESDIR}/0007-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch
${FILESDIR}/0008-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch
${FILESDIR}/0009-video-fbdev-Add-events-for-early-fb-event-support.patch
${FILESDIR}/0010-power-rk818-Configure-rk808-clkout2-function.patch
${FILESDIR}/0011-power-rk818-battery-Add-battery-driver-for-RK818.patch
${FILESDIR}/0012-power-supply-rk818-battery-Use-a-more-propper-compat.patch
${FILESDIR}/0013-power-supply-core-Don-t-ignore-max_current-of-0-when.patch
${FILESDIR}/0014-power-supply-rk818-charger-Implement-charger-driver-.patch
${FILESDIR}/0015-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch
${FILESDIR}/0016-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch
${FILESDIR}/0017-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch
${FILESDIR}/0018-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch
${FILESDIR}/0019-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch
${FILESDIR}/0020-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch
${FILESDIR}/0021-usb-typec-fusb302-Add-OF-extcon-support.patch
${FILESDIR}/0022-usb-typec-fusb302-Fix-register-definitions.patch
${FILESDIR}/0023-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch
${FILESDIR}/0024-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch
${FILESDIR}/0025-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch
${FILESDIR}/0026-media-i2c-imx258-Add-support-for-powerdown-gpio.patch
${FILESDIR}/0027-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch
${FILESDIR}/0028-media-i2c-imx258-Add-support-for-reset-gpio.patch
${FILESDIR}/0029-media-i2c-imx258-Add-support-for-power-supplies.patch
${FILESDIR}/0030-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch
${FILESDIR}/0031-drm-panel-hx8394-Improve-the-panel-driver-make-it-wo.patch
${FILESDIR}/0032-drm-panel-hx8394-Fix-mode-clock-for-the-pinephone-pr.patch
${FILESDIR}/0033-input-goodix-Add-option-to-power-off-the-controller-.patch
${FILESDIR}/0034-input-goodix-Don-t-disable-regulators-during-suspend.patch
${FILESDIR}/0035-input-touchscreen-goodix-Respect-IRQ-flags-from-DT-w.patch
${FILESDIR}/0036-input-touchscreen-goodix-Add-support-for-GT1158.patch
${FILESDIR}/0037-arm64-dts-rk3399-pinephone-pro-Add-support-for-Pinep.patch
${FILESDIR}/0038-arm64-dts-rk3399-pinephone-pro-Fixup-DT-validation-i.patch
${FILESDIR}/0039-arm64-dts-rk3399-pinephone-pro-Make-charging-and-per.patch
${FILESDIR}/0040-arm64-dts-rk3399-pinephone-pro-Fix-goodix-toucscreen.patch
${FILESDIR}/0041-arm64-dts-rk3399-pinephone-pro-Correct-the-pmu1830-i.patch
${FILESDIR}/0042-arm64-dts-rk3399-pinephone-pro-Power-off-goodix-touc.patch
${FILESDIR}/0043-arm64-dts-rk3399-pinephone-pro-Add-support-for-both-.patch
${FILESDIR}/0044-arm64-dts-rk3399-pinephone-pro-Fix-SD-card-power-sup.patch
${FILESDIR}/0045-arm64-dts-rk3399-pinephone-pro-Correct-the-battery-s.patch
${FILESDIR}/0046-arm64-dts-rk3399-pinephone-pro-Cleanup-some-USB-node.patch
${FILESDIR}/0047-arm64-dts-rk3399-pinephone-pro-Fix-PDOs-to-be-more-r.patch
${FILESDIR}/0048-arm64-dts-rk3399-pinephone-pro-Add-chassis-type-hand.patch
${FILESDIR}/0049-arm64-dts-rk3399-pinephone-pro-Add-mmc-aliases-to-ge.patch
${FILESDIR}/0050-arm64-dts-rk3399-pinephone-pro-Use-a-new-rk818-batte.patch
${FILESDIR}/0051-arm64-dts-rk3399-pinephone-pro-Full-support-for-Type.patch
${FILESDIR}/0052-arm64-dts-rk3399-pinephone-pro-Use-DCLK_VOP-_FRAC-to.patch
${FILESDIR}/0053-arm64-dts-rk3399-pinephone-pro-Add-support-for-power.patch
${FILESDIR}/0054-arm64-dts-rk3399-pinephone-pro-Add-audio-support.patch
${FILESDIR}/0055-arm64-dts-rk3399-pinephone-pro-Add-flash-and-fix-led.patch
${FILESDIR}/0056-arm64-dts-rk3399-pinephone-pro-add-modem-RI-pin.patch
${FILESDIR}/0057-arm64-dts-rk3399-pinephone-pro-improve-sound-device.patch
${FILESDIR}/0058-arm64-dts-rk3399-pinephone-pro-remove-front-camera-n.patch
# Pinephone Keyboard
${FILESDIR}/pp-keyboard.patch
${FILESDIR}/ppp-keyboard.patch
# Bootsplash
${FILESDIR}/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch ${FILESDIR}/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch
${FILESDIR}/0002-bootsplash.patch
${FILESDIR}/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch ${FILESDIR}/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch
${FILESDIR}/0003-bootsplash.patch
${FILESDIR}/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch ${FILESDIR}/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch
${FILESDIR}/0004-bootsplash.patch
${FILESDIR}/0004-revert-fbcon-remove-soft-scrollback-code.patch ${FILESDIR}/0004-revert-fbcon-remove-soft-scrollback-code.patch
${FILESDIR}/0001-bootsplash.patch
${FILESDIR}/0002-bootsplash.patch
${FILESDIR}/0003-bootsplash.patch
${FILESDIR}/0004-bootsplash.patch
${FILESDIR}/0005-bootsplash.patch ${FILESDIR}/0005-bootsplash.patch
${FILESDIR}/0006-bootsplash.patch ${FILESDIR}/0006-bootsplash.patch
${FILESDIR}/0007-bootsplash.patch ${FILESDIR}/0007-bootsplash.patch
@ -43,9 +100,6 @@ PATCHES=(
${FILESDIR}/0010-bootsplash.patch ${FILESDIR}/0010-bootsplash.patch
${FILESDIR}/0011-bootsplash.patch ${FILESDIR}/0011-bootsplash.patch
${FILESDIR}/0012-bootsplash.patch ${FILESDIR}/0012-bootsplash.patch
${FILESDIR}/ppp-keyboard.patch
${FILESDIR}/2423aac2d6f5db55da99e11fd799ee66fe6f54c6.patch
${FILESDIR}/d1d849cae12db71aa81ceedaedc1b17a34790367.patch
) )
src_prepare() { src_prepare() {
@ -72,3 +126,4 @@ pkg_postinst() {
pkg_postrm() { pkg_postrm() {
kernel-2_pkg_postrm kernel-2_pkg_postrm
} }