Compare commits

...
21 Commits
Author SHA1 Message Date
CTCaer 502a0ff21a soc: tegra: introduce reboot2payload
Some Tegra124 and Tegra21x boards have open-source
bootloaders injected via RCM rather than onboard. These
boards need special reboot handling, which we call
`Reboot2Payload`.

Co-developed-by: Thomas Makin <halorocker89@gmail.com>
Co-developed-by: Ezekiel Bethel <zek@9net.org>
2026-10-13 16:51:00 -05:00
tmakin 9359ba377c soc: tegra: add support for brom cmds
Tegra bootrom can signal PMIC and other onboard devices to handle
early-boot configuration. Downstream L4T kernel has long supported
this functionality, where commands are specified via device-tree and
can be hooked for power/reset events.

Based on:
- https://gitlab.com/nvidia/nv-tegra/linux-3.10/-/commit/4ac6f24c8988ef8f6d8100f9dceede5a3ff4a2d3
- https://gitlab.com/nvidia/nv-tegra/linux-4.4/-/commit/5ba61fa064fdd66c8e84592e721a5ac0fa78ed6e
- https://github.com/CTCaer/switch-l4t-kernel-4.9/commit/b4f03b6ab671597971bd9fc41482c0b52eb64bfd

Co-developed-by: Laxman Dewangan <ldewangan@nvidia.com>
Co-developed-by: CTCaer <ctcaer@gmail.com>
2026-10-13 16:40:44 -05:00
tmakin 63f7efc319 soc: tegra: add t21x panic handler 2026-10-12 16:50:55 -05:00
tmakin 08bd2cf2fd stmfts: update touch handling 2026-10-10 11:18:03 -05:00
tmakin 3e090e8a5a panel-nx: add drm orientation 2026-10-10 11:18:02 -05:00
Billy Laws 2aa5b04a01 [SQUASH] input: misc: Add support for max77620's onoff block
input: misc: Max77620 ON/OFF Block change to button press to key_sleep for linux.

input: misc: max77620-onoff: Ignore button release interrupt if the accompanying press was reported to userspace

Caused some userspaces to shutdown after wakeup from lp0 sleep if the
button was pressed during sleep and not released till after waking.

max77620-onoff: Refactor driver

- Add `maxim,onoff-keycode` under `onoff` child node to select custom ON/OFF button key code.
- Fix button stack at resume.

max77620-onoff: Correct regmap

max77620-onoff: correct irq priority and names

max77620-onoff: clear pending irq on probe

Change-Id: I033bd7a26a4e59b2508e90b4d9e42d2d52e5c17e
2026-10-10 11:17:17 -05:00
tmakin 5c7245e156 stmfts: support FTM4 chips
Some FingerTipS chips use FTM4 variants like Ftm4cd60d

Based loosely on
https://github.com/android-linux-stable/bluecross/blob/android-msm-bluecross-4.9/drivers/input/touchscreen/stm/ftm4_ts.c
and
https://github.com/CTCaer/switch-l4t-kernel-4.9/blob/linux-dev/drivers/input/touchscreen/stm/ftm4_ts.c

Assisted-by: Grok:grok-4.6
2026-10-07 10:26:55 -05:00
Petr Hodina 823de1bf0a arm64: dts: qcom: sdm845-google: Add STM FTS touchscreen support
Basic touchscreen connected to second i2c bus.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-06 19:01:54 -05:00
David Heidelberg 9261922c66 Input: stmfts - support FTS5
The FTS support SLPI and AP mode, introduce mode-switch GPIO to switch
between those two. Currently we can handle only full power AP mode, so we
just keep the AP on.

Useful for devices like Pixel 3 (blueline), Pixel 4a (sunfish),
Xiaomi Mi 8 (dipper), and many others.

Based on work of Petr Hodina <petr.hodina@protonmail.com>

Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-06 19:01:54 -05:00
David Heidelberg 6c42b74e14 dt-bindings: input: touchscreen: st,stmfts: Introduce STM FTS5
Introduce more recent STM FTS5 touchscreen support.

Signed-off-by: David Heidelberg <david@ixit.cz>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
2026-10-06 19:01:54 -05:00
David Heidelberg cd75bcb1f9 dt-bindings: input: touchscreen: st,stmfts: Improve example
The touchscreen-size-{x,y} is exact number, the -1 deduction is done on
driver side.

Example now use interrupts-extended and size obviously not deducted by
one.

Signed-off-by: David Heidelberg <david@ixit.cz>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
2026-10-06 19:01:43 -05:00
David Heidelberg 36fa0b8913 Input: stmfts - wait for controller ready after reset
After releasing the reset line stmfts_reset() sleeps a fixed 50 ms and
stmfts_power_on() another 50 ms before the first I2C access.  That is
enough for a warm reset, but when both supplies were really cut during
system suspend the controller boots from cold and can need longer.  If
it does, the first read fails, stmfts_resume() returns an error and the
touchscreen is left powered off with its interrupt disabled.

The controller posts a controller ready event once it has booted, and
the event parser already completes cmd_done on it.  Enable the interrupt
right after releasing reset and wait for that event instead of sleeping,
giving the controller 300 ms, the total budget the vendor driver allows.
Boards without a reset line keep the old timing.

Usually phones such as Pixel 4a and Xiaomi Mi 8 needs longer delay, so
without this change touchscreen stops working.

Fixes: 8a1f9de80e45 ("Input: stmfts - add optional reset GPIO support")
Cc: stable@vger.kernel.org
Co-developed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
2026-10-06 19:01:43 -05:00
Uwe Kleine-König (The Capable Hub) dcea3dc03a Input: Use named initializers for arrays of i2c_device_data
While being less compact, using named initializers allows to more easily
see which members of the structs are assigned which value without having
to lookup the declaration of the struct. And it's also more robust
against changes to the struct definition.

The mentioned robustness is relevant for a planned change to struct
i2c_device_id that replaces .driver_data by an anonymous union.

This patch doesn't modify the compiled arrays, only their representation
in source form benefits. The former was confirmed with x86 and arm64
builds.

Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
Link: https://patch.msgid.link/20260515164848.497608-2-u.kleine-koenig@baylibre.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 19:01:38 -05:00
Dmitry Torokhov dd36ee6907 Input: stmfts - fix formatting issues
Fix a few formatting issues reported by checkpatch.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 19:01:38 -05:00
Petr Hodina cdd38f1012 Input: stmfts - add optional reset GPIO support
Add support for an optional "reset-gpios" property. If present, the
driver drives the reset line high at probe time and releases it during
power-on, after the regulators have been enabled.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Co-developed-by: David Heidelberg <david@ixit.cz>
Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-8-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 19:01:38 -05:00
Petr Hodina f70d95850e Input: stmfts - use client to make future code cleaner
Make code cleaner, compiler will optimize it away anyway.

Preparation for FTM5 support, where more steps are needed.

Signed-off-by: Petr Hodina <petr.hodina@protonmail.com>
Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-6-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 19:01:38 -05:00
David Heidelberg 4f8d7f167d Input: stmfts - disable regulators and disable irq when power on fails
We must power off regulators and ensure that IRQ is disabled when
failing at power on phase. Create stmfts_configure function to limit
use of goto.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-5-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 18:55:01 -05:00
David Heidelberg 965c9d231b Input: stmfts - abstract reading information from the firmware
Improves readability and makes splitting power on function in following
commit easier.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-4-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 18:55:01 -05:00
David Heidelberg 2fcfbdae10 Input: stmfts - switch to devm_regulator_bulk_get_const
Switch to devm_regulator_bulk_get_const() to stop setting the supplies
list in probe(), and move the regulator_bulk_data struct in static const.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-3-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 18:55:01 -05:00
David Heidelberg d3fd5a30ad Input: stmfts - use dev struct directly
Makes the code better readable and noticably shorter.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-2-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 18:55:01 -05:00
David Heidelberg 91275a8004 Input: stmfts - fix the MODULE_LICENSE() string
Replace the bogus "GPL v2" with "GPL" as MODULE_LICNSE() string. The
value does not declare the module's exact license, but only lets the
module loader test whether the module is Free Software or not.

