From 83c53a6eef20a407488d5838e6eb80b3af79444b Mon Sep 17 00:00:00 2001 From: Gerben Jan Dijkman Date: Tue, 11 Jan 2022 10:27:31 +0100 Subject: [PATCH] Update --- ...ap-order-of-search-for-connection-to.patch | 35 - ...collect-fbdev-scrolling-acceleration.patch | 1038 ----- ...usued-softback_lines-cursor-argument.patch | 150 - ...-sdhci-arasan-Add-runtime-PM-support.patch | 152 - ...port-SCLK_CIF_OUT_SRC-to-device-tree.patch | 37 - ...-fbcon-remove-no-op-fbcon_set_origin.patch | 31 - ...04-media-rockchip-rga-Fix-probe-bugs.patch | 39 - ...rt-fbcon-remove-soft-scrollback-code.patch | 500 --- ...rockchip-Ensure-that-lane-is-properl.patch | 34 - ...mipi-dsi-Fix-missing-clk_disable_unp.patch | 48 - ...pi-dsi-Fix-enable-disable-of-dsi-con.patch | 145 - ...rockchip-Never-allow-lane-bandwidth-.patch | 28 - ...-cdn-dp-Disable-CDN-DP-on-disconnect.patch | 23 - ...dd-events-for-early-fb-event-support.patch | 69 - ...818-Configure-rk808-clkout2-function.patch | 40 - ...battery-Add-battery-driver-for-RK818.patch | 3964 ----------------- ...18-battery-Use-a-more-propper-compat.patch | 46 - ...e-Don-t-ignore-max_current-of-0-when.patch | 85 - ...18-charger-Implement-charger-driver-.patch | 699 --- ...2-Set-the-current-before-enabling-pu.patch | 47 - ...2-Extend-debugging-interface-with-dr.patch | 108 - ...2-Retry-reading-of-CC-pins-status-if.patch | 72 - ...2-More-useful-of-logging-status-on-i.patch | 186 - ...2-Update-VBUS-state-even-if-VBUS-int.patch | 39 - ...2-Make-tcpm-fusb302-logs-less-pollut.patch | 160 - ...-typec-fusb302-Add-OF-extcon-support.patch | 34 - ...pec-fusb302-Fix-register-definitions.patch | 45 - ...2-Clear-interrupts-before-we-start-t.patch | 37 - ...extcon-Add-typec-extcon-bridge-drive.patch | 388 -- ...ec-Make-sure-the-plug-orientation-is.patch | 64 - ...mx258-Add-support-for-powerdown-gpio.patch | 56 - ...-Don-t-be-too-strict-about-clock-rat.patch | 41 - ...2c-imx258-Add-support-for-reset-gpio.patch | 57 - ...mx258-Add-support-for-power-supplies.patch | 100 - ...-more-framerates-to-the-driver-some-.patch | 52 - ...eriment-Try-to-disable-denoising-sha.patch | 47 - ...ep-after-poweroff-to-ensure-next-pow.patch | 25 - ...-t-powerup-the-sensor-during-driver-.patch | 86 - ...035-media-ov5640-Implement-autofocus.patch | 405 -- ...a-ov5640-set-default-ae-target-lower.patch | 23 - ...-Add-driver-for-HX8394-based-HannSta.patch | 464 -- ...-Improve-the-panel-driver-make-it-wo.patch | 226 - ...-Fix-mode-clock-for-the-pinephone-pr.patch | 29 - ...-option-to-power-off-the-controller-.patch | 97 - ...-t-disable-regulators-during-suspend.patch | 49 - ...n-goodix-Respect-IRQ-flags-from-DT-w.patch | 53 - ...screen-goodix-Add-support-for-GT1158.patch | 23 - ...-pinephone-pro-Add-support-for-Pinep.patch | 1074 ----- ...-pinephone-pro-Fixup-DT-validation-i.patch | 101 - ...-pinephone-pro-Make-charging-and-per.patch | 34 - ...-pinephone-pro-Fix-goodix-toucscreen.patch | 30 - ...-pinephone-pro-Correct-the-pmu1830-i.patch | 26 - ...-pinephone-pro-Power-off-goodix-touc.patch | 25 - ...-pinephone-pro-Add-support-for-both-.patch | 198 - ...-pinephone-pro-Fix-SD-card-power-sup.patch | 71 - ...-pinephone-pro-Correct-the-battery-s.patch | 44 - ...-pinephone-pro-Cleanup-some-USB-node.patch | 32 - ...-pinephone-pro-Fix-PDOs-to-be-more-r.patch | 33 - ...-pinephone-pro-Add-chassis-type-hand.patch | 24 - ...-pinephone-pro-Add-mmc-aliases-to-ge.patch | 29 - ...-pinephone-pro-Use-a-new-rk818-batte.patch | 23 - ...-pinephone-pro-Full-support-for-Type.patch | 294 -- ...-pinephone-pro-Use-DCLK_VOP-_FRAC-to.patch | 37 - ...-pinephone-pro-Add-support-for-power.patch | 78 - ...3399-pinephone-pro-Add-audio-support.patch | 139 - ...-pinephone-pro-Add-flash-and-fix-led.patch | 105 - ...k3399-pinephone-pro-add-modem-RI-pin.patch | 48 - ...9-pinephone-pro-improve-sound-device.patch | 90 - .../pinephone-sources-5.16.0.ebuild | 65 +- 69 files changed, 1 insertion(+), 12775 deletions(-) delete mode 100644 sys-kernel/pinephone-sources/files/0001-base-property-Swap-order-of-search-for-connection-to.patch delete mode 100644 sys-kernel/pinephone-sources/files/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch delete mode 100644 sys-kernel/pinephone-sources/files/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch delete mode 100644 sys-kernel/pinephone-sources/files/0002-sdhci-arasan-Add-runtime-PM-support.patch delete mode 100644 sys-kernel/pinephone-sources/files/0003-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch delete mode 100644 sys-kernel/pinephone-sources/files/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch delete mode 100644 sys-kernel/pinephone-sources/files/0004-media-rockchip-rga-Fix-probe-bugs.patch delete mode 100644 sys-kernel/pinephone-sources/files/0004-revert-fbcon-remove-soft-scrollback-code.patch delete mode 100644 sys-kernel/pinephone-sources/files/0005-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch delete mode 100644 sys-kernel/pinephone-sources/files/0006-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch delete mode 100644 sys-kernel/pinephone-sources/files/0007-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch delete mode 100644 sys-kernel/pinephone-sources/files/0008-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0009-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch delete mode 100644 sys-kernel/pinephone-sources/files/0010-video-fbdev-Add-events-for-early-fb-event-support.patch delete mode 100644 sys-kernel/pinephone-sources/files/0011-power-rk818-Configure-rk808-clkout2-function.patch delete mode 100644 sys-kernel/pinephone-sources/files/0012-power-rk818-battery-Add-battery-driver-for-RK818.patch delete mode 100644 sys-kernel/pinephone-sources/files/0013-power-supply-rk818-battery-Use-a-more-propper-compat.patch delete mode 100644 sys-kernel/pinephone-sources/files/0014-power-supply-core-Don-t-ignore-max_current-of-0-when.patch delete mode 100644 sys-kernel/pinephone-sources/files/0015-power-supply-rk818-charger-Implement-charger-driver-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0016-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch delete mode 100644 sys-kernel/pinephone-sources/files/0017-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch delete mode 100644 sys-kernel/pinephone-sources/files/0018-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch delete mode 100644 sys-kernel/pinephone-sources/files/0019-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch delete mode 100644 sys-kernel/pinephone-sources/files/0020-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch delete mode 100644 sys-kernel/pinephone-sources/files/0021-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch delete mode 100644 sys-kernel/pinephone-sources/files/0022-usb-typec-fusb302-Add-OF-extcon-support.patch delete mode 100644 sys-kernel/pinephone-sources/files/0023-usb-typec-fusb302-Fix-register-definitions.patch delete mode 100644 sys-kernel/pinephone-sources/files/0024-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch delete mode 100644 sys-kernel/pinephone-sources/files/0025-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch delete mode 100644 sys-kernel/pinephone-sources/files/0026-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch delete mode 100644 sys-kernel/pinephone-sources/files/0027-media-i2c-imx258-Add-support-for-powerdown-gpio.patch delete mode 100644 sys-kernel/pinephone-sources/files/0028-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch delete mode 100644 sys-kernel/pinephone-sources/files/0029-media-i2c-imx258-Add-support-for-reset-gpio.patch delete mode 100644 sys-kernel/pinephone-sources/files/0030-media-i2c-imx258-Add-support-for-power-supplies.patch delete mode 100644 sys-kernel/pinephone-sources/files/0031-media-ov5640-Add-more-framerates-to-the-driver-some-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0032-media-ov5640-Experiment-Try-to-disable-denoising-sha.patch delete mode 100644 sys-kernel/pinephone-sources/files/0033-media-ov5640-Sleep-after-poweroff-to-ensure-next-pow.patch delete mode 100644 sys-kernel/pinephone-sources/files/0034-media-ov5640-Don-t-powerup-the-sensor-during-driver-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0035-media-ov5640-Implement-autofocus.patch delete mode 100644 sys-kernel/pinephone-sources/files/0036-media-ov5640-set-default-ae-target-lower.patch delete mode 100644 sys-kernel/pinephone-sources/files/0037-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch delete mode 100644 sys-kernel/pinephone-sources/files/0038-drm-panel-hx8394-Improve-the-panel-driver-make-it-wo.patch delete mode 100644 sys-kernel/pinephone-sources/files/0039-drm-panel-hx8394-Fix-mode-clock-for-the-pinephone-pr.patch delete mode 100644 sys-kernel/pinephone-sources/files/0040-input-goodix-Add-option-to-power-off-the-controller-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0041-input-goodix-Don-t-disable-regulators-during-suspend.patch delete mode 100644 sys-kernel/pinephone-sources/files/0042-input-touchscreen-goodix-Respect-IRQ-flags-from-DT-w.patch delete mode 100644 sys-kernel/pinephone-sources/files/0043-input-touchscreen-goodix-Add-support-for-GT1158.patch delete mode 100644 sys-kernel/pinephone-sources/files/0044-arm64-dts-rk3399-pinephone-pro-Add-support-for-Pinep.patch delete mode 100644 sys-kernel/pinephone-sources/files/0045-arm64-dts-rk3399-pinephone-pro-Fixup-DT-validation-i.patch delete mode 100644 sys-kernel/pinephone-sources/files/0046-arm64-dts-rk3399-pinephone-pro-Make-charging-and-per.patch delete mode 100644 sys-kernel/pinephone-sources/files/0047-arm64-dts-rk3399-pinephone-pro-Fix-goodix-toucscreen.patch delete mode 100644 sys-kernel/pinephone-sources/files/0048-arm64-dts-rk3399-pinephone-pro-Correct-the-pmu1830-i.patch delete mode 100644 sys-kernel/pinephone-sources/files/0049-arm64-dts-rk3399-pinephone-pro-Power-off-goodix-touc.patch delete mode 100644 sys-kernel/pinephone-sources/files/0050-arm64-dts-rk3399-pinephone-pro-Add-support-for-both-.patch delete mode 100644 sys-kernel/pinephone-sources/files/0051-arm64-dts-rk3399-pinephone-pro-Fix-SD-card-power-sup.patch delete mode 100644 sys-kernel/pinephone-sources/files/0052-arm64-dts-rk3399-pinephone-pro-Correct-the-battery-s.patch delete mode 100644 sys-kernel/pinephone-sources/files/0053-arm64-dts-rk3399-pinephone-pro-Cleanup-some-USB-node.patch delete mode 100644 sys-kernel/pinephone-sources/files/0054-arm64-dts-rk3399-pinephone-pro-Fix-PDOs-to-be-more-r.patch delete mode 100644 sys-kernel/pinephone-sources/files/0055-arm64-dts-rk3399-pinephone-pro-Add-chassis-type-hand.patch delete mode 100644 sys-kernel/pinephone-sources/files/0056-arm64-dts-rk3399-pinephone-pro-Add-mmc-aliases-to-ge.patch delete mode 100644 sys-kernel/pinephone-sources/files/0057-arm64-dts-rk3399-pinephone-pro-Use-a-new-rk818-batte.patch delete mode 100644 sys-kernel/pinephone-sources/files/0058-arm64-dts-rk3399-pinephone-pro-Full-support-for-Type.patch delete mode 100644 sys-kernel/pinephone-sources/files/0059-arm64-dts-rk3399-pinephone-pro-Use-DCLK_VOP-_FRAC-to.patch delete mode 100644 sys-kernel/pinephone-sources/files/0060-arm64-dts-rk3399-pinephone-pro-Add-support-for-power.patch delete mode 100644 sys-kernel/pinephone-sources/files/0061-arm64-dts-rk3399-pinephone-pro-Add-audio-support.patch delete mode 100644 sys-kernel/pinephone-sources/files/0062-arm64-dts-rk3399-pinephone-pro-Add-flash-and-fix-led.patch delete mode 100644 sys-kernel/pinephone-sources/files/0063-arm64-dts-rk3399-pinephone-pro-add-modem-RI-pin.patch delete mode 100644 sys-kernel/pinephone-sources/files/0064-arm64-dts-rk3399-pinephone-pro-improve-sound-device.patch diff --git a/sys-kernel/pinephone-sources/files/0001-base-property-Swap-order-of-search-for-connection-to.patch b/sys-kernel/pinephone-sources/files/0001-base-property-Swap-order-of-search-for-connection-to.patch deleted file mode 100644 index 8a3b62c..0000000 --- a/sys-kernel/pinephone-sources/files/0001-base-property-Swap-order-of-search-for-connection-to.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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); diff --git a/sys-kernel/pinephone-sources/files/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch b/sys-kernel/pinephone-sources/files/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch deleted file mode 100644 index 280ed96..0000000 --- a/sys-kernel/pinephone-sources/files/0001-revert-garbage-collect-fbdev-scrolling-acceleration.patch +++ /dev/null @@ -1,1038 +0,0 @@ ---- b/Documentation/gpu/todo.rst -+++ a/Documentation/gpu/todo.rst -@@ -314,19 +314,16 @@ - Garbage collect fbdev scrolling acceleration - -------------------------------------------- - -+Scroll acceleration is disabled in fbcon by hard-wiring p->scrollmode = -+SCROLL_REDRAW. There's a ton of code this will allow us to remove: --Scroll acceleration has been disabled in fbcon. Now it works as the old --SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was --removed from fbcon_ops. --Remaining tasks: - -+- lots of code in fbcon.c -+ -+- a bunch of the hooks in fbcon_ops, maybe the remaining hooks could be called --- a bunch of the hooks in fbcon_ops could be removed or simplified by calling - directly instead of the function table (with a switch on p->rotate) - - - fb_copyarea is unused after this, and can be deleted from all drivers - --- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as -- well as cfb_copyarea -- - Note that not all acceleration code can be deleted, since clearing and cursor - support is still accelerated, which might be good candidates for further - deletion projects. ---- b/drivers/video/fbdev/core/bitblit.c -+++ a/drivers/video/fbdev/core/bitblit.c -@@ -43,6 +43,21 @@ - } - } - -+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ struct fb_copyarea area; -+ -+ area.sx = sx * vc->vc_font.width; -+ area.sy = sy * vc->vc_font.height; -+ area.dx = dx * vc->vc_font.width; -+ area.dy = dy * vc->vc_font.height; -+ area.height = height * vc->vc_font.height; -+ area.width = width * vc->vc_font.width; -+ -+ info->fbops->fb_copyarea(info, &area); -+} -+ - static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) - { -@@ -378,6 +393,7 @@ - - void fbcon_set_bitops(struct fbcon_ops *ops) - { -+ ops->bmove = bit_bmove; - ops->clear = bit_clear; - ops->putcs = bit_putcs; - ops->clear_margins = bit_clear_margins; ---- b/drivers/video/fbdev/core/fbcon.c -+++ a/drivers/video/fbdev/core/fbcon.c -@@ -173,6 +173,8 @@ - int count, int ypos, int xpos); - static void fbcon_clear_margins(struct vc_data *vc, int bottom_only); - static void fbcon_cursor(struct vc_data *vc, int mode); -+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, -+ int height, int width); - static int fbcon_switch(struct vc_data *vc); - static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch); - static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table); -@@ -180,8 +182,16 @@ - /* - * Internal routines - */ -+static __inline__ void ywrap_up(struct vc_data *vc, int count); -+static __inline__ void ywrap_down(struct vc_data *vc, int count); -+static __inline__ void ypan_up(struct vc_data *vc, int count); -+static __inline__ void ypan_down(struct vc_data *vc, int count); -+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, -+ int dy, int dx, int height, int width, u_int y_break); - static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, - int unit); -+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, -+ int line, int count, int dy); - static void fbcon_modechanged(struct fb_info *info); - static void fbcon_set_all_vcs(struct fb_info *info); - static void fbcon_start(void); -@@ -1125,6 +1135,14 @@ - - ops->graphics = 0; - -+ /* -+ * No more hw acceleration for fbcon. -+ * -+ * FIXME: Garbage collect all the now dead code after sufficient time -+ * has passed. -+ */ -+ p->scrollmode = SCROLL_REDRAW; -+ - /* - * ++guenther: console.c:vc_allocate() relies on initializing - * vc_{cols,rows}, but we must not set those if we are only -@@ -1211,13 +1229,14 @@ - * This system is now divided into two levels because of complications - * caused by hardware scrolling. Top level functions: - * -+ * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins() -- * fbcon_clear(), fbcon_putc(), fbcon_clear_margins() - * - * handles y values in range [0, scr_height-1] that correspond to real - * screen positions. y_wrap shift means that first line of bitmap may be - * anywhere on this display. These functions convert lineoffsets to - * bitmap offsets and deal with the wrap-around case by splitting blits. - * -+ * fbcon_bmove_physical_8() -- These functions fast implementations - * fbcon_clear_physical_8() -- of original fbcon_XXX fns. - * fbcon_putc_physical_8() -- (font width != 8) may be added later - * -@@ -1390,6 +1409,224 @@ - } - } - -+static __inline__ void ywrap_up(struct vc_data *vc, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ -+ p->yscroll += count; -+ if (p->yscroll >= p->vrows) /* Deal with wrap */ -+ p->yscroll -= p->vrows; -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode |= FB_VMODE_YWRAP; -+ ops->update_start(info); -+ scrollback_max += count; -+ if (scrollback_max > scrollback_phys_max) -+ scrollback_max = scrollback_phys_max; -+ scrollback_current = 0; -+} -+ -+static __inline__ void ywrap_down(struct vc_data *vc, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ -+ p->yscroll -= count; -+ if (p->yscroll < 0) /* Deal with wrap */ -+ p->yscroll += p->vrows; -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode |= FB_VMODE_YWRAP; -+ ops->update_start(info); -+ scrollback_max -= count; -+ if (scrollback_max < 0) -+ scrollback_max = 0; -+ scrollback_current = 0; -+} -+ -+static __inline__ void ypan_up(struct vc_data *vc, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ -+ p->yscroll += count; -+ if (p->yscroll > p->vrows - vc->vc_rows) { -+ ops->bmove(vc, info, p->vrows - vc->vc_rows, -+ 0, 0, 0, vc->vc_rows, vc->vc_cols); -+ p->yscroll -= p->vrows - vc->vc_rows; -+ } -+ -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode &= ~FB_VMODE_YWRAP; -+ ops->update_start(info); -+ fbcon_clear_margins(vc, 1); -+ scrollback_max += count; -+ if (scrollback_max > scrollback_phys_max) -+ scrollback_max = scrollback_phys_max; -+ scrollback_current = 0; -+} -+ -+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ -+ p->yscroll += count; -+ -+ if (p->yscroll > p->vrows - vc->vc_rows) { -+ p->yscroll -= p->vrows - vc->vc_rows; -+ fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t); -+ } -+ -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode &= ~FB_VMODE_YWRAP; -+ ops->update_start(info); -+ fbcon_clear_margins(vc, 1); -+ scrollback_max += count; -+ if (scrollback_max > scrollback_phys_max) -+ scrollback_max = scrollback_phys_max; -+ scrollback_current = 0; -+} -+ -+static __inline__ void ypan_down(struct vc_data *vc, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ -+ p->yscroll -= count; -+ if (p->yscroll < 0) { -+ ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows, -+ 0, vc->vc_rows, vc->vc_cols); -+ p->yscroll += p->vrows - vc->vc_rows; -+ } -+ -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode &= ~FB_VMODE_YWRAP; -+ ops->update_start(info); -+ fbcon_clear_margins(vc, 1); -+ scrollback_max -= count; -+ if (scrollback_max < 0) -+ scrollback_max = 0; -+ scrollback_current = 0; -+} -+ -+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ -+ p->yscroll -= count; -+ -+ if (p->yscroll < 0) { -+ p->yscroll += p->vrows - vc->vc_rows; -+ fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count); -+ } -+ -+ ops->var.xoffset = 0; -+ ops->var.yoffset = p->yscroll * vc->vc_font.height; -+ ops->var.vmode &= ~FB_VMODE_YWRAP; -+ ops->update_start(info); -+ fbcon_clear_margins(vc, 1); -+ scrollback_max -= count; -+ if (scrollback_max < 0) -+ scrollback_max = 0; -+ scrollback_current = 0; -+} -+ -+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, -+ int line, int count, int dy) -+{ -+ unsigned short *s = (unsigned short *) -+ (vc->vc_origin + vc->vc_size_row * line); -+ -+ while (count--) { -+ unsigned short *start = s; -+ unsigned short *le = advance_row(s, 1); -+ unsigned short c; -+ int x = 0; -+ unsigned short attr = 1; -+ -+ do { -+ c = scr_readw(s); -+ if (attr != (c & 0xff00)) { -+ attr = c & 0xff00; -+ if (s > start) { -+ fbcon_putcs(vc, start, s - start, -+ dy, x); -+ x += s - start; -+ start = s; -+ } -+ } -+ console_conditional_schedule(); -+ s++; -+ } while (s < le); -+ if (s > start) -+ fbcon_putcs(vc, start, s - start, dy, x); -+ console_conditional_schedule(); -+ dy++; -+ } -+} -+ -+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info, -+ struct fbcon_display *p, int line, int count, int ycount) -+{ -+ int offset = ycount * vc->vc_cols; -+ unsigned short *d = (unsigned short *) -+ (vc->vc_origin + vc->vc_size_row * line); -+ unsigned short *s = d + offset; -+ struct fbcon_ops *ops = info->fbcon_par; -+ -+ while (count--) { -+ unsigned short *start = s; -+ unsigned short *le = advance_row(s, 1); -+ unsigned short c; -+ int x = 0; -+ -+ do { -+ c = scr_readw(s); -+ -+ if (c == scr_readw(d)) { -+ if (s > start) { -+ ops->bmove(vc, info, line + ycount, x, -+ line, x, 1, s-start); -+ x += s - start + 1; -+ start = s + 1; -+ } else { -+ x++; -+ start++; -+ } -+ } -+ -+ scr_writew(c, d); -+ console_conditional_schedule(); -+ s++; -+ d++; -+ } while (s < le); -+ if (s > start) -+ ops->bmove(vc, info, line + ycount, x, line, x, 1, -+ s-start); -+ console_conditional_schedule(); -+ if (ycount > 0) -+ line++; -+ else { -+ line--; -+ /* NOTE: We subtract two lines from these pointers */ -+ s -= vc->vc_size_row; -+ d -= vc->vc_size_row; -+ } -+ } -+} -+ - static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p, - int line, int count, int offset) - { -@@ -1450,6 +1687,7 @@ - { - struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct fbcon_display *p = &fb_display[vc->vc_num]; -+ int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK; - - if (fbcon_is_inactive(vc, info)) - return true; -@@ -1466,32 +1704,249 @@ - case SM_UP: - if (count > vc->vc_rows) /* Maximum realistic size */ - count = vc->vc_rows; -+ if (logo_shown >= 0) -+ goto redraw_up; -+ switch (p->scrollmode) { -+ case SCROLL_MOVE: -+ fbcon_redraw_blit(vc, info, p, t, b - t - count, -+ count); -+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -+ scr_memsetw((unsigned short *) (vc->vc_origin + -+ vc->vc_size_row * -+ (b - count)), -+ vc->vc_video_erase_char, -+ vc->vc_size_row * count); -+ return true; -+ -+ case SCROLL_WRAP_MOVE: -+ if (b - t - count > 3 * vc->vc_rows >> 2) { -+ if (t > 0) -+ fbcon_bmove(vc, 0, 0, count, 0, t, -+ vc->vc_cols); -+ ywrap_up(vc, count); -+ if (vc->vc_rows - b > 0) -+ fbcon_bmove(vc, b - count, 0, b, 0, -+ vc->vc_rows - b, -+ vc->vc_cols); -+ } else if (info->flags & FBINFO_READS_FAST) -+ fbcon_bmove(vc, t + count, 0, t, 0, -+ b - t - count, vc->vc_cols); -+ else -+ goto redraw_up; -+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_PAN_REDRAW: -+ if ((p->yscroll + count <= -+ 2 * (p->vrows - vc->vc_rows)) -+ && ((!scroll_partial && (b - t == vc->vc_rows)) -+ || (scroll_partial -+ && (b - t - count > -+ 3 * vc->vc_rows >> 2)))) { -+ if (t > 0) -+ fbcon_redraw_move(vc, p, 0, t, count); -+ ypan_up_redraw(vc, t, count); -+ if (vc->vc_rows - b > 0) -+ fbcon_redraw_move(vc, p, b, -+ vc->vc_rows - b, b); -+ } else -+ fbcon_redraw_move(vc, p, t + count, b - t - count, t); -+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_PAN_MOVE: -+ if ((p->yscroll + count <= -+ 2 * (p->vrows - vc->vc_rows)) -+ && ((!scroll_partial && (b - t == vc->vc_rows)) -+ || (scroll_partial -+ && (b - t - count > -+ 3 * vc->vc_rows >> 2)))) { -+ if (t > 0) -+ fbcon_bmove(vc, 0, 0, count, 0, t, -+ vc->vc_cols); -+ ypan_up(vc, count); -+ if (vc->vc_rows - b > 0) -+ fbcon_bmove(vc, b - count, 0, b, 0, -+ vc->vc_rows - b, -+ vc->vc_cols); -+ } else if (info->flags & FBINFO_READS_FAST) -+ fbcon_bmove(vc, t + count, 0, t, 0, -+ b - t - count, vc->vc_cols); -+ else -+ goto redraw_up; -+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_REDRAW: -+ redraw_up: -+ fbcon_redraw(vc, p, t, b - t - count, -+ count * vc->vc_cols); -+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -+ scr_memsetw((unsigned short *) (vc->vc_origin + -+ vc->vc_size_row * -+ (b - count)), -+ vc->vc_video_erase_char, -+ vc->vc_size_row * count); -+ return true; -+ } -+ break; -- fbcon_redraw(vc, p, t, b - t - count, -- count * vc->vc_cols); -- fbcon_clear(vc, b - count, 0, count, vc->vc_cols); -- scr_memsetw((unsigned short *) (vc->vc_origin + -- vc->vc_size_row * -- (b - count)), -- vc->vc_video_erase_char, -- vc->vc_size_row * count); -- return true; - - case SM_DOWN: - if (count > vc->vc_rows) /* Maximum realistic size */ - count = vc->vc_rows; -+ if (logo_shown >= 0) -+ goto redraw_down; -+ switch (p->scrollmode) { -+ case SCROLL_MOVE: -+ fbcon_redraw_blit(vc, info, p, b - 1, b - t - count, -+ -count); -+ fbcon_clear(vc, t, 0, count, vc->vc_cols); -+ scr_memsetw((unsigned short *) (vc->vc_origin + -+ vc->vc_size_row * -+ t), -+ vc->vc_video_erase_char, -+ vc->vc_size_row * count); -+ return true; -+ -+ case SCROLL_WRAP_MOVE: -+ if (b - t - count > 3 * vc->vc_rows >> 2) { -+ if (vc->vc_rows - b > 0) -+ fbcon_bmove(vc, b, 0, b - count, 0, -+ vc->vc_rows - b, -+ vc->vc_cols); -+ ywrap_down(vc, count); -+ if (t > 0) -+ fbcon_bmove(vc, count, 0, 0, 0, t, -+ vc->vc_cols); -+ } else if (info->flags & FBINFO_READS_FAST) -+ fbcon_bmove(vc, t, 0, t + count, 0, -+ b - t - count, vc->vc_cols); -+ else -+ goto redraw_down; -+ fbcon_clear(vc, t, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_PAN_MOVE: -+ if ((count - p->yscroll <= p->vrows - vc->vc_rows) -+ && ((!scroll_partial && (b - t == vc->vc_rows)) -+ || (scroll_partial -+ && (b - t - count > -+ 3 * vc->vc_rows >> 2)))) { -+ if (vc->vc_rows - b > 0) -+ fbcon_bmove(vc, b, 0, b - count, 0, -+ vc->vc_rows - b, -+ vc->vc_cols); -+ ypan_down(vc, count); -+ if (t > 0) -+ fbcon_bmove(vc, count, 0, 0, 0, t, -+ vc->vc_cols); -+ } else if (info->flags & FBINFO_READS_FAST) -+ fbcon_bmove(vc, t, 0, t + count, 0, -+ b - t - count, vc->vc_cols); -+ else -+ goto redraw_down; -+ fbcon_clear(vc, t, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_PAN_REDRAW: -+ if ((count - p->yscroll <= p->vrows - vc->vc_rows) -+ && ((!scroll_partial && (b - t == vc->vc_rows)) -+ || (scroll_partial -+ && (b - t - count > -+ 3 * vc->vc_rows >> 2)))) { -+ if (vc->vc_rows - b > 0) -+ fbcon_redraw_move(vc, p, b, vc->vc_rows - b, -+ b - count); -+ ypan_down_redraw(vc, t, count); -+ if (t > 0) -+ fbcon_redraw_move(vc, p, count, t, 0); -+ } else -+ fbcon_redraw_move(vc, p, t, b - t - count, t + count); -+ fbcon_clear(vc, t, 0, count, vc->vc_cols); -+ break; -+ -+ case SCROLL_REDRAW: -+ redraw_down: -+ fbcon_redraw(vc, p, b - 1, b - t - count, -+ -count * vc->vc_cols); -+ fbcon_clear(vc, t, 0, count, vc->vc_cols); -+ scr_memsetw((unsigned short *) (vc->vc_origin + -+ vc->vc_size_row * -+ t), -+ vc->vc_video_erase_char, -+ vc->vc_size_row * count); -+ return true; -+ } -- fbcon_redraw(vc, p, b - 1, b - t - count, -- -count * vc->vc_cols); -- fbcon_clear(vc, t, 0, count, vc->vc_cols); -- scr_memsetw((unsigned short *) (vc->vc_origin + -- vc->vc_size_row * -- t), -- vc->vc_video_erase_char, -- vc->vc_size_row * count); -- return true; - } - return false; - } - -+ -+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx, -+ int height, int width) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_display *p = &fb_display[vc->vc_num]; -+ -+ if (fbcon_is_inactive(vc, info)) -+ return; -+ -+ if (!width || !height) -+ return; -+ -+ /* Split blits that cross physical y_wrap case. -+ * Pathological case involves 4 blits, better to use recursive -+ * code rather than unrolled case -+ * -+ * Recursive invocations don't need to erase the cursor over and -+ * over again, so we use fbcon_bmove_rec() -+ */ -+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width, -+ p->vrows - p->yscroll); -+} -+ -+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx, -+ int dy, int dx, int height, int width, u_int y_break) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ u_int b; -+ -+ if (sy < y_break && sy + height > y_break) { -+ b = y_break - sy; -+ if (dy < sy) { /* Avoid trashing self */ -+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, -+ y_break); -+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, -+ height - b, width, y_break); -+ } else { -+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, -+ height - b, width, y_break); -+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, -+ y_break); -+ } -+ return; -+ } -+ -+ if (dy < y_break && dy + height > y_break) { -+ b = y_break - dy; -+ if (dy < sy) { /* Avoid trashing self */ -+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, -+ y_break); -+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, -+ height - b, width, y_break); -+ } else { -+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx, -+ height - b, width, y_break); -+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width, -+ y_break); -+ } -+ return; -+ } -+ ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, -+ height, width); -+} -+ - static void updatescrollmode(struct fbcon_display *p, - struct fb_info *info, - struct vc_data *vc) -@@ -1664,7 +2119,21 @@ - - updatescrollmode(p, info, vc); - -+ switch (p->scrollmode) { -+ case SCROLL_WRAP_MOVE: -+ scrollback_phys_max = p->vrows - vc->vc_rows; -+ break; -+ case SCROLL_PAN_MOVE: -+ case SCROLL_PAN_REDRAW: -+ scrollback_phys_max = p->vrows - 2 * vc->vc_rows; -+ if (scrollback_phys_max < 0) -+ scrollback_phys_max = 0; -+ break; -+ default: -+ scrollback_phys_max = 0; -+ break; -+ } -+ -- scrollback_phys_max = 0; - scrollback_max = 0; - scrollback_current = 0; - ---- b/drivers/video/fbdev/core/fbcon.h -+++ a/drivers/video/fbdev/core/fbcon.h -@@ -29,6 +29,7 @@ - /* Filled in by the low-level console driver */ - const u_char *fontdata; - int userfont; /* != 0 if fontdata kmalloc()ed */ -+ u_short scrollmode; /* Scroll Method */ - u_short inverse; /* != 0 text black on white as default */ - short yscroll; /* Hardware scrolling */ - int vrows; /* number of virtual rows */ -@@ -51,6 +52,8 @@ - }; - - struct fbcon_ops { -+ void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width); - void (*clear)(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width); - void (*putcs)(struct vc_data *vc, struct fb_info *info, -@@ -149,6 +152,62 @@ - #define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0) - #define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1) - -+ /* -+ * Scroll Method -+ */ -+ -+/* There are several methods fbcon can use to move text around the screen: -+ * -+ * Operation Pan Wrap -+ *--------------------------------------------- -+ * SCROLL_MOVE copyarea No No -+ * SCROLL_PAN_MOVE copyarea Yes No -+ * SCROLL_WRAP_MOVE copyarea No Yes -+ * SCROLL_REDRAW imageblit No No -+ * SCROLL_PAN_REDRAW imageblit Yes No -+ * SCROLL_WRAP_REDRAW imageblit No Yes -+ * -+ * (SCROLL_WRAP_REDRAW is not implemented yet) -+ * -+ * In general, fbcon will choose the best scrolling -+ * method based on the rule below: -+ * -+ * Pan/Wrap > accel imageblit > accel copyarea > -+ * soft imageblit > (soft copyarea) -+ * -+ * Exception to the rule: Pan + accel copyarea is -+ * preferred over Pan + accel imageblit. -+ * -+ * The above is typical for PCI/AGP cards. Unless -+ * overridden, fbcon will never use soft copyarea. -+ * -+ * If you need to override the above rule, set the -+ * appropriate flags in fb_info->flags. For example, -+ * to prefer copyarea over imageblit, set -+ * FBINFO_READS_FAST. -+ * -+ * Other notes: -+ * + use the hardware engine to move the text -+ * (hw-accelerated copyarea() and fillrect()) -+ * + use hardware-supported panning on a large virtual screen -+ * + amifb can not only pan, but also wrap the display by N lines -+ * (i.e. visible line i = physical line (i+N) % yres). -+ * + read what's already rendered on the screen and -+ * write it in a different place (this is cfb_copyarea()) -+ * + re-render the text to the screen -+ * -+ * Whether to use wrapping or panning can only be figured out at -+ * runtime (when we know whether our font height is a multiple -+ * of the pan/wrap step) -+ * -+ */ -+ -+#define SCROLL_MOVE 0x001 -+#define SCROLL_PAN_MOVE 0x002 -+#define SCROLL_WRAP_MOVE 0x003 -+#define SCROLL_REDRAW 0x004 -+#define SCROLL_PAN_REDRAW 0x005 -+ - #ifdef CONFIG_FB_TILEBLITTING - extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info); - #endif ---- b/drivers/video/fbdev/core/fbcon_ccw.c -+++ a/drivers/video/fbdev/core/fbcon_ccw.c -@@ -59,12 +59,31 @@ - } - } - -+ -+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fb_copyarea area; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ -+ area.sx = sy * vc->vc_font.height; -+ area.sy = vyres - ((sx + width) * vc->vc_font.width); -+ area.dx = dy * vc->vc_font.height; -+ area.dy = vyres - ((dx + width) * vc->vc_font.width); -+ area.width = height * vc->vc_font.height; -+ area.height = width * vc->vc_font.width; -+ -+ info->fbops->fb_copyarea(info, &area); -+} -+ - static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) - { -+ struct fbcon_ops *ops = info->fbcon_par; - struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; - - region.color = attr_bgcol_ec(bgshift,vc,info); - region.dx = sy * vc->vc_font.height; -@@ -121,7 +140,7 @@ - u32 cnt, pitch, size; - u32 attribute = get_attribute(info, scr_readw(s)); - u8 *dst, *buf = NULL; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; - - if (!ops->fontbuffer) - return; -@@ -210,7 +229,7 @@ - int attribute, use_sw = vc->vc_cursor_type & CUR_SW; - int err = 1, dx, dy; - char *src; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; - - if (!ops->fontbuffer) - return; -@@ -368,7 +387,7 @@ - { - struct fbcon_ops *ops = info->fbcon_par; - u32 yoffset; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; - int err; - - yoffset = (vyres - info->var.yres) - ops->var.xoffset; -@@ -383,6 +402,7 @@ - - void fbcon_rotate_ccw(struct fbcon_ops *ops) - { -+ ops->bmove = ccw_bmove; - ops->clear = ccw_clear; - ops->putcs = ccw_putcs; - ops->clear_margins = ccw_clear_margins; ---- b/drivers/video/fbdev/core/fbcon_cw.c -+++ a/drivers/video/fbdev/core/fbcon_cw.c -@@ -44,12 +44,31 @@ - } - } - -+ -+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fb_copyarea area; -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -+ -+ area.sx = vxres - ((sy + height) * vc->vc_font.height); -+ area.sy = sx * vc->vc_font.width; -+ area.dx = vxres - ((dy + height) * vc->vc_font.height); -+ area.dy = dx * vc->vc_font.width; -+ area.width = height * vc->vc_font.height; -+ area.height = width * vc->vc_font.width; -+ -+ info->fbops->fb_copyarea(info, &area); -+} -+ - static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) - { -+ struct fbcon_ops *ops = info->fbcon_par; - struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vxres = info->var.xres; - - region.color = attr_bgcol_ec(bgshift,vc,info); - region.dx = vxres - ((sy + height) * vc->vc_font.height); -@@ -106,7 +125,7 @@ - u32 cnt, pitch, size; - u32 attribute = get_attribute(info, scr_readw(s)); - u8 *dst, *buf = NULL; -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vxres = info->var.xres; - - if (!ops->fontbuffer) - return; -@@ -193,7 +212,7 @@ - int attribute, use_sw = vc->vc_cursor_type & CUR_SW; - int err = 1, dx, dy; - char *src; -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vxres = info->var.xres; - - if (!ops->fontbuffer) - return; -@@ -350,7 +369,7 @@ - static int cw_update_start(struct fb_info *info) - { - struct fbcon_ops *ops = info->fbcon_par; -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vxres = info->var.xres; - u32 xoffset; - int err; - -@@ -366,6 +385,7 @@ - - void fbcon_rotate_cw(struct fbcon_ops *ops) - { -+ ops->bmove = cw_bmove; - ops->clear = cw_clear; - ops->putcs = cw_putcs; - ops->clear_margins = cw_clear_margins; ---- b/drivers/video/fbdev/core/fbcon_rotate.h -+++ a/drivers/video/fbdev/core/fbcon_rotate.h -@@ -11,6 +11,15 @@ - #ifndef _FBCON_ROTATE_H - #define _FBCON_ROTATE_H - -+#define GETVYRES(s,i) ({ \ -+ (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \ -+ (i)->var.yres : (i)->var.yres_virtual; }) -+ -+#define GETVXRES(s,i) ({ \ -+ (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \ -+ (i)->var.xres : (i)->var.xres_virtual; }) -+ -+ - static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat) - { - u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8; ---- b/drivers/video/fbdev/core/fbcon_ud.c -+++ a/drivers/video/fbdev/core/fbcon_ud.c -@@ -44,13 +44,33 @@ - } - } - -+ -+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fb_copyarea area; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -+ -+ area.sy = vyres - ((sy + height) * vc->vc_font.height); -+ area.sx = vxres - ((sx + width) * vc->vc_font.width); -+ area.dy = vyres - ((dy + height) * vc->vc_font.height); -+ area.dx = vxres - ((dx + width) * vc->vc_font.width); -+ area.height = height * vc->vc_font.height; -+ area.width = width * vc->vc_font.width; -+ -+ info->fbops->fb_copyarea(info, &area); -+} -+ - static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) - { -+ struct fbcon_ops *ops = info->fbcon_par; - struct fb_fillrect region; - int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; -- u32 vxres = info->var.xres; - - region.color = attr_bgcol_ec(bgshift,vc,info); - region.dy = vyres - ((sy + height) * vc->vc_font.height); -@@ -142,8 +162,8 @@ - u32 mod = vc->vc_font.width % 8, cnt, pitch, size; - u32 attribute = get_attribute(info, scr_readw(s)); - u8 *dst, *buf = NULL; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; -- u32 vxres = info->var.xres; - - if (!ops->fontbuffer) - return; -@@ -239,8 +259,8 @@ - int attribute, use_sw = vc->vc_cursor_type & CUR_SW; - int err = 1, dx, dy; - char *src; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; -- u32 vxres = info->var.xres; - - if (!ops->fontbuffer) - return; -@@ -390,8 +410,8 @@ - { - struct fbcon_ops *ops = info->fbcon_par; - int xoffset, yoffset; -+ u32 vyres = GETVYRES(ops->p->scrollmode, info); -+ u32 vxres = GETVXRES(ops->p->scrollmode, info); -- u32 vyres = info->var.yres; -- u32 vxres = info->var.xres; - int err; - - xoffset = vxres - info->var.xres - ops->var.xoffset; -@@ -409,6 +429,7 @@ - - void fbcon_rotate_ud(struct fbcon_ops *ops) - { -+ ops->bmove = ud_bmove; - ops->clear = ud_clear; - ops->putcs = ud_putcs; - ops->clear_margins = ud_clear_margins; ---- b/drivers/video/fbdev/core/tileblit.c -+++ a/drivers/video/fbdev/core/tileblit.c -@@ -16,6 +16,21 @@ - #include - #include "fbcon.h" - -+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy, -+ int sx, int dy, int dx, int height, int width) -+{ -+ struct fb_tilearea area; -+ -+ area.sx = sx; -+ area.sy = sy; -+ area.dx = dx; -+ area.dy = dy; -+ area.height = height; -+ area.width = width; -+ -+ info->tileops->fb_tilecopy(info, &area); -+} -+ - static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, - int sx, int height, int width) - { -@@ -118,6 +133,7 @@ - struct fb_tilemap map; - struct fbcon_ops *ops = info->fbcon_par; - -+ ops->bmove = tile_bmove; - ops->clear = tile_clear; - ops->putcs = tile_putcs; - ops->clear_margins = tile_clear_margins; ---- b/drivers/video/fbdev/skeletonfb.c -+++ a/drivers/video/fbdev/skeletonfb.c -@@ -505,15 +505,15 @@ - } - - /** -+ * xxxfb_copyarea - REQUIRED function. Can use generic routines if -+ * non acclerated hardware and packed pixel based. -- * xxxfb_copyarea - OBSOLETE function. - * Copies one area of the screen to another area. -- * Will be deleted in a future version - * - * @info: frame buffer structure that represents a single frame buffer - * @area: Structure providing the data to copy the framebuffer contents - * from one region to another. - * -+ * This drawing operation copies a rectangular area from one area of the -- * This drawing operation copied a rectangular area from one area of the - * screen to another area. - */ - void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) -@@ -645,9 +645,9 @@ - .fb_setcolreg = xxxfb_setcolreg, - .fb_blank = xxxfb_blank, - .fb_pan_display = xxxfb_pan_display, -+ .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ -+ .fb_copyarea = xxxfb_copyarea, /* Needed !!! */ -+ .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ -- .fb_fillrect = xxxfb_fillrect, /* Needed !!! */ -- .fb_copyarea = xxxfb_copyarea, /* Obsolete */ -- .fb_imageblit = xxxfb_imageblit, /* Needed !!! */ - .fb_cursor = xxxfb_cursor, /* Optional !!! */ - .fb_sync = xxxfb_sync, - .fb_ioctl = xxxfb_ioctl, ---- b/include/linux/fb.h -+++ a/include/linux/fb.h -@@ -262,7 +262,7 @@ - - /* Draws a rectangle */ - void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); -+ /* Copy data from area to another */ -- /* Copy data from area to another. Obsolete. */ - void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); - /* Draws a image to the display */ - void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); diff --git a/sys-kernel/pinephone-sources/files/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch b/sys-kernel/pinephone-sources/files/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch deleted file mode 100644 index e7d4da5..0000000 --- a/sys-kernel/pinephone-sources/files/0002-revert-fbcon-remove-now-unusued-softback_lines-cursor-argument.patch +++ /dev/null @@ -1,150 +0,0 @@ ---- b/drivers/video/fbdev/core/bitblit.c -+++ a/drivers/video/fbdev/core/bitblit.c -@@ -234,7 +234,7 @@ - } - - static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -- int fg, int bg) - { - struct fb_cursor cursor; - struct fbcon_ops *ops = info->fbcon_par; -@@ -247,6 +247,15 @@ - - cursor.set = 0; - -+ if (softback_lines) { -+ if (y + softback_lines >= vc->vc_rows) { -+ mode = CM_ERASE; -+ ops->cursor_flash = 0; -+ return; -+ } else -+ y += softback_lines; -+ } -+ - c = scr_readw((u16 *) vc->vc_pos); - attribute = get_attribute(info, c); - src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height)); ---- b/drivers/video/fbdev/core/fbcon.c -+++ a/drivers/video/fbdev/core/fbcon.c -@@ -394,7 +394,7 @@ - c = scr_readw((u16 *) vc->vc_pos); - mode = (!ops->cursor_flash || ops->cursor_state.enable) ? - CM_ERASE : CM_DRAW; -+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), -- ops->cursor(vc, info, mode, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - console_unlock(); - } -@@ -1345,7 +1345,7 @@ - - ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; - -+ ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), -- ops->cursor(vc, info, mode, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - } - ---- b/drivers/video/fbdev/core/fbcon.h -+++ a/drivers/video/fbdev/core/fbcon.h -@@ -62,7 +62,7 @@ - void (*clear_margins)(struct vc_data *vc, struct fb_info *info, - int color, int bottom_only); - void (*cursor)(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg); -- int fg, int bg); - int (*update_start)(struct fb_info *info); - int (*rotate_font)(struct fb_info *info, struct vc_data *vc); - struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */ ---- b/drivers/video/fbdev/core/fbcon_ccw.c -+++ a/drivers/video/fbdev/core/fbcon_ccw.c -@@ -219,7 +219,7 @@ - } - - static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -- int fg, int bg) - { - struct fb_cursor cursor; - struct fbcon_ops *ops = info->fbcon_par; -@@ -236,6 +236,15 @@ - - cursor.set = 0; - -+ if (softback_lines) { -+ if (y + softback_lines >= vc->vc_rows) { -+ mode = CM_ERASE; -+ ops->cursor_flash = 0; -+ return; -+ } else -+ y += softback_lines; -+ } -+ - c = scr_readw((u16 *) vc->vc_pos); - attribute = get_attribute(info, c); - src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ---- b/drivers/video/fbdev/core/fbcon_cw.c -+++ a/drivers/video/fbdev/core/fbcon_cw.c -@@ -202,7 +202,7 @@ - } - - static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -- int fg, int bg) - { - struct fb_cursor cursor; - struct fbcon_ops *ops = info->fbcon_par; -@@ -219,6 +219,15 @@ - - cursor.set = 0; - -+ if (softback_lines) { -+ if (y + softback_lines >= vc->vc_rows) { -+ mode = CM_ERASE; -+ ops->cursor_flash = 0; -+ return; -+ } else -+ y += softback_lines; -+ } -+ - c = scr_readw((u16 *) vc->vc_pos); - attribute = get_attribute(info, c); - src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width)); ---- b/drivers/video/fbdev/core/fbcon_ud.c -+++ a/drivers/video/fbdev/core/fbcon_ud.c -@@ -249,7 +249,7 @@ - } - - static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -- int fg, int bg) - { - struct fb_cursor cursor; - struct fbcon_ops *ops = info->fbcon_par; -@@ -267,6 +267,15 @@ - - cursor.set = 0; - -+ if (softback_lines) { -+ if (y + softback_lines >= vc->vc_rows) { -+ mode = CM_ERASE; -+ ops->cursor_flash = 0; -+ return; -+ } else -+ y += softback_lines; -+ } -+ - c = scr_readw((u16 *) vc->vc_pos); - attribute = get_attribute(info, c); - src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height)); ---- b/drivers/video/fbdev/core/tileblit.c -+++ a/drivers/video/fbdev/core/tileblit.c -@@ -80,7 +80,7 @@ - } - - static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode, -+ int softback_lines, int fg, int bg) -- int fg, int bg) - { - struct fb_tilecursor cursor; - int use_sw = (vc->vc_cursor_type & 0x10); diff --git a/sys-kernel/pinephone-sources/files/0002-sdhci-arasan-Add-runtime-PM-support.patch b/sys-kernel/pinephone-sources/files/0002-sdhci-arasan-Add-runtime-PM-support.patch deleted file mode 100644 index 0ceed66..0000000 --- a/sys-kernel/pinephone-sources/files/0002-sdhci-arasan-Add-runtime-PM-support.patch +++ /dev/null @@ -1,152 +0,0 @@ -From: Manish Narani -Date: Tue, 18 Sep 2018 20:34:06 +0530 -Subject: [PATCH 16/36] sdhci: arasan: Add runtime PM support - -Add runtime PM support in Arasan SDHCI driver. - -Signed-off-by: Manish Narani ---- - drivers/mmc/host/sdhci-of-arasan.c | 88 +++++++++++++++++++++++++++++++++++++- - 1 file changed, 86 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c -index 6a2e5a4..e08d6ef 100644 ---- a/drivers/mmc/host/sdhci-of-arasan.c -+++ b/drivers/mmc/host/sdhci-of-arasan.c -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -27,6 +28,7 @@ - #include "cqhci.h" - #include "sdhci-pltfm.h" - -+#define SDHCI_ARASAN_AUTOSUSPEND_DELAY 2000 /* ms */ - #define SDHCI_ARASAN_VENDOR_REGISTER 0x78 - - #define SDHCI_ARASAN_ITAPDLY_REGISTER 0xF0F8 -@@ -472,6 +474,70 @@ static const struct sdhci_pltfm_data sdhci_arasan_thunderbay_pdata = { - SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400, - }; - -+#ifdef CONFIG_PM -+static int sdhci_arasan_runtime_suspend(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct sdhci_host *host = platform_get_drvdata(pdev); -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); -+ int ret; -+ -+ if (sdhci_arasan->has_cqe) { -+ ret = cqhci_suspend(host->mmc); -+ if (ret) -+ return ret; -+ } -+ -+ ret = sdhci_runtime_suspend_host(host); -+ if (ret) -+ return ret; -+ -+ if (host->tuning_mode != SDHCI_TUNING_MODE_3) -+ mmc_retune_needed(host->mmc); -+ -+ clk_disable(pltfm_host->clk); -+ clk_disable(sdhci_arasan->clk_ahb); -+ -+ return 0; -+} -+ -+static int sdhci_arasan_runtime_resume(struct device *dev) -+{ -+ struct platform_device *pdev = to_platform_device(dev); -+ struct sdhci_host *host = platform_get_drvdata(pdev); -+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -+ struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); -+ int ret; -+ -+ ret = clk_enable(sdhci_arasan->clk_ahb); -+ if (ret) { -+ dev_err(dev, "Cannot enable AHB clock.\n"); -+ return ret; -+ } -+ -+ ret = clk_enable(pltfm_host->clk); -+ if (ret) { -+ dev_err(dev, "Cannot enable SD clock.\n"); -+ return ret; -+ } -+ -+ ret = sdhci_runtime_resume_host(host, 0); -+ if (ret) -+ goto out; -+ -+ if (sdhci_arasan->has_cqe) -+ return cqhci_resume(host->mmc); -+ -+ return 0; -+out: -+ clk_disable(pltfm_host->clk); -+ clk_disable(sdhci_arasan->clk_ahb); -+ -+ return ret; -+} -+#endif /* ! CONFIG_PM */ -+ - #ifdef CONFIG_PM_SLEEP - /** - * sdhci_arasan_suspend - Suspend method for the driver -@@ -568,8 +634,10 @@ static int sdhci_arasan_resume(struct device *dev) - } - #endif /* ! CONFIG_PM_SLEEP */ - --static SIMPLE_DEV_PM_OPS(sdhci_arasan_dev_pm_ops, sdhci_arasan_suspend, -- sdhci_arasan_resume); -+static const struct dev_pm_ops sdhci_arasan_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(sdhci_arasan_suspend, sdhci_arasan_resume) -+ SET_RUNTIME_PM_OPS(sdhci_arasan_runtime_suspend, -+ sdhci_arasan_runtime_resume, NULL) }; - - /** - * sdhci_arasan_sdcardclk_recalc_rate - Return the card clock rate -@@ -1708,13 +1776,25 @@ static int sdhci_arasan_probe(struct platform_device *pdev) - host->mmc->caps2 |= MMC_CAP2_CQE_DCMD; - } - -+ pm_runtime_get_noresume(&pdev->dev); -+ pm_runtime_set_active(&pdev->dev); -+ pm_runtime_enable(&pdev->dev); -+ pm_runtime_set_autosuspend_delay(&pdev->dev, -+ SDHCI_ARASAN_AUTOSUSPEND_DELAY); -+ pm_runtime_use_autosuspend(&pdev->dev); -+ - ret = sdhci_arasan_add_host(sdhci_arasan); - if (ret) - goto err_add_host; - -+ pm_runtime_put_autosuspend(&pdev->dev); -+ - return 0; - - err_add_host: -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); - if (!IS_ERR(sdhci_arasan->phy)) - phy_exit(sdhci_arasan->phy); - unreg_clk: -@@ -1742,6 +1822,10 @@ static int sdhci_arasan_remove(struct platform_device *pdev) - phy_exit(sdhci_arasan->phy); - } - -+ pm_runtime_get_sync(&pdev->dev); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ - sdhci_arasan_unregister_sdclk(&pdev->dev); - - ret = sdhci_pltfm_unregister(pdev); diff --git a/sys-kernel/pinephone-sources/files/0003-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch b/sys-kernel/pinephone-sources/files/0003-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch deleted file mode 100644 index fd8585a..0000000 --- a/sys-kernel/pinephone-sources/files/0003-clk-rk3399-Export-SCLK_CIF_OUT_SRC-to-device-tree.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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 diff --git a/sys-kernel/pinephone-sources/files/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch b/sys-kernel/pinephone-sources/files/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch deleted file mode 100644 index 6491c54..0000000 --- a/sys-kernel/pinephone-sources/files/0003-revert-fbcon-remove-no-op-fbcon_set_origin.patch +++ /dev/null @@ -1,31 +0,0 @@ ---- b/drivers/video/fbdev/core/fbcon.c -+++ a/drivers/video/fbdev/core/fbcon.c -@@ -163,6 +163,8 @@ - - #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) - -+static int fbcon_set_origin(struct vc_data *); -+ - static int fbcon_cursor_noblink; - - #define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1) -@@ -2633,6 +2635,11 @@ - } - } - -+static int fbcon_set_origin(struct vc_data *vc) -+{ -+ return 0; -+} -+ - void fbcon_suspended(struct fb_info *info) - { - struct vc_data *vc = NULL; -@@ -3103,6 +3110,7 @@ - .con_font_default = fbcon_set_def_font, - .con_font_copy = fbcon_copy_font, - .con_set_palette = fbcon_set_palette, -+ .con_set_origin = fbcon_set_origin, - .con_invert_region = fbcon_invert_region, - .con_screen_pos = fbcon_screen_pos, - .con_getxy = fbcon_getxy, diff --git a/sys-kernel/pinephone-sources/files/0004-media-rockchip-rga-Fix-probe-bugs.patch b/sys-kernel/pinephone-sources/files/0004-media-rockchip-rga-Fix-probe-bugs.patch deleted file mode 100644 index a0e574f..0000000 --- a/sys-kernel/pinephone-sources/files/0004-media-rockchip-rga-Fix-probe-bugs.patch +++ /dev/null @@ -1,39 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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; - } diff --git a/sys-kernel/pinephone-sources/files/0004-revert-fbcon-remove-soft-scrollback-code.patch b/sys-kernel/pinephone-sources/files/0004-revert-fbcon-remove-soft-scrollback-code.patch deleted file mode 100644 index 4f97354..0000000 --- a/sys-kernel/pinephone-sources/files/0004-revert-fbcon-remove-soft-scrollback-code.patch +++ /dev/null @@ -1,500 +0,0 @@ ---- b/drivers/video/fbdev/core/fbcon.c -+++ a/drivers/video/fbdev/core/fbcon.c -@@ -122,6 +122,12 @@ - /* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO - enums. */ - static int logo_shown = FBCON_LOGO_CANSHOW; -+/* Software scrollback */ -+static int fbcon_softback_size = 32768; -+static unsigned long softback_buf, softback_curr; -+static unsigned long softback_in; -+static unsigned long softback_top, softback_end; -+static int softback_lines; - /* console mappings */ - static int first_fb_vc; - static int last_fb_vc = MAX_NR_CONSOLES - 1; -@@ -161,6 +167,8 @@ - - static const struct consw fb_con; - -+#define CM_SOFTBACK (8) -+ - #define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row) - - static int fbcon_set_origin(struct vc_data *); -@@ -365,6 +373,18 @@ - return color; - } - -+static void fbcon_update_softback(struct vc_data *vc) -+{ -+ int l = fbcon_softback_size / vc->vc_size_row; -+ -+ if (l > 5) -+ softback_end = softback_buf + l * vc->vc_size_row; -+ else -+ /* Smaller scrollback makes no sense, and 0 would screw -+ the operation totally */ -+ softback_top = 0; -+} -+ - static void fb_flashcursor(struct work_struct *work) - { - struct fb_info *info = container_of(work, struct fb_info, queue); -@@ -394,7 +414,7 @@ - c = scr_readw((u16 *) vc->vc_pos); - mode = (!ops->cursor_flash || ops->cursor_state.enable) ? - CM_ERASE : CM_DRAW; -+ ops->cursor(vc, info, mode, softback_lines, get_color(vc, info, c, 1), -- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - console_unlock(); - } -@@ -451,7 +471,13 @@ - } - - if (!strncmp(options, "scrollback:", 11)) { -+ options += 11; -+ if (*options) { -+ fbcon_softback_size = simple_strtoul(options, &options, 0); -+ if (*options == 'k' || *options == 'K') { -+ fbcon_softback_size *= 1024; -+ } -+ } -- pr_warn("Ignoring scrollback size option\n"); - continue; - } - -@@ -996,6 +1022,31 @@ - - set_blitting_type(vc, info); - -+ if (info->fix.type != FB_TYPE_TEXT) { -+ if (fbcon_softback_size) { -+ if (!softback_buf) { -+ softback_buf = -+ (unsigned long) -+ kvmalloc(fbcon_softback_size, -+ GFP_KERNEL); -+ if (!softback_buf) { -+ fbcon_softback_size = 0; -+ softback_top = 0; -+ } -+ } -+ } else { -+ if (softback_buf) { -+ kvfree((void *) softback_buf); -+ softback_buf = 0; -+ softback_top = 0; -+ } -+ } -+ if (softback_buf) -+ softback_in = softback_top = softback_curr = -+ softback_buf; -+ softback_lines = 0; -+ } -+ - /* Setup default font */ - if (!p->fontdata && !vc->vc_font.data) { - if (!fontname[0] || !(font = find_font(fontname))) -@@ -1169,6 +1220,9 @@ - if (logo) - fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows); - -+ if (vc == svc && softback_buf) -+ fbcon_update_softback(vc); -+ - if (ops->rotate_font && ops->rotate_font(info, vc)) { - ops->rotate = FB_ROTATE_UR; - set_blitting_type(vc, info); -@@ -1331,6 +1385,7 @@ - { - struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct fbcon_ops *ops = info->fbcon_par; -+ int y; - int c = scr_readw((u16 *) vc->vc_pos); - - ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms); -@@ -1334,11 +1389,19 @@ static void fbcon_cursor(struct vc_data - fbcon_add_cursor_timer(info); - - ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1; -+ if (mode & CM_SOFTBACK) { -+ mode &= ~CM_SOFTBACK; -+ y = softback_lines; -+ } else { -+ if (softback_lines) -+ fbcon_set_origin(vc); -+ y = 0; -+ } - - if (!ops->cursor) - return; - -- ops->cursor(vc, info, mode, 0, get_color(vc, info, c, 1), -+ ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1), - get_color(vc, info, c, 0)); - } - -@@ -1416,6 +1479,8 @@ - - if (con_is_visible(vc)) { - update_screen(vc); -+ if (softback_buf) -+ fbcon_update_softback(vc); - } - } - -@@ -1553,6 +1618,99 @@ - scrollback_current = 0; - } - -+static void fbcon_redraw_softback(struct vc_data *vc, struct fbcon_display *p, -+ long delta) -+{ -+ int count = vc->vc_rows; -+ unsigned short *d, *s; -+ unsigned long n; -+ int line = 0; -+ -+ d = (u16 *) softback_curr; -+ if (d == (u16 *) softback_in) -+ d = (u16 *) vc->vc_origin; -+ n = softback_curr + delta * vc->vc_size_row; -+ softback_lines -= delta; -+ if (delta < 0) { -+ if (softback_curr < softback_top && n < softback_buf) { -+ n += softback_end - softback_buf; -+ if (n < softback_top) { -+ softback_lines -= -+ (softback_top - n) / vc->vc_size_row; -+ n = softback_top; -+ } -+ } else if (softback_curr >= softback_top -+ && n < softback_top) { -+ softback_lines -= -+ (softback_top - n) / vc->vc_size_row; -+ n = softback_top; -+ } -+ } else { -+ if (softback_curr > softback_in && n >= softback_end) { -+ n += softback_buf - softback_end; -+ if (n > softback_in) { -+ n = softback_in; -+ softback_lines = 0; -+ } -+ } else if (softback_curr <= softback_in && n > softback_in) { -+ n = softback_in; -+ softback_lines = 0; -+ } -+ } -+ if (n == softback_curr) -+ return; -+ softback_curr = n; -+ s = (u16 *) softback_curr; -+ if (s == (u16 *) softback_in) -+ s = (u16 *) vc->vc_origin; -+ while (count--) { -+ unsigned short *start; -+ unsigned short *le; -+ unsigned short c; -+ int x = 0; -+ unsigned short attr = 1; -+ -+ start = s; -+ le = advance_row(s, 1); -+ do { -+ c = scr_readw(s); -+ if (attr != (c & 0xff00)) { -+ attr = c & 0xff00; -+ if (s > start) { -+ fbcon_putcs(vc, start, s - start, -+ line, x); -+ x += s - start; -+ start = s; -+ } -+ } -+ if (c == scr_readw(d)) { -+ if (s > start) { -+ fbcon_putcs(vc, start, s - start, -+ line, x); -+ x += s - start + 1; -+ start = s + 1; -+ } else { -+ x++; -+ start++; -+ } -+ } -+ s++; -+ d++; -+ } while (s < le); -+ if (s > start) -+ fbcon_putcs(vc, start, s - start, line, x); -+ line++; -+ if (d == (u16 *) softback_end) -+ d = (u16 *) softback_buf; -+ if (d == (u16 *) softback_in) -+ d = (u16 *) vc->vc_origin; -+ if (s == (u16 *) softback_end) -+ s = (u16 *) softback_buf; -+ if (s == (u16 *) softback_in) -+ s = (u16 *) vc->vc_origin; -+ } -+} -+ - static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p, - int line, int count, int dy) - { -@@ -1692,6 +1850,31 @@ - } - } - -+static inline void fbcon_softback_note(struct vc_data *vc, int t, -+ int count) -+{ -+ unsigned short *p; -+ -+ if (vc->vc_num != fg_console) -+ return; -+ p = (unsigned short *) (vc->vc_origin + t * vc->vc_size_row); -+ -+ while (count) { -+ scr_memcpyw((u16 *) softback_in, p, vc->vc_size_row); -+ count--; -+ p = advance_row(p, 1); -+ softback_in += vc->vc_size_row; -+ if (softback_in == softback_end) -+ softback_in = softback_buf; -+ if (softback_in == softback_top) { -+ softback_top += vc->vc_size_row; -+ if (softback_top == softback_end) -+ softback_top = softback_buf; -+ } -+ } -+ softback_curr = softback_in; -+} -+ - static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b, - enum con_scroll dir, unsigned int count) - { -@@ -1714,6 +1897,8 @@ - case SM_UP: - if (count > vc->vc_rows) /* Maximum realistic size */ - count = vc->vc_rows; -+ if (softback_top) -+ fbcon_softback_note(vc, t, count); - if (logo_shown >= 0) - goto redraw_up; - switch (p->scrollmode) { -@@ -2084,6 +2269,14 @@ - info = registered_fb[con2fb_map[vc->vc_num]]; - ops = info->fbcon_par; - -+ if (softback_top) { -+ if (softback_lines) -+ fbcon_set_origin(vc); -+ softback_top = softback_curr = softback_in = softback_buf; -+ softback_lines = 0; -+ fbcon_update_softback(vc); -+ } -+ - if (logo_shown >= 0) { - struct vc_data *conp2 = vc_cons[logo_shown].d; - -@@ -2407,6 +2600,9 @@ - int cnt; - char *old_data = NULL; - -+ if (con_is_visible(vc) && softback_lines) -+ fbcon_set_origin(vc); -+ - resize = (w != vc->vc_font.width) || (h != vc->vc_font.height); - if (p->userfont) - old_data = vc->vc_font.data; -@@ -2432,6 +2628,8 @@ - cols /= w; - rows /= h; - vc_resize(vc, cols, rows); -+ if (con_is_visible(vc) && softback_buf) -+ fbcon_update_softback(vc); - } else if (con_is_visible(vc) - && vc->vc_mode == KD_TEXT) { - fbcon_clear_margins(vc, 0); -@@ -2590,7 +2788,19 @@ - - static u16 *fbcon_screen_pos(struct vc_data *vc, int offset) - { -+ unsigned long p; -+ int line; -+ -+ if (vc->vc_num != fg_console || !softback_lines) -+ return (u16 *) (vc->vc_origin + offset); -+ line = offset / vc->vc_size_row; -+ if (line >= softback_lines) -+ return (u16 *) (vc->vc_origin + offset - -+ softback_lines * vc->vc_size_row); -+ p = softback_curr + offset; -+ if (p >= softback_end) -+ p += softback_buf - softback_end; -+ return (u16 *) p; -- return (u16 *) (vc->vc_origin + offset); - } - - static unsigned long fbcon_getxy(struct vc_data *vc, unsigned long pos, -@@ -2604,7 +2814,22 @@ - - x = offset % vc->vc_cols; - y = offset / vc->vc_cols; -+ if (vc->vc_num == fg_console) -+ y += softback_lines; - ret = pos + (vc->vc_cols - x) * 2; -+ } else if (vc->vc_num == fg_console && softback_lines) { -+ unsigned long offset = pos - softback_curr; -+ -+ if (pos < softback_curr) -+ offset += softback_end - softback_buf; -+ offset /= 2; -+ x = offset % vc->vc_cols; -+ y = offset / vc->vc_cols; -+ ret = pos + (vc->vc_cols - x) * 2; -+ if (ret == softback_end) -+ ret = softback_buf; -+ if (ret == softback_in) -+ ret = vc->vc_origin; - } else { - /* Should not happen */ - x = y = 0; -@@ -2632,11 +2857,106 @@ - a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | - (((a) & 0x0700) << 4); - scr_writew(a, p++); -+ if (p == (u16 *) softback_end) -+ p = (u16 *) softback_buf; -+ if (p == (u16 *) softback_in) -+ p = (u16 *) vc->vc_origin; -+ } -+} -+ -+static void fbcon_scrolldelta(struct vc_data *vc, int lines) -+{ -+ struct fb_info *info = registered_fb[con2fb_map[fg_console]]; -+ struct fbcon_ops *ops = info->fbcon_par; -+ struct fbcon_display *disp = &fb_display[fg_console]; -+ int offset, limit, scrollback_old; -+ -+ if (softback_top) { -+ if (vc->vc_num != fg_console) -+ return; -+ if (vc->vc_mode != KD_TEXT || !lines) -+ return; -+ if (logo_shown >= 0) { -+ struct vc_data *conp2 = vc_cons[logo_shown].d; -+ -+ if (conp2->vc_top == logo_lines -+ && conp2->vc_bottom == conp2->vc_rows) -+ conp2->vc_top = 0; -+ if (logo_shown == vc->vc_num) { -+ unsigned long p, q; -+ int i; -+ -+ p = softback_in; -+ q = vc->vc_origin + -+ logo_lines * vc->vc_size_row; -+ for (i = 0; i < logo_lines; i++) { -+ if (p == softback_top) -+ break; -+ if (p == softback_buf) -+ p = softback_end; -+ p -= vc->vc_size_row; -+ q -= vc->vc_size_row; -+ scr_memcpyw((u16 *) q, (u16 *) p, -+ vc->vc_size_row); -+ } -+ softback_in = softback_curr = p; -+ update_region(vc, vc->vc_origin, -+ logo_lines * vc->vc_cols); -+ } -+ logo_shown = FBCON_LOGO_CANSHOW; -+ } -+ fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); -+ fbcon_redraw_softback(vc, disp, lines); -+ fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); -+ return; - } -+ -+ if (!scrollback_phys_max) -+ return; -+ -+ scrollback_old = scrollback_current; -+ scrollback_current -= lines; -+ if (scrollback_current < 0) -+ scrollback_current = 0; -+ else if (scrollback_current > scrollback_max) -+ scrollback_current = scrollback_max; -+ if (scrollback_current == scrollback_old) -+ return; -+ -+ if (fbcon_is_inactive(vc, info)) -+ return; -+ -+ fbcon_cursor(vc, CM_ERASE); -+ -+ offset = disp->yscroll - scrollback_current; -+ limit = disp->vrows; -+ switch (disp->scrollmode) { -+ case SCROLL_WRAP_MOVE: -+ info->var.vmode |= FB_VMODE_YWRAP; -+ break; -+ case SCROLL_PAN_MOVE: -+ case SCROLL_PAN_REDRAW: -+ limit -= vc->vc_rows; -+ info->var.vmode &= ~FB_VMODE_YWRAP; -+ break; -+ } -+ if (offset < 0) -+ offset += limit; -+ else if (offset >= limit) -+ offset -= limit; -+ -+ ops->var.xoffset = 0; -+ ops->var.yoffset = offset * vc->vc_font.height; -+ ops->update_start(info); -+ -+ if (!scrollback_current) -+ fbcon_cursor(vc, CM_DRAW); - } - - static int fbcon_set_origin(struct vc_data *vc) - { -+ if (softback_lines) -+ fbcon_scrolldelta(vc, softback_lines); - return 0; - } - -@@ -2700,6 +3020,8 @@ - - fbcon_set_palette(vc, color_table); - update_screen(vc); -+ if (softback_buf) -+ fbcon_update_softback(vc); - } - } - -@@ -3110,6 +3432,7 @@ - .con_font_default = fbcon_set_def_font, - .con_font_copy = fbcon_copy_font, - .con_set_palette = fbcon_set_palette, -+ .con_scrolldelta = fbcon_scrolldelta, - .con_set_origin = fbcon_set_origin, - .con_invert_region = fbcon_invert_region, - .con_screen_pos = fbcon_screen_pos, -@@ -3344,6 +3667,9 @@ - } - #endif - -+ kvfree((void *)softback_buf); -+ softback_buf = 0UL; -+ - for_each_registered_fb(i) { - int pending = 0; - diff --git a/sys-kernel/pinephone-sources/files/0005-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch b/sys-kernel/pinephone-sources/files/0005-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch deleted file mode 100644 index 686dc3e..0000000 --- a/sys-kernel/pinephone-sources/files/0005-drm-dw-mipi-dsi-rockchip-Ensure-that-lane-is-properl.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: =?utf-8?q?Kamil_Trzci=C5=84ski?= -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 ---- - 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, diff --git a/sys-kernel/pinephone-sources/files/0006-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch b/sys-kernel/pinephone-sources/files/0006-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch deleted file mode 100644 index 425c986..0000000 --- a/sys-kernel/pinephone-sources/files/0006-drm-rockchip-dw-mipi-dsi-Fix-missing-clk_disable_unp.patch +++ /dev/null @@ -1,48 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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, diff --git a/sys-kernel/pinephone-sources/files/0007-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch b/sys-kernel/pinephone-sources/files/0007-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch deleted file mode 100644 index e2eddd2..0000000 --- a/sys-kernel/pinephone-sources/files/0007-drm-bridge-dw-mipi-dsi-Fix-enable-disable-of-dsi-con.patch +++ /dev/null @@ -1,145 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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, diff --git a/sys-kernel/pinephone-sources/files/0008-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch b/sys-kernel/pinephone-sources/files/0008-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch deleted file mode 100644 index 003fd7c..0000000 --- a/sys-kernel/pinephone-sources/files/0008-drm-dw-mipi-dsi-rockchip-Never-allow-lane-bandwidth-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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; diff --git a/sys-kernel/pinephone-sources/files/0009-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch b/sys-kernel/pinephone-sources/files/0009-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch deleted file mode 100644 index 187e5e2..0000000 --- a/sys-kernel/pinephone-sources/files/0009-drm-rockchip-cdn-dp-Disable-CDN-DP-on-disconnect.patch +++ /dev/null @@ -1,23 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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"); diff --git a/sys-kernel/pinephone-sources/files/0010-video-fbdev-Add-events-for-early-fb-event-support.patch b/sys-kernel/pinephone-sources/files/0010-video-fbdev-Add-events-for-early-fb-event-support.patch deleted file mode 100644 index d424c70..0000000 --- a/sys-kernel/pinephone-sources/files/0010-video-fbdev-Add-events-for-early-fb-event-support.patch +++ /dev/null @@ -1,69 +0,0 @@ -From: Ondrej Jirman -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 -Signed-off-by: Kyungmin Park ---- - drivers/video/fbdev/core/fbmem.c | 12 +++++++++++- - include/linux/fb.h | 5 +++++ - 2 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c -index 826175a..fb1651a 100644 ---- a/drivers/video/fbdev/core/fbmem.c -+++ b/drivers/video/fbdev/core/fbmem.c -@@ -1067,7 +1067,7 @@ int - fb_blank(struct fb_info *info, int blank) - { - struct fb_event event; -- int ret = -EINVAL; -+ int ret = -EINVAL, early_ret; - - if (blank > FB_BLANK_POWERDOWN) - blank = FB_BLANK_POWERDOWN; -@@ -1075,11 +1075,21 @@ fb_blank(struct fb_info *info, int blank) - event.info = info; - event.data = ␣ - -+ early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event); -+ - if (info->fbops->fb_blank) - ret = info->fbops->fb_blank(blank, info); - - if (!ret) - fb_notifier_call_chain(FB_EVENT_BLANK, &event); -+ else { -+ /* -+ * if fb_blank is failed then revert effects of -+ * the early blank event. -+ */ -+ if (!early_ret) -+ fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event); -+ } - - return ret; - } -diff --git a/include/linux/fb.h b/include/linux/fb.h -index 6f3db99..ffef502a 100644 ---- a/include/linux/fb.h -+++ b/include/linux/fb.h -@@ -137,6 +137,11 @@ struct fb_cursor_user { - /* A display blank is requested */ - #define FB_EVENT_BLANK 0x09 - -+/* A hardware display blank early change occured */ -+#define FB_EARLY_EVENT_BLANK 0x10 -+/* A hardware display blank revert early change occured */ -+#define FB_R_EARLY_EVENT_BLANK 0x11 -+ - struct fb_event { - struct fb_info *info; - void *data; diff --git a/sys-kernel/pinephone-sources/files/0011-power-rk818-Configure-rk808-clkout2-function.patch b/sys-kernel/pinephone-sources/files/0011-power-rk818-Configure-rk808-clkout2-function.patch deleted file mode 100644 index 8ff73f2..0000000 --- a/sys-kernel/pinephone-sources/files/0011-power-rk818-Configure-rk808-clkout2-function.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: =?utf-8?q?Kamil_Trzci=C5=84ski?= -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 ---- - 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 diff --git a/sys-kernel/pinephone-sources/files/0012-power-rk818-battery-Add-battery-driver-for-RK818.patch b/sys-kernel/pinephone-sources/files/0012-power-rk818-battery-Add-battery-driver-for-RK818.patch deleted file mode 100644 index fd0eb7e..0000000 --- a/sys-kernel/pinephone-sources/files/0012-power-rk818-battery-Add-battery-driver-for-RK818.patch +++ /dev/null @@ -1,3964 +0,0 @@ -From: =?utf-8?q?Kamil_Trzci=C5=84ski?= -Date: Sun, 3 Jan 2021 11:43:38 +0100 -Subject: [PATCH 12/36] power: rk818-battery: Add battery driver for RK818 -MIME-Version: 1.0 -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: 8bit - -This is forward ported driver from Rockchip BSP. - -Signed-of-by: Kamil Trzciński ---- - drivers/mfd/rk808.c | 40 +- - drivers/power/supply/Kconfig | 8 + - drivers/power/supply/Makefile | 1 + - drivers/power/supply/rk818_battery.c | 3568 ++++++++++++++++++++++++++++++++++ - drivers/power/supply/rk818_battery.h | 168 ++ - include/linux/mfd/rk808.h | 81 +- - 6 files changed, 3863 insertions(+), 3 deletions(-) - create mode 100644 drivers/power/supply/rk818_battery.c - create mode 100644 drivers/power/supply/rk818_battery.h - -diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c -index 1a6857e..7d1f000 100644 ---- a/drivers/mfd/rk808.c -+++ b/drivers/mfd/rk808.c -@@ -76,12 +76,47 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) - return true; - } - -+static bool rk818_is_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ /* -+ * Notes: -+ * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but -+ * we don't use that feature. It's better to cache. -+ * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since -+ * bits are cleared in case when we shutoff anyway, but better safe. -+ */ -+ -+ switch (reg) { -+ case RK808_SECONDS_REG ... RK808_WEEKS_REG: -+ case RK808_RTC_STATUS_REG: -+ case RK808_VB_MON_REG: -+ case RK808_THERMAL_REG: -+ case RK808_DCDC_EN_REG: -+ case RK808_LDO_EN_REG: -+ case RK808_DCDC_UV_STS_REG: -+ case RK808_LDO_UV_STS_REG: -+ case RK808_DCDC_PG_REG: -+ case RK808_LDO_PG_REG: -+ case RK808_DEVCTRL_REG: -+ case RK808_INT_STS_REG1: -+ case RK808_INT_STS_REG2: -+ case RK808_INT_STS_MSK_REG1: -+ case RK808_INT_STS_MSK_REG2: -+ case RK818_LDO8_ON_VSEL_REG: // TODO(ayufan):?? -+ case RK818_LDO8_SLP_VSEL_REG: // TODO(ayufan):?? -+ case RK818_SUP_STS_REG ... RK818_SAVE_DATA19: -+ return true; -+ } -+ -+ return false; -+} -+ - static const struct regmap_config rk818_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -- .max_register = RK818_USB_CTRL_REG, -+ .max_register = RK818_SAVE_DATA19, - .cache_type = REGCACHE_RBTREE, -- .volatile_reg = rk808_is_volatile_reg, -+ .volatile_reg = rk818_is_volatile_reg, - }; - - static const struct regmap_config rk805_regmap_config = { -@@ -170,6 +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 = "rk808-rtc", - .num_resources = ARRAY_SIZE(rtc_resources), -diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig -index 5cf5bb5..f5d4434 100644 ---- a/drivers/power/supply/Kconfig -+++ b/drivers/power/supply/Kconfig -@@ -854,4 +854,12 @@ config CHARGER_SURFACE - Microsoft Surface devices, i.e. Surface Pro 7, Surface Laptop 3, - Surface Book 3, and Surface Laptop Go. - -+config BATTERY_RK818 -+ bool "RK818 Battery driver" -+ depends on MFD_RK808 -+ default n -+ help -+ 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. -+ - endif # POWER_SUPPLY -diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile -index 4e55a11aab..1c725ee 100644 ---- a/drivers/power/supply/Makefile -+++ b/drivers/power/supply/Makefile -@@ -104,3 +104,4 @@ obj-$(CONFIG_RN5T618_POWER) += rn5t618_power.o - 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 -diff --git a/drivers/power/supply/rk818_battery.c b/drivers/power/supply/rk818_battery.c -new file mode 100644 -index 00000000..f09f456 ---- /dev/null -+++ b/drivers/power/supply/rk818_battery.c -@@ -0,0 +1,3568 @@ -+/* -+ * rk818 battery driver -+ * -+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd -+ * chenjh -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+//#include -+#include -+//#include -+#include -+#include -+#include -+//#include -+#include -+#include "rk818_battery.h" -+ -+static int dbg_enable = 0; -+module_param_named(dbg_level, dbg_enable, int, 0644); -+ -+#define DBG(args...) \ -+ do { \ -+ if (dbg_enable) { \ -+ pr_info(args); \ -+ } \ -+ } while (0) -+ -+#define BAT_INFO(fmt, args...) pr_info("rk818-bat: "fmt, ##args) -+ -+/* default param */ -+#define DEFAULT_BAT_RES 135 -+#define DEFAULT_SLP_ENTER_CUR 300 -+#define DEFAULT_SLP_EXIT_CUR 300 -+#define DEFAULT_SLP_FILTER_CUR 100 -+#define DEFAULT_PWROFF_VOL_THRESD 3400 -+#define DEFAULT_MONITOR_SEC 5 -+#define DEFAULT_ALGR_VOL_THRESD1 3850 -+#define DEFAULT_ALGR_VOL_THRESD2 3950 -+#define DEFAULT_MAX_SOC_OFFSET 60 -+#define DEFAULT_FB_TEMP TEMP_105C -+#define DEFAULT_ZERO_RESERVE_DSOC 10 -+#define DEFAULT_POFFSET 42 -+#define DEFAULT_COFFSET 0x832 -+#define DEFAULT_SAMPLE_RES 20 -+#define DEFAULT_ENERGY_MODE 0 -+#define INVALID_COFFSET_MIN 0x780 -+#define INVALID_COFFSET_MAX 0x980 -+#define INVALID_VOL_THRESD 2500 -+ -+/* sample resistor and division */ -+#define SAMPLE_RES_10MR 10 -+#define SAMPLE_RES_20MR 20 -+#define SAMPLE_RES_DIV1 1 -+#define SAMPLE_RES_DIV2 2 -+ -+/* virtual params */ -+#define VIRTUAL_CURRENT 1000 -+#define VIRTUAL_VOLTAGE 3888 -+#define VIRTUAL_SOC 66 -+#define VIRTUAL_PRESET 1 -+#define VIRTUAL_TEMPERATURE 188 -+#define VIRTUAL_STATUS POWER_SUPPLY_STATUS_CHARGING -+ -+/* charge */ -+#define FINISH_CHRG_CUR1 1000 -+#define FINISH_CHRG_CUR2 1500 -+#define FINISH_MAX_SOC_DELAY 20 -+#define TERM_CHRG_DSOC 88 -+#define TERM_CHRG_CURR 600 -+#define TERM_CHRG_K 650 -+#define SIMULATE_CHRG_INTV 8 -+#define SIMULATE_CHRG_CURR 400 -+#define SIMULATE_CHRG_K 1500 -+#define FULL_CHRG_K 400 -+ -+/* zero algorithm */ -+#define PWROFF_THRESD 3400 -+#define MIN_ZERO_DSOC_ACCURACY 10 /*0.01%*/ -+#define MIN_ZERO_OVERCNT 100 -+#define MIN_ACCURACY 1 -+#define DEF_PWRPATH_RES 50 -+#define WAIT_DSOC_DROP_SEC 15 -+#define WAIT_SHTD_DROP_SEC 30 -+#define ZERO_GAP_XSOC1 10 -+#define ZERO_GAP_XSOC2 5 -+#define ZERO_GAP_XSOC3 3 -+#define ZERO_LOAD_LVL1 1400 -+#define ZERO_LOAD_LVL2 600 -+#define ZERO_GAP_CALIB 5 -+ -+#define ADC_CALIB_THRESHOLD 4 -+#define ADC_CALIB_LMT_MIN 3 -+#define ADC_CALIB_CNT 5 -+#define NTC_CALC_FACTOR 7 -+ -+/* time */ -+#define POWER_ON_SEC_BASE 1 -+#define MINUTE(x) ((x) * 60) -+ -+/* sleep */ -+#define SLP_CURR_MAX 40 -+#define SLP_CURR_MIN 6 -+#define DISCHRG_TIME_STEP1 MINUTE(10) -+#define DISCHRG_TIME_STEP2 MINUTE(60) -+#define SLP_DSOC_VOL_THRESD 3600 -+#define REBOOT_PERIOD_SEC 180 -+#define REBOOT_MAX_CNT 80 -+ -+/* fcc */ -+#define MIN_FCC 500 -+ -+/* TS detect battery temperature */ -+#define ADC_CUR_MSK 0x03 -+#define ADC_CUR_20UA 0x00 -+#define ADC_CUR_40UA 0x01 -+#define ADC_CUR_60UA 0x02 -+#define ADC_CUR_80UA 0x03 -+ -+#define NTC_CALC_FACTOR_80UA 7 -+#define NTC_CALC_FACTOR_60UA 9 -+#define NTC_CALC_FACTOR_40UA 13 -+#define NTC_CALC_FACTOR_20UA 27 -+#define NTC_80UA_MAX_MEASURE 27500 -+#define NTC_60UA_MAX_MEASURE 36666 -+#define NTC_40UA_MAX_MEASURE 55000 -+#define NTC_20UA_MAX_MEASURE 110000 -+ -+static const char *bat_status[] = { -+ "charge off", "dead charge", "trickle charge", "cc cv", -+ "finish", "usb over vol", "bat temp error", "timer error", -+}; -+ -+struct rk818_battery { -+ struct platform_device *pdev; -+ struct rk808 *rk818; -+ struct regmap *regmap; -+ struct device *dev; -+ struct power_supply *bat; -+ struct power_supply *usb_psy; -+ struct power_supply *ac_psy; -+ struct battery_platform_data *pdata; -+ struct workqueue_struct *bat_monitor_wq; -+ struct delayed_work bat_delay_work; -+ struct delayed_work calib_delay_work; -+ // struct wake_lock wake_lock; -+ struct notifier_block fb_nb; -+ struct timer_list caltimer; -+ time64_t rtc_base; -+ int bat_res; -+ int chrg_status; -+ bool is_initialized; -+ bool is_first_power_on; -+ u8 res_div; -+ int current_max; -+ int voltage_max; -+ int current_avg; -+ int voltage_avg; -+ int voltage_ocv; -+ int voltage_relax; -+ int voltage_k; -+ int voltage_b; -+ int remain_cap; -+ int design_cap; -+ int nac; -+ int fcc; -+ int qmax; -+ int dsoc; -+ int rsoc; -+ int poffset; -+ int age_ocv_soc; -+ bool age_allow_update; -+ int age_level; -+ int age_ocv_cap; -+ int age_voltage; -+ int age_adjust_cap; -+ unsigned long age_keep_sec; -+ int zero_timeout_cnt; -+ int zero_remain_cap; -+ int zero_dsoc; -+ int zero_linek; -+ u64 zero_drop_sec; -+ u64 shtd_drop_sec; -+ int sm_remain_cap; -+ int sm_linek; -+ int sm_chrg_dsoc; -+ int sm_dischrg_dsoc; -+ int algo_rest_val; -+ int algo_rest_mode; -+ int sleep_sum_cap; -+ int sleep_remain_cap; -+ unsigned long sleep_dischrg_sec; -+ unsigned long sleep_sum_sec; -+ bool sleep_chrg_online; -+ u8 sleep_chrg_status; -+ bool adc_allow_update; -+ int fb_blank; -+ bool s2r; /*suspend to resume*/ -+ u32 work_mode; -+ int temperature; -+ u32 monitor_ms; -+ u32 pwroff_min; -+ u32 adc_calib_cnt; -+ unsigned long finish_base; -+ unsigned long boot_base; -+ unsigned long flat_match_sec; -+ unsigned long plug_in_base; -+ unsigned long plug_out_base; -+ u8 halt_cnt; -+ bool is_halt; -+ bool is_max_soc_offset; -+ bool is_sw_reset; -+ bool is_ocv_calib; -+ bool is_first_on; -+ bool is_force_calib; -+ int last_dsoc; -+ int ocv_pre_dsoc; -+ int ocv_new_dsoc; -+ int max_pre_dsoc; -+ int max_new_dsoc; -+ int force_pre_dsoc; -+ int force_new_dsoc; -+ int dbg_cap_low0; -+ int dbg_pwr_dsoc; -+ int dbg_pwr_rsoc; -+ int dbg_pwr_vol; -+ int dbg_chrg_min[10]; -+ int dbg_meet_soc; -+ int dbg_calc_dsoc; -+ int dbg_calc_rsoc; -+ u8 ac_in; -+ u8 usb_in; -+ int is_charging; -+ unsigned long charge_count; -+}; -+ -+#define DIV(x) ((x) ? (x) : 1) -+ -+static void rk_send_wakeup_key(void) -+{ -+ // TODO: WHAT TO DO HERE? -+} -+ -+static u64 get_boot_sec(void) -+{ -+ struct timespec64 ts; -+ -+ ktime_get_boottime_ts64(&ts); -+ -+ return ts.tv_sec; -+} -+ -+static unsigned long base2sec(unsigned long x) -+{ -+ if (x) -+ return (get_boot_sec() > x) ? (get_boot_sec() - x) : 0; -+ else -+ return 0; -+} -+ -+static unsigned long base2min(unsigned long x) -+{ -+ return base2sec(x) / 60; -+} -+ -+static u32 interpolate(int value, u32 *table, int size) -+{ -+ u8 i; -+ u16 d; -+ -+ for (i = 0; i < size; i++) { -+ if (value < table[i]) -+ break; -+ } -+ -+ if ((i > 0) && (i < size)) { -+ d = (value - table[i - 1]) * (MAX_INTERPOLATE / (size - 1)); -+ d /= table[i] - table[i - 1]; -+ d = d + (i - 1) * (MAX_INTERPOLATE / (size - 1)); -+ } else { -+ d = i * ((MAX_INTERPOLATE + size / 2) / size); -+ } -+ -+ if (d > 1000) -+ d = 1000; -+ -+ return d; -+} -+ -+/* (a*b)/c */ -+static int32_t ab_div_c(u32 a, u32 b, u32 c) -+{ -+ bool sign; -+ u32 ans = MAX_INT; -+ int tmp; -+ -+ sign = ((((a ^ b) ^ c) & 0x80000000) != 0); -+ if (c != 0) { -+ if (sign) -+ c = -c; -+ tmp = (a * b + (c >> 1)) / c; -+ if (tmp < MAX_INT) -+ ans = tmp; -+ } -+ -+ if (sign) -+ ans = -ans; -+ -+ return ans; -+} -+ -+static int rk818_bat_read(struct rk818_battery *di, u8 reg) -+{ -+ int ret, val; -+ -+ ret = regmap_read(di->regmap, reg, &val); -+ if (ret) -+ dev_err(di->dev, "read reg:0x%x failed\n", reg); -+ -+ return val; -+} -+ -+static int rk818_bat_write(struct rk818_battery *di, u8 reg, u8 buf) -+{ -+ int ret; -+ -+ ret = regmap_write(di->regmap, reg, buf); -+ if (ret) -+ dev_err(di->dev, "i2c write reg: 0x%2x error\n", reg); -+ -+ return ret; -+} -+ -+static int rk818_bat_set_bits(struct rk818_battery *di, u8 reg, u8 mask, u8 buf) -+{ -+ int ret; -+ -+ ret = regmap_update_bits(di->regmap, reg, mask, buf); -+ if (ret) -+ dev_err(di->dev, "write reg:0x%x failed\n", reg); -+ -+ return ret; -+} -+ -+static int rk818_bat_clear_bits(struct rk818_battery *di, u8 reg, u8 mask) -+{ -+ int ret; -+ -+ ret = regmap_update_bits(di->regmap, reg, mask, 0); -+ if (ret) -+ dev_err(di->dev, "clr reg:0x%02x failed\n", reg); -+ -+ return ret; -+} -+ -+static void rk818_bat_dump_regs(struct rk818_battery *di, u8 start, u8 end) -+{ -+ int i; -+ -+ if (!dbg_enable) -+ return; -+ -+ DBG("dump regs from: 0x%x-->0x%x\n", start, end); -+ for (i = start; i < end; i++) -+ DBG("0x%x: 0x%0x\n", i, rk818_bat_read(di, i)); -+} -+ -+static bool rk818_bat_chrg_online(struct rk818_battery *di) -+{ -+ u8 buf; -+ -+ buf = rk818_bat_read(di, RK818_VB_MON_REG); -+ -+ return (buf & PLUG_IN_STS) ? true : false; -+} -+ -+static int rk818_bat_get_coulomb_cap(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_GASCNT3_REG) << 24; -+ val |= rk818_bat_read(di, RK818_GASCNT2_REG) << 16; -+ val |= rk818_bat_read(di, RK818_GASCNT1_REG) << 8; -+ val |= rk818_bat_read(di, RK818_GASCNT0_REG) << 0; -+ -+ return (val / 2390) * di->res_div; -+} -+ -+static int rk818_bat_get_rsoc(struct rk818_battery *di) -+{ -+ int remain_cap; -+ -+ remain_cap = rk818_bat_get_coulomb_cap(di); -+ return (remain_cap + di->fcc / 200) * 100 / DIV(di->fcc); -+} -+ -+static ssize_t bat_info_store(struct device *dev, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ char cmd; -+ struct rk818_battery *di = dev_get_drvdata(dev); -+ -+ sscanf(buf, "%c", &cmd); -+ -+ if (cmd == 'n') -+ rk818_bat_set_bits(di, RK818_MISC_MARK_REG, -+ FG_RESET_NOW, FG_RESET_NOW); -+ else if (cmd == 'm') -+ rk818_bat_set_bits(di, RK818_MISC_MARK_REG, -+ FG_RESET_LATE, FG_RESET_LATE); -+ else if (cmd == 'c') -+ rk818_bat_clear_bits(di, RK818_MISC_MARK_REG, -+ FG_RESET_LATE | FG_RESET_NOW); -+ else if (cmd == 'r') -+ BAT_INFO("0x%2x\n", rk818_bat_read(di, RK818_MISC_MARK_REG)); -+ else -+ BAT_INFO("command error\n"); -+ -+ return count; -+} -+ -+static struct device_attribute rk818_bat_attr[] = { -+ __ATTR(bat, 0664, NULL, bat_info_store), -+}; -+ -+static void rk818_bat_enable_gauge(struct rk818_battery *di) -+{ -+ u8 buf; -+ -+ buf = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ buf |= GG_EN; -+ rk818_bat_write(di, RK818_TS_CTRL_REG, buf); -+} -+ -+static void rk818_bat_save_age_level(struct rk818_battery *di, u8 level) -+{ -+ rk818_bat_write(di, RK818_UPDAT_LEVE_REG, level); -+} -+ -+static u8 rk818_bat_get_age_level(struct rk818_battery *di) -+{ -+ return rk818_bat_read(di, RK818_UPDAT_LEVE_REG); -+} -+ -+static int rk818_bat_get_vcalib0(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_VCALIB0_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_VCALIB0_REGH) << 8; -+ -+ DBG("<%s>. voffset0: 0x%x\n", __func__, val); -+ return val; -+} -+ -+static int rk818_bat_get_vcalib1(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_VCALIB1_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_VCALIB1_REGH) << 8; -+ -+ DBG("<%s>. voffset1: 0x%x\n", __func__, val); -+ return val; -+} -+ -+static int rk818_bat_get_ioffset(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_IOFFSET_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_IOFFSET_REGH) << 8; -+ -+ DBG("<%s>. ioffset: 0x%x\n", __func__, val); -+ return val; -+} -+ -+static int rk818_bat_get_coffset(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_CAL_OFFSET_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_CAL_OFFSET_REGH) << 8; -+ -+ DBG("<%s>. coffset: 0x%x\n", __func__, val); -+ return val; -+} -+ -+static void rk818_bat_set_coffset(struct rk818_battery *di, int val) -+{ -+ u8 buf; -+ -+ if ((val < INVALID_COFFSET_MIN) || (val > INVALID_COFFSET_MAX)) { -+ BAT_INFO("set invalid coffset=0x%x\n", val); -+ return; -+ } -+ -+ buf = (val >> 8) & 0xff; -+ rk818_bat_write(di, RK818_CAL_OFFSET_REGH, buf); -+ buf = (val >> 0) & 0xff; -+ rk818_bat_write(di, RK818_CAL_OFFSET_REGL, buf); -+ DBG("<%s>. coffset: 0x%x\n", __func__, val); -+} -+ -+static void rk818_bat_init_voltage_kb(struct rk818_battery *di) -+{ -+ int vcalib0, vcalib1; -+ -+ vcalib0 = rk818_bat_get_vcalib0(di); -+ vcalib1 = rk818_bat_get_vcalib1(di); -+ di->voltage_k = (4200 - 3000) * 1000 / DIV(vcalib1 - vcalib0); -+ di->voltage_b = 4200 - (di->voltage_k * vcalib1) / 1000; -+ -+ DBG("voltage_k=%d(*1000),voltage_b=%d\n", di->voltage_k, di->voltage_b); -+} -+ -+static int rk818_bat_get_ocv_voltage(struct rk818_battery *di) -+{ -+ int vol, val = 0; -+ -+ val |= rk818_bat_read(di, RK818_BAT_OCV_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_BAT_OCV_REGH) << 8; -+ -+ vol = di->voltage_k * val / 1000 + di->voltage_b; -+ -+ return vol; -+} -+ -+static int rk818_bat_get_avg_voltage(struct rk818_battery *di) -+{ -+ int vol, val = 0; -+ -+ val |= rk818_bat_read(di, RK818_BAT_VOL_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_BAT_VOL_REGH) << 8; -+ -+ vol = di->voltage_k * val / 1000 + di->voltage_b; -+ -+ return vol; -+} -+ -+static bool is_rk818_bat_relax_mode(struct rk818_battery *di) -+{ -+ u8 status; -+ -+ status = rk818_bat_read(di, RK818_GGSTS_REG); -+ if (!(status & RELAX_VOL1_UPD) || !(status & RELAX_VOL2_UPD)) -+ return false; -+ else -+ return true; -+} -+ -+static u16 rk818_bat_get_relax_vol1(struct rk818_battery *di) -+{ -+ u16 vol, val = 0; -+ -+ val |= rk818_bat_read(di, RK818_RELAX_VOL1_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_RELAX_VOL1_REGH) << 8; -+ vol = di->voltage_k * val / 1000 + di->voltage_b; -+ -+ return vol; -+} -+ -+static u16 rk818_bat_get_relax_vol2(struct rk818_battery *di) -+{ -+ u16 vol, val = 0; -+ -+ val |= rk818_bat_read(di, RK818_RELAX_VOL2_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_RELAX_VOL2_REGH) << 8; -+ vol = di->voltage_k * val / 1000 + di->voltage_b; -+ -+ return vol; -+} -+ -+static u16 rk818_bat_get_relax_voltage(struct rk818_battery *di) -+{ -+ u16 relax_vol1, relax_vol2; -+ -+ if (!is_rk818_bat_relax_mode(di)) -+ return 0; -+ -+ relax_vol1 = rk818_bat_get_relax_vol1(di); -+ relax_vol2 = rk818_bat_get_relax_vol2(di); -+ -+ return relax_vol1 > relax_vol2 ? relax_vol1 : relax_vol2; -+} -+ -+static int rk818_bat_get_avg_current(struct rk818_battery *di) -+{ -+ int cur, val = 0; -+ -+ val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGH) << 8; -+ -+ if (val & 0x800) -+ val -= 4096; -+ cur = val * di->res_div * 1506 / 1000; -+ -+ return cur; -+} -+ -+static int rk818_bat_vol_to_ocvsoc(struct rk818_battery *di, int voltage) -+{ -+ u32 *ocv_table, temp; -+ int ocv_size, ocv_soc; -+ -+ ocv_table = di->pdata->ocv_table; -+ ocv_size = di->pdata->ocv_size; -+ temp = interpolate(voltage, ocv_table, ocv_size); -+ ocv_soc = ab_div_c(temp, MAX_PERCENTAGE, MAX_INTERPOLATE); -+ -+ return ocv_soc; -+} -+ -+static int rk818_bat_vol_to_ocvcap(struct rk818_battery *di, int voltage) -+{ -+ u32 *ocv_table, temp; -+ int ocv_size, cap; -+ -+ ocv_table = di->pdata->ocv_table; -+ ocv_size = di->pdata->ocv_size; -+ temp = interpolate(voltage, ocv_table, ocv_size); -+ cap = ab_div_c(temp, di->fcc, MAX_INTERPOLATE); -+ -+ return cap; -+} -+ -+static int rk818_bat_vol_to_zerosoc(struct rk818_battery *di, int voltage) -+{ -+ u32 *ocv_table, temp; -+ int ocv_size, ocv_soc; -+ -+ ocv_table = di->pdata->zero_table; -+ ocv_size = di->pdata->ocv_size; -+ temp = interpolate(voltage, ocv_table, ocv_size); -+ ocv_soc = ab_div_c(temp, MAX_PERCENTAGE, MAX_INTERPOLATE); -+ -+ return ocv_soc; -+} -+ -+static int rk818_bat_vol_to_zerocap(struct rk818_battery *di, int voltage) -+{ -+ u32 *ocv_table, temp; -+ int ocv_size, cap; -+ -+ ocv_table = di->pdata->zero_table; -+ ocv_size = di->pdata->ocv_size; -+ temp = interpolate(voltage, ocv_table, ocv_size); -+ cap = ab_div_c(temp, di->fcc, MAX_INTERPOLATE); -+ -+ return cap; -+} -+ -+static int rk818_bat_get_iadc(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGL) << 0; -+ val |= rk818_bat_read(di, RK818_BAT_CUR_AVG_REGH) << 8; -+ if (val > 2047) -+ val -= 4096; -+ -+ return val; -+} -+ -+static bool rk818_bat_adc_calib(struct rk818_battery *di) -+{ -+ int i, ioffset, coffset, adc, save_coffset; -+ -+ if ((di->chrg_status != CHARGE_FINISH) || -+ (di->adc_calib_cnt > ADC_CALIB_CNT) || -+ (base2min(di->boot_base) < ADC_CALIB_LMT_MIN) || -+ (abs(di->current_avg) < ADC_CALIB_THRESHOLD)) -+ return false; -+ -+ di->adc_calib_cnt++; -+ save_coffset = rk818_bat_get_coffset(di); -+ for (i = 0; i < 5; i++) { -+ adc = rk818_bat_get_iadc(di); -+ if (!rk818_bat_chrg_online(di)) { -+ rk818_bat_set_coffset(di, save_coffset); -+ BAT_INFO("quit, charger plugout when calib adc\n"); -+ return false; -+ } -+ coffset = rk818_bat_get_coffset(di); -+ rk818_bat_set_coffset(di, coffset + adc); -+ msleep(2000); -+ adc = rk818_bat_get_iadc(di); -+ if (abs(adc) < ADC_CALIB_THRESHOLD) { -+ coffset = rk818_bat_get_coffset(di); -+ ioffset = rk818_bat_get_ioffset(di); -+ di->poffset = coffset - ioffset; -+ rk818_bat_write(di, RK818_POFFSET_REG, di->poffset); -+ BAT_INFO("new offset:c=0x%x, i=0x%x, p=0x%x\n", -+ coffset, ioffset, di->poffset); -+ return true; -+ } else { -+ BAT_INFO("coffset calib again %d.., max_cnt=%d\n", -+ i, di->adc_calib_cnt); -+ rk818_bat_set_coffset(di, coffset); -+ msleep(2000); -+ } -+ } -+ -+ rk818_bat_set_coffset(di, save_coffset); -+ -+ return false; -+} -+ -+static void rk818_bat_set_ioffset_sample(struct rk818_battery *di) -+{ -+ u8 ggcon; -+ -+ ggcon = rk818_bat_read(di, RK818_GGCON_REG); -+ ggcon &= ~ADC_CAL_MIN_MSK; -+ ggcon |= ADC_CAL_8MIN; -+ rk818_bat_write(di, RK818_GGCON_REG, ggcon); -+} -+ -+static void rk818_bat_set_ocv_sample(struct rk818_battery *di) -+{ -+ u8 ggcon; -+ -+ ggcon = rk818_bat_read(di, RK818_GGCON_REG); -+ ggcon &= ~OCV_SAMP_MIN_MSK; -+ ggcon |= OCV_SAMP_8MIN; -+ rk818_bat_write(di, RK818_GGCON_REG, ggcon); -+} -+ -+static void rk818_bat_restart_relax(struct rk818_battery *di) -+{ -+ u8 ggsts; -+ -+ ggsts = rk818_bat_read(di, RK818_GGSTS_REG); -+ ggsts &= ~RELAX_VOL12_UPD_MSK; -+ rk818_bat_write(di, RK818_GGSTS_REG, ggsts); -+} -+ -+static void rk818_bat_set_relax_sample(struct rk818_battery *di) -+{ -+ u8 buf; -+ int enter_thres, exit_thres; -+ struct battery_platform_data *pdata = di->pdata; -+ -+ enter_thres = pdata->sleep_enter_current * 1000 / 1506 / DIV(di->res_div); -+ exit_thres = pdata->sleep_exit_current * 1000 / 1506 / DIV(di->res_div); -+ -+ /* set relax enter and exit threshold */ -+ buf = enter_thres & 0xff; -+ rk818_bat_write(di, RK818_RELAX_ENTRY_THRES_REGL, buf); -+ buf = (enter_thres >> 8) & 0xff; -+ rk818_bat_write(di, RK818_RELAX_ENTRY_THRES_REGH, buf); -+ -+ buf = exit_thres & 0xff; -+ rk818_bat_write(di, RK818_RELAX_EXIT_THRES_REGL, buf); -+ buf = (exit_thres >> 8) & 0xff; -+ rk818_bat_write(di, RK818_RELAX_EXIT_THRES_REGH, buf); -+ -+ /* reset relax update state */ -+ rk818_bat_restart_relax(di); -+ DBG("<%s>. sleep_enter_current = %d, sleep_exit_current = %d\n", -+ __func__, pdata->sleep_enter_current, pdata->sleep_exit_current); -+} -+ -+static bool is_rk818_bat_exist(struct rk818_battery *di) -+{ -+ return (rk818_bat_read(di, RK818_SUP_STS_REG) & BAT_EXS) ? true : false; -+} -+ -+static bool is_rk818_bat_first_pwron(struct rk818_battery *di) -+{ -+ u8 buf; -+ -+ buf = rk818_bat_read(di, RK818_GGSTS_REG); -+ if (buf & BAT_CON) { -+ buf &= ~BAT_CON; -+ rk818_bat_write(di, RK818_GGSTS_REG, buf); -+ return true; -+ } -+ -+ return false; -+} -+ -+static u8 rk818_bat_get_pwroff_min(struct rk818_battery *di) -+{ -+ u8 cur, last; -+ -+ cur = rk818_bat_read(di, RK818_NON_ACT_TIMER_CNT_REG); -+ last = rk818_bat_read(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG); -+ rk818_bat_write(di, RK818_NON_ACT_TIMER_CNT_SAVE_REG, cur); -+ -+ return (cur != last) ? cur : 0; -+} -+ -+static u8 is_rk818_bat_initialized(struct rk818_battery *di) -+{ -+ u8 val = rk818_bat_read(di, RK818_MISC_MARK_REG); -+ -+ if (val & FG_INIT) { -+ val &= ~FG_INIT; -+ rk818_bat_write(di, RK818_MISC_MARK_REG, val); -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+static bool is_rk818_bat_ocv_valid(struct rk818_battery *di) -+{ -+ return (!di->is_initialized && di->pwroff_min >= 30) ? true : false; -+} -+ -+static void rk818_bat_init_age_algorithm(struct rk818_battery *di) -+{ -+ int age_level, ocv_soc, ocv_cap, ocv_vol; -+ -+ if (di->is_first_power_on || is_rk818_bat_ocv_valid(di)) { -+ DBG("<%s> enter.\n", __func__); -+ ocv_vol = rk818_bat_get_ocv_voltage(di); -+ ocv_soc = rk818_bat_vol_to_ocvsoc(di, ocv_vol); -+ ocv_cap = rk818_bat_vol_to_ocvcap(di, ocv_vol); -+ if (ocv_soc < 20) { -+ di->age_voltage = ocv_vol; -+ di->age_ocv_cap = ocv_cap; -+ di->age_ocv_soc = ocv_soc; -+ di->age_adjust_cap = 0; -+ -+ if (ocv_soc <= 0) -+ di->age_level = 100; -+ else if (ocv_soc < 5) -+ di->age_level = 95; -+ else if (ocv_soc < 10) -+ di->age_level = 90; -+ else -+ di->age_level = 80; -+ -+ age_level = rk818_bat_get_age_level(di); -+ if (age_level > di->age_level) { -+ di->age_allow_update = false; -+ age_level -= 5; -+ if (age_level <= 80) -+ age_level = 80; -+ rk818_bat_save_age_level(di, age_level); -+ } else { -+ di->age_allow_update = true; -+ di->age_keep_sec = get_boot_sec(); -+ } -+ -+ BAT_INFO("init_age_algorithm: " -+ "age_vol:%d, age_ocv_cap:%d, " -+ "age_ocv_soc:%d, old_age_level:%d, " -+ "age_allow_update:%d, new_age_level:%d\n", -+ di->age_voltage, di->age_ocv_cap, -+ ocv_soc, age_level, di->age_allow_update, -+ di->age_level); -+ } -+ } -+} -+ -+static enum power_supply_property rk818_bat_props[] = { -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_CHARGE_COUNTER, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX, -+ POWER_SUPPLY_PROP_CURRENT_MAX, -+}; -+ -+static int rk818_bat_get_usb_psy(struct device *dev, void *data) -+{ -+ struct rk818_battery *di = data; -+ struct power_supply *psy = dev_get_drvdata(dev); -+ -+ if (psy->desc->type == POWER_SUPPLY_TYPE_USB) { -+ di->usb_psy = psy; -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static int rk818_bat_get_ac_psy(struct device *dev, void *data) -+{ -+ struct rk818_battery *di = data; -+ struct power_supply *psy = dev_get_drvdata(dev); -+ -+ if (psy->desc->type == POWER_SUPPLY_TYPE_MAINS) { -+ di->ac_psy = psy; -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static void rk818_bat_get_chrg_psy(struct rk818_battery *di) -+{ -+ if (!di->usb_psy) -+ class_for_each_device(power_supply_class, NULL, (void *)di, -+ rk818_bat_get_usb_psy); -+ if (!di->ac_psy) -+ class_for_each_device(power_supply_class, NULL, (void *)di, -+ rk818_bat_get_ac_psy); -+} -+ -+static int rk818_bat_get_charge_state(struct rk818_battery *di) -+{ -+ union power_supply_propval val; -+ int ret; -+ -+ if (!di->usb_psy || !di->ac_psy) -+ rk818_bat_get_chrg_psy(di); -+ -+ if (di->usb_psy) { -+ ret = di->usb_psy->desc->get_property(di->usb_psy, -+ POWER_SUPPLY_PROP_ONLINE, -+ &val); -+ if (!ret) -+ di->usb_in = val.intval; -+ } -+ -+ if (di->ac_psy) { -+ ret = di->ac_psy->desc->get_property(di->ac_psy, -+ POWER_SUPPLY_PROP_ONLINE, -+ &val); -+ if (!ret) -+ di->ac_in = val.intval; -+ } -+ -+ DBG("%s: ac_online=%d, usb_online=%d\n", -+ __func__, di->ac_in, di->usb_in); -+ -+ return (di->usb_in || di->ac_in); -+} -+ -+static int rk818_battery_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct rk818_battery *di = power_supply_get_drvdata(psy); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ val->intval = di->current_avg * 1000;/*uA*/ -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_CURRENT * 1000; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ val->intval = di->voltage_avg * 1000;/*uV*/ -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_VOLTAGE * 1000; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = is_rk818_bat_exist(di); -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_PRESET; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ val->intval = di->dsoc; -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_SOC; -+ DBG("<%s>. report dsoc: %d\n", __func__, val->intval); -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ val->intval = POWER_SUPPLY_HEALTH_GOOD; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = di->temperature; -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_TEMPERATURE; -+ break; -+ case POWER_SUPPLY_PROP_STATUS: -+ if (di->pdata->bat_mode == MODE_VIRTUAL) -+ val->intval = VIRTUAL_STATUS; -+ else if (di->dsoc == 100) -+ val->intval = POWER_SUPPLY_STATUS_FULL; -+ else if (rk818_bat_get_charge_state(di)) -+ val->intval = POWER_SUPPLY_STATUS_CHARGING; -+ else -+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_COUNTER: -+ val->intval = di->charge_count; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ val->intval = di->pdata->design_capacity * 1000;/* uAh */ -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX: -+ val->intval = di->voltage_max * 1000; /* uV */ -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_MAX: -+ val->intval = di->current_max * 1000; /* uA */ -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static const struct power_supply_desc rk818_bat_desc = { -+ .name = "battery", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = rk818_bat_props, -+ .num_properties = ARRAY_SIZE(rk818_bat_props), -+ .get_property = rk818_battery_get_property, -+}; -+ -+static int rk818_bat_init_power_supply(struct rk818_battery *di) -+{ -+ struct power_supply_config psy_cfg = { .drv_data = di, }; -+ -+ di->bat = devm_power_supply_register(di->dev, &rk818_bat_desc, &psy_cfg); -+ if (IS_ERR(di->bat)) { -+ dev_err(di->dev, "register bat power supply fail\n"); -+ return PTR_ERR(di->bat); -+ } -+ -+ return 0; -+} -+ -+static void rk818_bat_save_cap(struct rk818_battery *di, int cap) -+{ -+ u8 buf; -+ static u32 old_cap; -+ -+ if (cap >= di->qmax) -+ cap = di->qmax; -+ if (cap <= 0) -+ cap = 0; -+ if (old_cap == cap) -+ return; -+ -+ old_cap = cap; -+ buf = (cap >> 24) & 0xff; -+ rk818_bat_write(di, RK818_REMAIN_CAP_REG3, buf); -+ buf = (cap >> 16) & 0xff; -+ rk818_bat_write(di, RK818_REMAIN_CAP_REG2, buf); -+ buf = (cap >> 8) & 0xff; -+ rk818_bat_write(di, RK818_REMAIN_CAP_REG1, buf); -+ buf = (cap >> 0) & 0xff; -+ rk818_bat_write(di, RK818_REMAIN_CAP_REG0, buf); -+} -+ -+static int rk818_bat_get_prev_cap(struct rk818_battery *di) -+{ -+ int val = 0; -+ -+ val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG3) << 24; -+ val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG2) << 16; -+ val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG1) << 8; -+ val |= rk818_bat_read(di, RK818_REMAIN_CAP_REG0) << 0; -+ -+ return val; -+} -+ -+static void rk818_bat_save_fcc(struct rk818_battery *di, u32 fcc) -+{ -+ u8 buf; -+ -+ buf = (fcc >> 24) & 0xff; -+ rk818_bat_write(di, RK818_NEW_FCC_REG3, buf); -+ buf = (fcc >> 16) & 0xff; -+ rk818_bat_write(di, RK818_NEW_FCC_REG2, buf); -+ buf = (fcc >> 8) & 0xff; -+ rk818_bat_write(di, RK818_NEW_FCC_REG1, buf); -+ buf = (fcc >> 0) & 0xff; -+ rk818_bat_write(di, RK818_NEW_FCC_REG0, buf); -+ -+ BAT_INFO("save fcc: %d\n", fcc); -+} -+ -+static int rk818_bat_get_fcc(struct rk818_battery *di) -+{ -+ u32 fcc = 0; -+ -+ fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG3) << 24; -+ fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG2) << 16; -+ fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG1) << 8; -+ fcc |= rk818_bat_read(di, RK818_NEW_FCC_REG0) << 0; -+ -+ if (fcc < MIN_FCC) { -+ BAT_INFO("invalid fcc(%d), use design cap", fcc); -+ fcc = di->pdata->design_capacity; -+ rk818_bat_save_fcc(di, fcc); -+ } else if (fcc > di->pdata->design_qmax) { -+ BAT_INFO("invalid fcc(%d), use qmax", fcc); -+ fcc = di->pdata->design_qmax; -+ rk818_bat_save_fcc(di, fcc); -+ } -+ -+ return fcc; -+} -+ -+static void rk818_bat_init_coulomb_cap(struct rk818_battery *di, u32 capacity) -+{ -+ u8 buf; -+ u32 cap; -+ -+ cap = capacity * 2390 / DIV(di->res_div); -+ buf = (cap >> 24) & 0xff; -+ rk818_bat_write(di, RK818_GASCNT_CAL_REG3, buf); -+ buf = (cap >> 16) & 0xff; -+ rk818_bat_write(di, RK818_GASCNT_CAL_REG2, buf); -+ buf = (cap >> 8) & 0xff; -+ rk818_bat_write(di, RK818_GASCNT_CAL_REG1, buf); -+ buf = ((cap >> 0) & 0xff); -+ rk818_bat_write(di, RK818_GASCNT_CAL_REG0, buf); -+ -+ DBG("<%s>. new coulomb cap = %d\n", __func__, capacity); -+ di->remain_cap = capacity; -+ di->rsoc = rk818_bat_get_rsoc(di); -+} -+ -+static void rk818_bat_save_dsoc(struct rk818_battery *di, u8 save_soc) -+{ -+ static int last_soc = -1; -+ -+ if (last_soc != save_soc) { -+ rk818_bat_write(di, RK818_SOC_REG, save_soc); -+ last_soc = save_soc; -+ } -+} -+ -+static int rk818_bat_get_prev_dsoc(struct rk818_battery *di) -+{ -+ return rk818_bat_read(di, RK818_SOC_REG); -+} -+ -+static void rk818_bat_save_reboot_cnt(struct rk818_battery *di, u8 save_cnt) -+{ -+ rk818_bat_write(di, RK818_REBOOT_CNT_REG, save_cnt); -+} -+ -+static int rk818_bat_fb_notifier(struct notifier_block *nb, -+ unsigned long event, void *data) -+{ -+ struct rk818_battery *di; -+ struct fb_event *evdata = data; -+ -+ if (event != FB_EARLY_EVENT_BLANK && event != FB_EVENT_BLANK) -+ return NOTIFY_OK; -+ -+ di = container_of(nb, struct rk818_battery, fb_nb); -+ di->fb_blank = *(int *)evdata->data; -+ -+ return 0; -+} -+ -+static int rk818_bat_register_fb_notify(struct rk818_battery *di) -+{ -+ memset(&di->fb_nb, 0, sizeof(di->fb_nb)); -+ di->fb_nb.notifier_call = rk818_bat_fb_notifier; -+ -+ return fb_register_client(&di->fb_nb); -+} -+ -+static int rk818_bat_unregister_fb_notify(struct rk818_battery *di) -+{ -+ return fb_unregister_client(&di->fb_nb); -+} -+ -+static u8 rk818_bat_get_halt_cnt(struct rk818_battery *di) -+{ -+ return rk818_bat_read(di, RK818_HALT_CNT_REG); -+} -+ -+static void rk818_bat_inc_halt_cnt(struct rk818_battery *di) -+{ -+ u8 cnt; -+ -+ cnt = rk818_bat_read(di, RK818_HALT_CNT_REG); -+ rk818_bat_write(di, RK818_HALT_CNT_REG, ++cnt); -+} -+ -+static bool is_rk818_bat_last_halt(struct rk818_battery *di) -+{ -+ int pre_cap = rk818_bat_get_prev_cap(di); -+ int now_cap = rk818_bat_get_coulomb_cap(di); -+ -+ /* over 10%: system halt last time */ -+ if (abs(now_cap - pre_cap) > (di->fcc / 10)) { -+ rk818_bat_inc_halt_cnt(di); -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+static void rk818_bat_first_pwron(struct rk818_battery *di) -+{ -+ int ocv_vol; -+ -+ rk818_bat_save_fcc(di, di->design_cap); -+ ocv_vol = rk818_bat_get_ocv_voltage(di); -+ di->fcc = rk818_bat_get_fcc(di); -+ di->nac = rk818_bat_vol_to_ocvcap(di, ocv_vol); -+ di->rsoc = rk818_bat_vol_to_ocvsoc(di, ocv_vol); -+ di->dsoc = di->rsoc; -+ di->is_first_on = true; -+ -+ BAT_INFO("first on: dsoc=%d, rsoc=%d cap=%d, fcc=%d, ov=%d\n", -+ di->dsoc, di->rsoc, di->nac, di->fcc, ocv_vol); -+} -+ -+static void rk818_bat_not_first_pwron(struct rk818_battery *di) -+{ -+ int now_cap, pre_soc, pre_cap, ocv_cap, ocv_soc, ocv_vol; -+ -+ di->fcc = rk818_bat_get_fcc(di); -+ pre_soc = rk818_bat_get_prev_dsoc(di); -+ pre_cap = rk818_bat_get_prev_cap(di); -+ now_cap = rk818_bat_get_coulomb_cap(di); -+ di->is_halt = is_rk818_bat_last_halt(di); -+ di->halt_cnt = rk818_bat_get_halt_cnt(di); -+ di->is_initialized = is_rk818_bat_initialized(di); -+ di->is_ocv_calib = is_rk818_bat_ocv_valid(di); -+ -+ if (di->is_initialized) { -+ BAT_INFO("initialized yet..\n"); -+ goto finish; -+ } else if (di->is_halt) { -+ BAT_INFO("system halt last time... cap: pre=%d, now=%d\n", -+ pre_cap, now_cap); -+ if (now_cap < 0) -+ now_cap = 0; -+ rk818_bat_init_coulomb_cap(di, now_cap); -+ pre_cap = now_cap; -+ pre_soc = di->rsoc; -+ goto finish; -+ } else if (di->is_ocv_calib) { -+ ocv_vol = rk818_bat_get_ocv_voltage(di); -+ ocv_soc = rk818_bat_vol_to_ocvsoc(di, ocv_vol); -+ ocv_cap = rk818_bat_vol_to_ocvcap(di, ocv_vol); -+ pre_cap = ocv_cap; -+ di->ocv_pre_dsoc = pre_soc; -+ di->ocv_new_dsoc = ocv_soc; -+ if (abs(ocv_soc - pre_soc) >= di->pdata->max_soc_offset) { -+ di->ocv_pre_dsoc = pre_soc; -+ di->ocv_new_dsoc = ocv_soc; -+ di->is_max_soc_offset = true; -+ BAT_INFO("trigger max soc offset, dsoc: %d -> %d\n", -+ pre_soc, ocv_soc); -+ pre_soc = ocv_soc; -+ } -+ BAT_INFO("OCV calib: cap=%d, rsoc=%d\n", ocv_cap, ocv_soc); -+ } else if (di->pwroff_min > 0) { -+ ocv_vol = rk818_bat_get_ocv_voltage(di); -+ ocv_soc = rk818_bat_vol_to_ocvsoc(di, ocv_vol); -+ ocv_cap = rk818_bat_vol_to_ocvcap(di, ocv_vol); -+ di->force_pre_dsoc = pre_soc; -+ di->force_new_dsoc = ocv_soc; -+ if (abs(ocv_soc - pre_soc) >= 80) { -+ di->is_force_calib = true; -+ BAT_INFO("dsoc force calib: %d -> %d\n", -+ pre_soc, ocv_soc); -+ pre_soc = ocv_soc; -+ pre_cap = ocv_cap; -+ } -+ } -+ -+finish: -+ di->dsoc = pre_soc; -+ di->nac = pre_cap; -+ if (di->nac < 0) -+ di->nac = 0; -+ -+ BAT_INFO("dsoc=%d cap=%d v=%d ov=%d rv=%d min=%d psoc=%d pcap=%d\n", -+ di->dsoc, di->nac, rk818_bat_get_avg_voltage(di), -+ rk818_bat_get_ocv_voltage(di), rk818_bat_get_relax_voltage(di), -+ di->pwroff_min, rk818_bat_get_prev_dsoc(di), -+ rk818_bat_get_prev_cap(di)); -+} -+ -+static bool rk818_bat_ocv_sw_reset(struct rk818_battery *di) -+{ -+ u8 buf; -+ -+ buf = rk818_bat_read(di, RK818_MISC_MARK_REG); -+ if (((buf & FG_RESET_LATE) && di->pwroff_min >= 30) || -+ (buf & FG_RESET_NOW)) { -+ buf &= ~FG_RESET_LATE; -+ buf &= ~FG_RESET_NOW; -+ rk818_bat_write(di, RK818_MISC_MARK_REG, buf); -+ BAT_INFO("manual reset fuel gauge\n"); -+ return true; -+ } else { -+ return false; -+ } -+} -+ -+static void rk818_bat_init_rsoc(struct rk818_battery *di) -+{ -+ di->is_first_power_on = is_rk818_bat_first_pwron(di); -+ di->is_sw_reset = rk818_bat_ocv_sw_reset(di); -+ di->pwroff_min = rk818_bat_get_pwroff_min(di); -+ -+ if (di->is_first_power_on || di->is_sw_reset) -+ rk818_bat_first_pwron(di); -+ else -+ rk818_bat_not_first_pwron(di); -+} -+ -+static u8 rk818_bat_get_chrg_status(struct rk818_battery *di) -+{ -+ u8 status; -+ -+ status = rk818_bat_read(di, RK818_SUP_STS_REG) & CHRG_STATUS_MSK; -+ switch (status) { -+ case CHARGE_OFF: -+ DBG("CHARGE-OFF ...\n"); -+ break; -+ case DEAD_CHARGE: -+ BAT_INFO("DEAD CHARGE...\n"); -+ break; -+ case TRICKLE_CHARGE: -+ BAT_INFO("TRICKLE CHARGE...\n "); -+ break; -+ case CC_OR_CV: -+ DBG("CC or CV...\n"); -+ break; -+ case CHARGE_FINISH: -+ DBG("CHARGE FINISH...\n"); -+ break; -+ case USB_OVER_VOL: -+ BAT_INFO("USB OVER VOL...\n"); -+ break; -+ case BAT_TMP_ERR: -+ BAT_INFO("BAT TMP ERROR...\n"); -+ break; -+ case TIMER_ERR: -+ BAT_INFO("TIMER ERROR...\n"); -+ break; -+ case USB_EXIST: -+ BAT_INFO("USB EXIST...\n"); -+ break; -+ case USB_EFF: -+ BAT_INFO("USB EFF...\n"); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return status; -+} -+ -+static u8 rk818_bat_parse_fb_temperature(struct rk818_battery *di) -+{ -+ u8 reg; -+ int index, fb_temp; -+ -+ reg = DEFAULT_FB_TEMP; -+ fb_temp = di->pdata->fb_temp; -+ for (index = 0; index < ARRAY_SIZE(feedback_temp_array); index++) { -+ if (fb_temp < feedback_temp_array[index]) -+ break; -+ reg = (index << FB_TEMP_SHIFT); -+ } -+ -+ return reg; -+} -+ -+static u8 rk818_bat_parse_finish_ma(struct rk818_battery *di, int fcc) -+{ -+ u8 ma; -+ -+ if (di->pdata->sample_res == SAMPLE_RES_10MR) -+ ma = FINISH_100MA; -+ else if (fcc > 5000) -+ ma = FINISH_250MA; -+ else if (fcc >= 4000) -+ ma = FINISH_200MA; -+ else if (fcc >= 3000) -+ ma = FINISH_150MA; -+ else -+ ma = FINISH_100MA; -+ -+ return ma; -+} -+ -+static void rk818_bat_init_chrg_config(struct rk818_battery *di) -+{ -+ u8 usb_ctrl, chrg_ctrl2, chrg_ctrl3; -+ u8 thermal, ggcon, finish_ma, fb_temp; -+ -+ finish_ma = rk818_bat_parse_finish_ma(di, di->fcc); -+ fb_temp = rk818_bat_parse_fb_temperature(di); -+ -+ ggcon = rk818_bat_read(di, RK818_GGCON_REG); -+ thermal = rk818_bat_read(di, RK818_THERMAL_REG); -+ usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG); -+ chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2); -+ chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3); -+ -+ /* set charge finish current */ -+ chrg_ctrl3 |= CHRG_TERM_DIG_SIGNAL; -+ chrg_ctrl2 &= ~FINISH_CUR_MSK; -+ chrg_ctrl2 |= finish_ma; -+ -+ /* disable cccv mode */ -+ chrg_ctrl3 &= ~CHRG_TIMER_CCCV_EN; -+ -+ /* set feed back temperature */ -+ if (di->pdata->fb_temp) -+ usb_ctrl |= CHRG_CT_EN; -+ else -+ usb_ctrl &= ~CHRG_CT_EN; -+ thermal &= ~FB_TEMP_MSK; -+ thermal |= fb_temp; -+ -+ /* adc current mode */ -+ ggcon |= ADC_CUR_MODE; -+ -+ rk818_bat_write(di, RK818_GGCON_REG, ggcon); -+ rk818_bat_write(di, RK818_THERMAL_REG, thermal); -+ rk818_bat_write(di, RK818_USB_CTRL_REG, usb_ctrl); -+ rk818_bat_write(di, RK818_CHRG_CTRL_REG2, chrg_ctrl2); -+ rk818_bat_write(di, RK818_CHRG_CTRL_REG3, chrg_ctrl3); -+} -+ -+static void rk818_bat_init_coffset(struct rk818_battery *di) -+{ -+ int coffset, ioffset; -+ -+ ioffset = rk818_bat_get_ioffset(di); -+ di->poffset = rk818_bat_read(di, RK818_POFFSET_REG); -+ if (!di->poffset) -+ di->poffset = DEFAULT_POFFSET; -+ -+ coffset = di->poffset + ioffset; -+ if (coffset < INVALID_COFFSET_MIN || coffset > INVALID_COFFSET_MAX) -+ coffset = DEFAULT_COFFSET; -+ -+ rk818_bat_set_coffset(di, coffset); -+ -+ DBG("<%s>. offset: p=0x%x, i=0x%x, c=0x%x\n", -+ __func__, di->poffset, ioffset, rk818_bat_get_coffset(di)); -+} -+ -+static void rk818_bat_caltimer_isr(struct timer_list *t) -+{ -+ struct rk818_battery *di = from_timer(di, t, caltimer); -+ -+ mod_timer(&di->caltimer, jiffies + MINUTE(8) * HZ); -+ queue_delayed_work(di->bat_monitor_wq, &di->calib_delay_work, -+ msecs_to_jiffies(10)); -+} -+ -+static void rk818_bat_internal_calib(struct work_struct *work) -+{ -+ int ioffset, poffset; -+ struct rk818_battery *di = container_of(work, -+ struct rk818_battery, calib_delay_work.work); -+ -+ /* calib coffset */ -+ poffset = rk818_bat_read(di, RK818_POFFSET_REG); -+ if (poffset) -+ di->poffset = poffset; -+ else -+ di->poffset = DEFAULT_POFFSET; -+ -+ ioffset = rk818_bat_get_ioffset(di); -+ rk818_bat_set_coffset(di, ioffset + di->poffset); -+ -+ /* calib voltage kb */ -+ rk818_bat_init_voltage_kb(di); -+ BAT_INFO("caltimer: ioffset=0x%x, coffset=0x%x, poffset=%d\n", -+ ioffset, rk818_bat_get_coffset(di), di->poffset); -+} -+ -+static void rk818_bat_init_caltimer(struct rk818_battery *di) -+{ -+ timer_setup(&di->caltimer, rk818_bat_caltimer_isr, 0); -+ di->caltimer.expires = jiffies + MINUTE(8) * HZ; -+ add_timer(&di->caltimer); -+ INIT_DELAYED_WORK(&di->calib_delay_work, rk818_bat_internal_calib); -+} -+ -+static void rk818_bat_init_zero_table(struct rk818_battery *di) -+{ -+ int i, diff, min, max; -+ size_t ocv_size, length; -+ -+ ocv_size = di->pdata->ocv_size; -+ length = sizeof(di->pdata->zero_table) * ocv_size; -+ di->pdata->zero_table = -+ devm_kzalloc(di->dev, length, GFP_KERNEL); -+ if (!di->pdata->zero_table) { -+ di->pdata->zero_table = di->pdata->ocv_table; -+ dev_err(di->dev, "malloc zero table fail\n"); -+ return; -+ } -+ -+ min = di->pdata->pwroff_vol, -+ max = di->pdata->ocv_table[ocv_size - 4]; -+ diff = (max - min) / DIV(ocv_size - 1); -+ for (i = 0; i < ocv_size; i++) -+ di->pdata->zero_table[i] = min + (i * diff); -+ -+ for (i = 0; i < ocv_size; i++) -+ DBG("zero[%d] = %d\n", i, di->pdata->zero_table[i]); -+ -+ for (i = 0; i < ocv_size; i++) -+ DBG("ocv[%d] = %d\n", i, di->pdata->ocv_table[i]); -+} -+ -+static void rk818_bat_calc_sm_linek(struct rk818_battery *di) -+{ -+ int linek, current_avg; -+ u8 diff, delta; -+ -+ delta = abs(di->dsoc - di->rsoc); -+ diff = delta * 3;/* speed:3/4 */ -+ current_avg = rk818_bat_get_avg_current(di); -+ if (current_avg >= 0) { -+ if (di->dsoc < di->rsoc) -+ linek = 1000 * (delta + diff) / DIV(diff); -+ else if (di->dsoc > di->rsoc) -+ linek = 1000 * diff / DIV(delta + diff); -+ else -+ linek = 1000; -+ di->dbg_meet_soc = (di->dsoc >= di->rsoc) ? -+ (di->dsoc + diff) : (di->rsoc + diff); -+ } else { -+ if (di->dsoc < di->rsoc) -+ linek = -1000 * diff / DIV(delta + diff); -+ else if (di->dsoc > di->rsoc) -+ linek = -1000 * (delta + diff) / DIV(diff); -+ else -+ linek = -1000; -+ di->dbg_meet_soc = (di->dsoc >= di->rsoc) ? -+ (di->dsoc - diff) : (di->rsoc - diff); -+ } -+ -+ di->sm_linek = linek; -+ di->sm_remain_cap = di->remain_cap; -+ di->dbg_calc_dsoc = di->dsoc; -+ di->dbg_calc_rsoc = di->rsoc; -+ -+ DBG("<%s>.diff=%d, k=%d, cur=%d\n", __func__, diff, linek, current_avg); -+} -+ -+static void rk818_bat_calc_zero_linek(struct rk818_battery *di) -+{ -+ int dead_voltage, ocv_voltage; -+ int voltage_avg, current_avg, vsys; -+ int ocv_cap, dead_cap, xsoc; -+ int ocv_soc, dead_soc; -+ int pwroff_vol; -+ int i, cnt, vol_old, vol_now; -+ int org_linek = 0, min_gap_xsoc; -+ -+ if ((abs(di->current_avg) < 500) && (di->dsoc > 10)) -+ pwroff_vol = di->pdata->pwroff_vol + 50; -+ else -+ pwroff_vol = di->pdata->pwroff_vol; -+ -+ do { -+ vol_old = rk818_bat_get_avg_voltage(di); -+ msleep(100); -+ vol_now = rk818_bat_get_avg_voltage(di); -+ cnt++; -+ } while ((vol_old == vol_now) && (cnt < 11)); -+ -+ voltage_avg = 0; -+ for (i = 0; i < 10; i++) { -+ voltage_avg += rk818_bat_get_avg_voltage(di); -+ msleep(100); -+ } -+ -+ /* calc estimate ocv voltage */ -+ voltage_avg /= 10; -+ current_avg = rk818_bat_get_avg_current(di); -+ vsys = voltage_avg + (current_avg * DEF_PWRPATH_RES) / 1000; -+ -+ DBG("ZERO0: shtd_vol: org = %d, now = %d, zero_reserve_dsoc = %d\n", -+ di->pdata->pwroff_vol, pwroff_vol, di->pdata->zero_reserve_dsoc); -+ -+ dead_voltage = pwroff_vol - current_avg * -+ (di->bat_res + DEF_PWRPATH_RES) / 1000; -+ ocv_voltage = voltage_avg - (current_avg * di->bat_res) / 1000; -+ DBG("ZERO0: dead_voltage(shtd) = %d, ocv_voltage(now) = %d\n", -+ dead_voltage, ocv_voltage); -+ -+ /* calc estimate soc and cap */ -+ dead_soc = rk818_bat_vol_to_zerosoc(di, dead_voltage); -+ dead_cap = rk818_bat_vol_to_zerocap(di, dead_voltage); -+ DBG("ZERO0: dead_soc = %d, dead_cap = %d\n", -+ dead_soc, dead_cap); -+ -+ ocv_soc = rk818_bat_vol_to_zerosoc(di, ocv_voltage); -+ ocv_cap = rk818_bat_vol_to_zerocap(di, ocv_voltage); -+ DBG("ZERO0: ocv_soc = %d, ocv_cap = %d\n", -+ ocv_soc, ocv_cap); -+ -+ /* xsoc: available rsoc */ -+ xsoc = ocv_soc - dead_soc; -+ -+ /* min_gap_xsoc: reserve xsoc */ -+ if (abs(current_avg) > ZERO_LOAD_LVL1) -+ min_gap_xsoc = ZERO_GAP_XSOC3; -+ else if (abs(current_avg) > ZERO_LOAD_LVL2) -+ min_gap_xsoc = ZERO_GAP_XSOC2; -+ else -+ min_gap_xsoc = ZERO_GAP_XSOC1; -+ -+ if ((xsoc <= 30) && (di->dsoc >= di->pdata->zero_reserve_dsoc)) -+ min_gap_xsoc = min_gap_xsoc + ZERO_GAP_CALIB; -+ -+ di->zero_remain_cap = di->remain_cap; -+ di->zero_timeout_cnt = 0; -+ if ((di->dsoc <= 1) && (xsoc > 0)) { -+ di->zero_linek = 400; -+ di->zero_drop_sec = 0; -+ } else if (xsoc >= 0) { -+ di->zero_drop_sec = 0; -+ di->zero_linek = (di->zero_dsoc + xsoc / 2) / DIV(xsoc); -+ org_linek = di->zero_linek; -+ /* battery energy mode to use up voltage */ -+ if ((di->pdata->energy_mode) && -+ (xsoc - di->dsoc >= ZERO_GAP_XSOC3) && -+ (di->dsoc <= 10) && (di->zero_linek < 300)) { -+ di->zero_linek = 300; -+ DBG("ZERO-new: zero_linek adjust step0...\n"); -+ /* reserve enough power yet, slow down any way */ -+ } else if ((xsoc - di->dsoc >= min_gap_xsoc) || -+ ((xsoc - di->dsoc >= ZERO_GAP_XSOC2) && -+ (di->dsoc <= 10) && (xsoc > 15))) { -+ if (xsoc <= 20 && -+ di->dsoc >= di->pdata->zero_reserve_dsoc) -+ di->zero_linek = 1200; -+ else if (xsoc - di->dsoc >= 2 * min_gap_xsoc) -+ di->zero_linek = 400; -+ else if (xsoc - di->dsoc >= 3 + min_gap_xsoc) -+ di->zero_linek = 600; -+ else -+ di->zero_linek = 800; -+ DBG("ZERO-new: zero_linek adjust step1...\n"); -+ /* control zero mode beginning enter */ -+ } else if ((di->zero_linek > 1800) && (di->dsoc > 70)) { -+ di->zero_linek = 1800; -+ DBG("ZERO-new: zero_linek adjust step2...\n"); -+ /* dsoc close to xsoc: it must reserve power */ -+ } else if ((di->zero_linek > 1000) && (di->zero_linek < 1200)) { -+ di->zero_linek = 1200; -+ DBG("ZERO-new: zero_linek adjust step3...\n"); -+ /* dsoc[5~15], dsoc < xsoc */ -+ } else if ((di->dsoc <= 15 && di->dsoc > 5) && -+ (di->zero_linek <= 1200)) { -+ /* slow down */ -+ if (xsoc - di->dsoc >= min_gap_xsoc) -+ di->zero_linek = 800; -+ /* reserve power */ -+ else -+ di->zero_linek = 1200; -+ DBG("ZERO-new: zero_linek adjust step4...\n"); -+ /* dsoc[5, 100], dsoc < xsoc */ -+ } else if ((di->zero_linek < 1000) && (di->dsoc >= 5)) { -+ if ((xsoc - di->dsoc) < min_gap_xsoc) { -+ /* reserve power */ -+ di->zero_linek = 1200; -+ } else { -+ if (abs(di->current_avg) > 500)/* heavy */ -+ di->zero_linek = 900; -+ else -+ di->zero_linek = 1000; -+ } -+ DBG("ZERO-new: zero_linek adjust step5...\n"); -+ /* dsoc[0~5], dsoc < xsoc */ -+ } else if ((di->zero_linek < 1000) && (di->dsoc <= 5)) { -+ if ((xsoc - di->dsoc) <= 3) -+ di->zero_linek = 1200; -+ else -+ di->zero_linek = 800; -+ DBG("ZERO-new: zero_linek adjust step6...\n"); -+ } -+ } else { -+ /* xsoc < 0 */ -+ di->zero_linek = 1000; -+ if (!di->zero_drop_sec) -+ di->zero_drop_sec = get_boot_sec(); -+ if (base2sec(di->zero_drop_sec) >= WAIT_DSOC_DROP_SEC) { -+ DBG("ZERO0: t=%lu\n", base2sec(di->zero_drop_sec)); -+ di->zero_drop_sec = 0; -+ di->dsoc--; -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - -+ MIN_ACCURACY; -+ } -+ } -+ -+ if (voltage_avg < pwroff_vol - 70) { -+ if (!di->shtd_drop_sec) -+ di->shtd_drop_sec = get_boot_sec(); -+ if (base2sec(di->shtd_drop_sec) > WAIT_SHTD_DROP_SEC) { -+ BAT_INFO("voltage extreme low...soc:%d->0\n", di->dsoc); -+ di->shtd_drop_sec = 0; -+ di->dsoc = 0; -+ } -+ } else { -+ di->shtd_drop_sec = 0; -+ } -+ -+ DBG("ZERO-new: org_linek=%d, zero_linek=%d, dsoc=%d, Xsoc=%d, " -+ "rsoc=%d, gap=%d, v=%d, vsys=%d\n" -+ "ZERO-new: di->zero_dsoc=%d, zero_remain_cap=%d, zero_drop=%ld, " -+ "sht_drop=%ld\n\n", -+ org_linek, di->zero_linek, di->dsoc, xsoc, di->rsoc, -+ min_gap_xsoc, voltage_avg, vsys, di->zero_dsoc, di->zero_remain_cap, -+ base2sec(di->zero_drop_sec), base2sec(di->shtd_drop_sec)); -+} -+ -+static void rk818_bat_finish_algo_prepare(struct rk818_battery *di) -+{ -+ di->finish_base = get_boot_sec(); -+ if (!di->finish_base) -+ di->finish_base = 1; -+} -+ -+static void rk818_bat_smooth_algo_prepare(struct rk818_battery *di) -+{ -+ int tmp_soc; -+ -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc != di->dsoc) -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ -+ tmp_soc = di->sm_dischrg_dsoc / 1000; -+ if (tmp_soc != di->dsoc) -+ di->sm_dischrg_dsoc = -+ (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ -+ DBG("<%s>. tmp_soc=%d, dsoc=%d, dsoc:sm_dischrg=%d, sm_chrg=%d\n", -+ __func__, tmp_soc, di->dsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc); -+ -+ rk818_bat_calc_sm_linek(di); -+} -+ -+static void rk818_bat_zero_algo_prepare(struct rk818_battery *di) -+{ -+ int tmp_dsoc; -+ -+ di->zero_timeout_cnt = 0; -+ tmp_dsoc = di->zero_dsoc / 1000; -+ if (tmp_dsoc != di->dsoc) -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ -+ DBG("<%s>. first calc, reinit linek\n", __func__); -+ -+ rk818_bat_calc_zero_linek(di); -+} -+ -+static void rk818_bat_calc_zero_algorithm(struct rk818_battery *di) -+{ -+ int tmp_soc = 0, sm_delta_dsoc = 0; -+ -+ tmp_soc = di->zero_dsoc / 1000; -+ if (tmp_soc == di->dsoc) -+ goto out; -+ -+ DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc); -+ /* when discharge slow down, take sm chrg into calc */ -+ if (di->dsoc < di->rsoc) { -+ /* take sm charge rest into calc */ -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ sm_delta_dsoc = di->sm_chrg_dsoc - di->dsoc * 1000; -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ di->zero_dsoc += sm_delta_dsoc; -+ DBG("ZERO1: take sm chrg,delta=%d\n", sm_delta_dsoc); -+ } -+ } -+ -+ /* when discharge speed up, take sm dischrg into calc */ -+ if (di->dsoc > di->rsoc) { -+ /* take sm discharge rest into calc */ -+ tmp_soc = di->sm_dischrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ sm_delta_dsoc = di->sm_dischrg_dsoc - -+ ((di->dsoc + 1) * 1000 - MIN_ACCURACY); -+ di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - -+ MIN_ACCURACY; -+ di->zero_dsoc += sm_delta_dsoc; -+ DBG("ZERO1: take sm dischrg,delta=%d\n", sm_delta_dsoc); -+ } -+ } -+ -+ /* check overflow */ -+ if (di->zero_dsoc > (di->dsoc + 1) * 1000 - MIN_ACCURACY) { -+ DBG("ZERO1: zero dsoc overflow: %d\n", di->zero_dsoc); -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ } -+ -+ /* check new dsoc */ -+ tmp_soc = di->zero_dsoc / 1000; -+ if (tmp_soc != di->dsoc) { -+ /* avoid dsoc jump when heavy load */ -+ if ((di->dsoc - tmp_soc) > 1) { -+ di->dsoc--; -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ DBG("ZERO1: heavy load...\n"); -+ } else { -+ di->dsoc = tmp_soc; -+ } -+ di->zero_drop_sec = 0; -+ } -+ -+out: -+ DBG("ZERO1: zero_dsoc(Y0)=%d, dsoc=%d, rsoc=%d, tmp_soc=%d\n", -+ di->zero_dsoc, di->dsoc, di->rsoc, tmp_soc); -+ DBG("ZERO1: sm_dischrg_dsoc=%d, sm_chrg_dsoc=%d\n", -+ di->sm_dischrg_dsoc, di->sm_chrg_dsoc); -+} -+ -+static void rk818_bat_zero_algorithm(struct rk818_battery *di) -+{ -+ int delta_cap = 0, delta_soc = 0; -+ -+ di->zero_timeout_cnt++; -+ delta_cap = di->zero_remain_cap - di->remain_cap; -+ delta_soc = di->zero_linek * (delta_cap * 100) / DIV(di->fcc); -+ -+ DBG("ZERO1: zero_linek=%d, zero_dsoc(Y0)=%d, dsoc=%d, rsoc=%d\n" -+ "ZERO1: delta_soc(X0)=%d, delta_cap=%d, zero_remain_cap = %d\n" -+ "ZERO1: timeout_cnt=%d, sm_dischrg=%d, sm_chrg=%d\n\n", -+ di->zero_linek, di->zero_dsoc, di->dsoc, di->rsoc, -+ delta_soc, delta_cap, di->zero_remain_cap, -+ di->zero_timeout_cnt, di->sm_dischrg_dsoc, di->sm_chrg_dsoc); -+ -+ if ((delta_soc >= MIN_ZERO_DSOC_ACCURACY) || -+ (di->zero_timeout_cnt > MIN_ZERO_OVERCNT) || -+ (di->zero_linek == 0)) { -+ DBG("ZERO1:--------- enter calc -----------\n"); -+ di->zero_timeout_cnt = 0; -+ di->zero_dsoc -= delta_soc; -+ rk818_bat_calc_zero_algorithm(di); -+ rk818_bat_calc_zero_linek(di); -+ } -+} -+ -+static void rk818_bat_dump_time_table(struct rk818_battery *di) -+{ -+ u8 i; -+ static int old_index; -+ static int old_min; -+ int mod = di->dsoc % 10; -+ int index = di->dsoc / 10; -+ u32 time; -+ -+ if (rk818_bat_chrg_online(di)) -+ time = base2min(di->plug_in_base); -+ else -+ time = base2min(di->plug_out_base); -+ -+ if ((mod == 0) && (index > 0) && (old_index != index)) { -+ di->dbg_chrg_min[index - 1] = time - old_min; -+ old_min = time; -+ old_index = index; -+ } -+ -+ for (i = 1; i < 11; i++) -+ DBG("Time[%d]=%d, ", (i * 10), di->dbg_chrg_min[i - 1]); -+ DBG("\n"); -+} -+ -+static void rk818_bat_debug_info(struct rk818_battery *di) -+{ -+ u8 sup_tst, ggcon, ggsts, vb_mod, ts_ctrl, reboot_cnt; -+ u8 usb_ctrl, chrg_ctrl1, thermal; -+ u8 int_sts1, int_sts2; -+ u8 int_msk1, int_msk2; -+ u8 chrg_ctrl2, chrg_ctrl3, rtc, misc, dcdc_en; -+ char *work_mode[] = {"ZERO", "FINISH", "UN", "UN", "SMOOTH"}; -+ char *bat_mode[] = {"BAT", "VIRTUAL"}; -+ -+ if (rk818_bat_chrg_online(di)) -+ di->plug_out_base = get_boot_sec(); -+ else -+ di->plug_in_base = get_boot_sec(); -+ -+ rk818_bat_dump_time_table(di); -+ -+ if (!dbg_enable) -+ return; -+ -+ ts_ctrl = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ misc = rk818_bat_read(di, RK818_MISC_MARK_REG); -+ ggcon = rk818_bat_read(di, RK818_GGCON_REG); -+ ggsts = rk818_bat_read(di, RK818_GGSTS_REG); -+ sup_tst = rk818_bat_read(di, RK818_SUP_STS_REG); -+ vb_mod = rk818_bat_read(di, RK818_VB_MON_REG); -+ usb_ctrl = rk818_bat_read(di, RK818_USB_CTRL_REG); -+ chrg_ctrl1 = rk818_bat_read(di, RK818_CHRG_CTRL_REG1); -+ chrg_ctrl2 = rk818_bat_read(di, RK818_CHRG_CTRL_REG2); -+ chrg_ctrl3 = rk818_bat_read(di, RK818_CHRG_CTRL_REG3); -+ rtc = rk818_bat_read(di, 0); -+ thermal = rk818_bat_read(di, RK818_THERMAL_REG); -+ int_sts1 = rk818_bat_read(di, RK818_INT_STS_REG1); -+ int_sts2 = rk818_bat_read(di, RK818_INT_STS_REG2); -+ int_msk1 = rk818_bat_read(di, RK818_INT_STS_MSK_REG1); -+ int_msk2 = rk818_bat_read(di, RK818_INT_STS_MSK_REG2); -+ dcdc_en = rk818_bat_read(di, RK818_DCDC_EN_REG); -+ reboot_cnt = rk818_bat_read(di, RK818_REBOOT_CNT_REG); -+ -+ DBG("\n------- DEBUG REGS, [Ver: %s] -------------------\n" -+ "GGCON=0x%2x, GGSTS=0x%2x, RTC=0x%2x, DCDC_EN2=0x%2x\n" -+ "SUP_STS= 0x%2x, VB_MOD=0x%2x, USB_CTRL=0x%2x\n" -+ "THERMAL=0x%2x, MISC_MARK=0x%2x, TS_CTRL=0x%2x\n" -+ "CHRG_CTRL:REG1=0x%2x, REG2=0x%2x, REG3=0x%2x\n" -+ "INT_STS: REG1=0x%2x, REG2=0x%2x\n" -+ "INT_MSK: REG1=0x%2x, REG2=0x%2x\n", -+ DRIVER_VERSION, ggcon, ggsts, rtc, dcdc_en, -+ sup_tst, vb_mod, usb_ctrl, -+ thermal, misc, ts_ctrl, -+ chrg_ctrl1, chrg_ctrl2, chrg_ctrl3, -+ int_sts1, int_sts2, int_msk1, int_msk2 -+ ); -+ -+ DBG("###############################################################\n" -+ "Dsoc=%d, Rsoc=%d, Vavg=%d, Iavg=%d, Cap=%d, Fcc=%d, d=%d\n" -+ "K=%d, Mode=%s, Oldcap=%d, Is=%d, Ip=%d, Vs=%d\n" -+ "fb_temp=%d, bat_temp=%d, sample_res=%d, USB=%d, DC=%d\n" -+ "off:i=0x%x, c=0x%x, p=%d, Rbat=%d, age_ocv_cap=%d, fb=%d, hot=%d\n" -+ "adp:finish=%lu, boot_min=%lu, sleep_min=%lu, adc=%d, Vsys=%d\n" -+ "bat:%s, meet: soc=%d, calc: dsoc=%d, rsoc=%d, Vocv=%d\n" -+ "pwr: dsoc=%d, rsoc=%d, vol=%d, halt: st=%d, cnt=%d, reboot=%d\n" -+ "ocv_c=%d: %d -> %d; max_c=%d: %d -> %d; force_c=%d: %d -> %d\n" -+ "min=%d, init=%d, sw=%d, below0=%d, first=%d, changed=%d\n" -+ "###############################################################\n", -+ di->dsoc, di->rsoc, di->voltage_avg, di->current_avg, -+ di->remain_cap, di->fcc, di->rsoc - di->dsoc, -+ di->sm_linek, work_mode[di->work_mode], di->sm_remain_cap, -+ di->res_div * chrg_cur_sel_array[chrg_ctrl1 & 0x0f], -+ chrg_cur_input_array[usb_ctrl & 0x0f], -+ chrg_vol_sel_array[(chrg_ctrl1 & 0x70) >> 4], -+ feedback_temp_array[(thermal & 0x0c) >> 2], di->temperature, -+ di->pdata->sample_res, di->usb_in, di->ac_in, -+ rk818_bat_get_ioffset(di), -+ rk818_bat_get_coffset(di), di->poffset, di->bat_res, -+ di->age_adjust_cap, di->fb_blank, !!(thermal & HOTDIE_STS), -+ base2min(di->finish_base), -+ base2min(di->boot_base), di->sleep_sum_sec / 60, -+ di->adc_allow_update, -+ di->voltage_avg + di->current_avg * DEF_PWRPATH_RES / 1000, -+ bat_mode[di->pdata->bat_mode], di->dbg_meet_soc, di->dbg_calc_dsoc, -+ di->dbg_calc_rsoc, di->voltage_ocv, di->dbg_pwr_dsoc, -+ di->dbg_pwr_rsoc, di->dbg_pwr_vol, di->is_halt, di->halt_cnt, -+ reboot_cnt, di->is_ocv_calib, di->ocv_pre_dsoc, di->ocv_new_dsoc, -+ di->is_max_soc_offset, di->max_pre_dsoc, di->max_new_dsoc, -+ di->is_force_calib, di->force_pre_dsoc, di->force_new_dsoc, -+ di->pwroff_min, di->is_initialized, di->is_sw_reset, -+ di->dbg_cap_low0, di->is_first_on, di->last_dsoc -+ ); -+} -+ -+static void rk818_bat_init_capacity(struct rk818_battery *di, u32 cap) -+{ -+ int delta_cap; -+ -+ delta_cap = cap - di->remain_cap; -+ if (!delta_cap) -+ return; -+ -+ di->age_adjust_cap += delta_cap; -+ rk818_bat_init_coulomb_cap(di, cap); -+ rk818_bat_smooth_algo_prepare(di); -+ rk818_bat_zero_algo_prepare(di); -+} -+ -+static void rk818_bat_update_age_fcc(struct rk818_battery *di) -+{ -+ int fcc, remain_cap, age_keep_min, lock_fcc; -+ -+ lock_fcc = rk818_bat_get_coulomb_cap(di); -+ remain_cap = lock_fcc - di->age_ocv_cap - di->age_adjust_cap; -+ age_keep_min = base2min(di->age_keep_sec); -+ -+ DBG("%s: lock_fcc=%d, age_ocv_cap=%d, age_adjust_cap=%d, remain_cap=%d," -+ "age_allow_update=%d, age_keep_min=%d\n", -+ __func__, lock_fcc, di->age_ocv_cap, di->age_adjust_cap, remain_cap, -+ di->age_allow_update, age_keep_min); -+ -+ if ((di->chrg_status == CHARGE_FINISH) && (di->age_allow_update) && -+ (age_keep_min < 1200)) { -+ di->age_allow_update = false; -+ fcc = remain_cap * 100 / DIV(100 - di->age_ocv_soc); -+ BAT_INFO("lock_fcc=%d, calc_cap=%d, age: soc=%d, cap=%d, " -+ "level=%d, fcc:%d->%d?\n", -+ lock_fcc, remain_cap, di->age_ocv_soc, -+ di->age_ocv_cap, di->age_level, di->fcc, fcc); -+ -+ if ((fcc < di->qmax) && (fcc > MIN_FCC)) { -+ BAT_INFO("fcc:%d->%d!\n", di->fcc, fcc); -+ di->fcc = fcc; -+ rk818_bat_init_capacity(di, di->fcc); -+ rk818_bat_save_fcc(di, di->fcc); -+ rk818_bat_save_age_level(di, di->age_level); -+ } -+ } -+} -+ -+static void rk818_bat_wait_finish_sig(struct rk818_battery *di) -+{ -+ int chrg_finish_vol = di->pdata->max_chrg_voltage; -+ -+ if (!rk818_bat_chrg_online(di)) -+ return; -+ -+ if ((di->chrg_status == CHARGE_FINISH) && (di->adc_allow_update) && -+ (di->voltage_avg > chrg_finish_vol - 150)) { -+ rk818_bat_update_age_fcc(di); -+ if (rk818_bat_adc_calib(di)) -+ di->adc_allow_update = false; -+ } -+} -+ -+static void rk818_bat_finish_algorithm(struct rk818_battery *di) -+{ -+ unsigned long finish_sec, soc_sec; -+ int plus_soc, finish_current, rest = 0; -+ -+ /* rsoc */ -+ if ((di->remain_cap != di->fcc) && -+ (rk818_bat_get_chrg_status(di) == CHARGE_FINISH)) { -+ di->age_adjust_cap += (di->fcc - di->remain_cap); -+ rk818_bat_init_coulomb_cap(di, di->fcc); -+ } -+ -+ /* dsoc */ -+ if (di->dsoc < 100) { -+ if (!di->finish_base) -+ di->finish_base = get_boot_sec(); -+ finish_current = (di->rsoc - di->dsoc) > FINISH_MAX_SOC_DELAY ? -+ FINISH_CHRG_CUR2 : FINISH_CHRG_CUR1; -+ finish_sec = base2sec(di->finish_base); -+ soc_sec = di->fcc * 3600 / 100 / DIV(finish_current); -+ plus_soc = finish_sec / DIV(soc_sec); -+ if (finish_sec > soc_sec) { -+ rest = finish_sec % soc_sec; -+ di->dsoc += plus_soc; -+ di->finish_base = get_boot_sec(); -+ if (di->finish_base > rest) -+ di->finish_base = get_boot_sec() - rest; -+ } -+ DBG("<%s>.CHARGE_FINISH:dsoc<100,dsoc=%d\n" -+ "soc_time=%lu, sec_finish=%lu, plus_soc=%d, rest=%d\n", -+ __func__, di->dsoc, soc_sec, finish_sec, plus_soc, rest); -+ } -+} -+ -+static void rk818_bat_calc_smooth_dischrg(struct rk818_battery *di) -+{ -+ int tmp_soc = 0, sm_delta_dsoc = 0, zero_delta_dsoc = 0; -+ -+ tmp_soc = di->sm_dischrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) -+ goto out; -+ -+ DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc); -+ /* when dischrge slow down, take sm charge rest into calc */ -+ if (di->dsoc < di->rsoc) { -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ sm_delta_dsoc = di->sm_chrg_dsoc - di->dsoc * 1000; -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ di->sm_dischrg_dsoc += sm_delta_dsoc; -+ DBG("<%s>. take sm dischrg, delta=%d\n", -+ __func__, sm_delta_dsoc); -+ } -+ } -+ -+ /* when discharge speed up, take zero discharge rest into calc */ -+ if (di->dsoc > di->rsoc) { -+ tmp_soc = di->zero_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ zero_delta_dsoc = di->zero_dsoc - ((di->dsoc + 1) * -+ 1000 - MIN_ACCURACY); -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ di->sm_dischrg_dsoc += zero_delta_dsoc; -+ DBG("<%s>. take zero schrg, delta=%d\n", -+ __func__, zero_delta_dsoc); -+ } -+ } -+ -+ /* check up overflow */ -+ if ((di->sm_dischrg_dsoc) > ((di->dsoc + 1) * 1000 - MIN_ACCURACY)) { -+ DBG("<%s>. dischrg_dsoc up overflow\n", __func__); -+ di->sm_dischrg_dsoc = (di->dsoc + 1) * -+ 1000 - MIN_ACCURACY; -+ } -+ -+ /* check new dsoc */ -+ tmp_soc = di->sm_dischrg_dsoc / 1000; -+ if (tmp_soc != di->dsoc) { -+ di->dsoc = tmp_soc; -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ } -+out: -+ DBG("<%s>. dsoc=%d, rsoc=%d, dsoc:sm_dischrg=%d, sm_chrg=%d, zero=%d\n", -+ __func__, di->dsoc, di->rsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc, -+ di->zero_dsoc); -+ -+} -+ -+static void rk818_bat_calc_smooth_chrg(struct rk818_battery *di) -+{ -+ int tmp_soc = 0, sm_delta_dsoc = 0, zero_delta_dsoc = 0; -+ -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) -+ goto out; -+ -+ DBG("<%s>. enter: dsoc=%d, rsoc=%d\n", __func__, di->dsoc, di->rsoc); -+ /* when charge slow down, take zero & sm dischrg into calc */ -+ if (di->dsoc > di->rsoc) { -+ /* take sm discharge rest into calc */ -+ tmp_soc = di->sm_dischrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ sm_delta_dsoc = di->sm_dischrg_dsoc - -+ ((di->dsoc + 1) * 1000 - MIN_ACCURACY); -+ di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - -+ MIN_ACCURACY; -+ di->sm_chrg_dsoc += sm_delta_dsoc; -+ DBG("<%s>. take sm dischrg, delta=%d\n", -+ __func__, sm_delta_dsoc); -+ } -+ -+ /* take zero discharge rest into calc */ -+ tmp_soc = di->zero_dsoc / 1000; -+ if (tmp_soc == di->dsoc) { -+ zero_delta_dsoc = di->zero_dsoc - -+ ((di->dsoc + 1) * 1000 - MIN_ACCURACY); -+ di->zero_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ di->sm_chrg_dsoc += zero_delta_dsoc; -+ DBG("<%s>. take zero dischrg, delta=%d\n", -+ __func__, zero_delta_dsoc); -+ } -+ } -+ -+ /* check down overflow */ -+ if (di->sm_chrg_dsoc < di->dsoc * 1000) { -+ DBG("<%s>. chrg_dsoc down overflow\n", __func__); -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ } -+ -+ /* check new dsoc */ -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc != di->dsoc) { -+ di->dsoc = tmp_soc; -+ di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ } -+out: -+ DBG("<%s>.dsoc=%d, rsoc=%d, dsoc: sm_dischrg=%d, sm_chrg=%d, zero=%d\n", -+ __func__, di->dsoc, di->rsoc, di->sm_dischrg_dsoc, di->sm_chrg_dsoc, -+ di->zero_dsoc); -+} -+ -+static void rk818_bat_smooth_algorithm(struct rk818_battery *di) -+{ -+ int ydsoc = 0, delta_cap = 0, old_cap = 0; -+ unsigned long tgt_sec = 0; -+ -+ di->remain_cap = rk818_bat_get_coulomb_cap(di); -+ -+ /* full charge: slow down */ -+ if ((di->dsoc == 99) && (di->chrg_status == CC_OR_CV) && -+ (di->current_avg > 0)) { -+ di->sm_linek = FULL_CHRG_K; -+ /* terminal charge, slow down */ -+ } else if ((di->current_avg >= TERM_CHRG_CURR) && -+ (di->chrg_status == CC_OR_CV) && (di->dsoc >= TERM_CHRG_DSOC)) { -+ di->sm_linek = TERM_CHRG_K; -+ DBG("<%s>. terminal mode..\n", __func__); -+ /* simulate charge, speed up */ -+ } else if ((di->current_avg <= SIMULATE_CHRG_CURR) && -+ (di->current_avg > 0) && (di->chrg_status == CC_OR_CV) && -+ (di->dsoc < TERM_CHRG_DSOC) && -+ ((di->rsoc - di->dsoc) >= SIMULATE_CHRG_INTV)) { -+ di->sm_linek = SIMULATE_CHRG_K; -+ DBG("<%s>. simulate mode..\n", __func__); -+ } else { -+ /* charge and discharge switch */ -+ if ((di->sm_linek * di->current_avg <= 0) || -+ (di->sm_linek == TERM_CHRG_K) || -+ (di->sm_linek == FULL_CHRG_K) || -+ (di->sm_linek == SIMULATE_CHRG_K)) { -+ DBG("<%s>. linek mode, retinit sm linek..\n", __func__); -+ rk818_bat_calc_sm_linek(di); -+ } -+ } -+ -+ old_cap = di->sm_remain_cap; -+ /* -+ * when dsoc equal rsoc(not include full, term, simulate case), -+ * sm_linek should change to -1000/1000 smoothly to avoid dsoc+1/-1 -+ * right away, so change it after flat seconds -+ */ -+ if ((di->dsoc == di->rsoc) && (abs(di->sm_linek) != 1000) && -+ (di->sm_linek != FULL_CHRG_K && di->sm_linek != TERM_CHRG_K && -+ di->sm_linek != SIMULATE_CHRG_K)) { -+ if (!di->flat_match_sec) -+ di->flat_match_sec = get_boot_sec(); -+ tgt_sec = di->fcc * 3600 / 100 / DIV(abs(di->current_avg)) / 3; -+ if (base2sec(di->flat_match_sec) >= tgt_sec) { -+ di->flat_match_sec = 0; -+ di->sm_linek = (di->current_avg >= 0) ? 1000 : -1000; -+ } -+ DBG("<%s>. flat_sec=%ld, tgt_sec=%ld, sm_k=%d\n", __func__, -+ base2sec(di->flat_match_sec), tgt_sec, di->sm_linek); -+ } else { -+ di->flat_match_sec = 0; -+ } -+ -+ /* abs(k)=1000 or dsoc=100, stop calc */ -+ if ((abs(di->sm_linek) == 1000) || (di->current_avg >= 0 && -+ di->chrg_status == CC_OR_CV && di->dsoc >= 100)) { -+ DBG("<%s>. sm_linek=%d\n", __func__, di->sm_linek); -+ if (abs(di->sm_linek) == 1000) { -+ di->dsoc = di->rsoc; -+ di->sm_linek = (di->sm_linek > 0) ? 1000 : -1000; -+ DBG("<%s>. dsoc == rsoc, sm_linek=%d\n", -+ __func__, di->sm_linek); -+ } -+ di->sm_remain_cap = di->remain_cap; -+ di->sm_chrg_dsoc = di->dsoc * 1000; -+ di->sm_dischrg_dsoc = (di->dsoc + 1) * 1000 - MIN_ACCURACY; -+ DBG("<%s>. sm_dischrg_dsoc=%d, sm_chrg_dsoc=%d\n", -+ __func__, di->sm_dischrg_dsoc, di->sm_chrg_dsoc); -+ } else { -+ delta_cap = di->remain_cap - di->sm_remain_cap; -+ if (delta_cap == 0) { -+ DBG("<%s>. delta_cap = 0\n", __func__); -+ return; -+ } -+ ydsoc = di->sm_linek * abs(delta_cap) * 100 / DIV(di->fcc); -+ if (ydsoc == 0) { -+ DBG("<%s>. ydsoc = 0\n", __func__); -+ return; -+ } -+ di->sm_remain_cap = di->remain_cap; -+ -+ DBG("<%s>. k=%d, ydsoc=%d; cap:old=%d, new:%d; delta_cap=%d\n", -+ __func__, di->sm_linek, ydsoc, old_cap, -+ di->sm_remain_cap, delta_cap); -+ -+ /* discharge mode */ -+ if (ydsoc < 0) { -+ di->sm_dischrg_dsoc += ydsoc; -+ rk818_bat_calc_smooth_dischrg(di); -+ /* charge mode */ -+ } else { -+ di->sm_chrg_dsoc += ydsoc; -+ rk818_bat_calc_smooth_chrg(di); -+ } -+ -+ if (di->s2r) { -+ di->s2r = false; -+ rk818_bat_calc_sm_linek(di); -+ } -+ } -+} -+ -+/* -+ * cccv and finish switch all the time will cause dsoc freeze, -+ * if so, do finish chrg, 100ma is less than min finish_ma. -+ */ -+static bool rk818_bat_fake_finish_mode(struct rk818_battery *di) -+{ -+ if ((di->rsoc == 100) && (rk818_bat_get_chrg_status(di) == CC_OR_CV) && -+ (abs(di->current_avg) <= 100)) -+ return true; -+ else -+ return false; -+} -+ -+static void rk818_bat_display_smooth(struct rk818_battery *di) -+{ -+ /* discharge: reinit "zero & smooth" algorithm to avoid handling dsoc */ -+ if (di->s2r && !di->sleep_chrg_online) { -+ DBG("s2r: discharge, reset algorithm...\n"); -+ di->s2r = false; -+ rk818_bat_zero_algo_prepare(di); -+ rk818_bat_smooth_algo_prepare(di); -+ return; -+ } -+ -+ if (di->work_mode == MODE_FINISH) { -+ DBG("step1: charge finish...\n"); -+ rk818_bat_finish_algorithm(di); -+ if ((rk818_bat_get_chrg_status(di) != CHARGE_FINISH) && -+ !rk818_bat_fake_finish_mode(di)) { -+ if ((di->current_avg < 0) && -+ (di->voltage_avg < di->pdata->zero_algorithm_vol)) { -+ DBG("step1: change to zero mode...\n"); -+ rk818_bat_zero_algo_prepare(di); -+ di->work_mode = MODE_ZERO; -+ } else { -+ DBG("step1: change to smooth mode...\n"); -+ rk818_bat_smooth_algo_prepare(di); -+ di->work_mode = MODE_SMOOTH; -+ } -+ } -+ } else if (di->work_mode == MODE_ZERO) { -+ DBG("step2: zero algorithm...\n"); -+ rk818_bat_zero_algorithm(di); -+ if ((di->voltage_avg >= di->pdata->zero_algorithm_vol + 50) || -+ (di->current_avg >= 0)) { -+ DBG("step2: change to smooth mode...\n"); -+ rk818_bat_smooth_algo_prepare(di); -+ di->work_mode = MODE_SMOOTH; -+ } else if ((rk818_bat_get_chrg_status(di) == CHARGE_FINISH) || -+ rk818_bat_fake_finish_mode(di)) { -+ DBG("step2: change to finish mode...\n"); -+ rk818_bat_finish_algo_prepare(di); -+ di->work_mode = MODE_FINISH; -+ } -+ } else { -+ DBG("step3: smooth algorithm...\n"); -+ rk818_bat_smooth_algorithm(di); -+ if ((di->current_avg < 0) && -+ (di->voltage_avg < di->pdata->zero_algorithm_vol)) { -+ DBG("step3: change to zero mode...\n"); -+ rk818_bat_zero_algo_prepare(di); -+ di->work_mode = MODE_ZERO; -+ } else if ((rk818_bat_get_chrg_status(di) == CHARGE_FINISH) || -+ rk818_bat_fake_finish_mode(di)) { -+ DBG("step3: change to finish mode...\n"); -+ rk818_bat_finish_algo_prepare(di); -+ di->work_mode = MODE_FINISH; -+ } -+ } -+} -+ -+static void rk818_bat_relax_vol_calib(struct rk818_battery *di) -+{ -+ int soc, cap, vol; -+ -+ vol = di->voltage_relax; -+ soc = rk818_bat_vol_to_ocvsoc(di, vol); -+ cap = rk818_bat_vol_to_ocvcap(di, vol); -+ rk818_bat_init_capacity(di, cap); -+ BAT_INFO("sleep ocv calib: rsoc=%d, cap=%d\n", soc, cap); -+} -+ -+static void rk818_bat_relife_age_flag(struct rk818_battery *di) -+{ -+ u8 ocv_soc, ocv_cap, soc_level; -+ -+ if (di->voltage_relax <= 0) -+ return; -+ -+ ocv_soc = rk818_bat_vol_to_ocvsoc(di, di->voltage_relax); -+ ocv_cap = rk818_bat_vol_to_ocvcap(di, di->voltage_relax); -+ DBG("<%s>. ocv_soc=%d, min=%lu, vol=%d\n", __func__, -+ ocv_soc, di->sleep_dischrg_sec / 60, di->voltage_relax); -+ -+ /* sleep enough time and ocv_soc enough low */ -+ if (!di->age_allow_update && ocv_soc <= 10) { -+ di->age_voltage = di->voltage_relax; -+ di->age_ocv_cap = ocv_cap; -+ di->age_ocv_soc = ocv_soc; -+ di->age_adjust_cap = 0; -+ -+ if (ocv_soc <= 1) -+ di->age_level = 100; -+ else if (ocv_soc < 5) -+ di->age_level = 90; -+ else -+ di->age_level = 80; -+ -+ soc_level = rk818_bat_get_age_level(di); -+ if (soc_level > di->age_level) { -+ di->age_allow_update = false; -+ } else { -+ di->age_allow_update = true; -+ di->age_keep_sec = get_boot_sec(); -+ } -+ -+ BAT_INFO("resume: age_vol:%d, age_ocv_cap:%d, age_ocv_soc:%d, " -+ "soc_level:%d, age_allow_update:%d, " -+ "age_level:%d\n", -+ di->age_voltage, di->age_ocv_cap, ocv_soc, soc_level, -+ di->age_allow_update, di->age_level); -+ } -+} -+ -+static int rk818_bat_sleep_dischrg(struct rk818_battery *di) -+{ -+ bool ocv_soc_updated = false; -+ int tgt_dsoc, gap_soc, sleep_soc = 0; -+ int pwroff_vol = di->pdata->pwroff_vol; -+ unsigned long sleep_sec = di->sleep_dischrg_sec; -+ -+ DBG("<%s>. enter: dsoc=%d, rsoc=%d, rv=%d, v=%d, sleep_min=%lu\n", -+ __func__, di->dsoc, di->rsoc, di->voltage_relax, -+ di->voltage_avg, sleep_sec / 60); -+ -+ if (di->voltage_relax >= di->voltage_avg) { -+ rk818_bat_relax_vol_calib(di); -+ rk818_bat_restart_relax(di); -+ rk818_bat_relife_age_flag(di); -+ ocv_soc_updated = true; -+ } -+ -+ /* handle dsoc */ -+ if (di->dsoc <= di->rsoc) { -+ di->sleep_sum_cap = (SLP_CURR_MIN * sleep_sec / 3600); -+ sleep_soc = di->sleep_sum_cap * 100 / DIV(di->fcc); -+ tgt_dsoc = di->dsoc - sleep_soc; -+ if (sleep_soc > 0) { -+ BAT_INFO("calib0: rl=%d, dl=%d, intval=%d\n", -+ di->rsoc, di->dsoc, sleep_soc); -+ if (di->dsoc < 5) { -+ di->dsoc--; -+ } else if ((tgt_dsoc < 5) && (di->dsoc >= 5)) { -+ if (di->dsoc == 5) -+ di->dsoc--; -+ else -+ di->dsoc = 5; -+ } else if (tgt_dsoc > 5) { -+ di->dsoc = tgt_dsoc; -+ } -+ } -+ -+ DBG("%s: dsoc<=rsoc, sum_cap=%d==>sleep_soc=%d, tgt_dsoc=%d\n", -+ __func__, di->sleep_sum_cap, sleep_soc, tgt_dsoc); -+ } else { -+ /* di->dsoc > di->rsoc */ -+ di->sleep_sum_cap = (SLP_CURR_MAX * sleep_sec / 3600); -+ sleep_soc = di->sleep_sum_cap / DIV(di->fcc / 100); -+ gap_soc = di->dsoc - di->rsoc; -+ -+ BAT_INFO("calib1: rsoc=%d, dsoc=%d, intval=%d\n", -+ di->rsoc, di->dsoc, sleep_soc); -+ if (gap_soc > sleep_soc) { -+ if ((gap_soc - 5) > (sleep_soc * 2)) -+ di->dsoc -= (sleep_soc * 2); -+ else -+ di->dsoc -= sleep_soc; -+ } else { -+ di->dsoc = di->rsoc; -+ } -+ -+ DBG("%s: dsoc>rsoc, sum_cap=%d=>sleep_soc=%d, gap_soc=%d\n", -+ __func__, di->sleep_sum_cap, sleep_soc, gap_soc); -+ } -+ -+ if (di->voltage_avg <= pwroff_vol - 70) { -+ di->dsoc = 0; -+ rk_send_wakeup_key(); -+ BAT_INFO("low power sleeping, shutdown... %d\n", di->dsoc); -+ } -+ -+ if (ocv_soc_updated && sleep_soc && (di->rsoc - di->dsoc) < 5 && -+ di->dsoc < 40) { -+ di->dsoc--; -+ BAT_INFO("low power sleeping, reserved... %d\n", di->dsoc); -+ } -+ -+ if (di->dsoc <= 0) { -+ di->dsoc = 0; -+ rk_send_wakeup_key(); -+ BAT_INFO("sleep dsoc is %d...\n", di->dsoc); -+ } -+ -+ DBG("<%s>. out: dsoc=%d, rsoc=%d, sum_cap=%d\n", -+ __func__, di->dsoc, di->rsoc, di->sleep_sum_cap); -+ -+ return sleep_soc; -+} -+ -+static void rk818_bat_power_supply_changed(struct rk818_battery *di) -+{ -+ u8 status, thermal; -+ static int old_soc = -1; -+ -+ if (di->dsoc > 100) -+ di->dsoc = 100; -+ else if (di->dsoc < 0) -+ di->dsoc = 0; -+ -+ if (di->dsoc == old_soc) -+ return; -+ -+ thermal = rk818_bat_read(di, RK818_THERMAL_REG); -+ status = rk818_bat_read(di, RK818_SUP_STS_REG); -+ status = (status & CHRG_STATUS_MSK) >> 4; -+ old_soc = di->dsoc; -+ di->last_dsoc = di->dsoc; -+ power_supply_changed(di->bat); -+ BAT_INFO("changed: dsoc=%d, rsoc=%d, v=%d, ov=%d c=%d, " -+ "cap=%d, f=%d, st=%s, hotdie=%d\n", -+ di->dsoc, di->rsoc, di->voltage_avg, di->voltage_ocv, -+ di->current_avg, di->remain_cap, di->fcc, bat_status[status], -+ !!(thermal & HOTDIE_STS)); -+ -+ BAT_INFO("dl=%d, rl=%d, v=%d, halt=%d, halt_n=%d, max=%d, " -+ "init=%d, sw=%d, calib=%d, below0=%d, force=%d\n", -+ di->dbg_pwr_dsoc, di->dbg_pwr_rsoc, di->dbg_pwr_vol, -+ di->is_halt, di->halt_cnt, di->is_max_soc_offset, -+ di->is_initialized, di->is_sw_reset, di->is_ocv_calib, -+ di->dbg_cap_low0, di->is_force_calib); -+} -+ -+static u8 rk818_bat_check_reboot(struct rk818_battery *di) -+{ -+ u8 cnt; -+ -+ cnt = rk818_bat_read(di, RK818_REBOOT_CNT_REG); -+ cnt++; -+ -+ if (cnt >= REBOOT_MAX_CNT) { -+ BAT_INFO("reboot: %d --> %d\n", di->dsoc, di->rsoc); -+ di->dsoc = di->rsoc; -+ if (di->dsoc > 100) -+ di->dsoc = 100; -+ else if (di->dsoc < 0) -+ di->dsoc = 0; -+ rk818_bat_save_dsoc(di, di->dsoc); -+ cnt = REBOOT_MAX_CNT; -+ } -+ -+ rk818_bat_save_reboot_cnt(di, cnt); -+ DBG("reboot cnt: %d\n", cnt); -+ -+ return cnt; -+} -+ -+static void rk818_bat_rsoc_daemon(struct rk818_battery *di) -+{ -+ int est_vol, remain_cap; -+ static unsigned long sec; -+ -+ if ((di->remain_cap < 0) && (di->fb_blank != 0)) { -+ if (!sec) -+ sec = get_boot_sec(); -+ // wake_lock_timeout(&di->wake_lock, -+ // (di->pdata->monitor_sec + 1) * HZ); -+ -+ DBG("sec=%ld, hold_sec=%ld\n", sec, base2sec(sec)); -+ if (base2sec(sec) >= 60) { -+ sec = 0; -+ di->dbg_cap_low0++; -+ est_vol = di->voltage_avg - -+ (di->bat_res * di->current_avg) / 1000; -+ remain_cap = rk818_bat_vol_to_ocvcap(di, est_vol); -+ rk818_bat_init_capacity(di, remain_cap); -+ BAT_INFO("adjust cap below 0 --> %d, rsoc=%d\n", -+ di->remain_cap, di->rsoc); -+ // wake_unlock(&di->wake_lock); -+ } -+ } else { -+ sec = 0; -+ } -+} -+ -+static void rk818_bat_update_info(struct rk818_battery *di) -+{ -+ int is_charging; -+ -+ di->voltage_avg = rk818_bat_get_avg_voltage(di); -+ di->current_avg = rk818_bat_get_avg_current(di); -+ di->voltage_relax = rk818_bat_get_relax_voltage(di); -+ di->rsoc = rk818_bat_get_rsoc(di); -+ di->remain_cap = rk818_bat_get_coulomb_cap(di); -+ di->chrg_status = rk818_bat_get_chrg_status(di); -+ is_charging = rk818_bat_get_charge_state(di); -+ if (is_charging != di->is_charging) { -+ di->is_charging = is_charging; -+ if (is_charging) -+ di->charge_count++; -+ } -+ if (di->voltage_avg > di->voltage_max) -+ di->voltage_max = di->voltage_avg; -+ if (di->current_avg > di->current_max) -+ di->current_max = di->current_avg; -+ -+ /* smooth charge */ -+ if (di->remain_cap > di->fcc) { -+ di->sm_remain_cap -= (di->remain_cap - di->fcc); -+ DBG("<%s>. cap: remain=%d, sm_remain=%d\n", -+ __func__, di->remain_cap, di->sm_remain_cap); -+ rk818_bat_init_coulomb_cap(di, di->fcc); -+ } -+ -+ if (di->chrg_status != CHARGE_FINISH) -+ di->finish_base = get_boot_sec(); -+ -+ /* -+ * we need update fcc in continuous charging state, if discharge state -+ * keep at least 2 hour, we decide not to update fcc, so clear the -+ * fcc update flag: age_allow_update. -+ */ -+ if (base2min(di->plug_out_base) > 120) -+ di->age_allow_update = false; -+ -+ /* do adc calib: status must from cccv mode to finish mode */ -+ if (di->chrg_status == CC_OR_CV) { -+ di->adc_allow_update = true; -+ di->adc_calib_cnt = 0; -+ } -+} -+ -+static void rk818_bat_init_ts1_detect(struct rk818_battery *di) -+{ -+ u8 buf; -+ u32 *ntc_table = di->pdata->ntc_table; -+ -+ if (!di->pdata->ntc_size) -+ return; -+ -+ /* select ua */ -+ buf = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ buf &= ~TS1_CUR_MSK; -+ /* chose suitable UA for temperature detect */ -+ if (ntc_table[0] < NTC_80UA_MAX_MEASURE) { -+ di->pdata->ntc_factor = NTC_CALC_FACTOR_80UA; -+ di->pdata->ntc_uA = 80; -+ buf |= ADC_CUR_80UA; -+ } else if (ntc_table[0] < NTC_60UA_MAX_MEASURE) { -+ di->pdata->ntc_factor = NTC_CALC_FACTOR_60UA; -+ di->pdata->ntc_uA = 60; -+ buf |= ADC_CUR_60UA; -+ } else if (ntc_table[0] < NTC_40UA_MAX_MEASURE) { -+ di->pdata->ntc_factor = NTC_CALC_FACTOR_40UA; -+ di->pdata->ntc_uA = 40; -+ buf |= ADC_CUR_40UA; -+ } else { -+ di->pdata->ntc_factor = NTC_CALC_FACTOR_20UA; -+ di->pdata->ntc_uA = 20; -+ buf |= ADC_CUR_20UA; -+ } -+ rk818_bat_write(di, RK818_TS_CTRL_REG, buf); -+ -+ /* enable ADC_TS1_EN */ -+ buf = rk818_bat_read(di, RK818_ADC_CTRL_REG); -+ buf |= ADC_TS1_EN; -+ rk818_bat_write(di, RK818_ADC_CTRL_REG, buf); -+} -+ -+/* -+ * Due to hardware design issue, Vdelta = "(R_sample + R_other) * I_avg" will be -+ * included into TS1 adc value. We must subtract it to get correct adc value. -+ * The solution: -+ * -+ * (1) calculate Vdelta: -+ * -+ * adc1 - Vdelta ua1 (adc2 * ua1) - (adc1 * ua2) -+ * ------------- = ----- ==> equals: Vdelta = ----------------------------- -+ * adc2 - Vdelta ua2 ua1 - ua2 -+ * -+ * -+ * (2) calculate correct ADC value: -+ * -+ * charging: ADC = adc1 - abs(Vdelta); -+ * discharging: ADC = adc1 + abs(Vdelta); -+ */ -+static int rk818_bat_get_ntc_res(struct rk818_battery *di) -+{ -+ int adc1 = 0, adc2 = 0; -+ int ua1, ua2, v_delta, res, val; -+ u8 buf; -+ -+ /* read sample ua1 */ -+ buf = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ DBG("<%s>. read adc1, sample uA=%d\n", -+ __func__, ((buf & 0x03) + 1) * 20); -+ -+ /* read adc adc1 */ -+ ua1 = di->pdata->ntc_uA; -+ adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0; -+ adc1 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8; -+ -+ /* chose reference UA for adc2 */ -+ ua2 = (ua1 != 20) ? 20 : 40; -+ buf = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ buf &= ~TS1_CUR_MSK; -+ buf |= ((ua2 - 20) / 20); -+ rk818_bat_write(di, RK818_TS_CTRL_REG, buf); -+ -+ /* read adc adc2 */ -+ msleep(1000); -+ -+ /* read sample ua2 */ -+ buf = rk818_bat_read(di, RK818_TS_CTRL_REG); -+ DBG("<%s>. read adc2, sample uA=%d\n", -+ __func__, ((buf & 0x03) + 1) * 20); -+ -+ adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGL) << 0; -+ adc2 |= rk818_bat_read(di, RK818_TS1_ADC_REGH) << 8; -+ -+ DBG("<%s>. ua1=%d, ua2=%d, adc1=%d, adc2=%d\n", -+ __func__, ua1, ua2, adc1, adc2); -+ -+ /* calculate delta voltage */ -+ if (adc2 != adc1) -+ v_delta = abs((adc2 * ua1 - adc1 * ua2) / (ua2 - ua1)); -+ else -+ v_delta = 0; -+ -+ /* considering current avg direction, calcuate real adc value */ -+ val = (di->current_avg >= 0) ? (adc1 - v_delta) : (adc1 + v_delta); -+ -+ DBG("<%s>. Iavg=%d, Vdelta=%d, Vadc=%d\n", -+ __func__, di->current_avg, v_delta, val); -+ -+ res = val * di->pdata->ntc_factor; -+ -+ DBG("<%s>. val=%d, ntc_res=%d, ntc_factor=%d, Rdelta=%d\n", -+ __func__, val, res, di->pdata->ntc_factor, -+ v_delta * di->pdata->ntc_factor); -+ -+ DBG("<%s>. t=[%d'C(%d) ~ %dC(%d)]\n", __func__, -+ di->pdata->ntc_degree_from, di->pdata->ntc_table[0], -+ di->pdata->ntc_degree_from + di->pdata->ntc_size - 1, -+ di->pdata->ntc_table[di->pdata->ntc_size - 1]); -+ -+ rk818_bat_init_ts1_detect(di); -+ -+ return res; -+} -+ -+static BLOCKING_NOTIFIER_HEAD(rk818_bat_notifier_chain); -+ -+int rk818_bat_temp_notifier_register(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_register(&rk818_bat_notifier_chain, nb); -+} -+ -+int rk818_bat_temp_notifier_unregister(struct notifier_block *nb) -+{ -+ return blocking_notifier_chain_unregister(&rk818_bat_notifier_chain, nb); -+} -+ -+static void rk818_bat_temp_notifier_callback(int temp) -+{ -+ blocking_notifier_call_chain(&rk818_bat_notifier_chain, temp, NULL); -+} -+ -+static void rk818_bat_update_temperature(struct rk818_battery *di) -+{ -+ static int old_temp, first_time = 1; -+ u32 ntc_size, *ntc_table; -+ int i, res, temp; -+ -+ ntc_table = di->pdata->ntc_table; -+ ntc_size = di->pdata->ntc_size; -+ di->temperature = VIRTUAL_TEMPERATURE; -+ -+ if (ntc_size) { -+ res = rk818_bat_get_ntc_res(di); -+ if (res < ntc_table[ntc_size - 1]) { -+ di->temperature = di->pdata->ntc_degree_from + -+ di->pdata->ntc_size - 1; -+ BAT_INFO("bat ntc upper max degree: R=%d\n", res); -+ } else if (res > ntc_table[0]) { -+ di->temperature = di->pdata->ntc_degree_from; -+ BAT_INFO("bat ntc lower min degree: R=%d\n", res); -+ } else { -+ for (i = 0; i < ntc_size; i++) { -+ if (res >= ntc_table[i]) -+ break; -+ } -+ -+ /* if first in, init old_temp */ -+ temp = (i + di->pdata->ntc_degree_from) * 10; -+ if (first_time == 1) { -+ di->temperature = temp; -+ old_temp = temp; -+ first_time = 0; -+ } -+ -+ /* -+ * compare with old one, it's invalid when over 50 -+ * and we should use old data. -+ */ -+ if (abs(temp - old_temp) > 50) -+ temp = old_temp; -+ else -+ old_temp = temp; -+ -+ di->temperature = temp; -+ DBG("<%s>. temperature = %d\n", -+ __func__, di->temperature); -+ rk818_bat_temp_notifier_callback(di->temperature / 10); -+ } -+ } -+} -+ -+static void rk818_bat_init_dsoc_algorithm(struct rk818_battery *di) -+{ -+ u8 buf; -+ int16_t rest = 0; -+ unsigned long soc_sec; -+ const char *mode_name[] = { "MODE_ZERO", "MODE_FINISH", -+ "MODE_SMOOTH_CHRG", "MODE_SMOOTH_DISCHRG", "MODE_SMOOTH", }; -+ -+ /* get rest */ -+ rest |= rk818_bat_read(di, RK818_CALC_REST_REGH) << 8; -+ rest |= rk818_bat_read(di, RK818_CALC_REST_REGL) << 0; -+ -+ /* get mode */ -+ buf = rk818_bat_read(di, RK818_MISC_MARK_REG); -+ di->algo_rest_mode = (buf & ALGO_REST_MODE_MSK) >> ALGO_REST_MODE_SHIFT; -+ -+ if (rk818_bat_get_chrg_status(di) == CHARGE_FINISH) { -+ if (di->algo_rest_mode == MODE_FINISH) { -+ soc_sec = di->fcc * 3600 / 100 / FINISH_CHRG_CUR1; -+ if ((rest / DIV(soc_sec)) > 0) { -+ if (di->dsoc < 100) { -+ di->dsoc++; -+ di->algo_rest_val = rest % soc_sec; -+ BAT_INFO("algorithm rest(%d) dsoc " -+ "inc: %d\n", -+ rest, di->dsoc); -+ } else { -+ di->algo_rest_val = 0; -+ } -+ } else { -+ di->algo_rest_val = rest; -+ } -+ } else { -+ di->algo_rest_val = rest; -+ } -+ } else { -+ /* charge speed up */ -+ if ((rest / 1000) > 0 && rk818_bat_chrg_online(di)) { -+ if (di->dsoc < di->rsoc) { -+ di->dsoc++; -+ di->algo_rest_val = rest % 1000; -+ BAT_INFO("algorithm rest(%d) dsoc inc: %d\n", -+ rest, di->dsoc); -+ } else { -+ di->algo_rest_val = 0; -+ } -+ /* discharge speed up */ -+ } else if (((rest / 1000) < 0) && !rk818_bat_chrg_online(di)) { -+ if (di->dsoc > di->rsoc) { -+ di->dsoc--; -+ di->algo_rest_val = rest % 1000; -+ BAT_INFO("algorithm rest(%d) dsoc sub: %d\n", -+ rest, di->dsoc); -+ } else { -+ di->algo_rest_val = 0; -+ } -+ } else { -+ di->algo_rest_val = rest; -+ } -+ } -+ -+ if (di->dsoc >= 100) -+ di->dsoc = 100; -+ else if (di->dsoc <= 0) -+ di->dsoc = 0; -+ -+ /* init current mode */ -+ di->voltage_avg = rk818_bat_get_avg_voltage(di); -+ di->current_avg = rk818_bat_get_avg_current(di); -+ if (rk818_bat_get_chrg_status(di) == CHARGE_FINISH) { -+ rk818_bat_finish_algo_prepare(di); -+ di->work_mode = MODE_FINISH; -+ } else { -+ rk818_bat_smooth_algo_prepare(di); -+ di->work_mode = MODE_SMOOTH; -+ } -+ -+ DBG("<%s>. init: org_rest=%d, rest=%d, mode=%s; " -+ "doc(x1000): zero=%d, chrg=%d, dischrg=%d, finish=%lu\n", -+ __func__, rest, di->algo_rest_val, mode_name[di->algo_rest_mode], -+ di->zero_dsoc, di->sm_chrg_dsoc, di->sm_dischrg_dsoc, -+ di->finish_base); -+} -+ -+static void rk818_bat_save_algo_rest(struct rk818_battery *di) -+{ -+ u8 buf, mode; -+ int16_t algo_rest = 0; -+ int tmp_soc; -+ int zero_rest = 0, sm_chrg_rest = 0; -+ int sm_dischrg_rest = 0, finish_rest = 0; -+ const char *mode_name[] = { "MODE_ZERO", "MODE_FINISH", -+ "MODE_SMOOTH_CHRG", "MODE_SMOOTH_DISCHRG", "MODE_SMOOTH", }; -+ -+ /* zero dischrg */ -+ tmp_soc = (di->zero_dsoc) / 1000; -+ if (tmp_soc == di->dsoc) -+ zero_rest = di->zero_dsoc - ((di->dsoc + 1) * 1000 - -+ MIN_ACCURACY); -+ -+ /* sm chrg */ -+ tmp_soc = di->sm_chrg_dsoc / 1000; -+ if (tmp_soc == di->dsoc) -+ sm_chrg_rest = di->sm_chrg_dsoc - di->dsoc * 1000; -+ -+ /* sm dischrg */ -+ tmp_soc = (di->sm_dischrg_dsoc) / 1000; -+ if (tmp_soc == di->dsoc) -+ sm_dischrg_rest = di->sm_dischrg_dsoc - ((di->dsoc + 1) * 1000 - -+ MIN_ACCURACY); -+ -+ /* last time is also finish chrg, then add last rest */ -+ if (di->algo_rest_mode == MODE_FINISH && di->algo_rest_val) -+ finish_rest = base2sec(di->finish_base) + di->algo_rest_val; -+ else -+ finish_rest = base2sec(di->finish_base); -+ -+ /* total calc */ -+ if ((rk818_bat_chrg_online(di) && (di->dsoc > di->rsoc)) || -+ (!rk818_bat_chrg_online(di) && (di->dsoc < di->rsoc)) || -+ (di->dsoc == di->rsoc)) { -+ di->algo_rest_val = 0; -+ algo_rest = 0; -+ DBG("<%s>. step1..\n", __func__); -+ } else if (di->work_mode == MODE_FINISH) { -+ algo_rest = finish_rest; -+ DBG("<%s>. step2..\n", __func__); -+ } else if (di->algo_rest_mode == MODE_FINISH) { -+ algo_rest = zero_rest + sm_dischrg_rest + sm_chrg_rest; -+ DBG("<%s>. step3..\n", __func__); -+ } else { -+ if (rk818_bat_chrg_online(di) && (di->dsoc < di->rsoc)) -+ algo_rest = sm_chrg_rest + di->algo_rest_val; -+ else if (!rk818_bat_chrg_online(di) && (di->dsoc > di->rsoc)) -+ algo_rest = zero_rest + sm_dischrg_rest + -+ di->algo_rest_val; -+ else -+ algo_rest = zero_rest + sm_dischrg_rest + sm_chrg_rest + -+ di->algo_rest_val; -+ DBG("<%s>. step4..\n", __func__); -+ } -+ -+ /* check mode */ -+ if ((di->work_mode == MODE_FINISH) || (di->work_mode == MODE_ZERO)) { -+ mode = di->work_mode; -+ } else {/* MODE_SMOOTH */ -+ if (di->sm_linek > 0) -+ mode = MODE_SMOOTH_CHRG; -+ else -+ mode = MODE_SMOOTH_DISCHRG; -+ } -+ -+ /* save mode */ -+ buf = rk818_bat_read(di, RK818_MISC_MARK_REG); -+ buf &= ~ALGO_REST_MODE_MSK; -+ buf |= (mode << ALGO_REST_MODE_SHIFT); -+ rk818_bat_write(di, RK818_MISC_MARK_REG, buf); -+ -+ /* save rest */ -+ buf = (algo_rest >> 8) & 0xff; -+ rk818_bat_write(di, RK818_CALC_REST_REGH, buf); -+ buf = (algo_rest >> 0) & 0xff; -+ rk818_bat_write(di, RK818_CALC_REST_REGL, buf); -+ -+ DBG("<%s>. rest: algo=%d, mode=%s, last_rest=%d; zero=%d, " -+ "chrg=%d, dischrg=%d, finish=%lu\n", -+ __func__, algo_rest, mode_name[mode], di->algo_rest_val, zero_rest, -+ sm_chrg_rest, sm_dischrg_rest, base2sec(di->finish_base)); -+} -+ -+static void rk818_bat_save_data(struct rk818_battery *di) -+{ -+ rk818_bat_save_dsoc(di, di->dsoc); -+ rk818_bat_save_cap(di, di->remain_cap); -+ rk818_bat_save_algo_rest(di); -+} -+ -+static void rk818_battery_work(struct work_struct *work) -+{ -+ struct rk818_battery *di = -+ container_of(work, struct rk818_battery, bat_delay_work.work); -+ -+ rk818_bat_update_info(di); -+ rk818_bat_wait_finish_sig(di); -+ rk818_bat_rsoc_daemon(di); -+ rk818_bat_update_temperature(di); -+ rk818_bat_display_smooth(di); -+ rk818_bat_power_supply_changed(di); -+ rk818_bat_save_data(di); -+ rk818_bat_debug_info(di); -+ -+ queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work, -+ msecs_to_jiffies(di->monitor_ms)); -+} -+ -+static irqreturn_t rk818_vb_low_irq(int irq, void *bat) -+{ -+ struct rk818_battery *di = (struct rk818_battery *)bat; -+ -+ di->dsoc = 0; -+ rk_send_wakeup_key(); -+ BAT_INFO("lower power yet, power off system! v=%d, c=%d, dsoc=%d\n", -+ di->voltage_avg, di->current_avg, di->dsoc); -+ -+ return IRQ_HANDLED; -+} -+ -+static void rk818_bat_init_sysfs(struct rk818_battery *di) -+{ -+ int i, ret; -+ -+ for (i = 0; i < ARRAY_SIZE(rk818_bat_attr); i++) { -+ ret = sysfs_create_file(&di->dev->kobj, -+ &rk818_bat_attr[i].attr); -+ if (ret) -+ dev_err(di->dev, "create bat node(%s) error\n", -+ rk818_bat_attr[i].attr.name); -+ } -+} -+ -+static int rk818_bat_init_irqs(struct rk818_battery *di) -+{ -+ struct rk808 *rk818 = di->rk818; -+ struct platform_device *pdev = di->pdev; -+ int ret, vb_lo_irq; -+ -+ vb_lo_irq = regmap_irq_get_virq(rk818->irq_data, RK818_IRQ_VB_LO); -+ if (vb_lo_irq < 0) { -+ dev_err(di->dev, "vb_lo_irq request failed!\n"); -+ return vb_lo_irq; -+ } -+ -+ ret = devm_request_threaded_irq(di->dev, vb_lo_irq, NULL, -+ rk818_vb_low_irq, -+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT, -+ "rk818_vb_low", di); -+ if (ret) { -+ dev_err(&pdev->dev, "vb_lo_irq request failed!\n"); -+ return ret; -+ } -+ enable_irq_wake(vb_lo_irq); -+ -+ return 0; -+} -+ -+static void rk818_bat_init_info(struct rk818_battery *di) -+{ -+ di->design_cap = di->pdata->design_capacity; -+ di->qmax = di->pdata->design_qmax; -+ di->bat_res = di->pdata->bat_res; -+ di->monitor_ms = di->pdata->monitor_sec * TIMER_MS_COUNTS; -+ di->boot_base = POWER_ON_SEC_BASE; -+ di->res_div = (di->pdata->sample_res == SAMPLE_RES_20MR) ? -+ SAMPLE_RES_DIV1 : SAMPLE_RES_DIV2; -+} -+ -+static time64_t rk818_get_rtc_sec(void) -+{ -+ int err; -+ struct rtc_time tm; -+ struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); -+ -+ err = rtc_read_time(rtc, &tm); -+ if (err) { -+ dev_err(rtc->dev.parent, "read hardware clk failed\n"); -+ return 0; -+ } -+ -+ err = rtc_valid_tm(&tm); -+ if (err) { -+ dev_err(rtc->dev.parent, "invalid date time\n"); -+ return 0; -+ } -+ -+ return rtc_tm_to_time64(&tm); -+} -+ -+static int rk818_bat_rtc_sleep_sec(struct rk818_battery *di) -+{ -+ int interval_sec; -+ -+ interval_sec = rk818_get_rtc_sec() - di->rtc_base; -+ -+ return (interval_sec > 0) ? interval_sec : 0; -+} -+ -+static void rk818_bat_set_shtd_vol(struct rk818_battery *di) -+{ -+ u8 val; -+ -+ /* set vbat lowest 3.0v shutdown */ -+ val = rk818_bat_read(di, RK818_VB_MON_REG); -+ val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK); -+ val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN); -+ rk818_bat_write(di, RK818_VB_MON_REG, val); -+ -+ /* disable low irq */ -+ rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, -+ VB_LOW_INT_EN, VB_LOW_INT_EN); -+} -+ -+static void rk818_bat_init_fg(struct rk818_battery *di) -+{ -+ rk818_bat_enable_gauge(di); -+ rk818_bat_init_voltage_kb(di); -+ rk818_bat_init_coffset(di); -+ rk818_bat_set_relax_sample(di); -+ rk818_bat_set_ioffset_sample(di); -+ rk818_bat_set_ocv_sample(di); -+ rk818_bat_init_ts1_detect(di); -+ rk818_bat_init_rsoc(di); -+ rk818_bat_init_coulomb_cap(di, di->nac); -+ rk818_bat_init_age_algorithm(di); -+ rk818_bat_init_chrg_config(di); -+ rk818_bat_set_shtd_vol(di); -+ rk818_bat_init_zero_table(di); -+ rk818_bat_init_caltimer(di); -+ rk818_bat_init_dsoc_algorithm(di); -+ -+ di->voltage_avg = rk818_bat_get_avg_voltage(di); -+ di->voltage_ocv = rk818_bat_get_ocv_voltage(di); -+ di->voltage_relax = rk818_bat_get_relax_voltage(di); -+ di->current_avg = rk818_bat_get_avg_current(di); -+ di->remain_cap = rk818_bat_get_coulomb_cap(di); -+ di->dbg_pwr_dsoc = di->dsoc; -+ di->dbg_pwr_rsoc = di->rsoc; -+ di->dbg_pwr_vol = di->voltage_avg; -+ -+ rk818_bat_dump_regs(di, 0x99, 0xee); -+ DBG("nac=%d cap=%d ov=%d v=%d rv=%d dl=%d rl=%d c=%d\n", -+ di->nac, di->remain_cap, di->voltage_ocv, di->voltage_avg, -+ di->voltage_relax, di->dsoc, di->rsoc, di->current_avg); -+} -+ -+#ifdef CONFIG_OF -+static int rk818_bat_parse_dt(struct rk818_battery *di) -+{ -+ u32 out_value; -+ int length, ret; -+ size_t size; -+ struct device_node *np = di->dev->of_node; -+ struct battery_platform_data *pdata; -+ struct device *dev = di->dev; -+ -+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); -+ if (!pdata) -+ return -ENOMEM; -+ -+ di->pdata = pdata; -+ /* init default param */ -+ pdata->bat_res = DEFAULT_BAT_RES; -+ pdata->monitor_sec = DEFAULT_MONITOR_SEC; -+ pdata->pwroff_vol = DEFAULT_PWROFF_VOL_THRESD; -+ pdata->sleep_exit_current = DEFAULT_SLP_EXIT_CUR; -+ pdata->sleep_enter_current = DEFAULT_SLP_ENTER_CUR; -+ pdata->bat_mode = MODE_BATTARY; -+ pdata->max_soc_offset = DEFAULT_MAX_SOC_OFFSET; -+ pdata->sample_res = DEFAULT_SAMPLE_RES; -+ pdata->energy_mode = DEFAULT_ENERGY_MODE; -+ pdata->fb_temp = DEFAULT_FB_TEMP; -+ pdata->zero_reserve_dsoc = DEFAULT_ZERO_RESERVE_DSOC; -+ -+ /* parse necessary param */ -+ if (!of_find_property(np, "ocv_table", &length)) { -+ dev_err(dev, "ocv_table not found!\n"); -+ return -EINVAL; -+ } -+ -+ pdata->ocv_size = length / sizeof(u32); -+ if (pdata->ocv_size <= 0) { -+ dev_err(dev, "invalid ocv table\n"); -+ return -EINVAL; -+ } -+ -+ size = sizeof(*pdata->ocv_table) * pdata->ocv_size; -+ pdata->ocv_table = devm_kzalloc(di->dev, size, GFP_KERNEL); -+ if (!pdata->ocv_table) -+ return -ENOMEM; -+ -+ ret = of_property_read_u32_array(np, "ocv_table", -+ pdata->ocv_table, -+ pdata->ocv_size); -+ if (ret < 0) -+ return ret; -+ -+ ret = of_property_read_u32(np, "design_capacity", &out_value); -+ if (ret < 0) { -+ dev_err(dev, "design_capacity not found!\n"); -+ return ret; -+ } -+ pdata->design_capacity = out_value; -+ -+ ret = of_property_read_u32(np, "design_qmax", &out_value); -+ if (ret < 0) { -+ dev_err(dev, "design_qmax not found!\n"); -+ return ret; -+ } -+ pdata->design_qmax = out_value; -+ ret = of_property_read_u32(np, "max_chrg_voltage", &out_value); -+ if (ret < 0) { -+ dev_err(dev, "max_chrg_voltage missing!\n"); -+ return ret; -+ } -+ pdata->max_chrg_voltage = out_value; -+ if (out_value >= 4300) -+ pdata->zero_algorithm_vol = DEFAULT_ALGR_VOL_THRESD2; -+ else -+ pdata->zero_algorithm_vol = DEFAULT_ALGR_VOL_THRESD1; -+ -+ ret = of_property_read_u32(np, "fb_temperature", &pdata->fb_temp); -+ if (ret < 0) -+ dev_err(dev, "fb_temperature missing!\n"); -+ -+ ret = of_property_read_u32(np, "sample_res", &pdata->sample_res); -+ if (ret < 0) -+ dev_err(dev, "sample_res missing!\n"); -+ -+ ret = of_property_read_u32(np, "energy_mode", &pdata->energy_mode); -+ if (ret < 0) -+ dev_err(dev, "energy_mode missing!\n"); -+ -+ ret = of_property_read_u32(np, "max_soc_offset", -+ &pdata->max_soc_offset); -+ if (ret < 0) -+ dev_err(dev, "max_soc_offset missing!\n"); -+ -+ ret = of_property_read_u32(np, "monitor_sec", &pdata->monitor_sec); -+ if (ret < 0) -+ dev_err(dev, "monitor_sec missing!\n"); -+ -+ ret = of_property_read_u32(np, "zero_algorithm_vol", -+ &pdata->zero_algorithm_vol); -+ if (ret < 0) -+ dev_err(dev, "zero_algorithm_vol missing!\n"); -+ -+ ret = of_property_read_u32(np, "zero_reserve_dsoc", -+ &pdata->zero_reserve_dsoc); -+ -+ ret = of_property_read_u32(np, "virtual_power", &pdata->bat_mode); -+ if (ret < 0) -+ dev_err(dev, "virtual_power missing!\n"); -+ -+ ret = of_property_read_u32(np, "bat_res", &pdata->bat_res); -+ if (ret < 0) -+ dev_err(dev, "bat_res missing!\n"); -+ -+ ret = of_property_read_u32(np, "sleep_enter_current", -+ &pdata->sleep_enter_current); -+ if (ret < 0) -+ dev_err(dev, "sleep_enter_current missing!\n"); -+ -+ ret = of_property_read_u32(np, "sleep_exit_current", -+ &pdata->sleep_exit_current); -+ if (ret < 0) -+ dev_err(dev, "sleep_exit_current missing!\n"); -+ -+ ret = of_property_read_u32(np, "power_off_thresd", &pdata->pwroff_vol); -+ if (ret < 0) -+ dev_err(dev, "power_off_thresd missing!\n"); -+ -+ if (!of_find_property(np, "ntc_table", &length)) { -+ pdata->ntc_size = 0; -+ } else { -+ /* get ntc degree base value */ -+ ret = of_property_read_u32_index(np, "ntc_degree_from", 1, -+ &pdata->ntc_degree_from); -+ if (ret) { -+ dev_err(dev, "invalid ntc_degree_from\n"); -+ return -EINVAL; -+ } -+ -+ of_property_read_u32_index(np, "ntc_degree_from", 0, -+ &out_value); -+ if (out_value) -+ pdata->ntc_degree_from = -pdata->ntc_degree_from; -+ -+ pdata->ntc_size = length / sizeof(u32); -+ } -+ -+ if (pdata->ntc_size) { -+ size = sizeof(*pdata->ntc_table) * pdata->ntc_size; -+ pdata->ntc_table = devm_kzalloc(di->dev, size, GFP_KERNEL); -+ if (!pdata->ntc_table) -+ return -ENOMEM; -+ -+ ret = of_property_read_u32_array(np, "ntc_table", -+ pdata->ntc_table, -+ pdata->ntc_size); -+ if (ret < 0) -+ return ret; -+ } -+ -+ DBG("the battery dts info dump:\n" -+ "bat_res:%d\n" -+ "design_capacity:%d\n" -+ "design_qmax :%d\n" -+ "sleep_enter_current:%d\n" -+ "sleep_exit_current:%d\n" -+ "zero_algorithm_vol:%d\n" -+ "zero_reserve_dsoc:%d\n" -+ "monitor_sec:%d\n" -+ "max_soc_offset:%d\n" -+ "virtual_power:%d\n" -+ "pwroff_vol:%d\n" -+ "sample_res:%d\n" -+ "ntc_size=%d\n" -+ "ntc_degree_from:%d\n" -+ "ntc_degree_to:%d\n", -+ pdata->bat_res, pdata->design_capacity, pdata->design_qmax, -+ pdata->sleep_enter_current, pdata->sleep_exit_current, -+ pdata->zero_algorithm_vol, pdata->zero_reserve_dsoc, -+ pdata->monitor_sec, -+ pdata->max_soc_offset, pdata->bat_mode, pdata->pwroff_vol, -+ pdata->sample_res, pdata->ntc_size, pdata->ntc_degree_from, -+ pdata->ntc_degree_from + pdata->ntc_size - 1 -+ ); -+ -+ return 0; -+} -+#else -+static int rk818_bat_parse_dt(struct rk818_battery *di) -+{ -+ return -ENODEV; -+} -+#endif -+ -+static const struct of_device_id rk818_battery_of_match[] = { -+ {.compatible = "rk818-battery",}, -+ { }, -+}; -+ -+static int rk818_battery_probe(struct platform_device *pdev) -+{ -+ const struct of_device_id *of_id = -+ of_match_device(rk818_battery_of_match, &pdev->dev); -+ struct rk818_battery *di; -+ struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent); -+ int ret; -+ -+ if (!of_id) { -+ dev_err(&pdev->dev, "Failed to find matching dt id\n"); -+ return -ENODEV; -+ } -+ -+ di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); -+ if (!di) -+ return -ENOMEM; -+ -+ di->rk818 = rk818; -+ di->pdev = pdev; -+ di->dev = &pdev->dev; -+ di->regmap = rk818->regmap; -+ platform_set_drvdata(pdev, di); -+ -+ ret = rk818_bat_parse_dt(di); -+ if (ret < 0) { -+ dev_err(di->dev, "rk818 battery parse dt failed!\n"); -+ return ret; -+ } -+ -+ if (!is_rk818_bat_exist(di)) { -+ di->pdata->bat_mode = MODE_VIRTUAL; -+ dev_err(di->dev, "no battery, virtual power mode\n"); -+ } -+ -+ ret = rk818_bat_init_irqs(di); -+ if (ret != 0) { -+ dev_err(di->dev, "rk818 bat init irqs failed!\n"); -+ return ret; -+ } -+ -+ ret = rk818_bat_init_power_supply(di); -+ if (ret) { -+ dev_err(di->dev, "rk818 power supply register failed!\n"); -+ return ret; -+ } -+ -+ rk818_bat_init_info(di); -+ rk818_bat_init_fg(di); -+ rk818_bat_init_sysfs(di); -+ rk818_bat_register_fb_notify(di); -+ //wake_lock_init(&di->wake_lock, WAKE_LOCK_SUSPEND, "rk818_bat_lock"); -+ di->bat_monitor_wq = alloc_ordered_workqueue("%s", -+ WQ_MEM_RECLAIM | WQ_FREEZABLE, "rk818-bat-monitor-wq"); -+ INIT_DELAYED_WORK(&di->bat_delay_work, rk818_battery_work); -+ queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work, -+ msecs_to_jiffies(TIMER_MS_COUNTS * 5)); -+ -+ BAT_INFO("driver version %s\n", DRIVER_VERSION); -+ -+ return ret; -+} -+ -+static int rk818_battery_suspend(struct platform_device *dev, -+ pm_message_t state) -+{ -+ struct rk818_battery *di = platform_get_drvdata(dev); -+ u8 val, st; -+ -+ cancel_delayed_work_sync(&di->bat_delay_work); -+ -+ di->s2r = false; -+ di->sleep_chrg_online = rk818_bat_chrg_online(di); -+ di->sleep_chrg_status = rk818_bat_get_chrg_status(di); -+ di->current_avg = rk818_bat_get_avg_current(di); -+ di->remain_cap = rk818_bat_get_coulomb_cap(di); -+ di->rsoc = rk818_bat_get_rsoc(di); -+ di->rtc_base = rk818_get_rtc_sec(); -+ rk818_bat_save_data(di); -+ st = (rk818_bat_read(di, RK818_SUP_STS_REG) & CHRG_STATUS_MSK) >> 4; -+ -+ /* if not CHARGE_FINISH, reinit finish_base. -+ * avoid sleep loop between suspend and resume -+ */ -+ if (di->sleep_chrg_status != CHARGE_FINISH) -+ di->finish_base = get_boot_sec(); -+ -+ /* avoid: enter suspend from MODE_ZERO: load from heavy to light */ -+ if ((di->work_mode == MODE_ZERO) && -+ (di->sleep_chrg_online) && (di->current_avg >= 0)) { -+ DBG("suspend: MODE_ZERO exit...\n"); -+ /* it need't do prepare for mode finish and smooth, it will -+ * be done in display_smooth -+ */ -+ if (di->sleep_chrg_status == CHARGE_FINISH) { -+ di->work_mode = MODE_FINISH; -+ di->finish_base = get_boot_sec(); -+ } else { -+ di->work_mode = MODE_SMOOTH; -+ rk818_bat_smooth_algo_prepare(di); -+ } -+ } -+ -+ /* set vbat low than 3.4v to generate a wakeup irq */ -+ val = rk818_bat_read(di, RK818_VB_MON_REG); -+ val &= (~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK)); -+ val |= (RK818_VBAT_LOW_3V4 | EN_VBAT_LOW_IRQ); -+ rk818_bat_write(di, RK818_VB_MON_REG, val); -+ rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, VB_LOW_INT_EN, 0); -+ -+ BAT_INFO("suspend: dl=%d rl=%d c=%d v=%d cap=%d at=%ld ch=%d st=%s\n", -+ di->dsoc, di->rsoc, di->current_avg, -+ rk818_bat_get_avg_voltage(di), rk818_bat_get_coulomb_cap(di), -+ di->sleep_dischrg_sec, di->sleep_chrg_online, bat_status[st]); -+ -+ return 0; -+} -+ -+static int rk818_battery_resume(struct platform_device *dev) -+{ -+ struct rk818_battery *di = platform_get_drvdata(dev); -+ int interval_sec, time_step, pwroff_vol; -+ u8 val, st; -+ -+ di->s2r = true; -+ di->current_avg = rk818_bat_get_avg_current(di); -+ di->voltage_relax = rk818_bat_get_relax_voltage(di); -+ di->voltage_avg = rk818_bat_get_avg_voltage(di); -+ di->remain_cap = rk818_bat_get_coulomb_cap(di); -+ di->rsoc = rk818_bat_get_rsoc(di); -+ interval_sec = rk818_bat_rtc_sleep_sec(di); -+ di->sleep_sum_sec += interval_sec; -+ pwroff_vol = di->pdata->pwroff_vol; -+ st = (rk818_bat_read(di, RK818_SUP_STS_REG) & CHRG_STATUS_MSK) >> 4; -+ -+ if (!di->sleep_chrg_online) { -+ /* only add up discharge sleep seconds */ -+ di->sleep_dischrg_sec += interval_sec; -+ if (di->voltage_avg <= pwroff_vol + 50) -+ time_step = DISCHRG_TIME_STEP1; -+ else -+ time_step = DISCHRG_TIME_STEP2; -+ } -+ -+ BAT_INFO("resume: dl=%d rl=%d c=%d v=%d rv=%d " -+ "cap=%d dt=%d at=%ld ch=%d st=%s\n", -+ di->dsoc, di->rsoc, di->current_avg, di->voltage_avg, -+ di->voltage_relax, rk818_bat_get_coulomb_cap(di), interval_sec, -+ di->sleep_dischrg_sec, di->sleep_chrg_online, bat_status[st]); -+ -+ /* sleep: enough time and discharge */ -+ if ((di->sleep_dischrg_sec > time_step) && (!di->sleep_chrg_online)) { -+ if (rk818_bat_sleep_dischrg(di)) -+ di->sleep_dischrg_sec = 0; -+ } -+ -+ rk818_bat_save_data(di); -+ -+ /* set vbat lowest 3.0v shutdown */ -+ val = rk818_bat_read(di, RK818_VB_MON_REG); -+ val &= ~(VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK); -+ val |= (RK818_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN); -+ rk818_bat_write(di, RK818_VB_MON_REG, val); -+ rk818_bat_set_bits(di, RK818_INT_STS_MSK_REG1, -+ VB_LOW_INT_EN, VB_LOW_INT_EN); -+ -+ /* charge/lowpower lock: for battery work to update dsoc and rsoc */ -+ // if ((di->sleep_chrg_online) || -+ // (!di->sleep_chrg_online && di->voltage_avg < di->pdata->pwroff_vol)) -+ // wake_lock_timeout(&di->wake_lock, msecs_to_jiffies(2000)); -+ -+ queue_delayed_work(di->bat_monitor_wq, &di->bat_delay_work, -+ msecs_to_jiffies(1000)); -+ -+ return 0; -+} -+ -+static void rk818_battery_shutdown(struct platform_device *dev) -+{ -+ u8 cnt = 0; -+ struct rk818_battery *di = platform_get_drvdata(dev); -+ -+ cancel_delayed_work_sync(&di->bat_delay_work); -+ cancel_delayed_work_sync(&di->calib_delay_work); -+ rk818_bat_unregister_fb_notify(di); -+ del_timer(&di->caltimer); -+ if (base2sec(di->boot_base) < REBOOT_PERIOD_SEC) -+ cnt = rk818_bat_check_reboot(di); -+ else -+ rk818_bat_save_reboot_cnt(di, 0); -+ -+ BAT_INFO("shutdown: dl=%d rl=%d c=%d v=%d cap=%d f=%d ch=%d n=%d " -+ "mode=%d rest=%d\n", -+ di->dsoc, di->rsoc, di->current_avg, di->voltage_avg, -+ di->remain_cap, di->fcc, rk818_bat_chrg_online(di), cnt, -+ di->algo_rest_mode, di->algo_rest_val); -+} -+ -+static struct platform_driver rk818_battery_driver = { -+ .probe = rk818_battery_probe, -+ .suspend = rk818_battery_suspend, -+ .resume = rk818_battery_resume, -+ .shutdown = rk818_battery_shutdown, -+ .driver = { -+ .name = "rk818-battery", -+ .of_match_table = rk818_battery_of_match, -+ }, -+}; -+ -+static int __init battery_init(void) -+{ -+ return platform_driver_register(&rk818_battery_driver); -+} -+fs_initcall_sync(battery_init); -+ -+static void __exit battery_exit(void) -+{ -+ platform_driver_unregister(&rk818_battery_driver); -+} -+module_exit(battery_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:rk818-battery"); -+MODULE_AUTHOR("chenjh"); -\ No newline at end of file -diff --git a/drivers/power/supply/rk818_battery.h b/drivers/power/supply/rk818_battery.h -new file mode 100644 -index 00000000..2f4430a ---- /dev/null -+++ b/drivers/power/supply/rk818_battery.h -@@ -0,0 +1,168 @@ -+/* -+ * rk818_battery.h: fuel gauge driver structures -+ * -+ * Copyright (C) 2016 Rockchip Electronics Co., Ltd -+ * Author: chenjh -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms and conditions of the GNU General Public License, -+ * version 2, as published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope it will be useful, but WITHOUT -+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -+ * more details. -+ */ -+ -+#ifndef RK818_BATTERY -+#define RK818_BATTERY -+ -+/* RK818_INT_STS_MSK_REG2 */ -+#define PLUG_IN_MSK BIT(0) -+#define PLUG_OUT_MSK BIT(1) -+#define CHRG_CVTLMT_INT_MSK BIT(6) -+ -+/* RK818_TS_CTRL_REG */ -+#define GG_EN BIT(7) -+#define ADC_CUR_EN BIT(6) -+#define ADC_TS1_EN BIT(5) -+#define ADC_TS2_EN BIT(4) -+#define TS1_CUR_MSK 0x03 -+ -+/* RK818_GGCON */ -+#define OCV_SAMP_MIN_MSK 0x0c -+#define OCV_SAMP_8MIN (0x00 << 2) -+ -+#define ADC_CAL_MIN_MSK 0x30 -+#define ADC_CAL_8MIN (0x00 << 4) -+#define ADC_CUR_MODE BIT(1) -+ -+/* RK818_GGSTS */ -+#define BAT_CON BIT(4) -+#define RELAX_VOL1_UPD BIT(3) -+#define RELAX_VOL2_UPD BIT(2) -+#define RELAX_VOL12_UPD_MSK (RELAX_VOL1_UPD | RELAX_VOL2_UPD) -+ -+/* RK818_SUP_STS_REG */ -+#define CHRG_STATUS_MSK 0x70 -+#define BAT_EXS BIT(7) -+#define CHARGE_OFF (0x0 << 4) -+#define DEAD_CHARGE (0x1 << 4) -+#define TRICKLE_CHARGE (0x2 << 4) -+#define CC_OR_CV (0x3 << 4) -+#define CHARGE_FINISH (0x4 << 4) -+#define USB_OVER_VOL (0x5 << 4) -+#define BAT_TMP_ERR (0x6 << 4) -+#define TIMER_ERR (0x7 << 4) -+#define USB_VLIMIT_EN BIT(3) -+#define USB_CLIMIT_EN BIT(2) -+#define USB_EXIST BIT(1) -+#define USB_EFF BIT(0) -+ -+/* RK818_USB_CTRL_REG */ -+#define CHRG_CT_EN BIT(7) -+#define FINISH_CUR_MSK 0xc0 -+#define TEMP_105C (0x02 << 2) -+#define FINISH_100MA (0x00 << 6) -+#define FINISH_150MA (0x01 << 6) -+#define FINISH_200MA (0x02 << 6) -+#define FINISH_250MA (0x03 << 6) -+ -+/* RK818_CHRG_CTRL_REG3 */ -+#define CHRG_TERM_MODE_MSK BIT(5) -+#define CHRG_TERM_ANA_SIGNAL (0 << 5) -+#define CHRG_TERM_DIG_SIGNAL BIT(5) -+#define CHRG_TIMER_CCCV_EN BIT(2) -+#define CHRG_EN BIT(7) -+ -+/* RK818_VB_MON_REG */ -+#define RK818_VBAT_LOW_3V0 0x02 -+#define RK818_VBAT_LOW_3V4 0x06 -+#define PLUG_IN_STS BIT(6) -+ -+/* RK818_THERMAL_REG */ -+#define FB_TEMP_MSK 0x0c -+#define HOTDIE_STS BIT(1) -+ -+/* RK818_INT_STS_MSK_REG1 */ -+#define VB_LOW_INT_EN BIT(1) -+ -+/* RK818_MISC_MARK_REG */ -+#define FG_INIT BIT(5) -+#define FG_RESET_LATE BIT(4) -+#define FG_RESET_NOW BIT(3) -+#define ALGO_REST_MODE_MSK (0xc0) -+#define ALGO_REST_MODE_SHIFT 6 -+ -+/* bit shift */ -+#define FB_TEMP_SHIFT 2 -+ -+/* parse ocv table param */ -+#define TIMER_MS_COUNTS 1000 -+#define MAX_PERCENTAGE 100 -+#define MAX_INTERPOLATE 1000 -+#define MAX_INT 0x7FFF -+ -+#define DRIVER_VERSION "7.1" -+ -+struct battery_platform_data { -+ u32 *ocv_table; -+ u32 *zero_table; -+ u32 *ntc_table; -+ u32 ocv_size; -+ u32 max_chrg_voltage; -+ u32 ntc_size; -+ int ntc_degree_from; -+ u32 pwroff_vol; -+ u32 monitor_sec; -+ u32 zero_algorithm_vol; -+ u32 zero_reserve_dsoc; -+ u32 bat_res; -+ u32 design_capacity; -+ u32 design_qmax; -+ u32 sleep_enter_current; -+ u32 sleep_exit_current; -+ u32 max_soc_offset; -+ u32 sample_res; -+ u32 bat_mode; -+ u32 fb_temp; -+ u32 energy_mode; -+ u32 cccv_hour; -+ u32 ntc_uA; -+ u32 ntc_factor; -+}; -+ -+enum work_mode { -+ MODE_ZERO = 0, -+ MODE_FINISH, -+ MODE_SMOOTH_CHRG, -+ MODE_SMOOTH_DISCHRG, -+ MODE_SMOOTH, -+}; -+ -+enum bat_mode { -+ MODE_BATTARY = 0, -+ MODE_VIRTUAL, -+}; -+ -+static const u16 feedback_temp_array[] = { -+ 85, 95, 105, 115 -+}; -+ -+static const u16 chrg_vol_sel_array[] = { -+ 4050, 4100, 4150, 4200, 4250, 4300, 4350 -+}; -+ -+static const u16 chrg_cur_sel_array[] = { -+ 1000, 1200, 1400, 1600, 1800, 2000, 2250, 2400, 2600, 2800, 3000 -+}; -+ -+static const u16 chrg_cur_input_array[] = { -+ 450, 80, 850, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000 -+}; -+ -+void kernel_power_off(void); -+int rk818_bat_temp_notifier_register(struct notifier_block *nb); -+int rk818_bat_temp_notifier_unregister(struct notifier_block *nb); -+ -+#endif -\ No newline at end of file -diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h -index 2ec0520..5e33996 100644 ---- a/include/linux/mfd/rk808.h -+++ b/include/linux/mfd/rk808.h -@@ -138,6 +138,8 @@ enum rk818_reg { - RK818_ID_OTG_SWITCH, - }; - -+#define RK818_VB_MON_REG 0x21 -+#define RK818_THERMAL_REG 0x22 - #define RK818_DCDC_EN_REG 0x23 - #define RK818_LDO_EN_REG 0x24 - #define RK818_SLEEP_SET_OFF_REG1 0x25 -@@ -184,13 +186,90 @@ enum rk818_reg { - #define RK818_INT_STS_REG2 0x4e - #define RK818_INT_STS_MSK_REG2 0x4f - #define RK818_IO_POL_REG 0x50 -+#define RK818_OTP_VDD_EN_REG 0x51 - #define RK818_H5V_EN_REG 0x52 - #define RK818_SLEEP_SET_OFF_REG3 0x53 - #define RK818_BOOST_LDO9_ON_VSEL_REG 0x54 - #define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55 - #define RK818_BOOST_CTRL_REG 0x56 --#define RK818_DCDC_ILMAX 0x90 -+#define RK818_DCDC_ILMAX_REG 0x90 -+#define RK818_CHRG_COMP_REG 0x9a -+#define RK818_SUP_STS_REG 0xa0 - #define RK818_USB_CTRL_REG 0xa1 -+#define RK818_CHRG_CTRL_REG1 0xa3 -+#define RK818_CHRG_CTRL_REG2 0xa4 -+#define RK818_CHRG_CTRL_REG3 0xa5 -+#define RK818_BAT_CTRL_REG 0xa6 -+#define RK818_BAT_HTS_TS1_REG 0xa8 -+#define RK818_BAT_LTS_TS1_REG 0xa9 -+#define RK818_BAT_HTS_TS2_REG 0xaa -+#define RK818_BAT_LTS_TS2_REG 0xab -+#define RK818_TS_CTRL_REG 0xac -+#define RK818_ADC_CTRL_REG 0xad -+#define RK818_ON_SOURCE_REG 0xae -+#define RK818_OFF_SOURCE_REG 0xaf -+#define RK818_GGCON_REG 0xb0 -+#define RK818_GGSTS_REG 0xb1 -+#define RK818_FRAME_SMP_INTERV_REG 0xb2 -+#define RK818_AUTO_SLP_CUR_THR_REG 0xb3 -+#define RK818_GASCNT_CAL_REG3 0xb4 -+#define RK818_GASCNT_CAL_REG2 0xb5 -+#define RK818_GASCNT_CAL_REG1 0xb6 -+#define RK818_GASCNT_CAL_REG0 0xb7 -+#define RK818_GASCNT3_REG 0xb8 -+#define RK818_GASCNT2_REG 0xb9 -+#define RK818_GASCNT1_REG 0xba -+#define RK818_GASCNT0_REG 0xbb -+#define RK818_BAT_CUR_AVG_REGH 0xbc -+#define RK818_BAT_CUR_AVG_REGL 0xbd -+#define RK818_TS1_ADC_REGH 0xbe -+#define RK818_TS1_ADC_REGL 0xbf -+#define RK818_TS2_ADC_REGH 0xc0 -+#define RK818_TS2_ADC_REGL 0xc1 -+#define RK818_BAT_OCV_REGH 0xc2 -+#define RK818_BAT_OCV_REGL 0xc3 -+#define RK818_BAT_VOL_REGH 0xc4 -+#define RK818_BAT_VOL_REGL 0xc5 -+#define RK818_RELAX_ENTRY_THRES_REGH 0xc6 -+#define RK818_RELAX_ENTRY_THRES_REGL 0xc7 -+#define RK818_RELAX_EXIT_THRES_REGH 0xc8 -+#define RK818_RELAX_EXIT_THRES_REGL 0xc9 -+#define RK818_RELAX_VOL1_REGH 0xca -+#define RK818_RELAX_VOL1_REGL 0xcb -+#define RK818_RELAX_VOL2_REGH 0xcc -+#define RK818_RELAX_VOL2_REGL 0xcd -+#define RK818_BAT_CUR_R_CALC_REGH 0xce -+#define RK818_BAT_CUR_R_CALC_REGL 0xcf -+#define RK818_BAT_VOL_R_CALC_REGH 0xd0 -+#define RK818_BAT_VOL_R_CALC_REGL 0xd1 -+#define RK818_CAL_OFFSET_REGH 0xd2 -+#define RK818_CAL_OFFSET_REGL 0xd3 -+#define RK818_NON_ACT_TIMER_CNT_REG 0xd4 -+#define RK818_VCALIB0_REGH 0xd5 -+#define RK818_VCALIB0_REGL 0xd6 -+#define RK818_VCALIB1_REGH 0xd7 -+#define RK818_VCALIB1_REGL 0xd8 -+#define RK818_IOFFSET_REGH 0xdd -+#define RK818_IOFFSET_REGL 0xde -+#define RK818_SOC_REG 0xe0 -+#define RK818_REMAIN_CAP_REG3 0xe1 -+#define RK818_REMAIN_CAP_REG2 0xe2 -+#define RK818_REMAIN_CAP_REG1 0xe3 -+#define RK818_REMAIN_CAP_REG0 0xe4 -+#define RK818_UPDAT_LEVE_REG 0xe5 -+#define RK818_NEW_FCC_REG3 0xe6 -+#define RK818_NEW_FCC_REG2 0xe7 -+#define RK818_NEW_FCC_REG1 0xe8 -+#define RK818_NEW_FCC_REG0 0xe9 -+#define RK818_NON_ACT_TIMER_CNT_SAVE_REG 0xea -+#define RK818_OCV_VOL_VALID_REG 0xeb -+#define RK818_REBOOT_CNT_REG 0xec -+#define RK818_POFFSET_REG 0xed -+#define RK818_MISC_MARK_REG 0xee -+#define RK818_HALT_CNT_REG 0xef -+#define RK818_CALC_REST_REGH 0xf0 -+#define RK818_CALC_REST_REGL 0xf1 -+#define RK818_SAVE_DATA19 0xf2 - - #define RK818_H5V_EN BIT(0) - #define RK818_REF_RDY_CTRL BIT(1) diff --git a/sys-kernel/pinephone-sources/files/0013-power-supply-rk818-battery-Use-a-more-propper-compat.patch b/sys-kernel/pinephone-sources/files/0013-power-supply-rk818-battery-Use-a-more-propper-compat.patch deleted file mode 100644 index fd97202..0000000 --- a/sys-kernel/pinephone-sources/files/0013-power-supply-rk818-battery-Use-a-more-propper-compat.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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"); -\ No newline at end of file -+MODULE_AUTHOR("chenjh"); diff --git a/sys-kernel/pinephone-sources/files/0014-power-supply-core-Don-t-ignore-max_current-of-0-when.patch b/sys-kernel/pinephone-sources/files/0014-power-supply-core-Don-t-ignore-max_current-of-0-when.patch deleted file mode 100644 index ce6a96f..0000000 --- a/sys-kernel/pinephone-sources/files/0014-power-supply-core-Don-t-ignore-max_current-of-0-when.patch +++ /dev/null @@ -1,85 +0,0 @@ -From: Ondrej Jirman -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 ---- - drivers/power/supply/power_supply_core.c | 47 ++++++++++++++------------------ - 1 file changed, 20 insertions(+), 27 deletions(-) - -diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c -index fc12a4f..f681372 100644 ---- a/drivers/power/supply/power_supply_core.c -+++ b/drivers/power/supply/power_supply_core.c -@@ -375,41 +375,34 @@ int power_supply_is_system_supplied(void) - } - EXPORT_SYMBOL_GPL(power_supply_is_system_supplied); - --static int __power_supply_get_supplier_max_current(struct device *dev, -- void *data) --{ -- union power_supply_propval ret = {0,}; -- struct power_supply *epsy = dev_get_drvdata(dev); -- struct power_supply *psy = data; -- -- if (__power_supply_is_supplied_by(epsy, psy)) -- if (!epsy->desc->get_property(epsy, -- POWER_SUPPLY_PROP_CURRENT_MAX, -- &ret)) -- return ret.intval; -- -- return 0; --} -- - int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy) - { - union power_supply_propval val = {0,}; -- int curr; -+ struct class_dev_iter iter; -+ struct power_supply *epsy; -+ struct device *dev; -+ int ret; - - if (!psy->desc->set_property) - return -EINVAL; - -- /* -- * This function is not intended for use with a supply with multiple -- * suppliers, we simply pick the first supply to report a non 0 -- * max-current. -- */ -- curr = class_for_each_device(power_supply_class, NULL, psy, -- __power_supply_get_supplier_max_current); -- if (curr <= 0) -- return (curr == 0) ? -ENODEV : curr; -+ class_dev_iter_init(&iter, power_supply_class, NULL, NULL); -+ while ((dev = class_dev_iter_next(&iter))) { -+ epsy = dev_get_drvdata(dev); -+ -+ if (!__power_supply_is_supplied_by(epsy, psy)) -+ continue; - -- val.intval = curr; -+ ret = epsy->desc->get_property(epsy, -+ POWER_SUPPLY_PROP_CURRENT_MAX, -+ &val); -+ if (!ret) -+ break; -+ } -+ class_dev_iter_exit(&iter); -+ -+ if (ret) -+ return ret; - - return psy->desc->set_property(psy, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); diff --git a/sys-kernel/pinephone-sources/files/0015-power-supply-rk818-charger-Implement-charger-driver-.patch b/sys-kernel/pinephone-sources/files/0015-power-supply-rk818-charger-Implement-charger-driver-.patch deleted file mode 100644 index 37ea4fc..0000000 --- a/sys-kernel/pinephone-sources/files/0015-power-supply-rk818-charger-Implement-charger-driver-.patch +++ /dev/null @@ -1,699 +0,0 @@ -From: Ondrej Jirman -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 ---- - drivers/mfd/rk808.c | 1 + - drivers/power/supply/Kconfig | 8 + - drivers/power/supply/Makefile | 1 + - drivers/power/supply/rk818_charger.c | 637 +++++++++++++++++++++++++++++++++++ - 4 files changed, 647 insertions(+) - create mode 100644 drivers/power/supply/rk818_charger.c - -diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c -index a99fec0..75d18de 100644 ---- a/drivers/mfd/rk808.c -+++ b/drivers/mfd/rk808.c -@@ -206,6 +206,7 @@ static const struct mfd_cell rk818s[] = { - { .name = "rk808-clkout", }, - { .name = "rk808-regulator", }, - { .name = "rk818-battery", .of_compatible = "rockchip,rk818-battery", }, -+ { .name = "rk818-charger", .of_compatible = "rockchip,rk818-charger", }, - { - .name = "rk808-rtc", - .num_resources = ARRAY_SIZE(rtc_resources), -diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig -index f5d4434..6bf0834 100644 ---- a/drivers/power/supply/Kconfig -+++ b/drivers/power/supply/Kconfig -@@ -862,4 +862,12 @@ config BATTERY_RK818 - If you say yes here you will get support for the battery of RK818 PMIC. - This driver can give support for Rk818 Battery Charge Interface. - -+config CHARGER_RK818 -+ bool "RK818 Charger driver" -+ depends on MFD_RK808 -+ default n -+ help -+ If you say yes here you will get support for the charger of RK818 PMIC. -+ This driver can give support for Rk818 Charger Interface. -+ - endif # POWER_SUPPLY -diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile -index 1c725ee..3a1526f 100644 ---- a/drivers/power/supply/Makefile -+++ b/drivers/power/supply/Makefile -@@ -105,3 +105,4 @@ obj-$(CONFIG_BATTERY_ACER_A500) += acer_a500_battery.o - obj-$(CONFIG_BATTERY_SURFACE) += surface_battery.o - obj-$(CONFIG_CHARGER_SURFACE) += surface_charger.o - obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o -+obj-$(CONFIG_CHARGER_RK818) += rk818_charger.o -diff --git a/drivers/power/supply/rk818_charger.c b/drivers/power/supply/rk818_charger.c -new file mode 100644 -index 00000000..7b67a0b ---- /dev/null -+++ b/drivers/power/supply/rk818_charger.c -@@ -0,0 +1,637 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * rk818 usb power driver -+ * -+ * Copyright (c) 2021 Ondřej Jirman -+ */ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ 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, ®); -+ if (ret) -+ return ret; -+ -+ switch (reg & RK818_CHG_STS_MASK) { -+ case RK818_CHG_STS_USB_OV: -+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; -+ break; -+ case RK818_CHG_STS_BAT_TEMP_FAULT: -+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; -+ break; -+ case RK818_CHG_STS_TIMEOUT: -+ val->intval = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; -+ break; -+ default: -+ val->intval = POWER_SUPPLY_HEALTH_GOOD; -+ break; -+ } -+ -+ break; -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: -+ return rk818_charger_get_voltage_max(cg, &val->intval); -+ -+ case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: -+ ret = rk818_charger_get_current_max(cg, &val->intval); -+ val->intval /= 10; -+ return ret; -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: -+ return rk818_charger_get_current_max(cg, &val->intval); -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: -+ val->intval = 4350000; -+ break; -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: -+ val->intval = 3000000; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int rk818_charger_set_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ const union power_supply_propval *val) -+{ -+ struct rk818_charger *cg = power_supply_get_drvdata(psy); -+ int ret; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG1, -+ RK818_CHRG_CTRL_REG1_CHRG_EN, -+ val->intval ? RK818_CHRG_CTRL_REG1_CHRG_EN : 0); -+ if (ret) -+ dev_err(cg->dev, "failed to setup the charger (%d)\n", ret); -+ -+ return ret; -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: -+ return rk818_charger_set_voltage_max(cg, val->intval); -+ -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: -+ return rk818_charger_set_current_max(cg, val->intval); -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+static int rk818_charger_prop_writeable(struct power_supply *psy, -+ enum power_supply_property psp) -+{ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: -+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: -+ case POWER_SUPPLY_PROP_ONLINE: -+ return 1; -+ -+ default: -+ return 0; -+ } -+} -+ -+static enum power_supply_property rk818_charger_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_CHARGE_TYPE, -+ POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, -+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, -+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, -+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, -+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, -+ POWER_SUPPLY_PROP_PRECHARGE_CURRENT, -+}; -+ -+/* -+ * TODO: This functionality should be in a battery driver/supply, but that one -+ * is such a mess, I don't want to touch it now. Let's have a separate supply -+ * for controlling the charger for now, and a prayer for the poor soul that -+ * will have to understand and clean up the battery driver. -+ */ -+static const struct power_supply_desc rk818_charger_desc = { -+ .name = "rk818-charger", -+ .type = POWER_SUPPLY_TYPE_BATTERY, -+ .properties = rk818_charger_props, -+ .num_properties = ARRAY_SIZE(rk818_charger_props), -+ .property_is_writeable = rk818_charger_prop_writeable, -+ .get_property = rk818_charger_get_property, -+ .set_property = rk818_charger_set_property, -+}; -+ -+// }}} -+ -+static int rk818_charger_probe(struct platform_device *pdev) -+{ -+ struct rk808 *rk818 = dev_get_drvdata(pdev->dev.parent); -+ struct power_supply_config psy_cfg = { }; -+ struct device *dev = &pdev->dev; -+ struct rk818_charger *cg; -+ int ret; -+ -+ cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL); -+ if (!cg) -+ return -ENOMEM; -+ -+ cg->rk818 = rk818; -+ cg->dev = dev; -+ cg->regmap = rk818->regmap; -+ platform_set_drvdata(pdev, cg); -+ -+ psy_cfg.drv_data = cg; -+ psy_cfg.of_node = dev->of_node; -+ -+ cg->usb_psy = devm_power_supply_register(dev, &rk818_usb_desc, -+ &psy_cfg); -+ if (IS_ERR(cg->usb_psy)) -+ return dev_err_probe(dev, PTR_ERR(cg->usb_psy), -+ "register usb power supply fail\n"); -+ -+ cg->charger_psy = devm_power_supply_register(dev, &rk818_charger_desc, -+ &psy_cfg); -+ if (IS_ERR(cg->charger_psy)) -+ return dev_err_probe(dev, PTR_ERR(cg->charger_psy), -+ "register charger power supply fail\n"); -+ -+ /* disable voltage limit and enable input current limit */ -+ ret = regmap_update_bits(cg->regmap, RK818_SUP_STS_REG, -+ RK818_SUP_STS_USB_ILIM_EN | RK818_SUP_STS_USB_VLIM_EN, -+ RK818_SUP_STS_USB_ILIM_EN); -+ if (ret) -+ dev_warn(cg->dev, "failed to enable input current limit (%d)\n", ret); -+ -+ /* make sure analog control loop is enabled */ -+ ret = regmap_update_bits(cg->regmap, RK818_CHRG_CTRL_REG3, -+ RK818_CHRG_CTRL_REG3_CHRG_TERM_DIGITAL, -+ 0); -+ if (ret) -+ dev_warn(cg->dev, "failed to enable analog control loop (%d)\n", ret); -+ -+ /* enable charger and set some reasonable limits on each boot */ -+ ret = regmap_write(cg->regmap, RK818_CHRG_CTRL_REG1, -+ RK818_CHRG_CTRL_REG1_CHRG_EN -+ | (1) /* 1.2A */ -+ | (5 << 4) /* 4.3V */); -+ if (ret) -+ dev_warn(cg->dev, "failed to enable charger (%d)\n", ret); -+ -+ power_supply_set_input_current_limit_from_supplier(cg->usb_psy); -+ -+ return 0; -+} -+ -+static int rk818_charger_remove(struct platform_device *pdev) -+{ -+ //struct rk818_charger *cg = platform_get_drvdata(pdev); -+ -+ return 0; -+} -+ -+static void rk818_charger_shutdown(struct platform_device *pdev) -+{ -+} -+ -+static int rk818_charger_suspend(struct platform_device *pdev, -+ pm_message_t state) -+{ -+ return 0; -+} -+ -+static int rk818_charger_resume(struct platform_device *pdev) -+{ -+ return 0; -+} -+ -+static const struct of_device_id rk818_charger_of_match[] = { -+ { .compatible = "rockchip,rk818-charger", }, -+ { }, -+}; -+ -+static struct platform_driver rk818_charger_driver = { -+ .probe = rk818_charger_probe, -+ .remove = rk818_charger_remove, -+ .suspend = rk818_charger_suspend, -+ .resume = rk818_charger_resume, -+ .shutdown = rk818_charger_shutdown, -+ .driver = { -+ .name = "rk818-charger", -+ .of_match_table = rk818_charger_of_match, -+ }, -+}; -+ -+module_platform_driver(rk818_charger_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS("platform:rk818-charger"); -+MODULE_AUTHOR("Ondřej Jirman "); diff --git a/sys-kernel/pinephone-sources/files/0016-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch b/sys-kernel/pinephone-sources/files/0016-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch deleted file mode 100644 index f42aed2..0000000 --- a/sys-kernel/pinephone-sources/files/0016-usb-typec-fusb302-Set-the-current-before-enabling-pu.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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: diff --git a/sys-kernel/pinephone-sources/files/0017-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch b/sys-kernel/pinephone-sources/files/0017-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch deleted file mode 100644 index 0ab3229..0000000 --- a/sys-kernel/pinephone-sources/files/0017-usb-typec-fusb302-Extend-debugging-interface-with-dr.patch +++ /dev/null @@ -1,108 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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) diff --git a/sys-kernel/pinephone-sources/files/0018-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch b/sys-kernel/pinephone-sources/files/0018-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch deleted file mode 100644 index 096673e..0000000 --- a/sys-kernel/pinephone-sources/files/0018-usb-typec-fusb302-Retry-reading-of-CC-pins-status-if.patch +++ /dev/null @@ -1,72 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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, ®); -+ 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; - diff --git a/sys-kernel/pinephone-sources/files/0019-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch b/sys-kernel/pinephone-sources/files/0019-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch deleted file mode 100644 index 2cec92e..0000000 --- a/sys-kernel/pinephone-sources/files/0019-usb-typec-fusb302-More-useful-of-logging-status-on-i.patch +++ /dev/null @@ -1,186 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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; diff --git a/sys-kernel/pinephone-sources/files/0020-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch b/sys-kernel/pinephone-sources/files/0020-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch deleted file mode 100644 index 9335999..0000000 --- a/sys-kernel/pinephone-sources/files/0020-usb-typec-fusb302-Update-VBUS-state-even-if-VBUS-int.patch +++ /dev/null @@ -1,39 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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) { diff --git a/sys-kernel/pinephone-sources/files/0021-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch b/sys-kernel/pinephone-sources/files/0021-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch deleted file mode 100644 index 9a880fd..0000000 --- a/sys-kernel/pinephone-sources/files/0021-usb-typec-fusb302-Make-tcpm-fusb302-logs-less-pollut.patch +++ /dev/null @@ -1,160 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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) { diff --git a/sys-kernel/pinephone-sources/files/0022-usb-typec-fusb302-Add-OF-extcon-support.patch b/sys-kernel/pinephone-sources/files/0022-usb-typec-fusb302-Add-OF-extcon-support.patch deleted file mode 100644 index 64f2ffa..0000000 --- a/sys-kernel/pinephone-sources/files/0022-usb-typec-fusb302-Add-OF-extcon-support.patch +++ /dev/null @@ -1,34 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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; - diff --git a/sys-kernel/pinephone-sources/files/0023-usb-typec-fusb302-Fix-register-definitions.patch b/sys-kernel/pinephone-sources/files/0023-usb-typec-fusb302-Fix-register-definitions.patch deleted file mode 100644 index f06e87f..0000000 --- a/sys-kernel/pinephone-sources/files/0023-usb-typec-fusb302-Fix-register-definitions.patch +++ /dev/null @@ -1,45 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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 diff --git a/sys-kernel/pinephone-sources/files/0024-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch b/sys-kernel/pinephone-sources/files/0024-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch deleted file mode 100644 index 5909161..0000000 --- a/sys-kernel/pinephone-sources/files/0024-usb-typec-fusb302-Clear-interrupts-before-we-start-t.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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, ®); -+ if (ret < 0) -+ return ret; -+ - /* unmask TOGDONE interrupt */ - ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA, - FUSB_REG_MASKA_TOGDONE); diff --git a/sys-kernel/pinephone-sources/files/0025-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch b/sys-kernel/pinephone-sources/files/0025-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch deleted file mode 100644 index d8c007c..0000000 --- a/sys-kernel/pinephone-sources/files/0025-usb-typec-typec-extcon-Add-typec-extcon-bridge-drive.patch +++ /dev/null @@ -1,388 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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 -+ * -+ * This driver bridges standard type-c interfaces to drivers that -+ * expect extcon interface. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+MODULE_DESCRIPTION("typec -> extcon bridge driver"); diff --git a/sys-kernel/pinephone-sources/files/0026-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch b/sys-kernel/pinephone-sources/files/0026-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch deleted file mode 100644 index abb3c5c..0000000 --- a/sys-kernel/pinephone-sources/files/0026-phy-rockchip-typec-Make-sure-the-plug-orientation-is.patch +++ /dev/null @@ -1,64 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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); - diff --git a/sys-kernel/pinephone-sources/files/0027-media-i2c-imx258-Add-support-for-powerdown-gpio.patch b/sys-kernel/pinephone-sources/files/0027-media-i2c-imx258-Add-support-for-powerdown-gpio.patch deleted file mode 100644 index 6d20e9e..0000000 --- a/sys-kernel/pinephone-sources/files/0027-media-i2c-imx258-Add-support-for-powerdown-gpio.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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); - diff --git a/sys-kernel/pinephone-sources/files/0028-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch b/sys-kernel/pinephone-sources/files/0028-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch deleted file mode 100644 index ef345ec..0000000 --- a/sys-kernel/pinephone-sources/files/0028-media-i2c-imx258-Don-t-be-too-strict-about-clock-rat.patch +++ /dev/null @@ -1,41 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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; - } - diff --git a/sys-kernel/pinephone-sources/files/0029-media-i2c-imx258-Add-support-for-reset-gpio.patch b/sys-kernel/pinephone-sources/files/0029-media-i2c-imx258-Add-support-for-reset-gpio.patch deleted file mode 100644 index af85962..0000000 --- a/sys-kernel/pinephone-sources/files/0029-media-i2c-imx258-Add-support-for-reset-gpio.patch +++ /dev/null @@ -1,57 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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); - diff --git a/sys-kernel/pinephone-sources/files/0030-media-i2c-imx258-Add-support-for-power-supplies.patch b/sys-kernel/pinephone-sources/files/0030-media-i2c-imx258-Add-support-for-power-supplies.patch deleted file mode 100644 index 23c09d8..0000000 --- a/sys-kernel/pinephone-sources/files/0030-media-i2c-imx258-Add-support-for-power-supplies.patch +++ /dev/null @@ -1,100 +0,0 @@ -From: Ondrej Jirman -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 ---- - 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); diff --git a/sys-kernel/pinephone-sources/files/0031-media-ov5640-Add-more-framerates-to-the-driver-some-.patch b/sys-kernel/pinephone-sources/files/0031-media-ov5640-Add-more-framerates-to-the-driver-some-.patch deleted file mode 100644 index 5f3faf5..0000000 --- a/sys-kernel/pinephone-sources/files/0031-media-ov5640-Add-more-framerates-to-the-driver-some-.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Ondrej Jirman -Date: Fri, 24 Jan 2020 18:25:12 +0100 -Subject: [PATCH 091/194] media: ov5640: Add more framerates to the driver - (some of them even work!) - -Signed-off-by: Ondrej Jirman ---- - drivers/media/i2c/ov5640.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index ddbd713..624a3c0 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -112,7 +112,11 @@ enum ov5640_mode_id { - }; - - enum ov5640_frame_rate { -- OV5640_15_FPS = 0, -+ OV5640_2_FPS = 0, -+ OV5640_3_FPS, -+ OV5640_5_FPS, -+ OV5640_7_FPS, -+ OV5640_15_FPS, - OV5640_30_FPS, - OV5640_60_FPS, - OV5640_NUM_FRAMERATES, -@@ -156,6 +160,10 @@ MODULE_PARM_DESC(virtual_channel, - "MIPI CSI-2 virtual channel (0..3), default 0"); - - static const int ov5640_framerates[] = { -+ [OV5640_2_FPS] = 2, -+ [OV5640_3_FPS] = 3, -+ [OV5640_5_FPS] = 5, -+ [OV5640_7_FPS] = 7, - [OV5640_15_FPS] = 15, - [OV5640_30_FPS] = 30, - [OV5640_60_FPS] = 60, -@@ -2193,11 +2201,11 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, - u32 width, u32 height) - { - const struct ov5640_mode_info *mode; -- enum ov5640_frame_rate rate = OV5640_15_FPS; -+ enum ov5640_frame_rate rate = OV5640_2_FPS; - int minfps, maxfps, best_fps, fps; - int i; - -- minfps = ov5640_framerates[OV5640_15_FPS]; -+ minfps = ov5640_framerates[OV5640_2_FPS]; - maxfps = ov5640_framerates[OV5640_60_FPS]; - - if (fi->numerator == 0) { diff --git a/sys-kernel/pinephone-sources/files/0032-media-ov5640-Experiment-Try-to-disable-denoising-sha.patch b/sys-kernel/pinephone-sources/files/0032-media-ov5640-Experiment-Try-to-disable-denoising-sha.patch deleted file mode 100644 index a9b034a..0000000 --- a/sys-kernel/pinephone-sources/files/0032-media-ov5640-Experiment-Try-to-disable-denoising-sha.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Ondrej Jirman -Date: Fri, 24 Jan 2020 18:25:59 +0100 -Subject: [PATCH 158/465] media: ov5640: [Experiment] Try to disable - denoising/sharpening - -Not sure how this works exactly. More tests are needed. - -Signed-off-by: Ondrej Jirman ---- - drivers/media/i2c/ov5640.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 624a3c0..2f6f97e 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -1772,6 +1772,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; - unsigned long rate; - int ret; -+ u8 tmp; - - dn_mode = mode->dn_mode; - orig_dn_mode = orig_mode->dn_mode; -@@ -1844,6 +1845,22 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - if (ret < 0) - return ret; - -+ ret = ov5640_read_reg(sensor, 0x5308, &tmp); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_write_reg(sensor, 0x5308, tmp | 0x10 | 0x40); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_write_reg(sensor, 0x5306, 0); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_write_reg(sensor, 0x5302, 0); -+ if (ret) -+ return ret; -+ - sensor->pending_mode_change = false; - sensor->last_mode = mode; - diff --git a/sys-kernel/pinephone-sources/files/0033-media-ov5640-Sleep-after-poweroff-to-ensure-next-pow.patch b/sys-kernel/pinephone-sources/files/0033-media-ov5640-Sleep-after-poweroff-to-ensure-next-pow.patch deleted file mode 100644 index 4f68862..0000000 --- a/sys-kernel/pinephone-sources/files/0033-media-ov5640-Sleep-after-poweroff-to-ensure-next-pow.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Ondrej Jirman -Date: Sun, 26 Jan 2020 00:19:40 +0100 -Subject: [PATCH 093/194] media: ov5640: Sleep after poweroff to ensure next - poweron is not too early - -It's easy to use v4l2 userspace api in such a way that user can trigger -a brownout on the sensor instead of a proper powerdown and powerup. - -Signed-off-by: Ondrej Jirman ---- - drivers/media/i2c/ov5640.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 2f6f97e..8a53c0c 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -1971,6 +1971,7 @@ static void ov5640_set_power_off(struct ov5640_dev *sensor) - ov5640_power(sensor, false); - regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); - clk_disable_unprepare(sensor->xclk); -+ msleep(100); - } - - static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on) diff --git a/sys-kernel/pinephone-sources/files/0034-media-ov5640-Don-t-powerup-the-sensor-during-driver-.patch b/sys-kernel/pinephone-sources/files/0034-media-ov5640-Don-t-powerup-the-sensor-during-driver-.patch deleted file mode 100644 index 3da1f5d..0000000 --- a/sys-kernel/pinephone-sources/files/0034-media-ov5640-Don-t-powerup-the-sensor-during-driver-.patch +++ /dev/null @@ -1,86 +0,0 @@ -From: Ondrej Jirman -Date: Sun, 26 Jan 2020 00:28:10 +0100 -Subject: [PATCH 094/194] media: ov5640: Don't powerup the sensor during - driver probe - -It causes autofocus clicking during boot on some devices, and -it's enough to do it when turning on the sensor power by media -pipeline via s_power callback, later on. - -Signed-off-by: Ondrej Jirman ---- - drivers/media/i2c/ov5640.c | 40 ++++++++-------------------------------- - 1 file changed, 8 insertions(+), 32 deletions(-) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 8a53c0c..75f71e6 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -1932,6 +1932,7 @@ static void ov5640_reset(struct ov5640_dev *sensor) - static int ov5640_set_power_on(struct ov5640_dev *sensor) - { - struct i2c_client *client = sensor->i2c_client; -+ u16 chip_id; - int ret; - - ret = clk_prepare_enable(sensor->xclk); -@@ -1956,6 +1957,13 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor) - if (ret) - goto power_off; - -+ ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); -+ if (ret) { -+ dev_err(&client->dev, "%s: failed to read chip identifier\n", -+ __func__); -+ goto power_off; -+ } -+ - return 0; - - power_off: -@@ -3039,34 +3047,6 @@ static int ov5640_get_regulators(struct ov5640_dev *sensor) - sensor->supplies); - } - --static int ov5640_check_chip_id(struct ov5640_dev *sensor) --{ -- struct i2c_client *client = sensor->i2c_client; -- int ret = 0; -- u16 chip_id; -- -- ret = ov5640_set_power_on(sensor); -- if (ret) -- return ret; -- -- ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); -- if (ret) { -- dev_err(&client->dev, "%s: failed to read chip identifier\n", -- __func__); -- goto power_off; -- } -- -- if (chip_id != 0x5640) { -- dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", -- __func__, chip_id); -- ret = -ENXIO; -- } -- --power_off: -- ov5640_set_power_off(sensor); -- return ret; --} -- - static int ov5640_probe(struct i2c_client *client) - { - struct device *dev = &client->dev; -@@ -3184,10 +3164,6 @@ static int ov5640_probe(struct i2c_client *client) - - mutex_init(&sensor->lock); - -- ret = ov5640_check_chip_id(sensor); -- if (ret) -- goto entity_cleanup; -- - ret = ov5640_init_controls(sensor); - if (ret) - goto entity_cleanup; diff --git a/sys-kernel/pinephone-sources/files/0035-media-ov5640-Implement-autofocus.patch b/sys-kernel/pinephone-sources/files/0035-media-ov5640-Implement-autofocus.patch deleted file mode 100644 index 4260878..0000000 --- a/sys-kernel/pinephone-sources/files/0035-media-ov5640-Implement-autofocus.patch +++ /dev/null @@ -1,405 +0,0 @@ -From: Martijn Braam -Date: Mon, 28 Sep 2020 14:26:11 +0200 -Subject: [PATCH 120/194] media: ov5640: Implement autofocus - -The autofocus functionality needs a firmware blob loaded into the -internal microcontroller. - -V4L2 doesn't have an api to control all autofocus functionality, but -this at least makes it possible to focus on the center of the sensor. - -Signed-off-by: Martijn Braam ---- - drivers/media/i2c/ov5640.c | 273 +++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 273 insertions(+) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 75f71e6..246563e 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -9,6 +9,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -31,7 +32,11 @@ - - #define OV5640_DEFAULT_SLAVE_ID 0x3c - -+#define OV5640_REG_SYS_RESET00 0x3000 -+#define OV5640_REG_SYS_RESET01 0x3001 - #define OV5640_REG_SYS_RESET02 0x3002 -+#define OV5640_REG_SYS_CLOCK_ENABLE00 0x3004 -+#define OV5640_REG_SYS_CLOCK_ENABLE01 0x3005 - #define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006 - #define OV5640_REG_SYS_CTRL0 0x3008 - #define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42 -@@ -41,6 +46,14 @@ - #define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 - #define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 - #define OV5640_REG_PAD_OUTPUT00 0x3019 -+#define OV5640_REG_FW_CMD_MAIN 0x3022 -+#define OV5640_REG_FW_CMD_ACK 0x3023 -+#define OV5640_REG_FW_CMD_PARA0 0x3024 -+#define OV5640_REG_FW_CMD_PARA1 0x3025 -+#define OV5640_REG_FW_CMD_PARA2 0x3026 -+#define OV5640_REG_FW_CMD_PARA3 0x3027 -+#define OV5640_REG_FW_CMD_PARA4 0x3028 -+#define OV5640_REG_FW_STATUS 0x3029 - #define OV5640_REG_SYSTEM_CONTROL1 0x302e - #define OV5640_REG_SC_PLL_CTRL0 0x3034 - #define OV5640_REG_SC_PLL_CTRL1 0x3035 -@@ -59,6 +72,7 @@ - #define OV5640_REG_AEC_PK_MANUAL 0x3503 - #define OV5640_REG_AEC_PK_REAL_GAIN 0x350a - #define OV5640_REG_AEC_PK_VTS 0x350c -+#define OV5640_REG_VCM_CONTROL4 0x3606 - #define OV5640_REG_TIMING_DVPHO 0x3808 - #define OV5640_REG_TIMING_DVPVO 0x380a - #define OV5640_REG_TIMING_HTS 0x380c -@@ -96,6 +110,20 @@ - #define OV5640_REG_SDE_CTRL4 0x5584 - #define OV5640_REG_SDE_CTRL5 0x5585 - #define OV5640_REG_AVG_READOUT 0x56a1 -+#define OV5640_REG_FIRMWARE_BASE 0x8000 -+ -+#define OV5640_FW_STATUS_S_FIRMWARE 0x7f -+#define OV5640_FW_STATUS_S_STARTUP 0x7e -+#define OV5640_FW_STATUS_S_IDLE 0x70 -+#define OV5640_FW_STATUS_S_FOCUSING 0x00 -+#define OV5640_FW_STATUS_S_FOCUSED 0x10 -+ -+#define OV5640_FW_CMD_TRIGGER_FOCUS 0x03 -+#define OV5640_FW_CMD_CONTINUOUS_FOCUS 0x04 -+#define OV5640_FW_CMD_GET_FOCUS_RESULT 0x07 -+#define OV5640_FW_CMD_RELEASE_FOCUS 0x08 -+#define OV5640_FW_CMD_ZONE_CONFIG 0x12 -+#define OV5640_FW_CMD_DEFAULT_ZONES 0x80 - - enum ov5640_mode_id { - OV5640_MODE_QQVGA_160_120 = 0, -@@ -222,6 +250,12 @@ struct ov5640_ctrls { - struct v4l2_ctrl *auto_gain; - struct v4l2_ctrl *gain; - }; -+ struct { -+ struct v4l2_ctrl *focus_auto; -+ struct v4l2_ctrl *af_start; -+ struct v4l2_ctrl *af_stop; -+ struct v4l2_ctrl *af_status; -+ }; - struct v4l2_ctrl *brightness; - struct v4l2_ctrl *light_freq; - struct v4l2_ctrl *saturation; -@@ -265,6 +299,8 @@ struct ov5640_dev { - - bool pending_mode_change; - bool streaming; -+ -+ bool af_initialized; - }; - - static inline struct ov5640_dev *to_ov5640_dev(struct v4l2_subdev *sd) -@@ -1929,6 +1965,118 @@ static void ov5640_reset(struct ov5640_dev *sensor) - usleep_range(20000, 25000); - } - -+static int ov5640_copy_fw_to_device(struct ov5640_dev *sensor, -+ const struct firmware *fw) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ const u8 *data = (const u8 *)fw->data; -+ u8 fw_status; -+ int i; -+ int ret; -+ -+ // Putting MCU in reset state -+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20); -+ if (ret) -+ return ret; -+ -+ // Write firmware -+ for (i = 0; i < fw->size / sizeof(u8); i++) -+ ov5640_write_reg(sensor, -+ OV5640_REG_FIRMWARE_BASE + i, -+ data[i]); -+ -+ // Reset MCU state -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA0, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA1, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA2, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA3, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_CMD_PARA4, 0x00); -+ ov5640_write_reg(sensor, OV5640_REG_FW_STATUS, 0x7f); -+ -+ // Start AF MCU -+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00); -+ if (ret) -+ return ret; -+ -+ dev_info(&client->dev, "firmware upload success\n"); -+ -+ // Wait for firmware to be ready -+ for (i = 0; i < 5; i++) { -+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status); -+ if (fw_status == OV5640_FW_STATUS_S_IDLE) { -+ dev_info(&client->dev, "fw started after %d ms\n", i * 50); -+ return ret; -+ } -+ msleep(50); -+ } -+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x, retrying...\n", fw_status); -+ -+ // Putting MCU in reset state -+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x20); -+ if (ret) -+ return ret; -+ // Start AF MCU -+ ret = ov5640_write_reg(sensor, OV5640_REG_SYS_RESET00, 0x00); -+ if (ret) -+ return ret; -+ // Wait for firmware to be ready -+ for (i = 0; i < 5; i++) { -+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status); -+ if (fw_status == OV5640_FW_STATUS_S_IDLE) { -+ dev_info(&client->dev, "fw started after %d ms\n", i * 50); -+ return ret; -+ } -+ msleep(50); -+ } -+ dev_err(&client->dev, "uploaded firmware didn't start, got to 0x%x\n", fw_status); -+ return -ETIMEDOUT; -+} -+ -+static int ov5640_af_init(struct ov5640_dev *sensor) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ const char* fwname = "ov5640_af.bin"; -+ const struct firmware *fw; -+ int ret; -+ -+ if (sensor->af_initialized) { -+ return 0; -+ } -+ -+ if (firmware_request_nowarn(&fw, fwname, &client->dev) == 0) { -+ ret = ov5640_copy_fw_to_device(sensor, fw); -+ if (ret == 0) -+ sensor->af_initialized = 1; -+ } else { -+ dev_warn(&client->dev, "%s: no autofocus firmware available (%s)\n", -+ __func__, fwname); -+ ret = -1; -+ } -+ release_firmware(fw); -+ -+ if (ret) -+ return ret; -+ -+ // Enable AF systems -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE00, -+ (BIT(6) | BIT(5)), (BIT(6) | BIT(5))); -+ if (ret) -+ return ret; -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_CLOCK_ENABLE01, -+ BIT(6), BIT(6)); -+ if (ret) -+ return ret; -+ -+ // Set lens focus driver on -+ ov5640_write_reg(sensor, OV5640_REG_VCM_CONTROL4, 0x3f); -+ if (ret) -+ return ret; -+ -+ return ret; -+} -+ - static int ov5640_set_power_on(struct ov5640_dev *sensor) - { - struct i2c_client *client = sensor->i2c_client; -@@ -1950,6 +2098,8 @@ static int ov5640_set_power_on(struct ov5640_dev *sensor) - goto xclk_off; - } - -+ sensor->af_initialized = 0; -+ - ov5640_reset(sensor); - ov5640_power(sensor, true); - -@@ -2467,6 +2617,35 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, - is_jpeg ? (BIT(5) | BIT(3)) : 0); - } - -+static int ov5640_fw_command(struct ov5640_dev *sensor, int command) -+{ -+ u8 fw_ack; -+ int i; -+ int ret; -+ -+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_ACK, 0x01); -+ if(ret) -+ return ret; -+ -+ ret = ov5640_write_reg(sensor, OV5640_REG_FW_CMD_MAIN, command); -+ if(ret) -+ return ret; -+ -+ for (i = 0; i < 100; i++) { -+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_CMD_ACK, &fw_ack); -+ if (ret) -+ return ret; -+ -+ if (fw_ack == 0){ -+ return ret; -+ } -+ -+ msleep(50); -+ } -+ return -ETIMEDOUT; -+} -+ -+ - /* - * Sensor Controls. - */ -@@ -2583,6 +2762,41 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, - return ret; - } - -+static int ov5640_set_ctrl_focus(struct ov5640_dev *sensor, int command) -+{ -+ struct i2c_client *client = sensor->i2c_client; -+ int ret; -+ -+ ret = ov5640_af_init(sensor); -+ if (ret) { -+ dev_err(&client->dev, "%s: no autofocus firmware loaded\n", -+ __func__); -+ return 0; -+ } -+ -+ if (command == OV5640_FW_CMD_RELEASE_FOCUS) { -+ dev_dbg(&client->dev, "%s: Releasing autofocus\n", -+ __func__); -+ return ov5640_fw_command(sensor, OV5640_FW_CMD_RELEASE_FOCUS); -+ } -+ -+ // Restart zone config -+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_ZONE_CONFIG); -+ if (ret) -+ return ret; -+ -+ // Set default focus zones -+ ret = ov5640_fw_command(sensor, OV5640_FW_CMD_DEFAULT_ZONES); -+ if (ret) -+ return ret; -+ -+ dev_dbg(&client->dev, "%s: Triggering autofocus\n", -+ __func__); -+ -+ // Start focussing -+ return ov5640_fw_command(sensor, command); -+} -+ - static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) - { - struct ov5640_ctrls *ctrls = &sensor->ctrls; -@@ -2689,6 +2903,32 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value) - (BIT(2) | BIT(1)) : 0); - } - -+static int ov5640_get_af_status(struct ov5640_dev *sensor) -+{ -+ u8 fw_status; -+ int ret; -+ -+ ret = ov5640_read_reg(sensor, OV5640_REG_FW_STATUS, &fw_status); -+ if (ret) -+ return ret; -+ -+ switch (fw_status) { -+ case OV5640_FW_STATUS_S_FIRMWARE: -+ case OV5640_FW_STATUS_S_STARTUP: -+ return V4L2_AUTO_FOCUS_STATUS_FAILED; -+ break; -+ case OV5640_FW_STATUS_S_IDLE: -+ return V4L2_AUTO_FOCUS_STATUS_IDLE; -+ break; -+ case OV5640_FW_STATUS_S_FOCUSED: -+ return V4L2_AUTO_FOCUS_STATUS_REACHED; -+ break; -+ default: -+ return V4L2_AUTO_FOCUS_STATUS_BUSY; -+ break; -+ } -+} -+ - static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) - { - struct v4l2_subdev *sd = ctrl_to_sd(ctrl); -@@ -2710,6 +2950,12 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) - return val; - sensor->ctrls.exposure->val = val; - break; -+ case V4L2_CID_FOCUS_AUTO: -+ val = ov5640_get_af_status(sensor); -+ if (val < 0) -+ return val; -+ sensor->ctrls.af_status->val = val; -+ break; - } - - return 0; -@@ -2741,6 +2987,18 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov5640_set_ctrl_white_balance(sensor, ctrl->val); - break; -+ case V4L2_CID_FOCUS_AUTO: -+ if (ctrl->val) -+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_CONTINUOUS_FOCUS); -+ else -+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS); -+ break; -+ case V4L2_CID_AUTO_FOCUS_START: -+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_TRIGGER_FOCUS); -+ break; -+ case V4L2_CID_AUTO_FOCUS_STOP: -+ ret = ov5640_set_ctrl_focus(sensor, OV5640_FW_CMD_RELEASE_FOCUS); -+ break; - case V4L2_CID_HUE: - ret = ov5640_set_ctrl_hue(sensor, ctrl->val); - break; -@@ -2813,6 +3071,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) - ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, - 0, 1023, 1, 0); - -+ /* Autofocus */ -+ ctrls->focus_auto = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_AUTO, -+ 0, 1, 1, 0); -+ ctrls->af_start = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_START, -+ 0, 1, 1, 0); -+ ctrls->af_stop = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_FOCUS_STOP, -+ 0, 1, 1, 0); -+ ctrls->af_status = v4l2_ctrl_new_std(hdl, ops, -+ V4L2_CID_AUTO_FOCUS_STATUS, 0, -+ (V4L2_AUTO_FOCUS_STATUS_BUSY | -+ V4L2_AUTO_FOCUS_STATUS_REACHED | -+ V4L2_AUTO_FOCUS_STATUS_FAILED), -+ 0, V4L2_AUTO_FOCUS_STATUS_IDLE); -+ - ctrls->saturation = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, - 0, 255, 1, 64); - ctrls->hue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HUE, -@@ -2846,6 +3118,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) - v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false); - v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true); - v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true); -+ v4l2_ctrl_cluster(4, &ctrls->focus_auto); - - sensor->sd.ctrl_handler = hdl; - return 0; diff --git a/sys-kernel/pinephone-sources/files/0036-media-ov5640-set-default-ae-target-lower.patch b/sys-kernel/pinephone-sources/files/0036-media-ov5640-set-default-ae-target-lower.patch deleted file mode 100644 index 009d1bb..0000000 --- a/sys-kernel/pinephone-sources/files/0036-media-ov5640-set-default-ae-target-lower.patch +++ /dev/null @@ -1,23 +0,0 @@ -From: Martijn Braam -Date: Wed, 7 Oct 2020 17:33:43 +0200 -Subject: [PATCH 121/194] media: ov5640: set default ae target lower - -The OV5640 tries to overexpose all photos by about 1 stop. This makes -the exposure target one stop lower. ---- - drivers/media/i2c/ov5640.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 246563e..f01bf29 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -3355,7 +3355,7 @@ static int ov5640_probe(struct i2c_client *client) - &ov5640_mode_data[OV5640_MODE_VGA_640_480]; - sensor->last_mode = sensor->current_mode; - -- sensor->ae_target = 52; -+ sensor->ae_target = 28; - - /* optional indication of physical rotation of sensor */ - ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation", diff --git a/sys-kernel/pinephone-sources/files/0037-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch b/sys-kernel/pinephone-sources/files/0037-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch deleted file mode 100644 index fc6634b..0000000 --- a/sys-kernel/pinephone-sources/files/0037-drm-panel-hx8394-Add-driver-for-HX8394-based-HannSta.patch +++ /dev/null @@ -1,464 +0,0 @@ -From: =?utf-8?q?Kamil_Trzci=C5=84ski?= -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 -Signed-off-by: Ondrej Jirman ---- - 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include