See commit bf7fbeeae6 ("module: Cure the MODULE_LICENSE "GPL" vs.
"GPL v2" bogosity") in the details of the issue. The fix is to use
"GPL" for all modules under any variant of the GPL.

Signed-off-by: David Heidelberg <david@ixit.cz>
Link: https://patch.msgid.link/20260409-stmfts5-v4-1-64fe62027db5@ixit.cz
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2026-10-06 18:55:01 -05:00
86 changed files with 2341 additions and 236 deletions

No files matched your search

@@ -14,12 +14,11 @@ description:
functionality. Along with it the user can enable the touchkey which can work
as a basic HOME and BACK key for phones.
allOf:
- $ref: touchscreen.yaml#
properties:
compatible:
const: st,stmfts
enum:
- st,stmfts
- st,stmfts5
reg:
maxItems: 1
@@ -40,6 +39,14 @@ properties:
vdd-supply:
description: Power supply
mode-switch-gpios:
description: Optional switch between touchscreen SLPI and AP mode.
maxItems: 1
reset-gpios:
description: Reset GPIO (active-low)
maxItems: 1
required:
- compatible
- reg
@@ -47,6 +54,17 @@ required:
- interrupts
- vdd-supply
allOf:
- $ref: touchscreen.yaml#
- if:
not:
properties:
compatible:
const: st,stmfts5
then:
properties:
mode-switch-gpios: false
unevaluatedProperties: false
examples:
@@ -60,10 +78,9 @@ examples:
touchscreen@49 {
compatible = "st,stmfts";
reg = <0x49>;
interrupt-parent = <&gpa1>;
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
touchscreen-size-x = <1599>;
touchscreen-size-y = <2559>;
interrupts-extended = <&gpa1 1 IRQ_TYPE_LEVEL_LOW>;
touchscreen-size-x = <1600>;
touchscreen-size-y = <2560>;
touch-key-connected;
avdd-supply = <&ldo30_reg>;
vdd-supply = <&ldo31_reg>;
@@ -26,7 +26,24 @@
status = "okay";
/* ST,FTS @ 49 */
touchscreen@49 {
compatible = "st,stmfts5";
reg = <0x49>;
pinctrl-0 = <&touchscreen_irq_n>, <&touchscreen_reset>;
pinctrl-names = "default";
interrupts-extended = <&tlmm 125 IRQ_TYPE_LEVEL_LOW>;
mode-switch-gpios = <&tlmm 136 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 99 GPIO_ACTIVE_LOW>;
avdd-supply = <&vreg_l19a_3p3>;
vdd-supply = <&vreg_l14a_1p8>;
touchscreen-size-x = <1080>;
touchscreen-size-y = <2160>;
};
};
&mdss_dsi0 {
@@ -466,7 +466,7 @@
bias-pull-up;
};
touchscreen_pins: ts-pins-gpio-state {
touchscreen_irq_n: ts-irq-n-gpio-state {
pins = "gpio125";
function = "gpio";
drive-strength = <2>;
+21 -1
View File
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2018 SwtcR <swtcr0@gmail.com>
* Copyright (C) 2023-2024 Azkali <a.ffcc7@gmail.com>
* Copyright (C) 2023-2026 Azkali <a.ffcc7@gmail.com>
* Copyright (C) 2026 Thomas Makin <halorocker89@gmail.com>
*
* Based on Sharp ls043t1le01 panel driver by Werner Johansson <werner.johansson@sonymobile.com>
*
@@ -27,6 +28,7 @@
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_crtc.h>
#include <drm/drm_panel.h>
#include <drm/drm_modes.h>
@@ -110,6 +112,7 @@ struct nx_panel {
bool enabled;
const struct drm_display_mode *mode;
enum drm_panel_orientation orientation;
struct init_cmd *init_cmds;
struct init_cmd *suspend_cmds;
@@ -631,21 +634,32 @@ static int nx_panel_get_modes(struct drm_panel *panel,
connector->display_info.height_mm = 137;
connector->display_info.bpc = 8;
drm_connector_set_panel_orientation(connector, nx->orientation);
return 1;
}
static enum drm_panel_orientation nx_panel_get_orientation(struct drm_panel *panel)
{
struct nx_panel *nx = to_nx_panel(panel);
return nx->orientation;
}
static const struct drm_panel_funcs nx_panel_funcs = {
.prepare = nx_panel_prepare,
.unprepare = nx_panel_unprepare,
.enable = nx_panel_enable,
.disable = nx_panel_disable,
.get_modes = nx_panel_get_modes,
.get_orientation = nx_panel_get_orientation,
};
static int nx_panel_add(struct nx_panel *nx)
{
struct device *dev = &nx->dsi->dev;
struct device_node *np;
int ret;
nx->mode = &default_mode;
@@ -677,6 +691,12 @@ static int nx_panel_add(struct nx_panel *nx)
return -EPROBE_DEFER;
}
ret = of_drm_get_panel_orientation(dev->of_node, &nx->orientation);
if (ret < 0) {
dev_err(dev, "Failed to get orientation %d\n", ret);
return ret;
}
drm_panel_init(&nx->base, &nx->dsi->dev, &nx_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
+1 -1
View File
@@ -304,7 +304,7 @@ static int seesaw_probe(struct i2c_client *client)
}
static const struct i2c_device_id seesaw_id_table[] = {
{ SEESAW_DEVICE_NAME },
{ .name = SEESAW_DEVICE_NAME },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, seesaw_id_table);
+1 -1
View File
@@ -337,7 +337,7 @@ static void as5011_remove(struct i2c_client *client)
}
static const struct i2c_device_id as5011_id[] = {
{ MODULE_DEVICE_ALIAS },
{ .name = MODULE_DEVICE_ALIAS },
{ }
};
MODULE_DEVICE_TABLE(i2c, as5011_id);
+1 -1
View File
@@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, of_qwiic_match);
#endif /* CONFIG_OF */
static const struct i2c_device_id qwiic_id_table[] = {
{ KBUILD_MODNAME },
{ .name = KBUILD_MODNAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, qwiic_id_table);
+2 -2
View File
@@ -842,8 +842,8 @@ static int adp5588_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(adp5588_dev_pm_ops, adp5588_suspend, adp5588_resume);
static const struct i2c_device_id adp5588_id[] = {
{ "adp5588-keys" },
{ "adp5587-keys" },
{ .name = "adp5588-keys" },
{ .name = "adp5587-keys" },
{ }
};
MODULE_DEVICE_TABLE(i2c, adp5588_id);
+7 -7
View File
@@ -651,13 +651,13 @@ static const struct of_device_id cap11xx_dt_ids[] = {
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
static const struct i2c_device_id cap11xx_i2c_ids[] = {
{ "cap1106", (kernel_ulong_t)&cap1106_model },
{ "cap1126", (kernel_ulong_t)&cap1126_model },
{ "cap1188", (kernel_ulong_t)&cap1188_model },
{ "cap1203", (kernel_ulong_t)&cap1203_model },
{ "cap1206", (kernel_ulong_t)&cap1206_model },
{ "cap1293", (kernel_ulong_t)&cap1293_model },
{ "cap1298", (kernel_ulong_t)&cap1298_model },
{ .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model },
{ .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model },
{ .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model },
{ .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model },
{ .name = "cap1206", .driver_data = (kernel_ulong_t)&cap1206_model },
{ .name = "cap1293", .driver_data = (kernel_ulong_t)&cap1293_model },
{ .name = "cap1298", .driver_data = (kernel_ulong_t)&cap1298_model },
{ }
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
+1 -1
View File
@@ -209,7 +209,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
cypress_sf_suspend, cypress_sf_resume);
static const struct i2c_device_id cypress_sf_id_table[] = {
{ CYPRESS_SF_DEV_NAME },
{ .name = CYPRESS_SF_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
@@ -128,7 +128,7 @@ static int dir685_tk_probe(struct i2c_client *client)
}
static const struct i2c_device_id dir685_tk_id[] = {
{ "dir685tk" },
{ .name = "dir685tk" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dir685_tk_id);
+1 -1
View File
@@ -788,7 +788,7 @@ static int lm8323_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume);
static const struct i2c_device_id lm8323_id[] = {
{ "lm8323" },
{ .name = "lm8323" },
{ }
};
+1 -1
View File
@@ -194,7 +194,7 @@ static int lm8333_probe(struct i2c_client *client)
}
static const struct i2c_device_id lm8333_id[] = {
{ "lm8333" },
{ .name = "lm8333" },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm8333_id);
+1 -1
View File
@@ -270,7 +270,7 @@ static int max7359_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume);
static const struct i2c_device_id max7359_ids[] = {
{ "max7359" },
{ .name = "max7359" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max7359_ids);
+1 -1
View File
@@ -322,7 +322,7 @@ static int mpr_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
static const struct i2c_device_id mpr121_id[] = {
{ "mpr121_touchkey" },
{ .name = "mpr121_touchkey" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mpr121_id);
+1 -1
View File
@@ -233,7 +233,7 @@ static int qt1070_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume);
static const struct i2c_device_id qt1070_id[] = {
{ "qt1070" },
{ .name = "qt1070" },
{ }
};
MODULE_DEVICE_TABLE(i2c, qt1070_id);
+1 -1
View File
@@ -393,7 +393,7 @@ static int qt2160_probe(struct i2c_client *client)
}
static const struct i2c_device_id qt2160_idtable[] = {
{ "qt2160" },
{ .name = "qt2160" },
{ }
};
+1 -1
View File
@@ -354,7 +354,7 @@ static int tca8418_keypad_probe(struct i2c_client *client)
}
static const struct i2c_device_id tca8418_id[] = {
{ "tca8418", 8418, },
{ .name = "tca8418", .driver_data = 8418 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tca8418_id);
+1 -1
View File
@@ -326,7 +326,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
tm2_touchkey_suspend, tm2_touchkey_resume);
static const struct i2c_device_id tm2_touchkey_id_table[] = {
{ TM2_TOUCHKEY_DEV_NAME },
{ .name = TM2_TOUCHKEY_DEV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
+7
View File
@@ -282,6 +282,13 @@ config INPUT_MAX77693_HAPTIC
To compile this driver as module, choose M here: the
module will be called max77693-haptic.
config INPUT_MAX77620_ONOFF
tristate "MAX77620 ONOFF support"
depends on MFD_MAX77620
help
Support the ONOFF block of MAX77620 PMICs as an input device
reporting power button status.
config INPUT_MAX8925_ONKEY
tristate "MAX8925 ONKEY support"
depends on MFD_MAX8925
+1
View File
@@ -55,6 +55,7 @@ obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
obj-$(CONFIG_INPUT_MAX7360_ROTARY) += max7360-rotary.o
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX77620_ONOFF) += max77620-onoff.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
+5 -5
View File
@@ -72,11 +72,11 @@ static int ad714x_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad714x_id[] = {
{ "ad7142_captouch" },
{ "ad7143_captouch" },
{ "ad7147_captouch" },
{ "ad7147a_captouch" },
{ "ad7148_captouch" },
{ .name = "ad7142_captouch" },
{ .name = "ad7143_captouch" },
{ .name = "ad7147_captouch" },
{ .name = "ad7147a_captouch" },
{ .name = "ad7148_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad714x_id);
+1 -1
View File
@@ -96,7 +96,7 @@ static int adxl34x_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x" },
{ .name = "adxl34x" },
{ }
};
+1 -1
View File
@@ -192,7 +192,7 @@ static void apanel_shutdown(struct i2c_client *client)
}
static const struct i2c_device_id apanel_id[] = {
{ "fujitsu_apanel" },
{ .name = "fujitsu_apanel" },
{ }
};
MODULE_DEVICE_TABLE(i2c, apanel_id);
+1 -1
View File
@@ -257,7 +257,7 @@ static const struct of_device_id atmel_captouch_of_id[] = {
MODULE_DEVICE_TABLE(of, atmel_captouch_of_id);
static const struct i2c_device_id atmel_captouch_id[] = {
{ "atmel_captouch" },
{ .name = "atmel_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
+3 -3
View File
@@ -536,9 +536,9 @@ static int __maybe_unused bma150_resume(struct device *dev)
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
{ "bma150" },
{ "smb380" },
{ "bma023" },
{ .name = "bma150" },
{ .name = "smb380" },
{ .name = "bma023" },
{ }
};
+1 -1
View File
@@ -90,7 +90,7 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = {
};
static const struct i2c_device_id cma3000_i2c_id[] = {
{ "cma3000_d01" },
{ .name = "cma3000_d01" },
{ }
};
+1 -1
View File
@@ -1305,7 +1305,7 @@ MODULE_DEVICE_TABLE(of, da7280_of_match);
#endif
static const struct i2c_device_id da7280_i2c_id[] = {
{ "da7280", },
{ .name = "da7280" },
{ }
};
MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
+4 -4
View File
@@ -630,10 +630,10 @@ static int drv260x_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
{ "drv2604" },
{ "drv2604l" },
{ "drv2605" },
{ "drv2605l" },
{ .name = "drv2604" },
{ .name = "drv2604l" },
{ .name = "drv2605" },
{ .name = "drv2605l" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv260x_id);
+1 -1
View File
@@ -281,7 +281,7 @@ static int drv2665_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
static const struct i2c_device_id drv2665_id[] = {
{ "drv2665" },
{ .name = "drv2665" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2665_id);
+1 -1
View File
@@ -458,7 +458,7 @@ static int drv2667_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
static const struct i2c_device_id drv2667_id[] = {
{ "drv2667" },
{ .name = "drv2667" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2667_id);
+1 -1
View File
@@ -525,7 +525,7 @@ static int kxtj9_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
static const struct i2c_device_id kxtj9_id[] = {
{ NAME },
{ .name = NAME },
{ }
};
+235
View File
@@ -0,0 +1,235 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2018 Billy Laws
* Copyright (C) 2020-2022 CTCaer
*
* Author:
* Billy Laws <blaws05@gmail.com>
* CTCaer <ctcaer@gmail.com>
*
* Description:
* ONOFF driver for MAXIM 77620 charger/power-supply.
*/
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/max77620.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define ONOFF_IRQF 2
#define ONOFF_IRQR 3
/* MAX77620 IRQ ONOFF interrupts */
#define MAX77620_IRQ_ONOFF_MRWRN 0
#define MAX77620_IRQ_ONOFF_EN0_1SEC 1
#define MAX77620_IRQ_ONOFF_EN0_F 2
#define MAX77620_IRQ_ONOFF_EN0_R 3
#define MAX77620_IRQ_ONOFF_LID_F 4
#define MAX77620_IRQ_ONOFF_LID_R 5
#define MAX77620_IRQ_ONOFF_ACOK_F 6
#define MAX77620_IRQ_ONOFF_ACOK_R 7
struct max77620_onoff {
struct regmap *rmap;
struct input_dev *input;
int irq_f, irq_r;
unsigned int code;
bool suspended;
};
static const struct regmap_irq max77620_onoff_irqs[] = {
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_MRWRN, 0, MAX77620_IRQ_ONOFF_MRWRN_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_1SEC, 0, MAX77620_IRQ_ONOFF_EN0_1SEC_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_F, 0, MAX77620_IRQ_ONOFF_EN0_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_EN0_R, 0, MAX77620_IRQ_ONOFF_EN0_R_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_LID_F, 0, MAX77620_IRQ_ONOFF_LID_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_LID_R, 0, MAX77620_IRQ_ONOFF_LID_R_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_ACOK_F, 0, MAX77620_IRQ_ONOFF_ACOK_F_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_ONOFF_ACOK_R, 0, MAX77620_IRQ_ONOFF_ACOK_R_MASK),
};
static struct regmap_irq_chip max77620_onoff_irq_chip = {
.name = "max77620-onoff",
.irqs = max77620_onoff_irqs,
.num_irqs = ARRAY_SIZE(max77620_onoff_irqs),
.num_regs = 1,
.irq_reg_stride = 1,
.status_base = MAX77620_REG_ONOFFIRQ,
.mask_base = MAX77620_REG_ONOFFIRQM,
};
static irqreturn_t max77620_onoff_handler(int irq, void *data)
{
struct max77620_onoff *onoff = data;
bool pressed = irq == onoff->irq_r;
/* Skip release report in suspended state */
if (onoff->suspended && !pressed)
return IRQ_HANDLED;
input_report_key(onoff->input, onoff->code, pressed);
input_sync(onoff->input);
return IRQ_HANDLED;
}
static int max77620_onoff_probe(struct platform_device *pdev)
{
struct max77620_onoff *onoff;
struct device *dev, *parent;
struct max77620_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct device_node *np;
unsigned int code;
int irq, ret;
dev = &pdev->dev;
parent = dev->parent;
onoff = devm_kzalloc(dev, sizeof(*onoff), GFP_KERNEL);
if (!onoff)
return -ENOMEM;
onoff->rmap = chip->rmap;
ret = regmap_read(onoff->rmap, MAX77620_REG_ONOFFIRQ, &code);
if (ret < 0)
dev_err(dev, "Failed to clear onoff irq: %d\n", ret);
np = of_get_child_by_name(pdev->dev.parent->of_node, "onoff");
if (np && !of_device_is_available(np))
np = NULL;
if (np)
ret = of_property_read_u32(np, "maxim,onoff-keycode",
&code);
if (!np || ret < 0)
onoff->code = KEY_POWER;
else
onoff->code = code;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
onoff->input = devm_input_allocate_device(dev);
if (!onoff->input)
return -ENOMEM;
onoff->input->name = "max77620_onoff";
onoff->input->phys = "max77620_onoff/input0";
onoff->input->id.bustype = BUS_I2C;
input_set_capability(onoff->input, EV_KEY, onoff->code);
ret = devm_regmap_add_irq_chip(&pdev->dev, onoff->rmap, irq,
IRQF_ONESHOT, -1,
&max77620_onoff_irq_chip,
&chip->onoff_irq_data);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to add onoff irq_chip %d\n", ret);
goto fail;
}
onoff->irq_r = regmap_irq_get_virq(chip->onoff_irq_data,
MAX77620_IRQ_ONOFF_EN0_R);
onoff->irq_f = regmap_irq_get_virq(chip->onoff_irq_data,
MAX77620_IRQ_ONOFF_EN0_F);
ret = devm_request_any_context_irq(dev, onoff->irq_r,
max77620_onoff_handler,
IRQF_ONESHOT, "en0-down", onoff);
if (ret < 0)
goto fail;
ret = devm_request_any_context_irq(dev, onoff->irq_f,
max77620_onoff_handler,
IRQF_ONESHOT, "en0-up", onoff);
if (ret < 0)
goto fail;
platform_set_drvdata(pdev, onoff);
input_set_drvdata(onoff->input, onoff);
device_init_wakeup(dev, 1);
ret = input_register_device(onoff->input);
fail:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int max77620_onoff_suspend(struct device *dev)
{
struct max77620_onoff *onoff = dev_get_drvdata(dev);
onoff->suspended = true;
if (device_may_wakeup(dev))
return enable_irq_wake(onoff->irq_f);
return 0;
}
static int max77620_onoff_resume(struct device *dev)
{
struct max77620_onoff *onoff = dev_get_drvdata(dev);
unsigned int val, ret;
/* Clear ON/OFF interrupts */
ret = regmap_read(onoff->rmap, MAX77620_REG_ONOFFIRQ, &val);
if (ret < 0)
dev_err(dev, "Failed to clear onoff irq: %d\n", ret);
onoff->suspended = false;
/* If ON/OFF was pressed, report it */
if (val & MAX77620_IRQ_ONOFF_EN0_R_MASK) {
input_report_key(onoff->input, onoff->code, 1);
input_sync(onoff->input);
}
/* Unconditionally release after resume */
input_report_key(onoff->input, onoff->code, 0);
input_sync(onoff->input);
if (device_may_wakeup(dev))
return disable_irq_wake(onoff->irq_f);
return 0;
}
static const struct dev_pm_ops max77620_onoff_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(max77620_onoff_suspend,
max77620_onoff_resume)
};
#endif /* CONFIG_PM_SLEEP */
static struct platform_driver max77620_onoff_driver = {
.driver = {
.name = "max77620-onoff",
#ifdef CONFIG_PM_SLEEP
.pm = &max77620_onoff_pm_ops,
#endif
},
.probe = max77620_onoff_probe,
};
static int __init max77620_onoff_init(void)
{
return platform_driver_register(&max77620_onoff_driver);
}
subsys_initcall(max77620_onoff_init);
static void __exit max77620_onoff_exit(void)
{
platform_driver_unregister(&max77620_onoff_driver);
}
module_exit(max77620_onoff_exit);
MODULE_DESCRIPTION("MAXIM 77620 ONOFF driver");
MODULE_AUTHOR("Billy Laws <blaws05@gmail.com>");
MODULE_LICENSE("GPL v2");
+1 -1
View File
@@ -200,7 +200,7 @@ static int mma8450_probe(struct i2c_client *c)
}
static const struct i2c_device_id mma8450_id[] = {
{ MMA8450_DRV_NAME },
{ .name = MMA8450_DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, mma8450_id);
+1 -1
View File
@@ -189,7 +189,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops,
pcf8574_kp_suspend, pcf8574_kp_resume);
static const struct i2c_device_id pcf8574_kp_id[] = {
{ DRV_NAME },
{ .name = DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
+1 -1
View File
@@ -1456,7 +1456,7 @@ static const struct dev_pm_ops cyapa_pm_ops = {
};
static const struct i2c_device_id cyapa_id_table[] = {
{ "cyapa" },
{ .name = "cyapa" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+1 -1
View File
@@ -1407,7 +1407,7 @@ err:
static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
static const struct i2c_device_id elan_id[] = {
{ DRIVER_NAME },
{ .name = DRIVER_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, elan_id);
+1 -1
View File
@@ -607,7 +607,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
synaptics_i2c_resume);
static const struct i2c_device_id synaptics_i2c_id_table[] = {
{ "synaptics_i2c" },
{ .name = "synaptics_i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table);
+1 -1
View File
@@ -365,7 +365,7 @@ static const struct dev_pm_ops rmi_i2c_pm = {
};
static const struct i2c_device_id rmi_id[] = {
{ "rmi4_i2c" },
{ .name = "rmi4_i2c" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
+1 -1
View File
@@ -413,7 +413,7 @@ static const struct dev_pm_ops rmi_smb_pm = {
};
static const struct i2c_device_id rmi_id[] = {
{ "rmi4_smbus" },
{ .name = "rmi4_smbus" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
+2 -2
View File
@@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7879_id[] = {
{ "ad7879" },
{ "ad7889" },
{ .name = "ad7879" },
{ .name = "ad7889" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7879_id);
+1 -1
View File
@@ -164,7 +164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm,
ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
{ "ar1021" },
{ .name = "ar1021" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
+5 -5
View File
@@ -3420,11 +3420,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
#endif
static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts" },
{ "atmel_mxt_ts" },
{ "atmel_mxt_tp" },
{ "maxtouch" },
{ "mXT224" },
{ .name = "qt602240_ts" },
{ .name = "atmel_mxt_ts" },
{ .name = "atmel_mxt_tp" },
{ .name = "maxtouch" },
{ .name = "mXT224" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
+1 -1
View File
@@ -618,7 +618,7 @@ static int auo_pixcir_probe(struct i2c_client *client)
}
static const struct i2c_device_id auo_pixcir_idtable[] = {
{ "auo_pixcir_ts" },
{ .name = "auo_pixcir_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
+1 -1
View File
@@ -597,7 +597,7 @@ static int bu21013_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
static const struct i2c_device_id bu21013_id[] = {
{ DRIVER_TP },
{ .name = DRIVER_TP },
{ }
};
MODULE_DEVICE_TABLE(i2c, bu21013_id);
+1 -1
View File
@@ -442,7 +442,7 @@ static int bu21029_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
static const struct i2c_device_id bu21029_ids[] = {
{ DRIVER_NAME },
{ .name = DRIVER_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, bu21029_ids);
+1 -1
View File
@@ -322,7 +322,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm,
cy8ctma140_suspend, cy8ctma140_resume);
static const struct i2c_device_id cy8ctma140_idtable[] = {
{ CY8CTMA140_NAME },
{ .name = CY8CTMA140_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable);
+1 -1
View File
@@ -267,7 +267,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm,
cy8ctmg110_suspend, cy8ctmg110_resume);
static const struct i2c_device_id cy8ctmg110_idtable[] = {
{ CY8CTMG110_DRIVER_NAME, 1 },
{ .name = CY8CTMG110_DRIVER_NAME, .driver_data = 1 },
{ }
};
+1 -1
View File
@@ -938,7 +938,7 @@ static const struct of_device_id cyttsp5_of_match[] = {
MODULE_DEVICE_TABLE(of, cyttsp5_of_match);
static const struct i2c_device_id cyttsp5_i2c_id[] = {
{ CYTTSP5_NAME },
{ .name = CYTTSP5_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
+1 -1
View File
@@ -103,7 +103,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id cyttsp_i2c_id[] = {
{ CY_I2C_NAME },
{ .name = CY_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
+1 -1
View File
@@ -266,7 +266,7 @@ static int eeti_ts_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
static const struct i2c_device_id eeti_ts_id[] = {
{ "eeti_ts" },
{ .name = "eeti_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
+1 -1
View File
@@ -219,7 +219,7 @@ static int egalax_ts_probe(struct i2c_client *client)
}
static const struct i2c_device_id egalax_ts_id[] = {
{ "egalax_ts" },
{ .name = "egalax_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
+3 -3
View File
@@ -1615,9 +1615,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
elants_i2c_suspend, elants_i2c_resume);
static const struct i2c_device_id elants_i2c_id[] = {
{ DEVICE_NAME, EKTH3500 },
{ "ekth3500", EKTH3500 },
{ "ektf3624", EKTF3624 },
{ .name = DEVICE_NAME, .driver_data = EKTH3500 },
{ .name = "ekth3500", .driver_data = EKTH3500 },
{ .name = "ektf3624", .driver_data = EKTF3624 },
{ }
};
MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
+4 -4
View File
@@ -432,10 +432,10 @@ static int exc3000_probe(struct i2c_client *client)
}
static const struct i2c_device_id exc3000_id[] = {
{ "exc3000", EETI_EXC3000 },
{ "exc80h60", EETI_EXC80H60 },
{ "exc80h84", EETI_EXC80H84 },
{ "exc81w32", EETI_EXC81W32 },
{ .name = "exc3000", .driver_data = EETI_EXC3000 },
{ .name = "exc80h60", .driver_data = EETI_EXC80H60 },
{ .name = "exc80h84", .driver_data = EETI_EXC80H84 },
{ .name = "exc81w32", .driver_data = EETI_EXC81W32 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
+1 -1
View File
@@ -1523,7 +1523,7 @@ static int goodix_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
static const struct i2c_device_id goodix_ts_id[] = {
{ "GDIX1001:00" },
{ .name = "GDIX1001:00" },
{ }
};
MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
+1 -1
View File
@@ -1081,7 +1081,7 @@ static int hideep_probe(struct i2c_client *client)
}
static const struct i2c_device_id hideep_i2c_id[] = {
{ HIDEEP_I2C_NAME },
{ .name = HIDEEP_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, hideep_i2c_id);
+2 -2
View File
@@ -406,8 +406,8 @@ static const struct himax_chip hx83112b_chip = {
};
static const struct i2c_device_id himax_ts_id[] = {
{ "hx83100a", (kernel_ulong_t)&hx83100a_chip },
{ "hx83112b", (kernel_ulong_t)&hx83112b_chip },
{ .name = "hx83100a", .driver_data = (kernel_ulong_t)&hx83100a_chip },
{ .name = "hx83112b", .driver_data = (kernel_ulong_t)&hx83112b_chip },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, himax_ts_id);
+1 -1
View File
@@ -226,7 +226,7 @@ static int cst816x_probe(struct i2c_client *client)
}
static const struct i2c_device_id cst816x_id[] = {
{ .name = "cst816s", 0 },
{ .name = "cst816s" },
{ }
};
MODULE_DEVICE_TABLE(i2c, cst816x_id);
+4 -4
View File
@@ -1049,10 +1049,10 @@ static int ili210x_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ili210x_i2c_id[] = {
{ "ili210x", (long)&ili210x_chip },
{ "ili2117", (long)&ili211x_chip },
{ "ili2120", (long)&ili212x_chip },
{ "ili251x", (long)&ili251x_chip },
{ .name = "ili210x", .driver_data = (long)&ili210x_chip },
{ .name = "ili2117", .driver_data = (long)&ili211x_chip },
{ .name = "ili2120", .driver_data = (long)&ili212x_chip },
{ .name = "ili251x", .driver_data = (long)&ili251x_chip },
{ }
};
MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
+1 -1
View File
@@ -639,7 +639,7 @@ static int ilitek_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
static const struct i2c_device_id ilitek_ts_i2c_id[] = {
{ ILITEK_TS_NAME },
{ .name = ILITEK_TS_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id);
+1 -1
View File
@@ -213,7 +213,7 @@ static int max11801_ts_probe(struct i2c_client *client)
}
static const struct i2c_device_id max11801_ts_id[] = {
{ "max11801" },
{ .name = "max11801" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+1 -1
View File
@@ -1536,7 +1536,7 @@ MODULE_DEVICE_TABLE(acpi, mip4_acpi_match);
#endif
static const struct i2c_device_id mip4_i2c_ids[] = {
{ MIP4_DEVICE_NAME },
{ .name = MIP4_DEVICE_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids);
+1 -1
View File
@@ -211,7 +211,7 @@ static int migor_ts_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
static const struct i2c_device_id migor_ts_id[] = {
{ "migor_ts" },
{ .name = "migor_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, migor_ts_id);
+1 -1
View File
@@ -667,7 +667,7 @@ static int mms114_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
static const struct i2c_device_id mms114_id[] = {
{ "mms114" },
{ .name = "mms114" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mms114_id);
+2 -2
View File
@@ -326,8 +326,8 @@ static const struct of_device_id nvt_ts_of_match[] = {
MODULE_DEVICE_TABLE(of, nvt_ts_of_match);
static const struct i2c_device_id nvt_ts_i2c_id[] = {
{ "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data },
{ "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data },
{ .name = "nt11205-ts", .driver_data = (unsigned long)&nvt_nt11205_ts_data },
{ .name = "nt36672a-ts", .driver_data = (unsigned long)&nvt_nt36672a_ts_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id);
+2 -2
View File
@@ -580,8 +580,8 @@ static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
};
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
{ "pixcir_ts", (unsigned long) &pixcir_ts_data },
{ "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data },
{ .name = "pixcir_ts", .driver_data = (unsigned long)&pixcir_ts_data },
{ .name = "pixcir_tangoc", .driver_data = (unsigned long)&pixcir_tangoc_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
+2 -2
View File
@@ -1219,8 +1219,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
raydium_i2c_suspend, raydium_i2c_resume);
static const struct i2c_device_id raydium_i2c_id[] = {
{ "raydium_i2c" },
{ "rm32380" },
{ .name = "raydium_i2c" },
{ .name = "rm32380" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, raydium_i2c_id);
+1 -1
View File
@@ -1144,7 +1144,7 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
{ BU21023_NAME },
{ .name = BU21023_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
+1 -1
View File
@@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, s6sy761_of_match);
#endif
static const struct i2c_device_id s6sy761_id[] = {
{ "s6sy761" },
{ .name = "s6sy761" },
{ }
};
MODULE_DEVICE_TABLE(i2c, s6sy761_id);
+6 -6
View File
@@ -776,12 +776,12 @@ static int silead_ts_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
static const struct i2c_device_id silead_ts_id[] = {
{ "gsl1680" },
{ "gsl1688" },
{ "gsl3670" },
{ "gsl3675" },
{ "gsl3692" },
{ "mssl1680" },
{ .name = "gsl1680" },
{ .name = "gsl1688" },
{ .name = "gsl3670" },
{ .name = "gsl3675" },
{ .name = "gsl3692" },
{ .name = "mssl1680" },
{ }
};
MODULE_DEVICE_TABLE(i2c, silead_ts_id);
+2 -2
View File
@@ -374,8 +374,8 @@ MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
#endif
static const struct i2c_device_id sis_ts_id[] = {
{ SIS_I2C_NAME },
{ "9200-ts" },
{ .name = SIS_I2C_NAME },
{ .name = "9200-ts" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, sis_ts_id);
+2 -2
View File
@@ -453,8 +453,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
st1232_ts_suspend, st1232_ts_resume);
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, (unsigned long)&st1232_chip_info },
{ ST1633_TS_NAME, (unsigned long)&st1633_chip_info },
{ .name = ST1232_TS_NAME, .driver_data = (unsigned long)&st1232_chip_info },
{ .name = ST1633_TS_NAME, .driver_data = (unsigned long)&st1633_chip_info },
{ }
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -43,7 +43,7 @@ static int tsc2004_probe(struct i2c_client *i2c)
}
static const struct i2c_device_id tsc2004_idtable[] = {
{ "tsc2004" },
{ .name = "tsc2004" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsc2004_idtable);
+1 -1
View File
@@ -407,7 +407,7 @@ static int tsc2007_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsc2007_idtable[] = {
{ "tsc2007" },
{ .name = "tsc2007" },
{ }
};
+1 -1
View File
@@ -253,7 +253,7 @@ static int wacom_i2c_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
static const struct i2c_device_id wacom_i2c_id[] = {
{ "WAC_I2C_EMR" },
{ .name = "WAC_I2C_EMR" },
{ }
};
MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
+1 -1
View File
@@ -1140,7 +1140,7 @@ static int wdt87xx_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
static const struct i2c_device_id wdt87xx_dev_id[] = {
{ WDT87XX_NAME },
{ .name = WDT87XX_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id);
+1 -1
View File
@@ -236,7 +236,7 @@ static const struct of_device_id zet6223_of_match[] = {
MODULE_DEVICE_TABLE(of, zet6223_of_match);
static const struct i2c_device_id zet6223_id[] = {
{ "zet6223" },
{ .name = "zet6223" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zet6223_id);
+1 -1
View File
@@ -831,7 +831,7 @@ static int zforce_probe(struct i2c_client *client)
}
static const struct i2c_device_id zforce_idtable[] = {
{ "zforce-ts" },
{ .name = "zforce-ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
+8
View File
@@ -53,6 +53,10 @@ static const struct resource thermal_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_LBT_TJALRM2),
};
static const struct resource onoff_resources[] = {
DEFINE_RES_IRQ(MAX77620_IRQ_TOP_ONOFF),
};
static const struct regmap_irq max77620_top_irqs[] = {
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_GLBL, 0, MAX77620_IRQ_TOP_GLBL_MASK),
REGMAP_IRQ_REG(MAX77620_IRQ_TOP_SD, 0, MAX77620_IRQ_TOP_SD_MASK),
@@ -87,6 +91,10 @@ static const struct mfd_cell max77620_children[] = {
.name = "max77620-thermal",
.resources = thermal_resources,
.num_resources = ARRAY_SIZE(thermal_resources),
}, {
.name = "max77620-onoff",
.resources = onoff_resources,
.num_resources = ARRAY_SIZE(onoff_resources),
},
};
+10
View File
@@ -195,3 +195,13 @@ config SOC_TEGRA_CBB
Support for handling error from Tegra Control Backbone(CBB).
This driver handles the errors from CBB and prints debug
information about the failed transactions.
config SOC_TEGRA_R2P
tristate "Tegra Reboot 2 Payload support"
depends on ARCH_TEGRA_124_SOC || ARCH_TEGRA_210_SOC
default n
help
This enables a special reboot path which allows the board to reboot
to a specified bootloader other than the one in boot storage.
If in doubt, say N.
+1
View File
@@ -8,3 +8,4 @@ obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
obj-$(CONFIG_SOC_TEGRA20_VOLTAGE_COUPLER) += regulators-tegra20.o
obj-$(CONFIG_SOC_TEGRA30_VOLTAGE_COUPLER) += regulators-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_186_SOC) += ari-tegra186.o
obj-$(CONFIG_SOC_TEGRA_R2P) += r2p-tegra.o
+405 -15
View File
@@ -35,6 +35,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/panic_notifier.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
@@ -111,6 +112,8 @@
#define PMC_PWR_DET_VALUE 0xe4
#define KERNEL_PANIC_MAGIC 0x4E415054
#define PMC_USB_DEBOUNCE_DEL 0xec
#define PMC_USB_AO 0xf0
@@ -177,6 +180,26 @@
#define PMC_UTMIP_PAD_CFG0 0x4c0
#define PMC_UTMIP_UHSIC_SLEEP_CFG1 0x4d0
#define PMC_UTMIP_SLEEPWALK_P3 0x4e0
/* Scratch 250: Bootrom i2c command base */
#define PMC_BR_COMMAND_BASE 0x908
/* Bootrom comand register */
#define PMC_REG_8bit_MASK 0xFF
#define PMC_REG_16bit_MASK 0xFFFF
#define PMC_BR_COMMAND_I2C_ADD_MASK 0x7F
#define PMC_BR_COMMAND_WR_COMMANDS_MASK 0x3F
#define PMC_BR_COMMAND_WR_COMMANDS_SHIFT 8
#define PMC_BR_COMMAND_OPERAND_SHIFT 15
#define PMC_BR_COMMAND_CSUM_MASK 0xFF
#define PMC_BR_COMMAND_CSUM_SHIFT 16
#define PMC_BR_COMMAND_PMUX_MASK 0x7
#define PMC_BR_COMMAND_PMUX_SHIFT 24
#define PMC_BR_COMMAND_CTRL_ID_MASK 0x7
#define PMC_BR_COMMAND_CTRL_ID_SHIFT 27
#define PMC_BR_COMMAND_CTRL_TYPE_SHIFT 30
#define PMC_BR_COMMAND_RST_EN_SHIFT 31
/* Tegra186 and later */
#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2))
#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3)
@@ -292,6 +315,29 @@ struct tegra_powergate {
struct reset_control *reset;
};
struct tegra_bootrom_block {
const char *name;
int address;
bool reg_8bits;
bool data_8bits;
bool i2c_controller;
int controller_id;
bool enable_reset;
int ncommands;
u32 *commands;
};
struct tegra_bootrom_commands {
u32 command_retry_count;
u32 delay_between_commands;
u32 wait_before_bus_clear;
struct tegra_bootrom_block *blocks;
int nblocks;
};
static struct tegra_bootrom_commands *br_rst_commands;
static struct tegra_bootrom_commands *br_off_commands;
struct tegra_io_pad_soc {
enum tegra_io_pad id;
unsigned int dpd;
@@ -378,6 +424,7 @@ struct tegra_pmc_soc {
bool needs_mbist_war;
bool has_io_pad_wren;
bool maybe_tz_only;
bool has_bootrom_command;
const struct tegra_io_pad_soc *io_pads;
unsigned int num_io_pads;
@@ -419,6 +466,8 @@ struct tegra_pmc_soc {
bool has_usb_sleepwalk;
bool supports_core_domain;
bool has_single_mmio_aperture;
bool cboot_panic_notifier;
};
/**
@@ -505,6 +554,7 @@ struct tegra_pmc {
unsigned long *wake_cntrl_level_map;
struct notifier_block reboot_notifier;
struct notifier_block panic_notifier;
struct syscore syscore;
/* Pending wake IRQ processing */
@@ -523,7 +573,8 @@ to_powergate(struct generic_pm_domain *domain)
return container_of(domain, struct tegra_powergate, genpd);
}
static u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
// FIXME this prolly should not be public
u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
{
struct arm_smccc_res res;
@@ -544,6 +595,7 @@ static u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
return readl(pmc->base + offset);
}
EXPORT_SYMBOL(tegra_pmc_readl);
static void tegra_pmc_writel(struct tegra_pmc *pmc, u32 value,
unsigned long offset)
@@ -1310,21 +1362,10 @@ static int tegra_pmc_restart_handler(struct sys_off_data *data)
return NOTIFY_DONE;
}
static int tegra_pmc_power_off_handler(struct sys_off_data *data)
static int tegra_pmc_panic_handler(struct notifier_block *this,
unsigned long action, void *data)
{
struct tegra_pmc *pmc = data->cb_data;
/*
* Reboot Nexus 7 into special bootloader mode if USB cable is
* connected in order to display battery status and power off.
*/
if (of_machine_is_compatible("asus,grouper") &&
power_supply_is_system_supplied()) {
const u32 go_to_charger_mode = 0xa5a55a5a;
tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37);
tegra_pmc_restart(pmc);
}
tegra_pmc_writel(pmc, KERNEL_PANIC_MAGIC, PMC_SCRATCH37);
return NOTIFY_DONE;
}
@@ -1698,6 +1739,330 @@ static void tegra_powergate_remove_all(struct device_node *parent)
}
}
static int tegra_pmc_parse_bootrom_cmd(struct device *dev,
struct device_node *np,
struct tegra_bootrom_commands **br_cmds)
{
struct device_node *child;
struct tegra_bootrom_commands *bcommands;
int *command_ptr;
struct tegra_bootrom_block *block;
int nblocks;
u32 reg, data, pval;
u32 *wr_commands;
int count, nblock, ncommands, i, data_shift;
int ret;
int sz_bcommand, sz_blocks;
nblocks = of_get_available_child_count(np);
if (!nblocks) {
dev_info(dev, "PMC: No Bootrom Command\n");
return -ENOENT;
}
count = 0;
for_each_available_child_of_node(np, child) {
ret = of_property_count_u32_elems(child,
"nvidia,write-commands");
if (ret < 0) {
dev_err(dev, "PMC: Node %s does not have write-commnds\n",
child->full_name);
return -EINVAL;
}
count += ret / 2;
}
sz_bcommand = (sizeof(*bcommands) + 0x3) & ~0x3;
sz_blocks = (sizeof(*block) + 0x3) & ~0x3;
bcommands = devm_kzalloc(dev, sz_bcommand + nblocks * sz_blocks +
count * sizeof(u32), GFP_KERNEL);
if (!bcommands)
return -ENOMEM;
bcommands->nblocks = nblocks;
bcommands->blocks = (void *)bcommands + sz_bcommand;
command_ptr = (void *)bcommands->blocks + nblocks * sz_blocks;
of_property_read_u32(np, "nvidia,command-retries-count",
&bcommands->command_retry_count);
of_property_read_u32(np, "nvidia,delay-between-commands-us",
&bcommands->delay_between_commands);
ret = of_property_read_u32(np, "nvidia,wait-before-start-bus-clear-us",
&bcommands->wait_before_bus_clear);
if (ret < 0)
of_property_read_u32(np, "nvidia,wait-start-bus-clear-us",
&bcommands->wait_before_bus_clear);
nblock = 0;
for_each_available_child_of_node(np, child) {
block = &bcommands->blocks[nblock];
ret = of_property_read_u32(child, "reg", &pval);
if (ret) {
dev_err(dev, "PMC: Reg property missing on block %s\n",
child->name);
return ret;
}
block->address = pval;
of_property_read_string(child, "nvidia,command-names",
&block->name);
block->reg_8bits = !of_property_read_bool(child,
"nvidia,enable-16bit-register");
block->data_8bits = !of_property_read_bool(child,
"nvidia,enable-16bit-data");
block->i2c_controller = of_property_read_bool(child,
"nvidia,controller-type-i2c");
block->enable_reset = of_property_read_bool(child,
"nvidia,enable-controller-reset");
count = of_property_count_u32_elems(child,
"nvidia,write-commands");
ncommands = count / 2;
block->commands = command_ptr;
command_ptr += ncommands;
wr_commands = block->commands;
data_shift = (block->data_8bits) ? 8 : 16;
for (i = 0; i < ncommands; ++i) {
of_property_read_u32_index(child,
"nvidia,write-commands",
i * 2, &reg);
of_property_read_u32_index(child,
"nvidia,write-commands",
i * 2 + 1, &data);
wr_commands[i] = (data << data_shift) | reg;
}
block->ncommands = ncommands;
nblock++;
}
*br_cmds = bcommands;
return 0;
}
static int tegra_pmc_read_bootrom_cmd(struct device *dev,
struct tegra_bootrom_commands **br_rst_cmds,
struct tegra_bootrom_commands **br_off_cmds)
{
struct device_node *np = dev->of_node;
struct device_node *br_np, *rst_np, *off_np;
int ret;
*br_rst_cmds = NULL;
*br_off_cmds = NULL;
br_np = of_find_node_by_name(np, "bootrom-commands");
if (!br_np) {
dev_info(dev, "PMC: Bootrom commmands not found\n");
return -ENOENT;
}
rst_np = of_find_node_by_name(br_np, "reset-commands");
if (!rst_np) {
dev_info(dev, "PMC: bootrom-commands used for reset\n");
rst_np = br_np;
}
ret = tegra_pmc_parse_bootrom_cmd(dev, rst_np, br_rst_cmds);
if (ret < 0)
return ret;
if (rst_np == br_np)
return 0;
off_np = of_find_node_by_name(br_np, "power-off-commands");
if (!off_np)
return 0;
ret = tegra_pmc_parse_bootrom_cmd(dev, off_np, br_off_cmds);
if (ret < 0)
return ret;
return 0;
}
static int tegra_pmc_configure_bootrom_scratch(struct tegra_pmc *pmc,
struct tegra_bootrom_commands *br_commands,
struct tegra_br_cmd_cfg *bcfg, u32 bcfg_size)
{
struct tegra_bootrom_block *block;
int i, j, k;
u32 cmd, tmp_cmd;
int reg_offset = 1;
int bcfg_idx = 0;
u32 reg_data_mask, edit_data_mask;
int cmd_pw;
u32 block_add, block_val, csum;
for (i = 0; i < br_commands->nblocks; ++i) {
block = &br_commands->blocks[i];
cmd = block->address & PMC_BR_COMMAND_I2C_ADD_MASK;
cmd |= block->ncommands << PMC_BR_COMMAND_WR_COMMANDS_SHIFT;
if (!block->reg_8bits || !block->data_8bits)
cmd |= BIT(PMC_BR_COMMAND_OPERAND_SHIFT);
if (block->enable_reset)
cmd |= BIT(PMC_BR_COMMAND_RST_EN_SHIFT);
cmd |= (block->controller_id & PMC_BR_COMMAND_CTRL_ID_MASK) <<
PMC_BR_COMMAND_CTRL_ID_SHIFT;
/* Checksum will be added after parsing from reg/data */
tegra_pmc_writel(pmc, cmd, PMC_BR_COMMAND_BASE + (reg_offset * 4));
block_add = reg_offset * 4;
block_val = cmd;
reg_offset++;
cmd_pw = (block->reg_8bits && block->data_8bits) ? 2 : 1;
reg_data_mask = (cmd_pw == 2) ? 0xFFFF : 0xFFFFFFFFUL;
csum = 0;
for (j = 0; j < block->ncommands; j++) {
tmp_cmd = block->commands[j] & reg_data_mask;
if (bcfg_idx < bcfg_size &&
bcfg[bcfg_idx].dev == i &&
bcfg[bcfg_idx].idx == j) {
edit_data_mask = (cmd_pw == 2) ?
0xFF00UL : 0xFFFF0000UL;
tmp_cmd &= ~edit_data_mask;
tmp_cmd |= (bcfg[bcfg_idx].val <<
(cmd_pw == 2 ? 8 : 16)) & edit_data_mask;
bcfg_idx++;
}
cmd = tmp_cmd;
if (cmd_pw == 2) {
j++;
if (j == block->ncommands)
goto reg_update;
tmp_cmd = (block->commands[j] & reg_data_mask) << 16;
if (bcfg_idx < bcfg_size &&
bcfg[bcfg_idx].dev == i &&
bcfg[bcfg_idx].idx == j) {
edit_data_mask = 0xFF000000UL;
tmp_cmd &= ~edit_data_mask;
tmp_cmd |= (bcfg[bcfg_idx].val << 24) &
edit_data_mask;
bcfg_idx++;
}
cmd |= tmp_cmd;
}
reg_update:
tegra_pmc_writel(pmc, cmd, PMC_BR_COMMAND_BASE + (reg_offset * 4));
for (k = 0; k < 4; ++k)
csum += (cmd >> (k * 8)) & 0xFF;
reg_offset++;
}
for (k = 0; k < 4; ++k)
csum += (block_val >> (k * 8)) & 0xFF;
csum = 0x100 - csum;
block_val = (block_val & 0xFF00FFFF) | ((csum & 0xFF) << 16);
tegra_pmc_writel(pmc, block_val, PMC_BR_COMMAND_BASE + block_add);
}
cmd = br_commands->command_retry_count & 0x7;
cmd |= (br_commands->delay_between_commands & 0x1F) << 3;
cmd |= (br_commands->nblocks & 0x7) << 8;
cmd |= (br_commands->wait_before_bus_clear & 0x1F) << 11;
tegra_pmc_writel(pmc, cmd, PMC_BR_COMMAND_BASE);
return 0;
}
/**
* tegra_pmc_edit_bootrom_scratch_reset() - configure brom reset commands
* @pmc: power management controller
* @bcfg: bootrom command config structure
* @bcfg_size: size of bcfg
*
* Returns: 0 on success or a negative error code on failure.
*/
int tegra_pmc_edit_bootrom_scratch_reset(struct tegra_pmc *pmc,
struct tegra_br_cmd_cfg *bcfg, u32 bcfg_size)
{
if (br_rst_commands) {
tegra_pmc_configure_bootrom_scratch(pmc, br_rst_commands,
bcfg, bcfg_size);
return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL(tegra_pmc_edit_bootrom_scratch_reset);
static int tegra_pmc_init_bootrom_power_off_cmd(struct tegra_pmc *pmc)
{
int ret;
if (!br_off_commands) {
dev_info(pmc->dev, "PMC: Power Off Command not available\n");
return 0;
}
ret = tegra_pmc_configure_bootrom_scratch(pmc, br_off_commands, NULL, 0);
if (ret < 0) {
dev_err(pmc->dev, "PMC: Failed to configure power-off command: %d\n",
ret);
return ret;
}
dev_info(pmc->dev, "PMC: Successfully configure power-off commands\n");
return 0;
}
static int tegra_pmc_init_bootrom_cmds(struct tegra_pmc *pmc, struct device *dev)
{
int ret;
ret = tegra_pmc_read_bootrom_cmd(dev, &br_rst_commands,
&br_off_commands);
if (ret < 0) {
if (ret == -ENOENT)
ret = 0;
else
dev_info(dev,
"PMC: Failed to read bootrom cmd: %d\n", ret);
return ret;
}
ret = tegra_pmc_configure_bootrom_scratch(pmc, br_rst_commands, NULL, 0);
if (ret < 0) {
dev_info(dev, "PMC: Failed to write bootrom scratch register: %d\n",
ret);
return ret;
}
dev_info(dev, "PMC: Successfully configure bootrom reset commands\n");
return 0;
}
static int tegra_pmc_power_off_handler(struct sys_off_data *data)
{
struct tegra_pmc *pmc = data->cb_data;
if (br_off_commands) {
tegra_pmc_init_bootrom_power_off_cmd(pmc);
tegra_pmc_restart(pmc);
}
/*
* Reboot Nexus 7 into special bootloader mode if USB cable is
* connected in order to display battery status and power off.
*/
if (of_machine_is_compatible("asus,grouper") &&
power_supply_is_system_supplied()) {
const u32 go_to_charger_mode = 0xa5a55a5a;
tegra_pmc_writel(pmc, go_to_charger_mode, PMC_SCRATCH37);
tegra_pmc_restart(pmc);
}
return NOTIFY_DONE;
}
static const struct tegra_io_pad_soc *
tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
{
@@ -3182,6 +3547,9 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return dev_err_probe(&pdev->dev, PTR_ERR(pmc->clk),
"failed to get pclk\n");
if (pmc->soc->has_bootrom_command)
tegra_pmc_init_bootrom_cmds(pmc, &pdev->dev);
/*
* PMC should be last resort for restarting since it soft-resets
* CPU without resetting everything else.
@@ -3199,6 +3567,20 @@ static int tegra_pmc_probe(struct platform_device *pdev)
}
}
if (pmc->soc->cboot_panic_notifier) {
pmc->panic_notifier.notifier_call = tegra_pmc_panic_handler;
pmc->panic_notifier.priority = INT_MAX-1;
err = atomic_notifier_chain_register(&panic_notifier_list,
&pmc->panic_notifier);
if (err) {
dev_err(&pdev->dev,
"unable to register panic notifier, %d\n",
err);
return err;
}
}
err = devm_register_sys_off_handler(&pdev->dev,
SYS_OFF_MODE_RESTART,
SYS_OFF_PRIO_LOW,
@@ -3566,6 +3948,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.has_bootrom_command = false,
};
static const char * const tegra30_powergates[] = {
@@ -3628,6 +4011,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.has_bootrom_command = false,
};
static const char * const tegra114_powergates[] = {
@@ -3686,6 +4070,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.has_bootrom_command = false,
};
static const char * const tegra124_powergates[] = {
@@ -3838,6 +4223,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.has_bootrom_command = false,
};
static const char * const tegra210_powergates[] = {
@@ -4018,6 +4404,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.cboot_panic_notifier = true,
.has_bootrom_command = true,
};
static const char * const tegra210b01_powergates[] = {
@@ -4079,6 +4467,8 @@ static const struct tegra_pmc_soc tegra210b01_pmc_soc = {
.has_blink_output = true,
.has_usb_sleepwalk = true,
.has_single_mmio_aperture = true,
.cboot_panic_notifier = true,
.has_bootrom_command = true,
};
static const struct tegra_io_pad_soc tegra186_io_pads[] = {
+485
View File
@@ -0,0 +1,485 @@
/*
* Copyright (c) 2019, Ezekiel Bethel <zek@9net.org>
* Copyright (c) 2021-2022, CTCaer <ctcaer@gmail.com>
* Copyright (c) 2026 Thomas Makin <halorocker89@gmail.com>
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/firmware.h>
#include <linux/notifier.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <soc/tegra/pmc.h>
#define TEGRA_SIP_R2P_COPY_TO_IRAM 0xC2FFFE02u
#define R2P_WRITE_IRAM (0U << 0)
#define R2P_READ_IRAM (1U << 0)
#define TEGRA_SIP_R2P_DO_REBOOT 0xC2FFFE03u
#define TEGRA_SIP_R2P_SET_BIN_CFG 0xC2FFFE04u
#define IRAM_PAYLOAD_BASE 0x40010000u
#define IRAM_CHUNK_SIZE 0x4000
#define KERNEL_PANIC_MAGIC 0x4E415054
#define RTC_REBOOT_REASON_MAGIC 0x77
#define PMC_SCRATCH37 0x130
/* hekate/Nyx */
#define BOOT_CFG_AUTOBOOT_EN BIT(0)
#define BOOT_CFG_FROM_ID BIT(2)
#define EXTRA_CFG_NYX_UMS BIT(5)
#define EXTRA_CFG_NYX_RELOAD BIT(6)
enum {
NYX_UMS_SD_CARD = 0,
NYX_UMS_EMMC_BOOT0,
NYX_UMS_EMMC_BOOT1,
NYX_UMS_EMMC_GPP,
NYX_UMS_EMUMMC_BOOT0,
NYX_UMS_EMUMMC_BOOT1,
NYX_UMS_EMUMMC_GPP
};
enum {
REBOOT_REASON_NOP = 0, /* Use [config]. */
REBOOT_REASON_SELF = 1, /* Use autoboot_idx/autoboot_list. */
REBOOT_REASON_MENU = 2, /* Force menu. */
REBOOT_REASON_UMS = 3, /* Force selected UMS partition. */
REBOOT_REASON_REC = 4, /* Set PMC_SCRATCH0_MODE_RECOVERY and reboot to self. */
REBOOT_REASON_PANIC = 5 /* Inform bootloader that panic occured if T210B01. */
};
struct __attribute__((__packed__)) hekate_boot_cfg
{
u8 boot_cfg;
u8 autoboot;
u8 autoboot_list;
u8 extra_cfg;
union {
struct {
char id[8];
char emummc_path[0x78];
};
u8 ums;
u8 xt_str[0x80];
};
};
struct rtc_rr_dec
{
u16 reason:4;
u16 autoboot_idx:4;
u16 autoboot_list:1;
u16 ums_idx:3;
};
struct rtc_rr_enc
{
u16 val1:6; /* 6-bit reg. */
u16 val2:6; /* 6-bit reg. */
};
struct rtc_reboot_reason
{
union {
struct rtc_rr_dec dec;
struct rtc_rr_enc enc;
};
};
struct tegra_r2p_data
{
struct device *dev;
struct tegra_pmc *pmc;
struct notifier_block reboot_notifier;
char action[16];
int param1;
int param2;
char entry_id[8];
};
static int enabled = 0;
static int param1 = 0;
static int param2 = 0;
static char* action = NULL;
static char* entry_id = NULL;
module_param(enabled, int, 0664);
module_param(action, charp, 0664);
module_param(param1, int, 0664);
module_param(param2, int, 0664);
module_param(entry_id, charp, 0664);
MODULE_PARM_DESC(enabled, "Enable Reboot 2 Payload function");
MODULE_PARM_DESC(action, "Reboot action to take");
MODULE_PARM_DESC(param1, "Autoboot entry or UMS device index");
MODULE_PARM_DESC(param2, "Autooboot entry is ini list");
MODULE_PARM_DESC(entry_id, "Autoboot entry id");
struct platform_device *r2p_device = NULL;
static u32 tegra_r2p_set_cfg(struct hekate_boot_cfg *hekate_bcfg)
{
struct arm_smccc_res res;
u64 hekate_boot_smc_cfg[4];
memcpy(hekate_boot_smc_cfg, hekate_bcfg, sizeof(hekate_boot_smc_cfg));
arm_smccc_smc(TEGRA_SIP_R2P_SET_BIN_CFG, hekate_boot_smc_cfg[0], hekate_boot_smc_cfg[1],
hekate_boot_smc_cfg[2], hekate_boot_smc_cfg[3], 0, 0, 0, &res);
return (u32)res.a1;
}
static void tegra_r2p_setup(struct tegra_r2p_data *state, const char *cmd)
{
struct rtc_reboot_reason rr = {};
struct hekate_boot_cfg hekate_bcfg = {};
struct tegra_pmc *pmc = state->pmc;
uint32_t reboot_reason = REBOOT_REASON_NOP;
bool tegra210b01 = of_device_is_compatible(state->dev->of_node, "nvidia,tegra210b01-r2p");
u32 panic_code = tegra_pmc_readl(pmc, PMC_SCRATCH37);
bool panic_occurred = (panic_code == KERNEL_PANIC_MAGIC);
if (r2p_device == NULL) {
dev_err(&r2p_device->dev, "r2p device is null\n");
return;
}
/* Linux reboot reason */
if (cmd) {
if (!strcmp(cmd, "recovery")) {
reboot_reason = REBOOT_REASON_REC;
} else if (!strcmp(cmd, "bootloader")) {
reboot_reason = REBOOT_REASON_MENU;
} else if (!strcmp(cmd, "forced-recovery")) { /* RCM */
if (tegra210b01) return;
} else {
dev_err(&r2p_device->dev,
"Command '%s' not recognized\n", cmd);
}
}
/* Missing reboot reason or not matching, use r2p action. */
if (reboot_reason == REBOOT_REASON_NOP && strlen(state->action)) {
if (!strcmp(state->action, "self") ||
!strcmp(state->action, "via-payload")) { /* Deprecated */
reboot_reason = REBOOT_REASON_SELF;
} else if (!strcmp(state->action, "bootloader")) {
reboot_reason = REBOOT_REASON_MENU;
} else if (!strcmp(state->action, "ums")) {
reboot_reason = REBOOT_REASON_UMS;
} else if (!strcmp(state->action, "normal")) {
reboot_reason = REBOOT_REASON_NOP;
} else {
dev_err(&r2p_device->dev,
"Action '%s' not recognized\n", state->action);
}
}
/* If T210B01 and panic happened override reboot reason */
if (tegra210b01 && panic_occurred) {
reboot_reason = REBOOT_REASON_PANIC;
}
/* Prepare boot config data */
switch (reboot_reason) {
case REBOOT_REASON_NOP:
if (tegra210b01) return;
break;
case REBOOT_REASON_REC:
case REBOOT_REASON_SELF:
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
if (strlen(state->entry_id) != 0) {
hekate_bcfg.boot_cfg |= BOOT_CFG_FROM_ID;
strcpy(hekate_bcfg.id, state->entry_id);
}
hekate_bcfg.autoboot = state->param1;
hekate_bcfg.autoboot_list = state->param2;
rr.dec.reason = reboot_reason;
rr.dec.autoboot_idx = state->param1;
rr.dec.autoboot_list = state->param2;
break;
case REBOOT_REASON_MENU:
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
rr.dec.reason = reboot_reason;
break;
case REBOOT_REASON_UMS:
hekate_bcfg.boot_cfg = BOOT_CFG_AUTOBOOT_EN;
hekate_bcfg.extra_cfg = EXTRA_CFG_NYX_UMS;
hekate_bcfg.ums = state->param1;
rr.dec.reason = reboot_reason;
rr.dec.ums_idx = state->param1;
break;
case REBOOT_REASON_PANIC:
rr.dec.reason = reboot_reason;
break;
}
/* Notify TZ to use its preloaded payload */
if (!tegra210b01) {
/* Set hekate boot config. */
tegra_r2p_set_cfg(&hekate_bcfg);
} else {
struct tegra_br_cmd_cfg bcfg[4] = {
{ 0, 0, rr.enc.val1 },
{ 0, 1, rr.enc.val2 },
{ 0, 2, RTC_REBOOT_REASON_MAGIC },
{ 0, 3, RTC_REBOOT_REASON_MAGIC }
};
tegra_pmc_edit_bootrom_scratch_reset(pmc, bcfg, 4);
}
}
static int tegra_r2p_reboot_notify(struct notifier_block *this,
unsigned long action, void *data)
{
struct tegra_r2p_data *state = container_of(this, struct tegra_r2p_data,
reboot_notifier);
if (action == SYS_RESTART)
tegra_r2p_setup(state, data);
return NOTIFY_DONE;
}
static ssize_t action_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
int res;
if (strlen(state->action))
res = sprintf(buf, "%s\n", state->action);
else
res = sprintf(buf, "Not-set\n");
return res;
}
static ssize_t action_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
if (count > sizeof(state->action) - 1)
return -EINVAL;
strncpy(state->action, buf, sizeof(state->action) - 1);
state->action[sizeof(state->action) - 1] = 0;
/* Strip newline if it exists */
if (state->action[count - 1] == '\n')
state->action[count - 1] = 0;
return count;
}
static ssize_t entry_id_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
int res;
if (strlen(state->entry_id))
res = sprintf(buf, "%s\n", state->entry_id);
else
res = sprintf(buf, "Not-set\n");
return res;
}
static ssize_t entry_id_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
if (count > sizeof(state->entry_id) - 1)
return -EINVAL;
strncpy(state->entry_id, buf, sizeof(state->entry_id) - 1);
state->entry_id[sizeof(state->entry_id) - 1] = 0;
/* Strip newline if it exists */
if (state->entry_id[count - 1] == '\n')
state->entry_id[count - 1] = 0;
return count;
}
static ssize_t param1_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
return sprintf(buf, "%d\n", (int)state->param1);
}
static ssize_t param1_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
ssize_t res;
long value;
res = kstrtol(buf, 0, &value);
if (!res)
state->param1 = value;
return res ? res : count;
}
static ssize_t param2_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
return sprintf(buf, "%d\n", (int)state->param2);
}
static ssize_t param2_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct tegra_r2p_data *state = dev_get_drvdata(&r2p_device->dev);
ssize_t res;
long value;
res = kstrtol(buf, 0, &value);
if (!res)
state->param2 = value;
return res ? res : count;
}
static DEVICE_ATTR_RW(action);
static DEVICE_ATTR_RW(entry_id);
static DEVICE_ATTR_RW(param1);
static DEVICE_ATTR_RW(param2);
static struct attribute *r2p_sysfs_attrs[] = {
&dev_attr_action.attr,
&dev_attr_entry_id.attr,
&dev_attr_param1.attr,
&dev_attr_param2.attr,
NULL,
};
ATTRIBUTE_GROUPS(r2p_sysfs);
static int tegra_r2p_driver_probe(struct platform_device *pdev)
{
struct tegra_r2p_data *state;
struct tegra_pmc *pmc;
int err;
if (!enabled)
return 0;
r2p_device = pdev;
state = devm_kzalloc(&pdev->dev, sizeof(struct tegra_r2p_data), GFP_KERNEL);
/* Use nvidia,pmc to specify */
pmc = devm_tegra_pmc_get(&pdev->dev);
if (IS_ERR(pmc)) {
dev_err(&pdev->dev, "failed to get PMC\n");
return -EPROBE_DEFER;
}
/* Copy reboot action if valid */
if (action) {
strncpy(state->action, action, sizeof(state->action) - 1);
state->action[sizeof(state->action) - 1] = 0;
}
/* Copy entry ID if valid */
if (entry_id) {
strncpy(state->entry_id, entry_id, sizeof(state->entry_id) - 1);
state->entry_id[sizeof(state->entry_id) - 1] = 0;
}
/* Set reboot reason parameters. */
state->param1 = param1;
state->param2 = param2;
state->dev = &pdev->dev;
state->pmc = pmc;
dev_set_drvdata(&pdev->dev, state);
err = sysfs_create_groups(&pdev->dev.kobj, r2p_sysfs_groups);
if (err) {
dev_err(&pdev->dev, "sysfs creation failed\n");
return err;
}
state->reboot_notifier.notifier_call = tegra_r2p_reboot_notify;
err = devm_register_reboot_notifier(&pdev->dev,
&state->reboot_notifier);
if (err) {
dev_err(&pdev->dev,
"unable to register reboot notifier, %d\n",
err);
return err;
}
return 0;
}
static const struct of_device_id tegra_r2p_match[] = {
{ .compatible = "nvidia,tegra124-r2p", },
{ .compatible = "nvidia,tegra210-r2p", },
{ .compatible = "nvidia,tegra210b01-r2p", },
{ }
};
MODULE_DEVICE_TABLE(of, tegra_r2p_match);
static struct platform_driver tegra_r2p_driver = {
.probe = tegra_r2p_driver_probe,
.driver = {
.name = "tegra-r2p",
.owner = THIS_MODULE,
.of_match_table = tegra_r2p_match
},
};
static int __init tegra_r2p_init(void)
{
return platform_driver_register(&tegra_r2p_driver);
}
core_initcall(tegra_r2p_init);
static void __exit tegra_r2p_exit(void)
{
platform_driver_unregister(&tegra_r2p_driver);
}
module_exit(tegra_r2p_exit);
MODULE_AUTHOR("Thomas Makin <halorocker89@gmail.com>");
MODULE_DESCRIPTION("Reboot2Payload driver for Tegra124/210/210b01");
MODULE_LICENSE("GPL v2");
+10
View File
@@ -280,6 +280,15 @@
#define MAX77620_CNFGBBC_RESISTOR_MASK 0xC0
#define MAX77620_CNFGBBC_RESISTOR_SHIFT 6
#define MAX77620_IRQ_ONOFF_MRWRN_MASK BIT(0)
#define MAX77620_IRQ_ONOFF_EN0_1SEC_MASK BIT(1)
#define MAX77620_IRQ_ONOFF_EN0_F_MASK BIT(2)
#define MAX77620_IRQ_ONOFF_EN0_R_MASK BIT(3)
#define MAX77620_IRQ_ONOFF_LID_F_MASK BIT(4)
#define MAX77620_IRQ_ONOFF_LID_R_MASK BIT(5)
#define MAX77620_IRQ_ONOFF_ACOK_F_MASK BIT(6)
#define MAX77620_IRQ_ONOFF_ACOK_R_MASK BIT(7)
#define MAX77620_FPS_COUNT 3
/* Interrupts */
@@ -340,6 +349,7 @@ struct max77620_chip {
struct regmap_irq_chip_data *top_irq_data;
struct regmap_irq_chip_data *gpio_irq_data;
struct regmap_irq_chip_data *onoff_irq_data;
};
#endif /* _MFD_MAX77620_H_ */
+23
View File
@@ -149,6 +149,12 @@ enum tegra_io_pad {
TEGRA_IO_PAD_AO_HV,
};
struct tegra_br_cmd_cfg {
u32 dev;
u32 idx;
u32 val;
};
#ifdef CONFIG_SOC_TEGRA_PMC
struct tegra_pmc *devm_tegra_pmc_get(struct device *dev);
@@ -156,6 +162,10 @@ int tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id);
int tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id);
int tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id);
int tegra_pmc_edit_bootrom_scratch_reset(struct tegra_pmc *pmc,
struct tegra_br_cmd_cfg *bcfg, u32 bcfg_size);
u32 tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset);
/* Must be called with clk disabled, and returns with clk enabled */
int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
unsigned int id, struct clk *clk,
@@ -212,6 +222,19 @@ tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc, unsigned int id,
return -ENOSYS;
}
static inline int
tegra_pmc_edit_bootrom_scratch_reset(struct tegra_pmc *pmc,
struct tegra_br_cmd_cfg *bcfg, u32 bcfg_size)
{
return -ENOSYS;
}
static inline u32
tegra_pmc_readl(struct tegra_pmc *pmc, unsigned long offset)
{
return -ENOSYS;
}
static inline int
tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id)
{