Compare commits

...
Sign in to create a new pull request.

154 commits

Author SHA1 Message Date
Jami Kettunen
f54c5a81d5 fixup! arm64: dts: qcom: pmi8998: introduce spmi haptics 2022-05-16 20:18:29 +03:00
Jami Kettunen
c201f7d26b Revert "arm64: dts: qcom: msm8998-oneplus-common: Enable PMI8998 LPG leds"
This reverts commit d4bdb023ec13680afef836f59bfa8ca075a32682.
2022-05-16 20:18:29 +03:00
Konrad Dybcio
680f1d767f arm64: dts: qcom: msm8998: Add CAMSS nodes
Add nodes required to enable the camera subsystem.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:29 +03:00
Konrad Dybcio
fd75235407 arm64: dts: qcom: msm8998-oneplus: Add clocks & GDSC to simplefb
This is required to keep the display working with MMCC enabled until proper
panel support is in place.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:29 +03:00
Jami Kettunen
8d776b6bac arm64: dts: qcom: msm8998-oneplus-common: MMCC & MMSS_SMMU are enabled by default 2022-05-16 20:18:28 +03:00
Konrad Dybcio
173c4490d8 arm64: dts: qcom: msm8998*: Keep MMCC & MMSS_SMMU enabled by default
MMCC is a component of the SoC that should always be configured. It was kept
off due to misconfiguration on clamshell machines. Keep it disabled on these
ones and enable it by default on all the others.

Exactly the same story applies to MMSS_SMMU, which directly depends on MMCC.

Do note, that if a platform doesn't use neither EFIFB (only applies to WoA
devices in this case) or simplefb (applies to precisely 2 msm8998 devices
as of this commit), this will not cause any harm.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Jami Kettunen
a7034253a6 arm64: dts: qcom: msm8998-fxtec-pro1: s/"ok"/"okay"/g 2022-05-16 20:18:28 +03:00
Konrad Dybcio
a783ac0fc4 arm64: dts: qcom: msm8998-fxtek: Use "okay" instead of "ok"
This is the standard way.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
d004d65932 arm64: dts: qcom: msm8998-oneplus: Apply style fixes
Add some newlines, reorder some properties, remove some indentation to make
it more coherent.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
b9e6959f24 arm64: dts: qcom: msm8998-yoshino/oneplus: Use pm8005_regulators label
Now that a label is added, use it!

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
7006984173 arm64: dts: qcom: msm8998-yoshino: Remove simple-bus compatible from clocks{}
It's not necessary and the SoC clocks{} node doesn't use it either.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
81a6a3d1bf arm64: dts: qcom: msm8998-yoshino: Add USB extcon
While not strictly necessary, at least on maple, configure the USB extcon,
which requires two pins on Yoshino.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
a49ab17ef3 arm64: dts: qcom: msm8998-yoshino-lilac: Disable LVS1
It's disabled on downstream, follow it.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
8e7009c6a4 arm64: dts: qcom: msm8998-laptops: Clean up DTs
Reorder properties to match new laptop DTs, change hex to dec.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
36188aab1f arm64: dts: qcom: msm8998-clamshell: Clean up the DT
Keep the nodes and includes in order, clean up unnecessary properties & nodes.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
79b8204136 arm64: dts: qcom: msm8998*: Fix TLMM and pin nodes
Remove the unnecessary level of indentation, commonize SDC2 pins and notice
that SDCC2_CD_ON and _OFF is identical, deduplicate it!

Also, remove some unnecessary overrides and use decimal values in #-cells

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Konrad Dybcio
1d1e07f6b2 arm64: dts: qcom: msm8998-yoshino: Fix up SMD regulators formatting
Add a new line between each subnode and make the { } consistent.

Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:28 +03:00
Jami Kettunen
9d8a4cd664 [HACK] pmi8998 + msm8998-fxtec-pro1: drop pmi8998 fg entirely
TODO: verify that it cannot stay even as disabled in DT and still steals
the plugin IRQ from spmi-pmi8998-charger
2022-05-16 20:18:28 +03:00
Jami Kettunen
318a800f50 arm64: dts: msm8998-oneplus-common: enable SMB2 2022-05-16 20:18:28 +03:00
Jami Kettunen
fb500c1463 arm64: dts: qcom: msm8998-oneplus-common: add simple-battery 2022-05-16 20:18:28 +03:00
Jami Kettunen
51a255f60c arm64: dts: qcom: msm8998-oneplus-common: enable RRADC 2022-05-16 20:18:28 +03:00
Caleb Connolly
9543d37c57 REVERT series: soundwire: qcom: add pm runtime support
This series breaks audio on sdm845 form factor

Reverts commits:
- 04d46a7b38
- c7449e766d
- 74e79da9fd
2022-05-16 20:18:28 +03:00
Caleb Connolly
1cc9b8629e dt-bindings: power: supply: qcom,pmi8998-charger: add bindings for smb2 driver
Add devicetree bindings for the Qualcomm PMI8998/PM660 SMB2 charger
driver.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
aa70e83fb2 arm64: dts: qcom: pmi8998: add charger node
Add a node for the smb2 charger hardware found on the pmi8998.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
2f2877c67d power: supply: add Qualcomm PMI8998 SMB2 Charger driver
Add a driver for the SMB2 charger block found in the Qualcomm PMI8998
and PM660.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
1e8ea2a6f8 arm64: dts: qcom: pmi8998: add rradc node
Add a DT node for the Round Robin ADC found in the PMI8998 PMIC.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
9be0b9b432 iio: adc: qcom-spmi-rradc: introduce round robin adc
The Round Robin ADC is responsible for reading data about the rate of
charge from the USB or DC input ports, it can also read the battery
ID (resistence), skin temperature and the die temperature of the pmic.
It is found on the PMI8998 and PM660 Qualcomm PMICs.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2022-05-16 20:18:27 +03:00
Caleb Connolly
36a4f8b5ab dt-bindings: iio: adc: document qcom-spmi-rradc
Add dt-binding docs for the Qualcomm SPMI RRADC found in PMICs like
PMI8998 and PMI8994

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
2022-05-16 20:18:27 +03:00
Caleb Connolly
9d74954c83 mfd: qcom-spmi-pmic: read fab id on supported PMICs
The PMI8998 and PM660 expose the fab_id, this is needed by drivers like
the RRADC to calibrate ADC values.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
375e601b0f mfd: qcom-spmi-pmic: expose the PMIC revid information to clients
Some PMIC functions such as the RRADC need to be aware of the PMIC
chip revision information to implement errata or otherwise adjust
behaviour, export the PMIC information to enable this.

This is specifically required to enable the RRADC to adjust
coefficients based on which chip fab the PMIC was produced in,
this can vary per unique device and therefore has to be read at
runtime.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
2022-05-16 20:18:27 +03:00
Caleb Connolly
14240e555b spmi: add a helper to look up an SPMI device from a device node
The helper function spmi_device_from_of() takes a device node and
returns the SPMI device associated with it.
This is like of_find_device_by_node but for SPMI devices.

Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
2022-05-16 20:18:27 +03:00
Jami Kettunen
3b731c58f7 arm64: dts: qcom: msm8998-oneplus-common: s/"ok"/"okay"/g
This is the correct and documented way to enable nodes.
2022-05-16 20:18:27 +03:00
Jami Kettunen
32955e5311 [SUBMITME] arm64: dts: qcom: msm8998-oneplus-common: Add fuel gauge
The OnePlus 5/5T feature a BQ27411 fuel gauge for reading the battery
stats.
2022-05-16 20:18:27 +03:00
Jami Kettunen
e6fe8a2939 [TEMP] oneplus5: disable all speaker amp stuff
We don't want to blow this up while messing around with audio stuff
early on...
2022-05-16 20:18:27 +03:00
Jami Kettunen
a9d8059e3b arm64: dts: msm8998-oneplus-common: Add TFA9890 speaker amp bindings 2022-05-16 20:18:27 +03:00
Jami Kettunen
bd3638e5f0 arm64: dts: qcom: msm8998-oneplus-common: Enable PMI8998 LPG leds
Now the RGB notification LEDs can each be controlled individually :)
2022-05-16 20:18:27 +03:00
Jami Kettunen
e5c0aa04db [SUBMITME?] msm8998-oneplus-common: Configure Adreno 540 GPU 2022-05-16 20:18:27 +03:00
Jami Kettunen
bb71e33188 arm64: dts: qcom: msm8998-oneplus-common: Add ctl-no-start-read-quirk 2022-05-16 20:18:27 +03:00
Jami Kettunen
c049527d36 [SUBMITME?] arm64: dts: msm8998-oneplus-*: Configure S6E3FA5 & S6E3FC1 panels
These Samsung DSI panels are used on the OnePlus 5/5T respectively.
Additionally disable simplefb until a proper handoff solution can be
found to avoid conflicts between it and the MSM DRM driver.
2022-05-16 20:18:27 +03:00
Jami Kettunen
0dae5b9129 msm8998-oneplus-common: Configure IPA for cellular data 2022-05-16 20:18:27 +03:00
Jami Kettunen
528a4b5597 msm8998-oneplus-common: Configure CPUfreq scaling hardware 2022-05-16 20:18:26 +03:00
Jami Kettunen
f971394e75 arm64: dts: msm8998-oneplus-cheeseburger: Configure RMI4 F1A buttons
This allows the capacitive buttons below the touchscreen to be used on
e.g. Android normally :)
2022-05-16 20:18:26 +03:00
Jami Kettunen
a4158002db [SUBMITME?] msm8998-oneplus-common: Add remoteproc configuration & enable WLAN 2022-05-16 20:18:26 +03:00
Jami Kettunen
85f736137c [DROPME?] msm8998-oneplus-common: Configure blsp1_i2c5_sleep (TS) as no-pull 2022-05-16 20:18:26 +03:00
Jami Kettunen
89dc9c799f [SUBMITME?] dt-bindings: display: panel: Document Samsung S6E3FC1 display panel 2022-05-16 20:18:26 +03:00
Jami Kettunen
9127f7a0d2 [SUBMITME?] drm/panel: Add panel driver for Samsung S6E3FC1
The S6E3FC1 is 6" 1080x2160 MIPI DSI command mode AMOLED LCD display
found on OnePlus 5T (2017) smartphones.

The panel needs to be enabled from a device tree using the
"samsung,s6e3fc1" compatible.

This driver was generated using the following & includes some minor
cleanup (such as s/to_s6e3fc1/to_s6e3fc1_panel/g):
$ python3 lmdpdg.py dumpling.dtb -r vddio
2022-05-16 20:18:26 +03:00
Jami Kettunen
073b2ec6c5 [SQUASHME?] drm/panel: s6e3fa5: Read panel orientation
The panel is mounted upside down on the OnePlus 5, so we need to handle
this in the driver.
2022-05-16 20:18:26 +03:00
Jami Kettunen
ab0646be5b [SUBMITME?] arm64: dts: msm8998-oneplus-common: Drop unused regulators
Also comment the used ones.
2022-05-16 20:18:26 +03:00
Jami Kettunen
cc6ae8f741 [SUBMITME?] dt-bindings: display: panel: Document Samsung S6E3FA5 display panel 2022-05-16 20:18:26 +03:00
Jami Kettunen
b35fa76ebe arm64: qcom: msm8998-oneplus-common: Enable NFC 2022-05-16 20:18:26 +03:00
Jami Kettunen
a93aa446f0 [SUBMITME?] drm/panel: Add panel driver for Samsung S6E3FA5
The S6E3FA5 is 5.5" 1080x1920 MIPI DSI command mode AMOLED LCD display
found on OnePlus 5 (2017) smartphones.

The panel needs to be enabled from a device tree using the
"samsung,s6e3fa5" compatible.

This driver was generated using the following & includes some minor
cleanup (such as s/to_s6e3fa5/to_s6e3fa5_panel/g):
$ python3 lmdpdg.py cheeseburger.dtb -r vddio

Signed-off-by: Jami Kettunen <jami.kettunen@protonmail.com>
2022-05-16 20:18:26 +03:00
Jami Kettunen
8c162c7b1d arm64: dts: qcom: msm8998-oneplus-common: Enable PMI8998 LPG leds
Now the RGB notification LEDs can each be controlled individually :)
2022-05-16 20:18:26 +03:00
Jami Kettunen
6446c2488c [ANNOTATION] Apply some F(x)tec Pro1 patches 2022-05-16 20:18:26 +03:00
Danct12
2404fb068e arm64: dts: msm8998-fxtec-pro1: Add remoteproc configuration 2022-05-16 20:18:26 +03:00
Danct12
24031dc19e arm64: dts: msm8998-fxtec-pro1: Enable PMI8998 haptics 2022-05-16 20:18:26 +03:00
Danct12
fca28b5db3 arm64: dts: msm8998-fxtec-pro1: Configure PMI8998 fuel gauge
This will account for battery statistics reporting on the Fxtec Pro1 (QX1000)
2022-05-16 20:18:26 +03:00
Jami Kettunen
7c7e9fa734 pinctrl: Fix compilation of Awinic AW9523/B I2C GPIO Expander
Fixes the following link-time error:

    LD      .tmp_vmlinux.kallsyms1
  aarch64-linux-gnu-ld: Unexpected GOT/PLT entries detected!
  aarch64-linux-gnu-ld: Unexpected run-time procedure linkages detected!
  aarch64-linux-gnu-ld: drivers/pinctrl/pinctrl-aw9523.o: in function `aw9523_probe':
  .../drivers/pinctrl/pinctrl-aw9523.c:1004: undefined reference to `__devm_regmap_init_i2c'
  make[1]: *** [.../Makefile:1155: vmlinux] Error 1

Fixes: 96e86abbb4 ("pinctrl: Add driver for Awinic AW9523/B I2C GPIO Expander")
2022-05-16 20:18:26 +03:00
Jami Kettunen
c9d78cf41e [HACK] pinctrl: aw9523: Add workaround for F(x)tec Pro1 keyboard
This is a hack because the correct interrupt type(s) should should be
defined in msm8998-fxtec-pro1.dts instead of the driver.

(originally from Danct12)

This is a workaround for keyboard not working on Fxtec Pro1.

  genirq: Setting trigger mode 12 for irq 123 failed (aw9523_gpio_irq_type+0x0/0x20)
  gpio-fastmatrix-keyboard gpio-keyboard: Cannot get IRQ for gpio302
2022-05-16 20:18:25 +03:00
Jami Kettunen
95a3ce8e8d [ANNOTATION] Apply miscellaneous hacks and patches 2022-05-16 20:18:25 +03:00
Jami Kettunen
1078cd7bd2 [SUBMITME?] drm/msm: Add ctl_no_start_read_quirk for MSM8998 2022-05-16 20:18:25 +03:00
Jami Kettunen
c7a4d28052 module: demote invalid ELF header magic error message to pr_debug
This happens anytime busybox modprobe loads a compressed module and
looks especially ugly on postmarketOS for example (or basically any
initramfs); this error is rather pointless since the module is loaded
anyway afterwards.

Upstream (busybox) has no plans to do anything about this error getting
spammed:
https://www.mail-archive.com/busybox@busybox.net/msg27078.html
2022-05-16 20:18:25 +03:00
Jami Kettunen
781749a1d5 ASoC: codecs: tfa989x: Add support for tfa9890
This speaker amp model appears to be rather popular on phones and is
used for example by the OnePlus 5/5T.
2022-05-16 20:18:25 +03:00
Jami Kettunen
b3ed1c0268 [SUBMITME?] Input: synaptics-rmi4 - add support for F1A
RMI4 F1A supports the simple capacitive buttons function, it's used for
example on embedded devices such as smartphones for capacitive Android
back and recents buttons.
2022-05-16 20:18:25 +03:00
Jami Kettunen
8c70dec901 [SUBMITME] drm/msm: add missing a540 MODULE_FIRMWARE declarations 2022-05-16 20:18:25 +03:00
Bjorn Andersson
66839f23bc arm64: dts: qcom: Add LPG to pmi8998
Add PWM/LPG nodes to the PMICs currently supported by the binding.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
(JAMI: fixed up for v5.16-rc1, dropped pm*8994 & pm8916)
2022-05-16 20:18:25 +03:00
Jami Kettunen
ba9b32de5c arm64: dts: qcom: msm8998: add IPA information
Add support for the MSM8998 SoC, which includes IPA version 3.1.
2022-05-16 20:18:25 +03:00
Jami Kettunen
82d44416f3 [SUBMITME?] drm/msm: Mention DSI 10nm PHY support for MSM8998 2022-05-16 20:18:25 +03:00
Jami Kettunen
3cfa2d8875 [SUBMITME] dt-bindings: Document bindings for all MSM8998 devices 2022-05-16 20:18:25 +03:00
Jami Kettunen
f705e0eaf0 [HACK] net: ipa: Disable automatic suspend
1aac309d32 ("net: ipa: use autosuspend") currently causes my device to
enter 900E crashdump mode as soon as IPA is probed :/

With this we at least can run ModemManager once again...
2022-05-16 20:18:25 +03:00
Jami Kettunen
fd25347f1d [HACK] [SUBMITME?] ath10k: Fake MSA ready event after event server arrival
This finally allowed me to get past the 2 ath10k_info()'s in qmi.c!

However, this doesn't fix everything; it seems you *have* to run
diag-router from https://github.com/andersson/diag to calm the firmware
down and stop constantly crashing; need to look into a way to get Wi-Fi
working later without needing this debug crap to be running.

This should possible be submitted as a quirk to the ath10k driver as
modem on mainline 8998 should be running now as well...
2022-05-16 20:18:25 +03:00
Jami Kettunen
4056ae0297 [HACK] drm: Don't WARN_ON() drm_connector_set_panel_orientation() call
This method is used by OnePlus 5 (cheeseburger) during
s6e3fa5_get_modes() and calling it here (which is what all other panel
drivers seem to do as well) causes a massively long 140-line stacktrace
for the 2 hit WARN_ON()s:

  ------------[ cut here ]------------
  WARNING: CPU: 5 PID: 103 at drivers/gpu/drm/drm_mode_object.c:45 drm_mode_object_add+0x80/0x90
  Modules linked in: hci_uart apr fastrpc msm pdr_interface qrtr_smd btqca bluetooth gpu_sched nxp_nci_i2c nxp_nci nci drm_kms_helper nfc rmi_i2c rmi_core ecdh_generic ecc libaes ath10k_snoc ath10k_core cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea ath i2c_qup msm_serial serial_core mac80211 libarc4 sha256_generic libsha256 leds_qcom_lpg cfg80211 led_class_multicolor qcom_fg rtc_pm8xxx ipa qrtr qcom_q6v5_mss qcom_q6v5_pas qcom_stats qcom_pil_info qcom_q6v5 qcom_sysmon qcom_common qcom_smd mdt_loader qmi_helpers smp2p rpmsg_char leds_gpio evdev led_class rmtfs_mem qcom_hwspinlock rfkill dm_mod uinput loop
  CPU: 5 PID: 103 Comm: kworker/u16:5 Tainted: G        W         5.17.0-rc5-msm8998 #7
  Hardware name: OnePlus 5 (DT)
  Workqueue: events_unbound deferred_probe_work_func
  pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
  pc : drm_mode_object_add+0x80/0x90
  lr : drm_property_create+0xd4/0x190
  sp : ffffff808193b210
  x29: ffffff808193b210 x28: 0000000000000020 x27: 0000000000001000
  x26: 0000000000001000 x25: 0000000000000001 x24: ffffffc0087f1f78
  x23: ffffffc008833928 x22: 0000000000000004 x21: 00000000b0b0b0b0
  x20: ffffff8088570b90 x19: ffffff8084b26000 x18: 00000000fffffffb
  x17: 0000007a00440000 x16: 0000000000000000 x15: 0000000000000020
  x14: ffffffffffffffff x13: ffffff8088570b70 x12: ffffff8088570b55
  x11: 0000000000000000 x10: 0000000000000078 x9 : 0000000000000000
  x8 : ffffff8088570c80 x7 : 0000000000000000 x6 : 000000000000003f
  x5 : 0000000000000040 x4 : 0000000000000000 x3 : 0000000000000004
  x2 : 00000000b0b0b0b0 x1 : ffffff8088570b90 x0 : 0000000000000001
  Call trace:
   drm_mode_object_add+0x80/0x90
   drm_property_create+0xd4/0x190
   drm_property_create_enum+0x28/0x90
   drm_connector_set_panel_orientation+0x8c/0xb0
   s6e3fa5_get_modes+0x64/0x80
   drm_panel_get_modes+0x20/0x40
   dsi_mgr_connector_get_modes+0x28/0x40 [msm]
   drm_helper_probe_single_connector_modes+0x19c/0x770 [drm_kms_helper]
   drm_client_modeset_probe+0x1a4/0x1144
   __drm_fb_helper_initial_config_and_unlock+0x30/0x500 [drm_kms_helper]
   drm_fb_helper_initial_config+0x44/0x50 [drm_kms_helper]
   msm_fbdev_init+0x84/0xec [msm]
   msm_drm_bind+0x51c/0x5e0 [msm]
   try_to_bring_up_master+0x218/0x300
   __component_add+0x9c/0x180
   component_add+0x10/0x1c
   dsi_dev_attach+0x1c/0x24 [msm]
   dsi_host_attach+0x90/0x140 [msm]
   mipi_dsi_attach+0x24/0x34
   s6e3fa5_probe+0x10c/0x1cc
   mipi_dsi_drv_probe+0x1c/0x24
   really_probe+0x1b0/0x430
   __driver_probe_device+0x10c/0x180
   driver_probe_device+0x3c/0xf0
   __device_attach_driver+0x94/0x120
   bus_for_each_drv+0x64/0xa0
   __device_attach+0xa8/0x19c
   device_initial_probe+0x10/0x20
   bus_probe_device+0x90/0xa0
   device_add+0x364/0x83c
   mipi_dsi_device_register_full+0xc4/0x150
   mipi_dsi_host_register+0xb8/0x14c
   msm_dsi_host_register+0x3c/0x54 [msm]
   msm_dsi_manager_register+0x144/0x260 [msm]
   dsi_dev_probe+0x124/0x1a4 [msm]
   platform_probe+0x64/0xcc
   really_probe+0x1b0/0x430
   __driver_probe_device+0x10c/0x180
   driver_probe_device+0x3c/0xf0
   __device_attach_driver+0x94/0x120
   bus_for_each_drv+0x64/0xa0
   __device_attach+0xa8/0x19c
   device_initial_probe+0x10/0x20
   bus_probe_device+0x90/0xa0
   deferred_probe_work_func+0x9c/0xf0
   process_one_work+0x1d0/0x350
   worker_thread+0x134/0x450
   kthread+0x104/0x10c
   ret_from_fork+0x10/0x20
  ---[ end trace 0000000000000000 ]---
  ------------[ cut here ]------------
  WARNING: CPU: 5 PID: 103 at drivers/gpu/drm/drm_mode_object.c:242 drm_object_attach_property+0x6c/0xb0
  Modules linked in: hci_uart apr fastrpc msm pdr_interface qrtr_smd btqca bluetooth gpu_sched nxp_nci_i2c nxp_nci nci drm_kms_helper nfc rmi_i2c rmi_core ecdh_generic ecc libaes ath10k_snoc ath10k_core cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea ath i2c_qup msm_serial serial_core mac80211 libarc4 sha256_generic libsha256 leds_qcom_lpg cfg80211 led_class_multicolor qcom_fg rtc_pm8xxx ipa qrtr qcom_q6v5_mss qcom_q6v5_pas qcom_stats qcom_pil_info qcom_q6v5 qcom_sysmon qcom_common qcom_smd mdt_loader qmi_helpers smp2p rpmsg_char leds_gpio evdev led_class rmtfs_mem qcom_hwspinlock rfkill dm_mod uinput loop
  CPU: 5 PID: 103 Comm: kworker/u16:5 Tainted: G        W         5.17.0-rc5-msm8998 #7
  Hardware name: OnePlus 5 (DT)
  Workqueue: events_unbound deferred_probe_work_func
  pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
  pc : drm_object_attach_property+0x6c/0xb0
  lr : drm_connector_set_panel_orientation+0x54/0xb0
  sp : ffffff808193b2b0
  x29: ffffff808193b2b0 x28: 0000000000000020 x27: 0000000000001000
  x26: 0000000000001000 x25: 0000000000000001 x24: ffffffc0087f1f78
  x23: 0000000000000000 x22: 0000000000000000 x21: ffffff8084b26000
  x20: ffffff8088570b00 x19: ffffff8084b90800 x18: 00000000fffffffb
  x17: 0000007a00440000 x16: 0000000000000000 x15: 0000000000000020
  x14: ffffffffffffffff x13: ffffff8088570b70 x12: ffffff8088570b55
  x11: 0000000000000000 x10: 0000000000000078 x9 : ffffff8088570e20
  x8 : ffffff8088570e38 x7 : 00000000c0c0c0c0 x6 : 00000000c0c0c0c0
  x5 : 0000000000000000 x4 : 0000000000000001 x3 : 0000000000000006
  x2 : 0000000000000001 x1 : ffffff8088570b80 x0 : ffffff8084b90840
  Call trace:
   drm_object_attach_property+0x6c/0xb0
   s6e3fa5_get_modes+0x64/0x80
   drm_panel_get_modes+0x20/0x40
   dsi_mgr_connector_get_modes+0x28/0x40 [msm]
   drm_helper_probe_single_connector_modes+0x19c/0x770 [drm_kms_helper]
   drm_client_modeset_probe+0x1a4/0x1144
   __drm_fb_helper_initial_config_and_unlock+0x30/0x500 [drm_kms_helper]
   drm_fb_helper_initial_config+0x44/0x50 [drm_kms_helper]
   msm_fbdev_init+0x84/0xec [msm]
   msm_drm_bind+0x51c/0x5e0 [msm]
   try_to_bring_up_master+0x218/0x300
   __component_add+0x9c/0x180
   component_add+0x10/0x1c
   dsi_dev_attach+0x1c/0x24 [msm]
   dsi_host_attach+0x90/0x140 [msm]
   mipi_dsi_attach+0x24/0x34
   s6e3fa5_probe+0x10c/0x1cc
   mipi_dsi_drv_probe+0x1c/0x24
   really_probe+0x1b0/0x430
   __driver_probe_device+0x10c/0x180
   driver_probe_device+0x3c/0xf0
   __device_attach_driver+0x94/0x120
   bus_for_each_drv+0x64/0xa0
   __device_attach+0xa8/0x19c
   device_initial_probe+0x10/0x20
   bus_probe_device+0x90/0xa0
   device_add+0x364/0x83c
   mipi_dsi_device_register_full+0xc4/0x150
   mipi_dsi_host_register+0xb8/0x14c
   msm_dsi_host_register+0x3c/0x54 [msm]
   msm_dsi_manager_register+0x144/0x260 [msm]
   dsi_dev_probe+0x124/0x1a4 [msm]
   platform_probe+0x64/0xcc
   really_probe+0x1b0/0x430
   __driver_probe_device+0x10c/0x180
   driver_probe_device+0x3c/0xf0
   __device_attach_driver+0x94/0x120
   bus_for_each_drv+0x64/0xa0
   __device_attach+0xa8/0x19c
   device_initial_probe+0x10/0x20
   bus_probe_device+0x90/0xa0
   deferred_probe_work_func+0x9c/0xf0
   process_one_work+0x1d0/0x350
   worker_thread+0x134/0x450
   kthread+0x104/0x10c
   ret_from_fork+0x10/0x20
  ---[ end trace 0000000000000000 ]---
2022-05-16 20:18:25 +03:00
Jami Kettunen
e816b8fe88 [HACK] scripts: Stop appending "+" to localversion
This always gets added and doesn't look nice in the version string, so
it's purely for aesthetic reasons :p
2022-05-16 20:18:25 +03:00
Jami Kettunen
3ff7a942b0 [ANNOTATION] [DROPME?] Import WIP "Qualcomm SPMI Fuel Gauge" driver
Drop pmi8994 DTS changes though.

https://gitlab.com/sdm845-mainline/linux/-/commits/driver/pmi8998_fg/
2022-05-16 20:18:25 +03:00
Jami Kettunen
22b8d2d562 power: supply: qcom_fg: Report online property 2022-05-16 20:18:25 +03:00
Yassine Oudjana
834ad221c2 power: pmi8998_fg: Rename to qcom_fg and add support for PMI8994/6
This adds support for accessing SRAM. That includes requesting and releasing
access to SRAM by setting some registers and handling the mem-avail IRQ,
configuring access, and reading from/writing to it.

Pre-gen3 fuel gauges require reading from SRAM to get voltage, current
and temperature data. Getting capacity is identical to gen3.

Tested on Xiaomi Mi Note 2 with PMI8996.
2022-05-16 20:18:25 +03:00
Yassine Oudjana
6aa60af1f4 power: pmi8998_fg: Remove some trailing spaces and tabs
This should be squashed.
2022-05-16 20:18:24 +03:00
Joel Selvaraj
86e498bd27 fg: clean and read charge full and max voltage from dts 2022-05-16 20:18:24 +03:00
Joel Selvaraj
7a76735a1a power: supply: add battery charging status feature 2022-05-16 20:18:24 +03:00
Joel Selvaraj
bdc340aad6 arm64: dts: qcom: pmi8998: Add nodes for pmi8998 fuel guage 2022-05-16 20:18:24 +03:00
Joel Selvaraj
325f8f089c power: supply: introduce pmi8998 fuel guage driver 2022-05-16 20:18:24 +03:00
Jami Kettunen
b6c62f87c2 [ANNOTATION] Import SPMI haptics driver v4 (2022-04-03)
Drop SDM845 DTS changes though.

Link: https://patchwork.kernel.org/project/linux-arm-msm/cover/20211210022639.2779173-1-caleb@connolly.tech/
2022-05-16 20:18:24 +03:00
Jami Kettunen
b82d6a0281 arm64: dts: qcom: msm8998-oneplus-common: Enable PMI8998 haptics
The OnePlus 5 and 5T both have a haptics engine connected to PMI8998.

Signed-off-by: Jami Kettunen <jami.kettunen@somainline.org>
Signed-off-by: Caleb Connolly <caleb@connolly.tech>
2022-05-16 20:18:24 +03:00
Caleb Connolly
12f9b8d9f0 arm64: dts: qcom: pmi8998: introduce spmi haptics
Add bindings for Qualcomm SPMI haptics on platforms using pmi8998.

Signed-off-by: Caleb Connolly <caleb@connolly.tech>
2022-05-16 20:18:24 +03:00
Caleb Connolly
ff3115b481 input: add Qualcomm SPMI haptics driver
Add support for the haptics found in pmi8998 and related PMICs.
Based on the ff-memless interface. Currently this driver provides
a partial implementation of hardware features.

This driver only supports LRAs (Linear Resonant Actuators) in the "buffer"
mode with a single wave pattern.

Signed-off-by: Caleb Connolly <caleb@connolly.tech>
2022-05-16 20:18:24 +03:00
Caleb Connolly
f0a8b6e89a dt-bindings: input: add Qualcomm SPMI haptics driver
Add bindings for qcom PMIC SPMI haptics driver.

Signed-off-by: Caleb Connolly <caleb@connolly.tech>
2022-05-16 20:18:24 +03:00
Jami Kettunen
a26d1cd582 [ANNOTATION] Base @ angelo/5.14-msm8998-audio-working
I also rebased this tree on the linus/v5.18-rc1 tag and while at it
finally dropped changes irrelevant to msm8998.
2022-05-16 20:18:24 +03:00
AngeloGioacchino Del Regno
2f3388b57f adreno 5xx: TTBR1 extravaganza on MSM8998
(JAMI: fixup for 5.16)
2022-05-16 20:18:24 +03:00
Jami Kettunen
b6058d4b69 arm64: dts: qcom: msm8998-xperia: various tests
Originally from: c215a022
2022-05-16 20:18:24 +03:00
Jami Kettunen
116e690ea9 ASoC: wcd9335: various tests
Originally from: c215a022
2022-05-16 20:18:24 +03:00
AngeloGioacchino Del Regno
0a29c0b89a iommu/arm-smmu-qcom: Add MSM8998 and SDM660 mss compatibles for identity
Add MSM8998 and SDM660's mss-pil compatibles to switch the default
iommu domain type to IDENTITY, as similarly required by SDM845 and
others.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:24 +03:00
AngeloGioacchino Del Regno
4bce98942e iommu/arm-smmu-qcom: Skip the TTBR1 quirk for MSM8998 and SDM630
Similarly to MSM8996 DragonBoard 820c, MSM8998 and SDM630 are equipped
with Adreno 5xx series, which doesn't have separate pagetables support
at the moment of writing.
Skip the TTBR1 quirk for these two SoCs as to get Adreno in a usable
state.
2022-05-16 20:18:24 +03:00
AngeloGioacchino Del Regno
1831d80a62 arm64: dts: qcom: AUDIO WORKS oon MSM8998 Sony Yoshino platform!!! 2022-05-16 20:18:24 +03:00
AngeloGioacchino Del Regno
3d14a424f6 ASoC: codecs: wcd9335: Fix headphone jack commit for new upstream kernel 2022-05-16 20:18:24 +03:00
Srinivas Kandagatla
2e4e748dfb ASoC: wcd9335: add mbhc support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
2022-05-16 20:18:23 +03:00
Jami Kettunen
8be99e829f arm64: dts: qcom: Enable audio on MSM8998 Sony Yoshino platform
Originally from: d95b982a
2022-05-16 20:18:23 +03:00
Jami Kettunen
6efcd7b899 arm64: dts: qcom: msm8998: More audio related node changes
Originally from: d95b982a
2022-05-16 20:18:23 +03:00
Jami Kettunen
7e06fc2d18 fixup! arm64: dts: qcom: msm8998: Configure Adreno GPU and related IOMMU 2022-05-16 20:18:23 +03:00
Jami Kettunen
2b8f96aa93 mfd: wcd9335: Add support to wcd9335 codec
Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC.

This codec has integrated SoundWire controller, pin controller and
interrupt controller.

Originally from: d95b982a
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
e0d2636522 arm64: dts: qcom: msm8998: Add disabled slimbus support
Add generic slimbus configuration to MSM8998 and keep it disabled.
It is expected that this will be enabled in board-specific device
trees when supported, along with the right audio codec.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
Jami Kettunen
aca5fb15f3 ASoC: qcom: lpass-msm8998: Add platform driver for lpass audio
Add platform driver for configuring msm8998 lpass core I2S and
DMA configuration to support playback & capture to external codecs
connected over primary & secondary MI2S interfaces.

(driver originally split from 4d7e1ead3b ("fastmatrix yaml fix"))
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
9581fa8de1 ASoC: qcom: Add MSM8998 sound card support
Add MSM8998 sound support: this driver supports basic functionality
and headphone jack.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
(JAMI: fixup for 5.17)
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
99c850a614 arm64: dts: qcom: msm8998-xperia: Enable lpass smmu
To support audio dsp functionality, enable the lpass smmu.
The firmware distributed with the MSM8998 Sony Xperia smartphones
requires us to skip resetting CB12 of this SMMU and to use CB11
as a context bank to emulate bypass streams.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
(JAMI: fixed up for v5.16-rc1)
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
91e8d0a7e3 arm64: dts: qcom: msm8998: Add APR services configuration
Add the standard APR Q6 services configuration for MSM8998, used by
boards supporting the audio dsp.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
133ad65952 arm64: dts: qcom: msm8998: Define fastrpc ADSP compute context banks
If the target board supports ADSP, it is essential to have fastrpc
compute context banks defined. This commit adds the always usable
unsecured context banks only.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
92f004b0d6 arm64: dts: qcom: msm8998: Add disabled support for lpass iommu for q6
Add support for the LPASS (Q6) SMMU and keep it disabled as this is
used only when the audio DSP is present and used, which is not
mandatory to have.
It is expected for board-specific device-trees to enable this node
if supported.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
145a93bd75 clk: qcom: gcc-msm8998: Add LPASS adsp and core GDSCs
As a final step to entirely enable the required clock tree for the
lpass iommu and audio dsp, add the lpass core/adsp GDSCs.

As a side note, it was found out that disabling the lpass core GDSC
at any time would cause a system lockup (and reboot): disabling
this GDSC will leave the lpass iommu completely unclocked, losing
its state entirely - including the secure contexts that have been
previously set-up from the bootloader/TrustZone.
Losing this IOMMU configuration will trigger a hypervisor fault,
which will reboot the system; the only workaround for this issue
is to declare the lpass core gdsc as always-on.

It should also not be forgotten that this is all about firmware and
there may be a version of it that doesn't enable this GDSC at all
before booting Linux, which is the reason why this specific declaration
wasn't simply omitted.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
c46a614b94 dt-bindings: clock: gcc-msm8998: Add LPASS adsp/core GDSCs definitions
Add the GDSC definitions for the LPASS_ADSP_GDSC and LPASS_CORE_GDSC
as a final step to enable the required clock tree for the lpass iommu
and for the audio dsp itself.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
7e8c1242b9 clk: qcom: gcc-msm8998: Add q6 bimc and lpass core, adsp SMMU clocks
Add the Q6 BIMC, LPASS core/adsp SMMU clocks to support audio related
functionality on MSM8998 and APQ variants. Please note that the Q6 and
the lpass iommu also need GDSCs to be enabled in order to initialize,
which are going to be added in a later commit.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
e9876801a4 dt-bindings: clock: gcc-msm8998: Add Q6 and LPASS clocks definitions
Add definitions for the Q6 BIMC, LPASS core and adsp smmu clocks,
required to enable audio functionality on MSM8998.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
(JAMI: merge with e122a6a4 for 5.17)
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
135f4581f9 arm64: dts: qcom: msm8998: Add imem pil-reloc-info for firmware loading
Firmware loading (mainly the modem) may require IMEM PIL relocation
informations: specify this imem region in dt for qcom_pil_info to
use it.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:23 +03:00
AngeloGioacchino Del Regno
e69696c619 arm64: dts: qcom: msm8998: Add qcom,adreno-smmu compatible 2022-05-16 20:18:22 +03:00
Jami Kettunen
074aaa8473 regulator: qcom-labibb: Always disable interrupts during OCP & SC
Originally from: cd95ecae
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
f54f240f0e yoshino: Fix too high overheating backlight, enable all wled strings maple 2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
be43e65b09 drm/msm/dsi_phy_10nm: Fix bad VCO rate calculation 2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
b054c98322 clk: qcom: mmcc-msm8998: Set CLK_GET_RATE_NOCACHE to pixel/byte clks
The pixel and byte clocks rate should not be cached, as a VCO shutdown
may clear the frequency setup and this may not be set again due to the
cached rate being present.
This will also be useful when shadow clocks will be implemented in
the DSI PLL for seamless timing/resolution switch.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
4892231a0b clk: qcom: gcc-msm8998: Set MISC flags, mark hmss/gpu-ahb critical
It is being evaluated whether this commit is really needed.
DONOTUPSTREAM.

(JAMI: fixed up for v5.16-rc1)
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
03528b4dc3 input: keyboard: Add Fast GPIO-driven keyboard/keypad matrix driver
This driver is a reimplementation of matrix_keyboard, on which it
is heavily based: the former was made back in 2009 and then
lightly updated in 2012 to add some support for device-tree / OF.

It turns out that this is not enough, nor OF is fully supported,
as the global (or "clustered") interrupt is never probed, nor it
made usage of the GPIOD API which, nowadays, really simplifies
the job - but not only: it also provides means to set GPIO arrays
for controllers that are supporting this.
The latter is very important when dealing with slow GPIOs such as
I2C and/or SPI expanders (and, again, not only); by using the new
APIs everything fits the new systems, from simplifications of the
probe/remove functions to opening possibility of using expanders
to drive key matrices with or without protection diodes.

But then, why wasn't the old matrix_keyboard driver modified
instead of creating a new one?
The problem there is that the old driver is made to support the
old platform_device style and it's currently still being used by
some PXA boards that are not (yet?) ported to device-tree, so it
would be impossible to modernize it for good, which means that to
support GPIOD (which is - really - required for the aforementioned
reasons) and to fully support DT it would be necessary to wrap the
old GPIO API around the new GPIOD one, creating overhead and also
probably unnecessary memory usage, other than a very big driver
which, at least on embedded devices (having limited resources),
would be simply bad. Leaving the fact that I haven't got any old
board so it's impossible for me to analyze and optimize for them.

Since 98% of the users of the old driver are infact platforms that
have been ported to (or are born with) DT, the introduction of a
new driver that's purely made for them seemed to be the best
choice, also because the expectations are (I think) that all of
the old ARM-based boards will be ported to DT anyway, which will
actually deprecate the good old matrix_keyboard driver.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
102e20cf5c dt-bindings: input: Add binding for gpio-fastmatrix-keyboard
Add documentation for the gpio-fastmatrix-keyboard driver.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
(JAMI: merge with e7aa905a for 5.17)
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
d91a158c48 dt-bindings: pinctrl: Add bindings for Awinic AW9523/AW9523B
Add bindings for the Awinic AW9523/AW9523B I2C GPIO Expander driver.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
6ed7bb6ccb pinctrl: Add driver for Awinic AW9523/B I2C GPIO Expander
The Awinic AW9523(B) is a multi-function I2C gpio expander in a
TQFN-24L package, featuring PWM (max 37mA per pin, or total max
power 3.2Watts) for LED driving capability.

It has two ports with 8 pins per port (for a total of 16 pins),
configurable as either PWM with 1/256 stepping or GPIO input/output,
1.8V logic input; each GPIO can be configured as input or output
independently from each other.

This IC also has an internal interrupt controller, which is capable
of generating an interrupt for each GPIO, depending on the
configuration, and will raise an interrupt on the INTN pin to
advertise this to an external interrupt controller.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
Caleb Connolly
eb4cf9f26d interconnect: qcom: msm8998: fix a typo'd QNODE
Fixes a WARN generated by referencing the same node id multiple times
2022-05-16 20:18:22 +03:00
Konrad Dybcio
13c726e975 interconnect: qcom: Add MSM8998 interconnect provider driver
Introduce a driver for the Qualcomm interconnect busses found in
the MSM/APQ8998 SoCs.
The topology consists of several NoCs that are controlled by a
remote processor that collects the aggregated bandwidth for each
master-slave pairs.

On a note, these chips are managing the "bus QoS" in a "hybrid"
fashion: some of the paths in the topology are managed through
and by, of course) the RPM uC, while some others are "AP Owned",
meaning that the AP shall do direct writes to the appropriate
QoS registers for the specific paths and ports, instead of sending
an indication to the RPM and leaving the job to that one.

Co-authored-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
(JAMI: fixup for 5.17)
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
d13bca386e dt-bindings: interconnect: Add bindings for Qualcomm MSM8998 NoC
Add the bindings for the Qualcomm MSM8998 NoC interconnects.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
64b3b43c82 dt-bindings: i2c: qcom,i2c-qup: Document noise rejection properties
Document the new noise rejection properties "qcom,noise-reject-sda"
and "qcom,noise-reject-scl".

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
3b742fd91f i2c: qup: Introduce SCL/SDA noise rejection
Some I2C devices may be glitchy due to electrical noise coming
from the device itself or because of possible board design issues.
To overcome this issue, the QUP's I2C in Qualcomm SoCs supports
a noise rejection setting for both SCL and SDA lines.

Introduce a setting for noise rejection through device properties,
"qcom,noise-reject-sda" and "qcom,noise-reject-scl", which will
be used to set the level of noise rejection sensitivity.
If the properties are not specified, noise rejection will not be
enabled.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
25a4d55178 dt-bindings: i2c: qcom,i2c-qup: Convert txt to YAML schema
Convert the qcom,i2c-qup binding to YAML schema.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
aa37efa24a arm64: dts: msm8998: Add SAW, CPRh and CPUFREQ to enable CPU scaling
Add the SAW (SPM), CPR-Hardened, CPUFREQ-HW nodes and relative OPP
tables (and also assign them to the CPU nodes, as required) in order
to enable CPU scaling on the MSM8998 SoC.

The CPR-Hardened and CPUFREQ-HW nodes are disabled by default as to
not change the previous default behavior. Since the drivers are not
yet accounting for speed-binning, these OPPs are referred to the
most common binning for this chip, which I have found on six phones
from Sony and one from FxTec (silver bin0, perf bin2).

At least until speed-binning gets done in the cpufreq-hw and CPR
drivers, users should enable CPR-Hardened and CPUFREQ in their own
board DT.
This is done like that because these drivers are really big, so the
idea is to keep the "base" version easier (but perfectly working),
before adding speed-binning "complications", which may... or may not
be necessary.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
[Fixed up for 5.18 by Jami]
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
db192abed8 arm64: dts: msm8998: Wire up interconnects to MDP and GPU
Wire up the interconnects to both the MDP and the Adreno GPU in
order to get the right balance between performance and power
consumption of both devices.
2022-05-16 20:18:22 +03:00
AngeloGioacchino Del Regno
b30d89fb02 arm64: dts: qcom: Enable panel etc. on MSM8998 F(x)tec Pro1 QX1000
(JAMI: fixup for 5.16)
2022-05-16 20:18:21 +03:00
Konrad Dybcio
b674c37b7f arm64: dts: qcom: pm8998: Add VREF_1P25 and REF_GND VADC channels
Signed-off-by: Konrad Dybcio <konrad.dybcio@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
59db3b27f9 arm64: dts: msm8998: Wire up interconnects and OPPs to sdhci port 2
Wire up the OPP table and interconnects to the SDHCI port 2 to
improve performance and power consumption.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
4b558a6f1f arm64: dts: msm8998: Add interconnect nodes
This SoC features Network-on-Chip (NoC) and Bus Integrated Memory
Controller (BIMC) interconnects: add the required nodes now that
the driver is present.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
736fe764a9 arm64: dts: msm8998: Add disabled configuration for DPU1/DSI
This SoC supports both the MDP5 and DPU1 drivers, but the
latter was chosen as it's more feature-complete;

Configure the DPU1, DSI and related phy and pll in order to
achieve display functionality and keep it disabled.
Enabling it will be done on board specific DT when needed,
as not all boards have a usable display attached to them.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
0e2dd49587 arm64: dts: qcom: Enable panel etc. on MSM8998 Sony Yoshino platform
(JAMI: fixup for 5.16)
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
04c84d9bd6 dt-bindings: soc: qcom: cpr3: Add bindings for CPR3 driver
Add the bindings for the CPR3 driver to the documentation.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
Reviewed-by: Rob Herring <robh@kernel.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
796be4147b MAINTAINERS: Add entry for Qualcomm CPRv3/v4/Hardened driver
Add maintainers entry for the Qualcomm CPR3/CPR4/CPRh driver.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
0eadc9da26 soc: qcom: Add support for Core Power Reduction v3, v4 and Hardened
This commit introduces a new driver, based on the one for cpr v1,
to enable support for the newer Qualcomm Core Power Reduction
hardware, known downstream as CPR3, CPR4 and CPRh, and support
for MSM8998 and SDM630 CPU power reduction.

In these new versions of the hardware, support for various new
features was introduced, including voltage reduction for the GPU,
security hardening and a new way of controlling CPU DVFS,
consisting in internal communication between microcontrollers,
specifically the CPR-Hardened and the Operating State Manager.

The CPR v3, v4 and CPRh are present in a broad range of SoCs,
from the mid-range to the high end ones including, but not limited
to, MSM8953/8996/8998, SDM630/636/660/845.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
abe7a81ddb arm64: qcom: qcs404: Change CPR nvmem-names
The CPR driver's common functions were split and put in another
file in order to support newer CPR revisions: to simplify the
commonization, the expected names of the fuses had to be changed
in order for both new and old support to use the same fuse name
retrieval function and keeping the naming consistent.

The thread id was added to the fuse name and, since CPRv1 does
not support threads, it is expected to always read ID 0, which
means that the expected name here is now "cpr0_(fuse_name)"
instead of "cpr_(fuse_name)": luckily, QCS404 is the only user
so change it accordingly.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
d8e6ee7aae soc: qcom: cpr: Move common functions to new file
In preparation for implementing a new driver that will be handling
CPRv3, CPRv4 and CPR-Hardened, format out common functions to a new
file.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>

(JAMI: fixup for 5.15 & 5.17)
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
002609b104 dt-bindings: cpufreq: qcom-hw: Make reg-names a required property
The property reg-names is required after the addition of the OSM
programming sequence, as that mandates specifying different register
domains; to avoid confusion and improve devicetree readability,
specifying the regions names was made mandatory.
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
f7c470d02b dt-bindings: cpufreq: qcom-hw: Add bindings for 8998
The OSM programming addition has been done under the
qcom,cpufreq-hw-8998 compatible name: specify the requirement
of two additional register spaces for this functionality.
This implementation, with the same compatible, has been
tested on MSM8998 and SDM630.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
[Fixed up for 5.18 by Jami]
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
8fe59fda3f cpufreq: qcom-hw: Allow getting the maximum transition latency for OPPs
In order to fine-tune the frequency scaling from various governors,
allow to set a maximum transition latency from OPPs, which may be
different depending on the SoC.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
[Fixup for 5.18 by Jami]
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
9a1c992448 cpufreq: qcom-hw: Implement CPRh aware OSM programming
On new SoCs (SDM845 onwards) the Operating State Manager (OSM) is
being programmed in the bootloader and write-protected by the
hypervisor, leaving to the OS read-only access to some of its
registers (in order to read the Lookup Tables and also some
status registers) and write access to the p-state register, for
for the OS to request a specific performance state to trigger a
DVFS switch on the CPU through the OSM hardware.

On old SoCs though (MSM8998, SDM630/660 and variants), the
bootloader will *not* initialize the OSM (and the CPRh, as it
is a requirement for it) before booting the OS, making any
request to trigger a performance state change ineffective, as
the hardware doesn't have any Lookup Table, nor is storing any
parameter to trigger a DVFS switch. In this case, basically all
of the OSM registers are *not* write protected for the OS, even
though some are - but write access is granted through SCM calls.

This commit introduces support for OSM programming, which has to
be done on these old SoCs that were distributed (almost?) always
with a bootloader that does not do any CPRh nor OSM init before
booting the kernel.
In order to program the OSM on these SoCs, it is necessary to
fullfill a "special" requirement: the Core Power Reduction
Hardened (CPRh) hardware block must be initialized, as the OSM
is "talking" to it in order to perform the Voltage part of DVFS;
here, we are calling initialization of this through Linux generic
power domains, specifically by requesting a genpd attach from the
qcom-cpufreq-hw driver, which will give back voltages associated
to each CPU frequency that has been declared in the OPPs, scaled
and interpolated with the previous one, and will also give us
parameters for the Array Power Mux (APM) and mem-acc, in order
for this driver to be then able to generate the Lookup Tables
that will be finally programmed to the OSM hardware.

After writing the parameters to the OSM and enabling it, all the
programming work will never happen anymore until a OS reboot, so
all of the allocations and "the rest" will be disposed-of: this
is done mainly to leave the code that was referred only to the
new SoCs intact, as to also emphasize on the fact that the OSM
HW is, in the end, the exact same; apart some register offsets
that are slightly different, the entire logic is the same.

This also adds the parameters to support CPU scaling on SDM630
and MSM8998.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
[Fixup for 5.18 by Jami]
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
4825848801 cpufreq: qcom-hw: Add kerneldoc to some functions
Some functions may not be very straightforward to understand:
add kerneldoc to some ones in order to improve readability.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
Manivannan Sadhasivam
0d6a88c0dd dt-bindings: arm: cpus: Document 'qcom,freq-domain' property
Add devicetree documentation for 'qcom,freq-domain' property specific
to Qualcomm CPUs. This property is used to reference the CPUFREQ node
along with Domain ID (0/1).

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
6577ea59d0 cpufreq: Add MSM8998 to cpufreq-dt-platdev blocklist
Add the MSM8998 to the blocklist since the CPU scaling is handled
out of this.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:21 +03:00
AngeloGioacchino Del Regno
712bb69209 iommu/arm-smmu-qcom: Don't modify sACR on hypervisor secured iommus
Avoid modifying the contents of the secure Auxiliary Control Register
on some Qualcomm SoCs: due to a hypervisor configuration on some
firmware versions, this would result in a system crash.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:20 +03:00
AngeloGioacchino Del Regno
4a5043f59c iommu/arm-smmu-qcom: Avoid disabling secured context banks
Some Qualcomm SoCs' TZ/hypervisor configuration is disallowing the
disablement of some context banks, being them used for tzapps and/or
remote processors; any attempt to disable such CBs will result in
triggering a fault and the system will freeze and/or reset.

For this reason, get a list of context banks that should never get
disabled during smmu initialization through a DT array property
`qcom,reset-nodisable-cbs`.
It was chosen to not hardcode the CBs as this is dependant on the
SoC's firmware, which may vary on different boards.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:20 +03:00
AngeloGioacchino Del Regno
634f4b6e01 iommu/arm-smmu: Allow skipping context bank disable at reset time
On some SoCs some IOMMU context banks are actively used from TZ
during system boot, or some hypervisor configurations will trigger
a system reset upon disabling some protected/secured CBs.

Allow skipping the disablement of such contexts at IOMMU reset time
during initialization with a new implementation detail to work around
this quirk.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:20 +03:00
AngeloGioacchino Del Regno
4e202034f9 iommu/arm-smmu-qcom: Allow choosing a custom bypass emulation context
It cannot be taken for granted that the last IOMMU context is free
and available for us to use it to emulate bypass streams and, at least
on MSM8998's lpass iommu, using the last one will produce a crash;
please note that this may not be only dependant on the SoC, but also
on the firmware version.

To overcome to this issue, allow specifying a different context for
bypass emulation with the optional DT property "qcom,bypass-cbndx":
if this property is not found this means that we are either booting
with ACPI instead or that we don't want to specify a custom cb because
the default one (the last context bank) is fine.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
2022-05-16 20:18:20 +03:00
Marijn Suijten
7819576b3a leds: ledtrig-pattern: Use last_repeat when applying hw pattern
`last_repeat` holds the actual value requested by the user whereas
`repeat` is a software iteration variable that is unused in hardware
patterns.

Furthermore `last_repeat` is the field returned to the user when reading
the `repeat` sysfs property.  This field is initialized to `-1` which is
- together with `1` - the only valid value in the upcoming Qualcomm LPG
driver.  It is thus unexpected when `repeat` with an initialization
value of `0` is passed into the the driver, when the sysfs property
clearly presents a value of `-1`.

Signed-off-by: Marijn Suijten <marijn.suijten@somainline.org>
2022-05-16 20:18:20 +03:00
Jami Kettunen
04e0752bfc [ANNOTATION] Import Qualcomm LPG driver v14 (2022-04-03)
Link: https://patchwork.kernel.org/project/linux-arm-msm/patch/20220303214300.59468-1-bjorn.andersson@linaro.org/
2022-05-16 20:18:20 +03:00
Bjorn Andersson
19299a38ca leds: Add driver for Qualcomm LPG
The Light Pulse Generator (LPG) is a PWM-block found in a wide range of
PMICs from Qualcomm. These PMICs typically comes with 1-8 LPG instances,
with their output being routed to various other components, such as
current sinks or GPIOs.

Each LPG instance can operate on fixed parameters or based on a shared
lookup-table, altering the duty cycle over time. This provides the means
for hardware assisted transitions of LED brightness.

A typical use case for the fixed parameter mode is to drive a PWM
backlight control signal, the driver therefor allows each LPG instance
to be exposed to the kernel either through the LED framework or the PWM
framework.

A typical use case for the LED configuration is to drive RGB LEDs in
smartphones etc, for which the driver supports multiple channels to be
ganged up to a MULTICOLOR LED. In this configuration the pattern
generators will be synchronized, to allow for multi-color patterns.

The idea of modelling this as a LED driver ontop of a PWM driver was
considered, but setting the properties related to patterns does not fit
in the PWM API. Similarly the idea of just duplicating the lower bits in
a PWM and LED driver separately was considered, but this would not allow
the PWM channels and LEDs to be configured on a per-board basis. The
driver implements the more complex LED interface, and provides a PWM
interface on the side of that, in the same driver.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Tested-by: Douglas Anderson <dianders@chromium.org>
2022-05-16 20:18:20 +03:00
Bjorn Andersson
64131e0549 dt-bindings: leds: Add Qualcomm Light Pulse Generator binding
This adds the binding document describing the three hardware blocks
related to the Light Pulse Generator found in a wide range of Qualcomm
PMICs.

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Reviewed-by: Stephen Boyd <swboyd@chromium.org>
Reviewed-by: Rob Herring <robh@kernel.org>
2022-05-16 20:18:20 +03:00
120 changed files with 20937 additions and 1109 deletions

View file

@ -316,6 +316,12 @@ properties:
* arm/msm/qcom,kpss-acc.txt
qcom,freq-domain:
$ref: '/schemas/types.yaml#/definitions/phandle-array'
description: |
CPUs supporting freq-domain must set their "qcom,freq-domain" property
with phandle to a cpufreq_hw node followed by the Domain ID(0/1).
rockchip,pmu:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: |

View file

@ -41,6 +41,7 @@ description: |
sa8155p
sc7180
sc7280
msm8998
sdm630
sdm632
sdm660
@ -225,6 +226,20 @@ properties:
- google,senor
- const: qcom,sc7280
- items:
- enum:
- asus,novago-tp370ql
- fxtec,pro1
- hp,envy-x2
- lenovo,miix-630
- oneplus,cheeseburger
- oneplus,dumpling
- qcom,msm8998-mtp
- sony,xperia-lilac
- sony,xperia-maple
- sony,xperia-poplar
- const: qcom,msm8998
- items:
- enum:
- fairphone,fp3

View file

@ -18,6 +18,10 @@ description: |
properties:
compatible:
oneOf:
- description: Non-secure v1 of CPUFREQ HW
items:
- const: qcom,cpufreq-hw-8998
- description: v1 of CPUFREQ HW
items:
- const: qcom,cpufreq-hw
@ -28,19 +32,9 @@ properties:
- qcom,sm8250-cpufreq-epss
- const: qcom,cpufreq-epss
reg:
minItems: 2
items:
- description: Frequency domain 0 register region
- description: Frequency domain 1 register region
- description: Frequency domain 2 register region
reg: {}
reg-names:
minItems: 2
items:
- const: freq-domain0
- const: freq-domain1
- const: freq-domain2
reg-names: {}
clocks:
items:
@ -55,9 +49,52 @@ properties:
'#freq-domain-cells':
const: 1
if:
properties:
compatible:
contains:
const: qcom,cpufreq-hw-8998
then:
properties:
reg:
minItems: 2
items:
- description: Frequency domain 0 register region
- description: Operating State Manager domain 0 register region
- description: Frequency domain 1 register region
- description: Operating State Manager domain 1 register region
- description: PLL ACD domain 0 register region (if ACD programming required)
- description: PLL ACD domain 1 register region (if ACD programming required)
reg-names:
minItems: 2
items:
- const: "osm-domain0"
- const: "freq-domain0"
- const: "osm-domain1"
- const: "freq-domain1"
- const: "osm-acd0"
- const: "osm-acd1"
else:
properties:
reg:
minItems: 2
items:
- description: Frequency domain 0 register region
- description: Frequency domain 1 register region
- description: Frequency domain 2 register region
reg-names:
minItems: 2
items:
- const: "freq-domain0"
- const: "freq-domain1"
- const: "freq-domain2"
required:
- compatible
- reg
- reg-names
- clocks
- clock-names
- '#freq-domain-cells'

View file

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/samsung,s6e3fa5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S6E3FA5 AMOLED panel with command mode DSI controller
maintainers:
- Jami Kettunen <jami.kettunen@somainline.org>
description: |+
This panel is found on the OnePlus 3T as well as OnePlus 5,
however on the 3T it runs in video mode while this driver
currently only support the command mode variant found on the
5.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: samsung,s6e3fa5
reg: true
reset-gpios: true
disp-te-gpios: true
vddio-supply:
description: vddio supply
required:
- compatible
- reg
- vddio-supply
- reset-gpios
- disp-te-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
reg = <0>;
compatible = "samsung,s6e3fa5";
vddio-supply = <&vreg_l14a_1p88>;
reset-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
disp-te-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
};
};

View file

@ -0,0 +1,52 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/samsung,s6e3fc1.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S6E3FC1 AMOLED panel with command mode DSI controller
maintainers:
- Jami Kettunen <jami.kettunen@somainline.org>
description: |+
This panel is found on the OnePlus 5T and it runs in command mode.
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
const: samsung,s6e3fc1
reg: true
reset-gpios: true
disp-te-gpios: true
vddio-supply:
description: vddio supply
required:
- compatible
- reg
- vddio-supply
- reset-gpios
- disp-te-gpios
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
reg = <0>;
compatible = "samsung,s6e3fc1";
vddio-supply = <&vreg_l14a_1p88>;
reset-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
disp-te-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
};
};

View file

@ -1,40 +0,0 @@
Qualcomm Universal Peripheral (QUP) I2C controller
Required properties:
- compatible: Should be:
* "qcom,i2c-qup-v1.1.1" for 8660, 8960 and 8064.
* "qcom,i2c-qup-v2.1.1" for 8974 v1.
* "qcom,i2c-qup-v2.2.1" for 8974 v2 and later.
- reg: Should contain QUP register address and length.
- interrupts: Should contain I2C interrupt.
- clocks: A list of phandles + clock-specifiers, one for each entry in
clock-names.
- clock-names: Should contain:
* "core" for the core clock
* "iface" for the AHB clock
- #address-cells: Should be <1> Address cells for i2c device address
- #size-cells: Should be <0> as i2c addresses have no size component
Optional properties:
- clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
defaults to 100kHz if omitted.
Child nodes should conform to i2c bus binding.
Example:
i2c@f9924000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
clock-frequency = <355000>;
#address-cells = <1>;
#size-cells = <0>;
};

View file

@ -0,0 +1,101 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/qcom,i2c-qup.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Universal Peripheral (QUP) I2C controller
maintainers:
- Andy Gross <agross@kernel.org>
- Bjorn Andersson <bjorn.andersson@linaro.org>
description: Binding for Qualcomm "QUP" I2C controllers
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
enum:
- qcom,i2c-qup-v1.1.1
- qcom,i2c-qup-v2.1.1
- qcom,i2c-qup-v2.2.1
reg:
items:
- description: QUP I2C register iospace
clocks:
items:
- description: Core QUP I2C clock
- description: AHB clock
clock-names:
items:
- const: core
- const: iface
clock-frequency:
minimum: 100000
maximum: 1000000
default: 100000
dmas:
items:
- description: RX DMA Channel phandle
- description: TX DMA Channel phandle
dma-names:
items:
- const: rx
- const: tx
'#address-cells':
const: 1
'#size-cells':
const: 0
qcom,noise-reject-sda:
$ref: /schemas/types.yaml#/definitions/uint32
description: Noise rejection level for the SDA line.
minimum: 0
maximum: 3
default: 0
qcom,noise-reject-scl:
$ref: /schemas/types.yaml#/definitions/uint32
description: Noise rejection level for the SCL line.
minimum: 0
maximum: 3
default: 0
required:
- compatible
- clocks
- clock-names
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-msm8998.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2c@c175000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0x0c175000 0x600>;
interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>,
<&gcc GCC_BLSP1_AHB_CLK>;
clock-names = "core", "iface";
clock-frequency = <400000>;
dmas = <&blsp_dma 4>, <&blsp_dma 5>;
dma-names = "rx", "tx";
#address-cells = <1>;
#size-cells = <0>;
};

View file

@ -0,0 +1,51 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/qcom,spmi-rradc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm's SPMI PMIC Round Robin ADC
maintainers:
- Caleb Connolly <caleb.connolly@linaro.org>
description: |
The Qualcomm SPMI Round Robin ADC (RRADC) provides interface to clients to
read the voltage, current and temperature for supported peripherals such as
the battery thermistor die temperature, charger temperature, USB and DC input
voltage / current and battery ID resistor.
properties:
compatible:
enum:
- qcom,pmi8998-rradc
- qcom,pm660-rradc
reg:
maxItems: 1
qcom,batt-id-delay-ms:
description: Sets the hardware settling time for the battery ID resistor.
enum: [0, 1, 4, 12, 20, 40, 60, 80]
"#io-channel-cells":
const: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
pmic {
#address-cells = <1>;
#size-cells = <0>;
pmic_rradc: adc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
#io-channel-cells = <1>;
};
};

View file

@ -0,0 +1,129 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/gpio-fastmatrix-keyboard.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Fast modern GPIO-driven keyboard/keypad matrix driver binding
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
description: |
A simple common binding for matrix-connected keyboards/keypads, targeted at
defining the keys in the scope of linux key codes since that is a stable and
standardized interface at this time.
This driver uses the GPIOD API in order to support setting (and reading) an
entire array of GPIOs which is very fast (if the controller supports it) and
a requirement to support full keyboard matrices on slow external GPIO I2C
expanders, but also a great latency enhancement for faster GPIO controllers.
allOf:
- $ref: input.yaml#
properties:
compatible:
const: gpio-fastmatrix-keyboard
label:
description: Descriptive name of the key.
linux,keymap:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
An array of packed 1-cell entries containing the equivalent of row,
column and linux key-code as specified in dt-bindings/input/input.h
autorescan-ms:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Activates auto-rescanning of the matrix after receiving and processing
an event for quirky hardware that won't re-send interrupts on fast-press,
fast-depress, or multiple keys pressed events.
This time is expressed in milliseconds; if not specified, the feature is
disabled.
col-scan-delay-us:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Time to wait in microseconds for scan after activating a column.
If not specified, the default is 0 (no wait).
debounce-delay-ms:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Matrix button debouncing interval time in milliseconds.
If not specified, debouncing is disabled.
drive-inactive-cols:
type: boolean
description: Keep direction of inactive columns as output
col-gpios:
minItems: 2
maxItems: 20
keypad,num-rows:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of row lines connected to the keypad controller.
keypad,num-columns:
$ref: /schemas/types.yaml#/definitions/uint32
description: Number of column lines connected to the keypad controller.
pinctrl-0:
maxItems: 1
pinctrl-names:
maxItems: 1
row-gpios:
minItems: 2
maxItems: 20
required:
- compatible
- row-gpios
- col-gpios
- linux,keymap
- keypad,num-rows
- keypad,num-columns
additionalProperties: true
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
gpio-keyboard {
compatible = "gpio-fastmatrix-keyboard";
label = "Keyboard over I2C Expander";
row-gpios =
<&gpioext0 0 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 1 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 2 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 3 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 4 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 5 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 6 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 7 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
col-gpios =
<&gpioext0 8 GPIO_ACTIVE_LOW>,
<&gpioext0 9 GPIO_ACTIVE_LOW>,
<&gpioext0 10 GPIO_ACTIVE_LOW>,
<&gpioext0 11 GPIO_ACTIVE_LOW>,
<&gpioext0 12 GPIO_ACTIVE_LOW>,
<&gpioext0 13 GPIO_ACTIVE_LOW>,
<&gpioext0 14 GPIO_ACTIVE_LOW>,
<&gpioext0 15 GPIO_ACTIVE_LOW>;
linux,keymap = <
MATRIX_KEY(0, 0, KEY_F1) MATRIX_KEY(1, 0, KEY_H)
MATRIX_KEY(2, 0, KEY_B) MATRIX_KEY(3, 0, KEY_7)
/* ... */
>;
keypad,num-rows = <8>;
keypad,num-columns = <8>;
};

View file

@ -0,0 +1,123 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright 2020 Unisoc Inc.
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/qcom,spmi-haptics.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies Inc PMI8998 spmi haptics
maintainers:
- Caleb Connolly <caleb@connolly.tech>
description: |
Qualcomm SPMI haptics is a peripheral on some QTI PMICs. It supports linear resonant
actuators and eccentric rotating mass type haptics commonly found in mobile devices.
It supports multiple sources of wave data such as an internal buffer, direct play
(from kernel or userspace) as well as an audio output mode.
properties:
compatible:
items:
- enum:
- qcom,pmi8998-haptics
- qcom,pmi8996-haptics
- qcom,pmi8941-haptics
reg:
maxItems: 1
interrupts:
items:
- description: short circuit interrupt
- description: play interrupt
interrupt-names:
items:
- const: short
- const: play
qcom,actuator-type:
description: |
The type of actuator attached to the hardware.
Allowed values are,
0 - HAP_TYPE_LRA
1 - HAP_TYPE_ERM
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 1 ]
default: 0
qcom,wave-shape:
description: |
Selects the wave shape to use.
Allowed values are,
0 - HAP_WAVE_SINE
1 - HAP_WAVE_SQUARE
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 1 ]
default: 0
qcom,play-mode:
description: |
Selects the play mode to use.
Allowed values are,
0 - HAP_PLAY_DIRECT
1 - HAP_PLAY_BUFFER
2 - HAP_PLAY_AUDIO
3 - HAP_PLAY_PWM
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 0, 1, 2, 3 ]
default: 2
qcom,wave-play-rate-us:
description: |
Wave sample durection in microseconds, 1/f where f
is the resonant frequency of the actuator.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 20475
qcom,brake-pattern:
minItems: 4
maxItems: 4
description: |
The brake pattern are the strengths of the pattern
used to brake the haptics. Allowed values are,
0 - 0V
1 - Vmax/4
2 - Vmax/2
3 - Vmax
$ref: /schemas/types.yaml#/definitions/uint32-array
default: [0x3, 0x3, 0x2, 0x1]
required:
- compatible
- reg
- interrupts
- qcom,wave-play-rate-us
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/qcom,spmi-haptics.h>
spmi {
#address-cells = <1>;
#size-cells = <0>;
pmi8998_haptics: haptics@c000 {
compatible = "qcom,pmi8998-haptics";
reg = <0xc000>;
interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "short", "play";
qcom,wave-shape = <HAP_WAVE_SINE>;
qcom,play-mode = <HAP_PLAY_BUFFER>;
qcom,brake-pattern = <0x3 0x3 0x2 0x1>;
status = "disabled";
};
};

View file

@ -0,0 +1,158 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,msm8998.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm MSM8998 Network-On-Chip interconnect
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
- Konrad Dybcio <konrad.dybcio@somainline.org>
description: |
The Qualcomm MSM8998 interconnect providers support adjusting the
bandwidth requirements between the various NoC fabrics.
properties:
reg:
maxItems: 1
compatible:
enum:
- qcom,msm8998-a1noc
- qcom,msm8998-a2noc
- qcom,msm8998-bimc
- qcom,msm8998-cnoc
- qcom,msm8998-gnoc
- qcom,msm8998-mnoc
- qcom,msm8998-snoc
'#interconnect-cells':
const: 1
clocks:
minItems: 1
maxItems: 3
clock-names:
minItems: 1
maxItems: 3
required:
- compatible
- reg
- '#interconnect-cells'
- clock-names
- clocks
additionalProperties: false
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8998-mnoc
then:
properties:
clocks:
items:
- description: Bus Clock.
- description: Bus A Clock.
- description: CPU-NoC High-performance Bus Clock.
clock-names:
items:
- const: bus
- const: bus_a
- const: iface
- if:
properties:
compatible:
contains:
enum:
- qcom,msm8998-a2noc
- qcom,msm8998-bimc
- qcom,msm8998-cnoc
- qcom,msm8998-gnoc
- qcom,msm8998-snoc
then:
properties:
clocks:
items:
- description: Bus Clock.
- description: Bus A Clock.
clock-names:
items:
- const: bus
- const: bus_a
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
#include <dt-bindings/clock/qcom,mmcc-msm8998.h>
bimc: interconnect@1008000 {
compatible = "qcom,msm8998-bimc";
reg = <0x01008000 0x78000>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
<&rpmcc RPM_SMD_BIMC_A_CLK>;
};
cnoc: interconnect@1500000 {
compatible = "qcom,msm8998-cnoc";
reg = <0x01500000 0x10000>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
<&rpmcc RPM_SMD_CNOC_A_CLK>;
};
snoc: interconnect@1625000 {
compatible = "qcom,msm8998-snoc";
reg = <0x01625000 0x6100>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
<&rpmcc RPM_SMD_SNOC_A_CLK>;
};
a1noc: interconnect@1669000 {
compatible = "qcom,msm8998-a1noc";
reg = <0x01669000 0x5020>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
<&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
};
a2noc: interconnect@1705000 {
compatible = "qcom,msm8998-a2noc";
reg = <0x01705000 0xa090>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
<&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
};
mnoc: interconnect@1744000 {
compatible = "qcom,msm8998-mnoc";
reg = <0x01744000 0xb010>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a", "iface";
clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
<&rpmcc RPM_SMD_MMAXI_A_CLK>,
<&mmcc AHB_CLK_SRC>;
};
gnoc: interconnect@17900000 {
compatible = "qcom,msm8998-gnoc";
reg = <0x17900000 0xe000>;
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&xo_board>, <&xo_board>;
};

View file

@ -0,0 +1,173 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/leds-qcom-lpg.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Light Pulse Generator
maintainers:
- Bjorn Andersson <bjorn.andersson@linaro.org>
description: >
The Qualcomm Light Pulse Generator consists of three different hardware blocks;
a ramp generator with lookup table, the light pulse generator and a three
channel current sink. These blocks are found in a wide range of Qualcomm PMICs.
properties:
compatible:
enum:
- qcom,pm8150b-lpg
- qcom,pm8150l-lpg
- qcom,pm8916-pwm
- qcom,pm8941-lpg
- qcom,pm8994-lpg
- qcom,pmc8180c-lpg
- qcom,pmi8994-lpg
- qcom,pmi8998-lpg
"#pwm-cells":
const: 2
"#address-cells":
const: 1
"#size-cells":
const: 0
qcom,power-source:
$ref: /schemas/types.yaml#/definitions/uint32
description:
power-source used to drive the output, as defined in the datasheet.
Should be specified if the TRILED block is present
enum: [0, 1, 3]
qcom,dtest:
$ref: /schemas/types.yaml#/definitions/uint32-matrix
description: >
A list of integer pairs, where each pair represent the dtest line the
particular channel should be connected to and the flags denoting how the
value should be outputed, as defined in the datasheet. The number of
pairs should be the same as the number of channels.
items:
items:
- description: dtest line to attach
- description: flags for the attachment
multi-led:
type: object
$ref: leds-class-multicolor.yaml#
properties:
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^led@[0-9a-f]$":
type: object
$ref: common.yaml#
patternProperties:
"^led@[0-9a-f]$":
type: object
$ref: common.yaml#
properties:
reg: true
required:
- reg
required:
- compatible
additionalProperties: false
examples:
- |
#include <dt-bindings/leds/common.h>
led-controller {
compatible = "qcom,pmi8994-lpg";
#address-cells = <1>;
#size-cells = <0>;
qcom,power-source = <1>;
qcom,dtest = <0 0>,
<0 0>,
<0 0>,
<4 1>;
led@1 {
reg = <1>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_INDICATOR;
function-enumerator = <1>;
};
led@2 {
reg = <2>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_INDICATOR;
function-enumerator = <0>;
default-state = "on";
};
led@3 {
reg = <3>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_INDICATOR;
function-enumerator = <2>;
};
led@4 {
reg = <4>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_INDICATOR;
function-enumerator = <3>;
};
};
- |
#include <dt-bindings/leds/common.h>
led-controller {
compatible = "qcom,pmi8994-lpg";
#address-cells = <1>;
#size-cells = <0>;
qcom,power-source = <1>;
multi-led {
color = <LED_COLOR_ID_RGB>;
function = LED_FUNCTION_STATUS;
#address-cells = <1>;
#size-cells = <0>;
led@1 {
reg = <1>;
color = <LED_COLOR_ID_RED>;
};
led@2 {
reg = <2>;
color = <LED_COLOR_ID_GREEN>;
};
led@3 {
reg = <3>;
color = <LED_COLOR_ID_BLUE>;
};
};
};
- |
pwm-controller {
compatible = "qcom,pm8916-pwm";
#pwm-cells = <2>;
};
...

View file

@ -0,0 +1,139 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/awinic,aw9523-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Awinic AW9523/AW9523B I2C GPIO Expander
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
description: |
The Awinic AW9523/AW9523B I2C GPIO Expander featuring 16 multi-function
I/O, 256 steps PWM mode and interrupt support.
properties:
compatible:
const: awinic,aw9523-pinctrl
reg:
maxItems: 1
'#gpio-cells':
description: |
Specifying the pin number and flags, as defined in
include/dt-bindings/gpio/gpio.h
const: 2
gpio-controller: true
gpio-ranges:
maxItems: 1
interrupt-controller: true
interrupts:
maxItems: 1
description: Specifies the INTN pin IRQ.
'#interrupt-cells':
description:
Specifies the PIN numbers and Flags, as defined in defined in
include/dt-bindings/interrupt-controller/irq.h
const: 2
reset-gpios:
maxItems: 1
#PIN CONFIGURATION NODES
patternProperties:
'-pins$':
type: object
description:
Pinctrl node's client devices use subnodes for desired pin configuration.
Client device subnodes use below standard properties.
$ref: "/schemas/pinctrl/pincfg-node.yaml"
properties:
pins:
description:
List of gpio pins affected by the properties specified in
this subnode.
items:
pattern: "^gpio([0-9]|1[0-5])$"
minItems: 1
maxItems: 16
function:
description:
Specify the alternative function to be configured for the
specified pins.
enum: [ gpio, pwm ]
bias-disable: true
bias-pull-down: true
bias-pull-up: true
drive-open-drain: true
drive-push-pull: true
input-enable: true
input-disable: true
output-high: true
output-low: true
required:
- pins
- function
additionalProperties: false
required:
- compatible
- reg
- gpio-controller
- '#gpio-cells'
- gpio-ranges
additionalProperties: false
examples:
# Example configuration to drive pins for a keyboard matrix
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
aw9523: gpio-expander@58 {
compatible = "awinic,aw9523-pinctrl";
reg = <0x58>;
interrupt-parent = <&tlmm>;
interrupts = <50 IRQ_TYPE_EDGE_FALLING>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&tlmm 0 0 16>;
interrupt-controller;
#interrupt-cells = <2>;
reset-gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
keyboard-matrix-col-pins {
pins = "gpio8", "gpio9", "gpio10", "gpio11",
"gpio12", "gpio13", "gpio14", "gpio15";
function = "gpio";
input-disable;
output-low;
};
keyboard-matrix-row-pins {
pins = "gpio0", "gpio1", "gpio2", "gpio3",
"gpio4", "gpio5", "gpio6", "gpio7";
function = "gpio";
bias-pull-up;
drive-open-drain;
input-enable;
};
};
};

View file

@ -0,0 +1,82 @@
# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/supply/qcom,pmi8998-charger.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm PMI8998/PM660 Switch-Mode Battery Charger "2"
maintainers:
- Caleb Connolly <caleb.connolly@linaro.org>
properties:
compatible:
enum:
- qcom,pmi8998-charger
- qcom,pm660-charger
reg:
maxItems: 1
interrupts:
maxItems: 4
interrupt-names:
items:
- const: usb-plugin
- const: bat-ov
- const: wdog-bark
- const: usbin-icl-change
io-channels:
items:
- description: USB in current in uA
- description: USB in voltage in uV
io-channel-names:
items:
- const: usbin_i
- const: usbin_v
monitored-battery:
description: phandle to the simple-battery node
$ref: /schemas/types.yaml#/definitions/phandle
required:
- compatible
- reg
- interrupts
- interrupt-names
- io-channels
- io-channel-names
- monitored-battery
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
pmic {
#address-cells = <1>;
#size-cells = <0>;
#interrupt-cells = <4>;
charger@1000 {
compatible = "qcom,pmi8998-charger";
reg = <0x1000>;
interrupts = <0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>,
<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "usb-plugin", "bat-ov", "wdog-bark", "usbin-icl-change";
io-channels = <&pmi8998_rradc 3>,
<&pmi8998_rradc 4>;
io-channel-names = "usbin_i",
"usbin_v";
monitored-battery = <&battery>;
};
};

View file

@ -0,0 +1,241 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/soc/qcom/qcom,cpr3.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: Qualcomm Core Power Reduction v3/v4/Hardened (CPR3, CPR4, CPRh)
description: |
CPR (Core Power Reduction) is a technology to reduce core power on a CPU
or other device. Each OPP of a device corresponds to a "corner" that has
a range of valid voltages for a particular frequency. While the device is
running at a particular frequency, CPR monitors dynamic factors such as
temperature, etc. and suggests or, in the CPR-Hardened case performs,
adjustments to the voltage to save power and meet silicon characteristic
requirements.
maintainers:
- AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
properties:
compatible:
oneOf:
- description: CPRv3 controller
items:
- const: qcom,cpr3
- description: CPRv4 controller
items:
- const: qcom,cpr4
- description: CPRv4-Hardened controller
items:
- enum:
- qcom,msm8998-cprh
- qcom,sdm630-cprh
- const: qcom,cprh
reg:
description: Base address and size of the CPR controller(s)
minItems: 1
maxItems: 2
interrupts:
maxItems: 1
clock-names:
items:
- const: "ref"
clocks:
items:
- description: CPR reference clock
vdd-supply:
description: Autonomous Phase Control (APC) or other power supply
'#power-domain-cells':
const: 1
acc-syscon:
description: phandle to syscon for writing ACC settings
nvmem-cells:
description: Cells containing the fuse corners and revision data
minItems: 10
maxItems: 32
nvmem-cell-names:
minItems: 10
maxItems: 32
operating-points-v2: true
required:
- compatible
- reg
- clock-names
- clocks
- "#power-domain-cells"
- nvmem-cells
- nvmem-cell-names
- operating-points-v2
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-msm8998.h>
#include <dt-bindings/interrupt-controller/irq.h>
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu@0 {
compatible = "qcom,kryo280";
device_type = "cpu";
reg = <0x0 0x0>;
operating-points-v2 = <&cpu_gold_opp_table>;
power-domains = <&apc_cprh 0>;
power-domain-names = "cprh";
};
cpu@100 {
compatible = "qcom,kryo280";
device_type = "cpu";
reg = <0x0 0x0>;
operating-points-v2 = <&cpu_silver_opp_table>;
power-domains = <&apc_cprh 1>;
power-domain-names = "cprh";
};
};
cpu_silver_opp_table: cpu-silver-opp-table {
compatible = "operating-points-v2";
opp-shared;
opp-1843200000 {
opp-hz = /bits/ 64 <1843200000>;
required-opps = <&cprh_opp3>;
};
opp-1094400000 {
opp-hz = /bits/ 64 <1094400000>;
required-opps = <&cprh_opp2>;
};
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
required-opps = <&cprh_opp1>;
};
};
cpu_gold_opp_table: cpu-gold-opp-table {
compatible = "operating-points-v2";
opp-shared;
opp-2208000000 {
opp-hz = /bits/ 64 <2208000000>;
required-opps = <&cprh_opp3>;
};
opp-1113600000 {
opp-hz = /bits/ 64 <1113600000>;
required-opps = <&cprh_opp2>;
};
opp-300000000 {
opp-hz = /bits/ 64 <300000000>;
required-opps = <&cprh_opp1>;
};
};
cprh_opp_table: cpr-hardened-opp-table {
compatible = "operating-points-v2-qcom-level";
cprh_opp1: opp1 {
opp-level = <1>;
qcom,opp-fuse-level = <1>;
};
cprh_opp2: opp2 {
opp-level = <2>;
qcom,opp-fuse-level = <2>;
};
cprh_opp3: opp3 {
opp-level = <3>;
qcom,opp-fuse-level = <2 3>;
};
};
apc_cprh: power-controller@179c8000 {
compatible = "qcom,msm8998-cprh", "qcom,cprh";
reg = <0x0179c8000 0x4000>, <0x0179c4000 0x4000>;
clocks = <&gcc GCC_HMSS_RBCPR_CLK>;
clock-names = "ref";
#power-domain-cells = <1>;
operating-points-v2 = <&cprh_opp_table>;
nvmem-cells = <&cpr_efuse_speedbin>,
<&cpr_fuse_revision>,
<&cpr_quot0_pwrcl>,
<&cpr_quot1_pwrcl>,
<&cpr_quot2_pwrcl>,
<&cpr_quot3_pwrcl>,
<&cpr_quot_offset1_pwrcl>,
<&cpr_quot_offset2_pwrcl>,
<&cpr_quot_offset3_pwrcl>,
<&cpr_init_voltage0_pwrcl>,
<&cpr_init_voltage1_pwrcl>,
<&cpr_init_voltage2_pwrcl>,
<&cpr_init_voltage3_pwrcl>,
<&cpr_ro_sel0_pwrcl>,
<&cpr_ro_sel1_pwrcl>,
<&cpr_ro_sel2_pwrcl>,
<&cpr_ro_sel3_pwrcl>,
<&cpr_quot0_perfcl>,
<&cpr_quot1_perfcl>,
<&cpr_quot2_perfcl>,
<&cpr_quot3_perfcl>,
<&cpr_quot_offset1_perfcl>,
<&cpr_quot_offset2_perfcl>,
<&cpr_quot_offset3_perfcl>,
<&cpr_init_voltage0_perfcl>,
<&cpr_init_voltage1_perfcl>,
<&cpr_init_voltage2_perfcl>,
<&cpr_init_voltage3_perfcl>,
<&cpr_ro_sel0_perfcl>,
<&cpr_ro_sel1_perfcl>,
<&cpr_ro_sel2_perfcl>,
<&cpr_ro_sel3_perfcl>;
nvmem-cell-names = "cpr_speed_bin",
"cpr_fuse_revision",
"cpr0_quotient1",
"cpr0_quotient2",
"cpr0_quotient3",
"cpr0_quotient4",
"cpr0_quotient_offset2",
"cpr0_quotient_offset3",
"cpr0_quotient_offset4",
"cpr0_init_voltage1",
"cpr0_init_voltage2",
"cpr0_init_voltage3",
"cpr0_init_voltage4",
"cpr0_ring_osc1",
"cpr0_ring_osc2",
"cpr0_ring_osc3",
"cpr0_ring_osc4",
"cpr1_quotient1",
"cpr1_quotient2",
"cpr1_quotient3",
"cpr1_quotient4",
"cpr1_quotient_offset2",
"cpr1_quotient_offset3",
"cpr1_quotient_offset4",
"cpr1_init_voltage1",
"cpr1_init_voltage2",
"cpr1_init_voltage3",
"cpr1_init_voltage4",
"cpr1_ring_osc1",
"cpr1_ring_osc2",
"cpr1_ring_osc3",
"cpr1_ring_osc4";
};
...

View file

@ -22,19 +22,7 @@ board specific bus parameters.
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: should specify the SoundWire Controller core and optional
wake IRQ
- interrupt-names:
Usage: Optional
Value type: boolean
Value type: <stringlist>
Definition: should be "core" for core and "wakeup" for wake interrupt.
- wakeup-source:
Usage: Optional
Value type: boolean
Definition: should specify if SoundWire Controller is wake up capable.
Definition: should specify the SoundWire Controller IRQ
- clock-names:
Usage: required

View file

@ -0,0 +1,76 @@
.. SPDX-License-Identifier: GPL-2.0
==============================
Kernel driver for Qualcomm LPG
==============================
Description
-----------
The Qualcomm LPG can be found in a variety of Qualcomm PMICs and consists of a
number of PWM channels, a programmable pattern lookup table and a RGB LED
current sink.
To facilitate the various use cases, the LPG channels can be exposed as
individual LEDs, grouped together as RGB LEDs or otherwise be accessed as PWM
channels. The output of each PWM channel is routed to other hardware
blocks, such as the RGB current sink, GPIO pins etc.
The each PWM channel can operate with a period between 27us and 384 seconds and
has a 9 bit resolution of the duty cycle.
In order to provide support for status notifications with the CPU subsystem in
deeper idle states the LPG provides pattern support. This consists of a shared
lookup table of brightness values and per channel properties to select the
range within the table to use, the rate and if the pattern should repeat.
The pattern for a channel can be programmed using the "pattern" trigger, using
the hw_pattern attribute.
/sys/class/leds/<led>/hw_pattern
--------------------------------
Specify a hardware pattern for a Qualcomm LPG LED.
The pattern is a series of brightness and hold-time pairs, with the hold-time
expressed in milliseconds. The hold time is a property of the pattern and must
therefor be identical for each element in the pattern (except for the pauses
described below).
Simple pattern::
"255 500 0 500"
^
|
255 +----+ +----+
| | | | ...
0 | +----+ +----
+---------------------->
0 5 10 15 time (100ms)
The LPG supports specifying a longer hold-time for the first and last element
in the pattern, the so called "low pause" and "high pause".
Low-pause pattern::
"255 1000 0 500 255 500 0 500"
^
|
255 +--------+ +----+ +----+ +--------+
| | | | | | | | ...
0 | +----+ +----+ +----+ +----
+----------------------------->
0 5 10 15 20 25 time (100ms)
Similarily, the last entry can be stretched by using a higher hold-time on the
last entry.
In order to save space in the shared lookup table the LPG supports "ping-pong"
mode, in which case each run through the pattern is performed by first running
the pattern forward, then backwards. This mode is automatically used by the
driver when the given pattern is a palindrome. In this case the "high pause"
denotes the wait time before the pattern is run in reverse and as such the
specified hold-time of the middle item in the pattern is allowed to have a
different hold-time.

View file

@ -16291,6 +16291,12 @@ S: Maintained
F: Documentation/devicetree/bindings/power/avs/qcom,cpr.yaml
F: drivers/soc/qcom/cpr.c
QUALCOMM CORE POWER REDUCTION v3/v4/Hardened AVS DRIVER
M: AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>
S: Maintained
F: Documentation/devicetree/bindings/soc/qcom/qcom,cpr3.yaml
F: drivers/soc/qcom/cpr3.c
QUALCOMM CPUFREQ DRIVER MSM8996/APQ8096
M: Ilia Lin <ilia.lin@kernel.org>
L: linux-pm@vger.kernel.org

View file

@ -16,20 +16,22 @@
touchpad@15 {
compatible = "hid-over-i2c";
interrupt-parent = <&tlmm>;
interrupts = <0x7b IRQ_TYPE_LEVEL_LOW>;
reg = <0x15>;
hid-descr-addr = <0x0001>;
pinctrl-names = "default";
pinctrl-0 = <&touchpad>;
interrupt-parent = <&tlmm>;
interrupts = <123 IRQ_TYPE_LEVEL_LOW>;
hid-descr-addr = <0x0001>;
};
keyboard@3a {
compatible = "hid-over-i2c";
interrupt-parent = <&tlmm>;
interrupts = <0x25 IRQ_TYPE_LEVEL_LOW>;
reg = <0x3a>;
interrupt-parent = <&tlmm>;
interrupts = <37 IRQ_TYPE_LEVEL_LOW>;
hid-descr-addr = <0x0001>;
};
};
@ -37,12 +39,3 @@
&sdhc2 {
cd-gpios = <&tlmm 95 GPIO_ACTIVE_HIGH>;
};
&tlmm {
touchpad: touchpad {
config {
pins = "gpio123";
bias-pull-up;
};
};
};

View file

@ -8,13 +8,10 @@
*/
#include "msm8998.dtsi"
#include "pm8998.dtsi"
#include "pm8005.dtsi"
#include "pm8998.dtsi"
/ {
chosen {
};
vph_pwr: vph-pwr-regulator {
compatible = "regulator-fixed";
regulator-name = "vph_pwr";
@ -37,6 +34,28 @@
};
};
&blsp1_uart3_on {
rx {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 45 (RX). This is needed to
* avoid garbage data when the TX pin of the Bluetooth
* module is in tri-state (module powered off or not
* driving the signal yet).
*/
bias-pull-up;
};
cts {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
* of the Bluetooth module.
*/
bias-pull-down;
};
};
/*
* The laptop FW does not appear to support the retention state as it is
* not advertised as enabled in ACPI, and enabling it in DT can cause boot
@ -74,6 +93,20 @@
cpu-idle-states = <&BIG_CPU_SLEEP_1>;
};
/*
* If EFIFB is used, enabling MMCC will cause important MMSS clocks to be cleaned
* up, because as far as Linux is concerned - they are unused. Disable it by default
* on clamshell devices, as it will break them, unless either simplefb is configured to
* hold a vote for these clocks, or panels are brought up properly, using drm/msm.
*/
&mmcc {
status = "disabled";
};
&mmss_smmu {
status = "disabled";
};
&pcie0 {
status = "okay";
};
@ -82,20 +115,16 @@
status = "okay";
};
&pm8005_lsid1 {
pm8005-regulators {
compatible = "qcom,pm8005-regulators";
&pm8005_regulators {
vdd_s1-supply = <&vph_pwr>;
vdd_s1-supply = <&vph_pwr>;
pm8005_s1: s1 { /* VDD_GFX supply */
regulator-min-microvolt = <524000>;
regulator-max-microvolt = <1100000>;
regulator-enable-ramp-delay = <500>;
pm8005_s1: s1 { /* VDD_GFX supply */
regulator-min-microvolt = <524000>;
regulator-max-microvolt = <1100000>;
regulator-enable-ramp-delay = <500>;
/* hack until we rig up the gpu consumer */
regulator-always-on;
};
/* hack until we rig up the gpu consumer */
regulator-always-on;
};
};
@ -143,127 +172,156 @@
regulator-min-microvolt = <1352000>;
regulator-max-microvolt = <1352000>;
};
vreg_s4a_1p8: s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-allow-set-load;
};
vreg_s5a_2p04: s5 {
regulator-min-microvolt = <1904000>;
regulator-max-microvolt = <2040000>;
};
vreg_s7a_1p025: s7 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1028000>;
};
vreg_l1a_0p875: l1 {
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
regulator-allow-set-load;
};
vreg_l2a_1p2: l2 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-allow-set-load;
};
vreg_l3a_1p0: l3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l5a_0p8: l5 {
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <800000>;
};
vreg_l6a_1p8: l6 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <1808000>;
};
vreg_l7a_1p8: l7 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-allow-set-load;
};
vreg_l8a_1p2: l8 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
vreg_l9a_1p8: l9 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l10a_1p8: l10 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l11a_1p0: l11 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l12a_1p8: l12 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l13a_2p95: l13 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l14a_1p88: l14 {
regulator-min-microvolt = <1880000>;
regulator-max-microvolt = <1880000>;
};
vreg_l15a_1p8: l15 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l16a_2p7: l16 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
vreg_l17a_1p3: l17 {
regulator-min-microvolt = <1304000>;
regulator-max-microvolt = <1304000>;
regulator-allow-set-load;
};
vreg_l18a_2p7: l18 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
vreg_l19a_3p0: l19 {
regulator-min-microvolt = <3008000>;
regulator-max-microvolt = <3008000>;
};
vreg_l20a_2p95: l20 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
};
vreg_l21a_2p95: l21 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
regulator-system-load = <800000>;
};
vreg_l22a_2p85: l22 {
regulator-min-microvolt = <2864000>;
regulator-max-microvolt = <2864000>;
};
vreg_l23a_3p3: l23 {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3312000>;
};
vreg_l24a_3p075: l24 {
regulator-min-microvolt = <3088000>;
regulator-max-microvolt = <3088000>;
};
vreg_l25a_3p3: l25 {
regulator-min-microvolt = <3104000>;
regulator-max-microvolt = <3312000>;
regulator-allow-set-load;
};
vreg_l26a_1p2: l26 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
vreg_l28_3p0: l28 {
regulator-min-microvolt = <3008000>;
regulator-max-microvolt = <3008000>;
@ -278,7 +336,6 @@
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
};
};
@ -286,17 +343,6 @@
status = "okay";
};
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
touchpad: touchpad {
config {
pins = "gpio123";
bias-pull-up; /* pull up */
};
};
};
&sdhc2 {
status = "okay";
@ -304,8 +350,17 @@
vqmmc-supply = <&vreg_l13a_2p95>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
pinctrl-0 = <&sdc2_on &sdc2_cd>;
pinctrl-1 = <&sdc2_off &sdc2_cd>;
};
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
touchpad: touchpad-pin {
pins = "gpio123";
bias-pull-up;
};
};
&ufshc {
@ -341,26 +396,3 @@
vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;
vdd-3.3-ch0-supply = <&vreg_l25a_3p3>;
};
/* PINCTRL - board-specific pinctrl */
&blsp1_uart3_on {
rx {
/delete-property/ bias-disable;
/*
* Configure a pull-up on 45 (RX). This is needed to
* avoid garbage data when the TX pin of the Bluetooth
* module is in tri-state (module powered off or not
* driving the signal yet).
*/
bias-pull-up;
};
cts {
/delete-property/ bias-disable;
/*
* Configure a pull-down on 47 (CTS) to match the pull
* of the Bluetooth module.
*/
bias-pull-down;
};
};

View file

@ -18,6 +18,15 @@
chassis-type = "handset";
qcom,board-id = <0x02000b 0x10>;
/* This part enables graphical output via bootloader-enabled display */
chosen {
bootargs = "earlycon=tty0 console=tty0 clk_ignore_unused";
#address-cells = <2>;
#size-cells = <2>;
ranges;
};
/*
* Until we hook up type-c detection, we
* have to stick with this. But it works.
@ -46,6 +55,8 @@
gpio-kb-extra-keys {
compatible = "gpio-keys";
label = "Keyboard extra keys";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&gpio_kb_pins_extra>;
@ -98,6 +109,39 @@
};
};
gpio_keyboard: gpio-keyboard {
compatible = "gpio-fastmatrix-keyboard";
label = "F(x)Tec Pro1 Hardware Keyboard";
row-gpios =
<&gpioext0 0 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 1 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 2 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 3 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 4 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 5 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 6 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>,
<&gpioext0 7 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>;
col-gpios =
<&gpioext0 8 GPIO_ACTIVE_LOW>,
<&gpioext0 9 GPIO_ACTIVE_LOW>,
<&gpioext0 10 GPIO_ACTIVE_LOW>,
<&gpioext0 11 GPIO_ACTIVE_LOW>,
<&gpioext0 12 GPIO_ACTIVE_LOW>,
<&gpioext0 13 GPIO_ACTIVE_LOW>,
<&gpioext0 14 GPIO_ACTIVE_LOW>,
<&gpioext0 15 GPIO_ACTIVE_LOW>;
keypad,num-rows = <8>;
keypad,num-columns = <8>;
pinctrl-names = "default";
pinctrl-0 = <&keyboard_pins_col>, <&keyboard_pins_row>;
autorescan-ms = <5>;
debounce-delay-ms = <1>;
col-scan-delay-us = <1500>;
};
gpio-keys {
compatible = "gpio-keys";
label = "Side buttons";
@ -177,6 +221,53 @@
};
};
disp_vcc_vreg: disp-vcc-regulator {
compatible = "regulator-fixed";
regulator-name = "disp_vcc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};
disp_vddio_vreg: disp-vddio-regulator {
compatible = "regulator-fixed";
regulator-name = "disp_vddio";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-boot-on;
regulator-always-on;
regulator-allow-set-load;
};
disp_vci_vreg: disp-vci-regulator {
compatible = "regulator-fixed";
regulator-name = "disp_vci";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
regulator-boot-on;
regulator-always-on;
regulator-allow-set-load;
};
disp_elvdd_vreg: disp-elvdd-regulator {
compatible = "regulator-fixed";
regulator-name = "disp_elvdd";
regulator-min-microvolt = <4600000>;
regulator-max-microvolt = <4600000>;
regulator-boot-on;
regulator-always-on;
};
disp_elvss_vreg: disp-elvss-regulator {
compatible = "regulator-fixed";
regulator-name = "disp_elvss";
regulator-min-microvolt = <2400000>;
regulator-max-microvolt = <2400000>;
regulator-boot-on;
regulator-always-on;
};
ts_vio_vreg: ts-vio-vreg {
compatible = "regulator-fixed";
regulator-name = "ts_vio_reg";
@ -189,8 +280,62 @@
};
};
&adreno_gpu {
status = "okay";
zap-shader {
memory-region = <&zap_shader_region>;
firmware-name = "qcom/a540_zap.mbn";
};
};
&adreno_smmu {
status = "okay";
};
&apc_cprh {
status = "okay";
};
&blsp1_i2c6 {
status = "okay";
gpioext0: gpio-expander@58 {
compatible = "awinic,aw9523-pinctrl";
reg = <0x58>;
interrupt-parent = <&tlmm>;
interrupts = <50 IRQ_TYPE_EDGE_FALLING>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&gpioext0 0 0 16>;
interrupt-controller;
#interrupt-cells = <2>;
pinctrl-0 = <&gpio_expander_int_n>, <&gpio_expander_rst_n>;
pinctrl-names = "default";
reset-gpios = <&tlmm 51 GPIO_ACTIVE_HIGH>;
keyboard_pins_col: keyboard-matrix-col-pins {
pins = "gpio8", "gpio9", "gpio10", "gpio11",
"gpio12", "gpio13", "gpio14", "gpio15";
function = "gpio";
output-low;
};
keyboard_pins_row: keyboard-matrix-row-pins {
pins = "gpio0", "gpio1", "gpio2", "gpio3",
"gpio4", "gpio5", "gpio6", "gpio7";
function = "gpio";
drive-open-drain;
input-enable;
};
};
};
&blsp2_i2c1 {
status = "ok";
status = "okay";
qcom,noise-reject-scl = <3>;
qcom,noise-reject-sda = <3>;
touchscreen@14 {
compatible = "goodix,gt9286";
@ -205,15 +350,141 @@
};
};
&mmcc {
status = "ok";
&cpufreq_hw {
status = "okay";
};
&mmss_smmu {
status = "ok";
&dsi0 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
vdd-supply = <&vreg_l1a_0p875>;
vdda-supply = <&vreg_l2a_1p2>;
panel: panel@0 {
compatible = "boe,bf060y8m-aj0";
reg = <0>;
reset-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
disp-te-gpios = <&tlmm 10 GPIO_ACTIVE_LOW>;
no-hpd;
vcc-supply = <&disp_vcc_vreg>;
vddio-supply = <&disp_vddio_vreg>;
vci-supply = <&disp_vci_vreg>;
elvdd-supply = <&disp_elvdd_vreg>;
elvss-supply = <&disp_elvss_vreg>;
pinctrl-names = "default";
pinctrl-0 = <&panel_reset_n &disp_en_default &mdp_vsync_n>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
};
&dsi0_phy {
status = "okay";
};
&dsi0_out {
remote-endpoint = <&panel_in>;
data-lanes = <0 1 2 3>;
};
&gcc {
status = "okay";
};
&gpucc {
status = "okay";
};
&gpio_keyboard {
linux,keymap = <
MATRIX_KEY(0, 0, KEY_F1) MATRIX_KEY(1, 0, KEY_H)
MATRIX_KEY(2, 0, KEY_B) MATRIX_KEY(3, 0, KEY_7)
MATRIX_KEY(4, 0, KEY_UP) MATRIX_KEY(5, 0, KEY_ENTER)
MATRIX_KEY(6, 0, KEY_Y) MATRIX_KEY(7, 0, KEY_COMMA)
MATRIX_KEY(0, 1, KEY_3) MATRIX_KEY(1, 1, KEY_S)
MATRIX_KEY(2, 1, KEY_Z) MATRIX_KEY(3, 1, KEY_M)
MATRIX_KEY(4, 1, KEY_I) MATRIX_KEY(5, 1, KEY_9)
MATRIX_KEY(6, 1, KEY_W) MATRIX_KEY(7, 1, KEY_J)
MATRIX_KEY(0, 2, KEY_LEFT) MATRIX_KEY(1, 2, KEY_G)
MATRIX_KEY(2, 2, KEY_V) MATRIX_KEY(3, 2, KEY_6)
MATRIX_KEY(4, 2, KEY_RIGHT) MATRIX_KEY(5, 2, KEY_DELETE)
MATRIX_KEY(6, 2, KEY_T) MATRIX_KEY(7, 2, KEY_DOT)
MATRIX_KEY(0, 3, KEY_SLASH) MATRIX_KEY(1, 3, KEY_A)
MATRIX_KEY(2, 3, KEY_RIGHTBRACE) MATRIX_KEY(3, 3, KEY_HOMEPAGE)
MATRIX_KEY(4, 3, KEY_P) MATRIX_KEY(5, 3, KEY_MINUS)
MATRIX_KEY(6, 3, KEY_Q) MATRIX_KEY(7, 3, KEY_L)
MATRIX_KEY(0, 4, KEY_BACKSPACE) MATRIX_KEY(1, 4, KEY_D)
MATRIX_KEY(2, 4, KEY_X) MATRIX_KEY(3, 4, KEY_K)
MATRIX_KEY(4, 4, KEY_SEMICOLON) MATRIX_KEY(5, 4, KEY_EQUAL)
MATRIX_KEY(6, 4, KEY_E) MATRIX_KEY(7, 4, KEY_APOSTROPHE)
MATRIX_KEY(0, 5, KEY_CAPSLOCK) MATRIX_KEY(1, 5, KEY_BACKSLASH)
MATRIX_KEY(2, 5, KEY_LEFTBRACE) MATRIX_KEY(3, 5, KEY_DOWN)
MATRIX_KEY(4, 5, KEY_O) MATRIX_KEY(5, 5, KEY_0)
MATRIX_KEY(6, 5, KEY_GRAVE) MATRIX_KEY(7, 5, KEY_K)
MATRIX_KEY(0, 6, KEY_SPACE) MATRIX_KEY(1, 6, KEY_F)
MATRIX_KEY(2, 6, KEY_C) MATRIX_KEY(3, 6, KEY_N)
MATRIX_KEY(4, 6, KEY_U) MATRIX_KEY(5, 6, KEY_8)
MATRIX_KEY(6, 6, KEY_R) MATRIX_KEY(7, 6, KEY_5)
MATRIX_KEY(0, 7, KEY_ESC) MATRIX_KEY(1, 7, KEY_1)
MATRIX_KEY(2, 7, KEY_RESERVED) MATRIX_KEY(3, 7, KEY_RESERVED)
MATRIX_KEY(4, 7, KEY_2) MATRIX_KEY(5, 7, KEY_4)
MATRIX_KEY(6, 7, KEY_TAB) MATRIX_KEY(7, 7, KEY_RESERVED)
>;
};
&mdss {
status = "okay";
};
&mdss_mdp {
status = "okay";
};
&remoteproc_adsp {
status = "okay";
firmware-name = "qcom/msm8998/fxtec/adsp.mbn";
};
&remoteproc_mss {
firmware-name = "qcom/msm8998/fxtec/mba.mbn", "qcom/msm8998/fxtec/modem.mbn";
};
&remoteproc_slpi {
status = "okay";
firmware-name = "qcom/msm8998/fxtec/slpi_v2.mbn";
};
&pmi8998_haptics {
status = "okay";
qcom,wave-play-rate-us = <5000>;
};
/* HACK! Push GPU voltage high until GPU CPR is hooked up */
&pm8005_s1 {
regulator-min-microvolt = <988000>;
regulator-max-microvolt = <1100000>;
};
&pm8998_gpio {
unknown_pin_a: unk-active {
pins = "gpio5";
function = "normal";
input-enable;
bias-pull-up;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_HIGH>;
};
vol_up_pin_a: vol-up-active {
pins = "gpio6";
function = "normal";
@ -267,6 +538,26 @@
bias-pull-up;
};
gpio_expander_int_n: gpio-exp-intn-def {
pins = "gpio50";
function = "gpio";
drive-strength = <2>;
input-enable;
};
gpio_expander_rst_n: gpio-exp-rst-def {
pins = "gpio51";
function = "gpio";
drive-strength = <8>;
};
disp_en_default: disp-en {
pins = "gpio62";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
ts_vio_default: ts-vio-def {
pins = "gpio81";
function = "gpio";
@ -295,14 +586,21 @@
bias-disable;
drive-strength = <8>;
};
panel_reset_n: panel-rst-n {
pins = "gpio94";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
};
&ufshc {
status = "ok";
status = "okay";
};
&ufsphy {
status = "ok";
status = "okay";
};
&usb3_dwc3 {

View file

@ -16,13 +16,14 @@
keyboard@3a {
compatible = "hid-over-i2c";
interrupt-parent = <&tlmm>;
interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>;
reg = <0x3a>;
hid-descr-addr = <0x0001>;
pinctrl-names = "default";
pinctrl-0 = <&touchpad>;
interrupt-parent = <&tlmm>;
interrupts = <121 IRQ_TYPE_LEVEL_LOW>;
hid-descr-addr = <0x0001>;
};
};

View file

@ -16,13 +16,14 @@
keyboard@3a {
compatible = "hid-over-i2c";
interrupt-parent = <&tlmm>;
interrupts = <0x79 IRQ_TYPE_LEVEL_LOW>;
reg = <0x3a>;
hid-descr-addr = <0x0001>;
pinctrl-names = "default";
pinctrl-0 = <&touchpad>;
interrupt-parent = <&tlmm>;
interrupts = <121 IRQ_TYPE_LEVEL_LOW>;
hid-descr-addr = <0x0001>;
};
};

View file

@ -348,8 +348,8 @@
vqmmc-supply = <&vreg_l13a_2p95>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
pinctrl-0 = <&sdc2_on &sdc2_cd>;
pinctrl-1 = <&sdc2_off &sdc2_cd>;
};
&stm {

View file

@ -41,3 +41,19 @@
};
};
};
/* Capacitive keypad buttons */
&rmi4_i2c {
rmi4-f1a@1a {
reg = <0x1a>;
syna,codes = <KEY_BACK KEY_APPSELECT>;
};
};
/* Display */
&panel {
compatible = "samsung,s6e3fa5";
/* The panel is mounted upside down on the OnePlus 5 */
rotation = <180>;
};

View file

@ -9,11 +9,12 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
#include "msm8998.dtsi"
#include "pm8005.dtsi"
#include "pm8998.dtsi"
#include "pmi8998.dtsi"
#include "pm8005.dtsi"
/ {
/* Required for bootloader to select correct board */
@ -32,6 +33,20 @@
height = <1920>;
stride = <(1080 * 4)>;
format = "a8r8g8b8";
/*
* That's a lot of clocks, but it's necessary due
* to unused clk cleanup & no panel driver yet..
*/
clocks = <&mmcc MDSS_AHB_CLK>,
<&mmcc MDSS_AXI_CLK>,
<&mmcc MDSS_VSYNC_CLK>,
<&mmcc MDSS_MDP_CLK>,
<&mmcc MDSS_BYTE0_CLK>,
<&mmcc MDSS_BYTE0_INTF_CLK>,
<&mmcc MDSS_PCLK0_CLK>,
<&mmcc MDSS_ESC0_CLK>;
power-domains = <&mmcc MDSS_GDSC>;
status = "disabled";
};
};
@ -67,6 +82,15 @@
reg = <0x0 0xf6900000 0x0 0x2000>;
no-map;
};
blp637_bat: battery {
compatible = "simple-battery";
voltage-max-design-microvolt = <4370000>;
voltage-min-design-microvolt = <3700000>;
charge-full-design-microamp-hours = <3300000>;
energy-full-design-microwatt-hours = <12700000>;
operating-range-celsius = <0 45>;
};
};
gpio-keys {
@ -152,10 +176,18 @@
reg = <0x0 0x95715000 0x0 0x100000>;
};
&apc_cprh {
status = "okay";
};
&cpufreq_hw {
status = "okay";
};
&blsp1_i2c5 {
status = "okay";
touchscreen@20 {
rmi4_i2c: touchscreen@20 {
compatible = "syna,rmi4-i2c";
reg = <0x20>;
#address-cells = <1>;
@ -188,6 +220,29 @@
};
};
&blsp1_i2c5_sleep {
/delete-property/ bias-pull-up;
/* Configure a no-pull on TP I2C sleep to match downstream. */
bias-disable;
};
&blsp1_i2c6 {
status = "okay";
nfc@28 {
compatible = "nxp,nxp-nci-i2c";
reg = <0x28>;
interrupt-parent = <&tlmm>;
interrupts = <92 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&tlmm 116 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&nfc_int_active &nfc_enable_active>;
};
};
&blsp1_uart3 {
status = "okay";
@ -224,39 +279,88 @@
};
};
&blsp2_i2c1 {
status = "okay";
fuel-gauge@55 {
compatible = "ti,bq27411";
reg = <0x55>;
/*
* TODO: Adding this appears to not change any reported stats in:
* $ cat /sys/class/power_supply/bq27411-0/uevent
*/
monitored-battery = <&blp637_bat>;
};
};
&blsp2_i2c3 {
status = "disabled";
audio-codec@36 {
compatible = "nxp,tfa9890";
reg = <0x36>;
/*
* vddd-supply = <&vreg_bob>;
* vreg_l20a_2p95? 2950000->2960000 mV @ 200->800000 mA?
*/
sound-name-prefix = "Mono Speaker";
#sound-dai-cells = <0>;
status = "disabled";
};
};
&blsp2_uart1 {
status = "okay";
};
&pm8005_lsid1 {
pm8005-regulators {
compatible = "qcom,pm8005-regulators";
&ipa {
status = "okay";
vdd_s1-supply = <&vph_pwr>;
memory-region = <&ipa_fws_region>; // ipa_fw_mem? ipa_gsi_mem?
firmware-name = "qcom/msm8998/oneplus/ipa_fws.mbn";
};
pm8005_s1: s1 { /* VDD_GFX supply */
regulator-min-microvolt = <524000>;
regulator-max-microvolt = <1100000>;
regulator-enable-ramp-delay = <500>;
/* hack until we rig up the gpu consumer */
regulator-always-on;
};
&pm8005_regulators {
/* VDD_GFX supply */
pm8005_s1: s1 {
regulator-min-microvolt = <524000>;
regulator-max-microvolt = <1100000>;
regulator-enable-ramp-delay = <500>;
/* Hack until we rig up the gpu consumer */
regulator-always-on;
};
};
&pm8998_gpio {
vol_keys_default: vol-keys-default {
pinconf {
pins = "gpio5", "gpio6";
function = "normal";
bias-pull-up;
input-enable;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
};
pins = "gpio5", "gpio6";
function = "normal";
bias-pull-up;
input-enable;
qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
};
};
&pmi8998_haptics {
status = "okay";
qcom,wave-play-rate-us = <4255>;
};
&pmi8998_charger {
status = "okay";
monitored-battery = <&blp637_bat>;
};
// cat /sys/bus/iio/devices/iio:device0/in_current0_*
&pmi8998_rradc {
status = "okay";
};
&qusb2phy {
status = "okay";
@ -269,30 +373,18 @@
pm8998-regulators {
compatible = "qcom,rpm-pm8998-regulators";
vdd_s1-supply = <&vph_pwr>;
vdd_s2-supply = <&vph_pwr>;
vdd_s1-supply = <&vph_pwr>; /* GPU? */
vdd_s3-supply = <&vph_pwr>;
vdd_s4-supply = <&vph_pwr>;
vdd_s5-supply = <&vph_pwr>;
vdd_s6-supply = <&vph_pwr>;
vdd_s7-supply = <&vph_pwr>;
vdd_s8-supply = <&vph_pwr>;
vdd_s9-supply = <&vph_pwr>;
vdd_s10-supply = <&vph_pwr>;
vdd_s11-supply = <&vph_pwr>;
vdd_s12-supply = <&vph_pwr>;
vdd_s13-supply = <&vph_pwr>;
vdd_l1_l27-supply = <&vreg_s7a_1p025>;
vdd_l2_l8_l17-supply = <&vreg_s3a_1p35>;
vdd_l3_l11-supply = <&vreg_s7a_1p025>;
vdd_l4_l5-supply = <&vreg_s7a_1p025>;
vdd_l1-supply = <&vreg_s7a_1p025>;
vdd_l2_l17-supply = <&vreg_s3a_1p35>;
vdd_l5-supply = <&vreg_s7a_1p025>;
vdd_l6-supply = <&vreg_s5a_2p04>;
vdd_l7_l12_l14_l15-supply = <&vreg_s5a_2p04>;
vdd_l9-supply = <&vreg_bob>;
vdd_l10_l23_l25-supply = <&vreg_bob>;
vdd_l13_l19_l21-supply = <&vreg_bob>;
vdd_l16_l28-supply = <&vreg_bob>;
vdd_l18_l22-supply = <&vreg_bob>;
vdd_l7_l12_l14-supply = <&vreg_s5a_2p04>;
vdd_l25-supply = <&vreg_bob>;
vdd_l28-supply = <&vreg_bob>;
vdd_l20_l24-supply = <&vreg_bob>;
vdd_l26-supply = <&vreg_s3a_1p35>;
vdd_lvs1_lvs2-supply = <&vreg_s4a_1p8>;
@ -301,127 +393,90 @@
regulator-min-microvolt = <1352000>;
regulator-max-microvolt = <1352000>;
};
vreg_s4a_1p8: s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-allow-set-load;
};
vreg_s5a_2p04: s5 {
regulator-min-microvolt = <1904000>;
regulator-max-microvolt = <2040000>;
};
vreg_s7a_1p025: s7 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1028000>;
};
vreg_l1a_0p875: l1 {
vreg_l1a_0p875: l1 { /* UFS PHY */
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
};
vreg_l2a_1p2: l2 {
vreg_l2a_1p2: l2 { /* UFS PHY */
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
vreg_l3a_1p0: l3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l5a_0p8: l5 {
vreg_l5a_0p8: l5 { /* Wi-Fi */
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <800000>;
};
vreg_l6a_1p8: l6 {
vreg_l6a_1p8: l6 { /* Touchscreen */
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <1808000>;
};
vreg_l7a_1p8: l7 {
vreg_l7a_1p8: l7 { /* Wi-Fi + BT */
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l8a_1p2: l8 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
vreg_l9a_1p8: l9 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l10a_1p8: l10 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l11a_1p0: l11 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l12a_1p8: l12 {
vreg_l12a_1p8: l12 { /* QUSB2 PHY */
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l13a_2p95: l13 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l14a_1p88: l14 {
vreg_l14a_1p88: l14 { /* DSI display */
regulator-min-microvolt = <1880000>;
regulator-max-microvolt = <1880000>;
};
vreg_l15a_1p8: l15 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l16a_2p7: l16 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
vreg_l17a_1p3: l17 {
vreg_l17a_1p3: l17 { /* Wi-Fi + BT */
regulator-min-microvolt = <1304000>;
regulator-max-microvolt = <1304000>;
};
vreg_l18a_2p7: l18 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
vreg_l19a_3p0: l19 {
regulator-min-microvolt = <3008000>;
regulator-max-microvolt = <3008000>;
};
vreg_l20a_2p95: l20 {
vreg_l20a_2p95: l20 { /* UFS HC */
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
};
vreg_l21a_2p95: l21 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
regulator-system-load = <800000>;
};
vreg_l22a_2p85: l22 {
regulator-min-microvolt = <2864000>;
regulator-max-microvolt = <2864000>;
};
vreg_l23a_3p3: l23 {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3312000>;
};
vreg_l24a_3p075: l24 {
vreg_l24a_3p075: l24 { /* QUSB2 PHY */
regulator-min-microvolt = <3088000>;
regulator-max-microvolt = <3088000>;
};
vreg_l25a_3p3: l25 {
vreg_l25a_3p3: l25 { /* Wi-Fi + BT */
regulator-min-microvolt = <3104000>;
regulator-max-microvolt = <3312000>;
};
vreg_l26a_1p2: l26 {
vreg_l26a_1p2: l26 { /* UFS PHY + HC */
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-allow-set-load;
};
vreg_l28_3p0: l28 {
vreg_l28_3p0: l28 { /* Touchscreen */
regulator-min-microvolt = <3008000>;
regulator-max-microvolt = <3008000>;
};
vreg_lvs1a_1p8: lvs1 { };
vreg_lvs2a_1p8: lvs2 { };
};
@ -438,9 +493,140 @@
};
};
&remoteproc_adsp {
status = "okay";
firmware-name = "qcom/msm8998/oneplus/adsp.mbn";
};
&remoteproc_mss {
status = "okay";
firmware-name = "qcom/msm8998/oneplus/mba.mbn", "qcom/msm8998/oneplus/modem.mbn";
};
&remoteproc_slpi {
status = "okay";
firmware-name = "qcom/msm8998/oneplus/slpi_v2.mbn";
};
&mdss {
status = "okay";
};
&mdss_mdp {
status = "okay";
/* It appears CTL_START register always reads back as 0 */
qcom,ctl-no-start-read-quirk;
};
&dsi0 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
vdd-supply = <&vreg_l1a_0p875>;
vdda-supply = <&vreg_l2a_1p2>;
panel: panel@0 {
reg = <0>;
reset-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>;
disp-te-gpios = <&tlmm 11 GPIO_ACTIVE_LOW>;
vddio-supply = <&vreg_l14a_1p88>; // TODO: Could this be moved under dsi0?
pinctrl-names = "default";
pinctrl-0 = <&panel_reset_n &disp_en_default &mdp_vsync_n>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
};
&dsi0_phy {
status = "okay";
vdds-supply = <&vreg_l1a_0p875>;
};
&dsi0_out {
remote-endpoint = <&panel_in>;
data-lanes = <0 1 2 3>;
};
/* Adreno 540 GPU */
&gpucc {
status = "okay";
};
&gpu_mem {
compatible = "shared-dma-pool";
};
&adreno_gpu {
status = "okay";
zap-shader {
memory-region = <&zap_shader_region>; // gpu_mem?
firmware-name = "qcom/msm8998/oneplus/a540_zap.mbn";
};
/*
* We are lacking support for the GPU regulator. Hence, disable higher
* frequencies for now to prevent the platform from hanging on high
* graphics loads. Perhaps the pm8005_s1 voltage below could be
* adjusted but I'd rather not touch it.
*/
opp-table {
/delete-node/ opp-710000097;
/delete-node/ opp-670000048;
/delete-node/ opp-596000097;
/delete-node/ opp-515000097;
};
};
&adreno_smmu {
status = "okay";
};
/*
* HACK: Shoot GPU voltage high to stabilize Adreno 540 at high frequencies
* until the GPU CPR is brought up.
*/
&pm8005_s1 {
regulator-min-microvolt = <988000>; /* 0,524V -> 0,988V */
//regulator-max-microvolt = <1100000>;
};
&tlmm {
gpio-reserved-ranges = <0 4>, <81 4>;
disp_en_default: disp-en {
pins = "gpio62";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
panel_reset_n: panel-rst-n {
pins = "gpio94";
function = "gpio";
drive-strength = <8>;
bias-disable;
};
mdp_vsync_n: mdp-vsync-n {
pins = "gpio11";
function = "mdp_vsync_a";
drive-strength = <2>;
bias-pull-down;
};
hall_sensor_default: hall-sensor-default {
pins = "gpio124";
function = "gpio";
@ -462,6 +648,20 @@
drive-strength = <8>;
bias-pull-up;
};
nfc_int_active: nfc_int_active {
pins = "gpio92";
function = "gpio";
drive-strength = <6>;
bias-pull-up;
};
nfc_enable_active: nfc_enable_active {
pins = "gpio12", "gpio116";
function = "gpio";
drive-strength = <6>;
bias-pull-up;
};
};
&ufshc {
@ -503,7 +703,7 @@
};
&wifi {
/* Leave disabled until MSS is functional */
status = "okay";
vdd-0.8-cx-mx-supply = <&vreg_l5a_0p8>;
vdd-1.8-xo-supply = <&vreg_l7a_1p8>;
vdd-1.3-rfa-supply = <&vreg_l17a_1p3>;

View file

@ -24,3 +24,8 @@
&rmi4_f12 {
touchscreen-y-mm = <137>;
};
/* Display */
&panel {
compatible = "samsung,s6e3fc1";
};

View file

@ -25,7 +25,16 @@
qcom,soft-start-us = <800>;
};
&wcd9335 {
pinctrl-0 = <&cdc_reset_n &wcd_int_n>;
pinctrl-names = "default";
};
&vreg_l22a_2p85 {
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
&vreg_lvs1a_1p8 {
status = "disabled";
};

View file

@ -26,6 +26,28 @@
};
};
&dsi0 {
qcom,dual-dsi-mode;
qcom,master-dsi;
};
&dsi1 {
vdd-supply = <&vreg_l1a_0p875>;
vdda-supply = <&vreg_l2a_1p2>;
qcom,dual-dsi-mode;
status = "ok";
};
&dsi1_out {
remote-endpoint = <&panel_in1>;
data-lanes = <0 1 2 3>;
};
&dsi1_phy {
vdds-supply = <&vreg_l1a_0p875>;
status = "ok";
};
&ibb {
regulator-min-microvolt = <5600000>;
regulator-max-microvolt = <5600000>;
@ -37,6 +59,32 @@
qcom,soft-start-us = <200>;
};
&panel {
compatible = "sharp,ls055d1sx04";
dvdd-supply = <&disp_dvdd_vreg>;
ports {
port@1 {
reg = <1>;
panel_in1: endpoint {
remote-endpoint = <&dsi1_out>;
};
};
};
};
&pm8005_gpio {
ear_en_default: ear-en-active {
pins = "gpio1";
function = "normal";
bias-disable;
drive-push-pull;
output-high;
power-source = <1>; /* 1.8V */
qcom,drive-strength = <1>;
};
};
&pmi8998_gpio {
disp_dvdd_en: disp-dvdd-en-active {
pins = "gpio10";
@ -53,3 +101,17 @@
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
&pmi8998_wled {
status = "okay";
//qcom,auto-string-detection;
qcom,num-strings = <3>;
qcom,enabled-strings = <0 1 2>;
};
&wcd9335 {
pinctrl-0 = <&cdc_reset_n &wcd_int_n &ear_en_default>;
pinctrl-names = "default";
};

View file

@ -25,6 +25,11 @@
qcom,soft-start-us = <800>;
};
&wcd9335 {
pinctrl-0 = <&cdc_reset_n &wcd_int_n>;
pinctrl-names = "default";
};
&vreg_l18a_2p85 {
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;

View file

@ -20,9 +20,11 @@
qcom,msm-id = <0x124 0x20000>, <0x124 0x20001>; /* 8998v2, v2.1 */
qcom,board-id = <8 0>;
clocks {
compatible = "simple-bus";
chosen {
bootargs = "clk_ignore_unused root=/dev/mmcblk0p1";
};
clocks {
div1_mclk: divclk1 {
compatible = "gpio-gate-clock";
pinctrl-0 = <&audio_mclk_pin>;
@ -84,6 +86,15 @@
pinctrl-0 = <&ts_vddio_en>;
};
/* The gpio-vibrator driver enforces requiring a regulator */
vib_vreg: vib-regulator {
compatible = "regulator-fixed";
regulator-name = "vib";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
vph_pwr: vph-pwr-regulator {
compatible = "regulator-fixed";
regulator-name = "vph_pwr";
@ -91,6 +102,14 @@
regulator-boot-on;
};
extcon_usb: extcon-usb {
compatible = "linux,extcon-usb-gpio";
id-gpio = <&tlmm 38 GPIO_ACTIVE_HIGH>;
vbus-gpio = <&tlmm 128 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb_extcon_active &usb_vbus_active>;
};
gpio-keys {
compatible = "gpio-keys";
label = "Side buttons";
@ -184,11 +203,28 @@
vibrator {
compatible = "gpio-vibrator";
enable-gpios = <&pmi8998_gpio 5 GPIO_ACTIVE_HIGH>;
vcc-supply = <&vib_vreg>;
pinctrl-names = "default";
pinctrl-0 = <&vib_default>;
};
};
&adreno_gpu {
status = "ok";
zap-shader {
memory-region = <&zap_shader_region>;
};
};
&adreno_smmu {
status = "ok";
};
&apc_cprh {
status = "ok";
};
&blsp1_i2c5 {
status = "okay";
clock-frequency = <355000>;
@ -241,10 +277,79 @@
};
};
&blsp2_i2c1 {
tof-sensor@29 {
compatible = "st,vl53l0x";
reg = <0x29>;
interrupt-parent = <&tlmm>;
interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
#io-channel-cells = <1>;
label = "back_camera_tof";
pinctrl-names = "default";
pinctrl-0 = <&tof_int_n &tof_rst_n>;
};
};
&blsp2_uart1 {
status = "okay";
};
&cpufreq_hw {
status = "ok";
};
&dsi0 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
vdd-supply = <&vreg_l1a_0p875>;
vdda-supply = <&vreg_l2a_1p2>;
panel: panel@0 {
reg = <0>;
backlight = <&pmi8998_wled>;
disp-te-gpios = <&tlmm 10 GPIO_ACTIVE_HIGH>;
reset-gpios = <&tlmm 94 GPIO_ACTIVE_HIGH>;
avdd-supply = <&lab>;
avee-supply = <&ibb>;
vddio-supply = <&vreg_l14a_1p85>;
tavdd-supply = <&vreg_l28_3p0>;
tvddio-supply = <&touch_vddio_vreg>;
pinctrl-names = "default";
pinctrl-0 = <&panel_reset_n &mdp_vsync_n>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
panel_in0: endpoint {
remote-endpoint = <&dsi0_out>;
};
};
};
};
};
&dsi0_out {
remote-endpoint = <&panel_in0>;
data-lanes = <0 1 2 3>;
};
&dsi0_phy {
status = "okay";
vdds-supply = <&vreg_l1a_0p875>;
};
&gpucc {
status = "ok";
};
&ibb {
regulator-min-microamp = <800000>;
regulator-max-microamp = <800000>;
@ -270,6 +375,13 @@
regulator-soft-start;
};
&lpass_q6_smmu {
qcom,bypass-cbndx = /bits/ 8 <11>;
qcom,reset-nodisable-cbs = /bits/ 8 <12>;
status = "ok";
};
&mmcc {
status = "ok";
};
@ -278,19 +390,23 @@
status = "ok";
};
&pm8005_lsid1 {
pm8005-regulators {
compatible = "qcom,pm8005-regulators";
&mdss {
status = "okay";
};
vdd_s1-supply = <&vph_pwr>;
/* VDD_GFX supply */
pm8005_s1: s1 {
regulator-min-microvolt = <524000>;
regulator-max-microvolt = <1088000>;
regulator-enable-ramp-delay = <500>;
regulator-always-on;
};
&pm8005_regulators {
/* VDD_GFX supply */
pm8005_s1: s1 {
/*
* HACK: Set enough voltage for max GPU frequency
* and set the regulator always on until the
* GPU Core Power Reduction gets available
*/
regulator-min-microvolt = <988000>;
regulator-max-microvolt = <1088000>;
regulator-enable-ramp-delay = <500>;
/* Hack until we rig up the gpu consumer */
regulator-always-on;
};
};
@ -324,6 +440,13 @@
function = "func2";
power-source = <0>;
};
nfc_clk_req_pin: nfc-clk-req-active {
pins = "gpio21";
function = PMIC_GPIO_FUNC_NORMAL;
input-enable;
power-source = <1>;
};
};
&pmi8998_gpio {
@ -358,6 +481,37 @@
};
};
&pmi8998_wled {
status = "okay";
default-brightness = <800>;
qcom,switching-freq = <800>;
qcom,ovp-millivolt = <29600>;
qcom,current-boost-limit = <970>;
qcom,current-limit-microamp = <25000>;
qcom,num-strings = <2>;
qcom,enabled-strings = <0 1>;
};
&q6asmdai {
dai@0 {
reg = <0>;
};
dai@1 {
reg = <1>;
};
dai@2 {
reg = <2>;
};
dai@3 {
reg = <3>;
// direction = <2>;
// is-compress-dai;
};
};
&qusb2phy {
status = "okay";
@ -365,6 +519,19 @@
vdda-phy-dpdm-supply = <&vreg_l24a_3p075>;
};
&remoteproc_adsp {
firmware-name = "adsp.mdt";
status = "okay";
};
&remoteproc_mss {
status = "disabled";
};
&remoteproc_slpi {
firmware-name = "slpi.mdt";
};
&rpm_requests {
pm8998-regulators {
compatible = "qcom,rpm-pm8998-regulators";
@ -401,131 +568,162 @@
regulator-min-microvolt = <1352000>;
regulator-max-microvolt = <1352000>;
};
vreg_s4a_1p8: s4 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-system-load = <100000>;
regulator-allow-set-load;
};
vreg_s5a_2p04: s5 {
regulator-min-microvolt = <1904000>;
regulator-max-microvolt = <2032000>;
};
vreg_s7a_1p025: s7 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1028000>;
};
vreg_l1a_0p875: l1 {
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
regulator-system-load = <73400>;
regulator-allow-set-load;
};
vreg_l2a_1p2: l2 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-system-load = <12560>;
regulator-allow-set-load;
};
vreg_l3a_1p0: l3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l5a_0p8: l5 {
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <800000>;
};
vreg_l6a_1p8: l6 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l7a_1p8: l7 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l8a_1p2: l8 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
vreg_l9a_1p8: l9 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l10a_1p8: l10 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
};
vreg_l11a_1p0: l11 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
vreg_l12a_1p8: l12 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l13a_2p95: l13 {
regulator-min-microvolt = <1808000>;
regulator-max-microvolt = <2960000>;
regulator-allow-set-load;
};
vreg_l14a_1p85: l14 {
regulator-min-microvolt = <1848000>;
regulator-max-microvolt = <1856000>;
regulator-system-load = <32000>;
regulator-allow-set-load;
};
vreg_l15a_1p8: l15 {
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
vreg_l16a_2p7: l16 {
regulator-min-microvolt = <2704000>;
regulator-max-microvolt = <2704000>;
};
vreg_l17a_1p3: l17 {
regulator-min-microvolt = <1304000>;
regulator-max-microvolt = <1304000>;
};
vreg_l18a_2p85: l18 {};
vreg_l18a_2p85: l18 { };
vreg_l19a_2p7: l19 {
regulator-min-microvolt = <2696000>;
regulator-max-microvolt = <2704000>;
};
vreg_l20a_2p95: l20 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-system-load = <10000>;
regulator-allow-set-load;
};
vreg_l21a_2p95: l21 {
regulator-min-microvolt = <2960000>;
regulator-max-microvolt = <2960000>;
regulator-system-load = <800000>;
regulator-allow-set-load;
};
vreg_l22a_2p85: l22 { };
vreg_l23a_3p3: l23 {
regulator-min-microvolt = <3312000>;
regulator-max-microvolt = <3312000>;
};
vreg_l24a_3p075: l24 {
regulator-min-microvolt = <3088000>;
regulator-max-microvolt = <3088000>;
};
vreg_l25a_3p3: l25 {
regulator-min-microvolt = <3104000>;
regulator-max-microvolt = <3312000>;
};
vreg_l26a_1p2: l26 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-allow-set-load;
};
vreg_l28_3p0: l28 {
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
vreg_lvs1a_1p8: lvs1 { };
vreg_lvs2a_1p8: lvs2 { };
};
@ -549,8 +747,373 @@
vqmmc-supply = <&vreg_l13a_2p95>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>;
pinctrl-0 = <&sdc2_on &sdc2_cd>;
pinctrl-1 = <&sdc2_off &sdc2_cd>;
};
/* EAR-EN is NXP NX5L2750C */
/* Downstream example
&snd_9335 {
qcom,msm-mbhc-hphl-swh = <1>;
/delete-property/ qcom,hph-en1-gpio;
/delete-property/ qcom,hph-en0-gpio;
/delete-property/ qcom,us-euro-gpios;
qcom,ear-en-gpios = <&pm8005_gpios 1 0>;
qcom,audio-routing =
"AIF4 VI", "MCLK",
"RX_BIAS", "MCLK",
"MADINPUT", "MCLK",
"AMIC2", "MIC BIAS2",
"MIC BIAS2", "Headset Mic",
"MIC BIAS2", "ANCRight Headset Mic",
"AMIC3", "MIC BIAS3",
"MIC BIAS3", "ANCLeft Headset Mic",
"DMIC0", "MIC BIAS1",
"MIC BIAS1", "Digital Mic0",
"DMIC3", "MIC BIAS4",
"MIC BIAS4", "Digital Mic3",
"SpkrLeft IN", "SPK1 OUT",
"SpkrRight IN", "SPK2 OUT";
};
*/
&slimbam {
status = "okay";
};
&slim {
status = "okay";
};
&slim_ngd {
tasha_ifd: tas-ifd {
compatible = "slim217,1a0";
reg = <0 0>;
};
wcd9335: codec@1{
compatible = "slim217,1a0";
reg = <1 0>;
clock-names = "mclk", "slimbus";
clocks = <&div1_mclk>,
<&rpmcc RPM_SMD_LN_BB_CLK1>;
#clock-cells = <0>;
interrupt-parent = <&tlmm>;
interrupts = <54 IRQ_TYPE_LEVEL_HIGH>,
<53 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "intr1", "intr2";
interrupt-controller;
#interrupt-cells = <1>;
reset-gpios = <&tlmm 64 GPIO_ACTIVE_HIGH>;
slim-ifc-dev = <&tasha_ifd>;
vdd-buck-supply = <&vreg_s4a_1p8>;
vdd-buck-sido-supply = <&vreg_s4a_1p8>;
vdd-tx-supply = <&vreg_s4a_1p8>;
vdd-rx-supply = <&vreg_s4a_1p8>;
vdd-io-supply = <&vreg_s4a_1p8>;
qcom,mbhc-vthreshold = <1700>;
/* On SoMC Yoshino, HPHL is normally open, GND normally closed */
qcom,hphl-jack-type-normally-open;
//qcom,gnd-jack-type-normally-open;
#address-cells = <1>;
#size-cells = <1>;
#sound-dai-cells = <1>;
swm: swm@c85 {
compatible = "qcom,soundwire-v1.3.0";
reg = <0xc85 0x40>;
interrupts-extended = <&wcd9335 13>;
qcom,dout-ports = <6>;
qcom,din-ports = <2>;
qcom,ports-sinterval-low =/bits/ 8 <0x07 0x1F 0x3F 0x7 0x1F 0x3F 0x0F 0x0F>;
qcom,ports-offset1 = /bits/ 8 <0x01 0x02 0x0C 0x6 0x12 0x0D 0x07 0x0A >;
qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x1F 0x00 0x00 0x1F 0x00 0x00>;
/*downstream is <0xFF 0x00 0x1F 0xFF 0x00 0x1F 0x00 0x00>;*/
qcom,ports-block-pack-mode = /bits/ 8 <0xFF 0xFF 0x01 0xFF 0xFF 0x01 0xFF 0xFF>;
clocks = <&xo>;
clock-names = "iface";
#address-cells = <2>;
#size-cells = <0>;
#sound-dai-cells = <1>;
left_spkr: wsa8810-left {
compatible = "sdw10217201000";
reg = <0 1>;
powerdown-gpios = <&tlmm 65 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&wsa_leftspk_pwr_n>;
pinctrl-names = "default";
#thermal-sensor-cells = <0>;
sound-name-prefix = "SpkrRight";
#sound-dai-cells = <0>;
};
right_spkr: wsa8810-right {
compatible = "sdw10217201000";
powerdown-gpios = <&tlmm 66 GPIO_ACTIVE_HIGH>;
reg = <0 2>;
pinctrl-0 = <&wsa_rightspk_pwr_n>;
pinctrl-names = "default";
#thermal-sensor-cells = <0>;
sound-name-prefix = "SpkrLeft";
#sound-dai-cells = <0>;
};
};
};
};
/* NOTES */
/*
# This is Dragonboard 820C
EnableSequence [
cset "name='SLIM RX0 MUX' ZERO"
cset "name='SLIM RX1 MUX' ZERO"
cset "name='SLIM RX2 MUX' ZERO"
cset "name='SLIM RX3 MUX' ZERO"
cset "name='SLIM RX4 MUX' ZERO"
cset "name='SLIM RX5 MUX' AIF4_PB"
cset "name='SLIM RX6 MUX' AIF4_PB"
cset "name='SLIM RX7 MUX' ZERO"
cset "name='RX INT1_2 MUX' RX5"
cset "name='RX INT2_2 MUX' RX6"
## gain to 0dB
cset "name='RX5 Digital Volume' 68"
## gain to 0dB
cset "name='RX6 Digital Volume' 68"
cset "name='SLIMBUS_6_RX Audio Mixer MultiMedia2' 1"
cset "name='RX INT1 DEM MUX' CLSH_DSM_OUT"
cset "name='RX INT2 DEM MUX' CLSH_DSM_OUT"
]
######### WORKS!!!!!! SHE SPEEEEEAKS!!!!!!! #########
tinymix set "SLIM RX2 MUX" ZERO
tinymix set "SLIM RX3 MUX" ZERO
tinymix set "SLIM RX4 MUX" ZERO
tinymix set "SLIM RX5 MUX" ZERO
tinymix set "SLIM RX6 MUX" ZERO
tinymix set "SLIM RX7 MUX" ZERO
tinymix set "SLIM RX0 MUX" AIF1_PB
tinymix set "SLIM RX1 MUX" AIF1_PB
tinymix set "RX INT1_2 MUX" RX0
tinymix set "RX INT2_2 MUX" RX1
tinymix set "RX INT1_1 MIX1 INP0" RX0
tinymix set "RX INT2_1 MIX1 INP0" RX1
tinymix set "SLIMBUS_0_RX Audio Mixer MultiMedia1" 1
tinymix set "RX INT1 DEM MUX" CLSH_DSM_OUT
tinymix set "RX INT2 DEM MUX" CLSH_DSM_OUT
tinymix set "SLIM TX0 MUX" DEC0
tinymix set "AIF1_CAP Mixer SLIM TX0" 1
tinymix set "RX INT2_1 MIX1 INP0" RX1
tinymix set "RX INT1_1 MIX1 INP0" RX0
tinymix set "RX INT1_1 MIX1 INP0" RX2
tinymix set "RX INT1_1 MIX1 INP0" RX0
tinymix set "RX INT1_1 MIX1 INP0" RX2
tinymix set "RX INT2_1 MIX1 INP0" RX2
tinymix set "RX INT2_1 MIX1 INP0" RX1
tinymix set "RX INT1_1 MIX1 INP0" RX0
tinymix set "RX INT0_1 MIX1 INP0" RX0
tinymix set "RX INT0_1 MIX1 INP0" RX1
tinymix set "RX INT0_1 MIX1 INP0" RX2
tinymix set "RX INT0_1 MIX1 INP0" RX0
tinymix set "RX INT3_1 MIX1 INP0" RX0
tinymix set "RX INT4_1 MIX1 INP0" RX0
tinymix set "RX INT5_1 MIX1 INP0" RX0
tinymix set "RX INT6_1 MIX1 INP0" RX1
tinymix set "RX INT7_1 MIX1 INP0" RX1
tinymix set "RX INT7_1 MIX1 INP0" RX1
tinymix set "RX INT8_1 MIX1 INP0" RX1
tinymix set "RX INT0_1 MIX1 INP1" RX0
tinymix set "RX INT0_1 MIX1 INP1" RX2
tinymix set "RX INT0_1 MIX1 INP1" RX0
tinymix set "RX INT1_1 MIX1 INP1" RX0
tinymix set "RX INT2_1 MIX1 INP1" RX0
tinymix set "RX INT3_1 MIX1 INP1" RX0
tinymix set "RX INT4_1 MIX1 INP1" RX0
tinymix set "RX INT5_1 MIX1 INP1" RX0
tinymix set "RX INT6_1 MIX1 INP1" RX0
tinymix set "RX INT7_1 MIX1 INP1" RX0
tinymix set "RX INT8_1 MIX1 INP1" RX0
tinymix set "RX INT0_1 MIX1 INP2" RX1
tinymix set "RX INT1_1 MIX1 INP2" RX1
tinymix set "RX INT2_1 MIX1 INP2" RX1
tinymix set "RX INT3_1 MIX1 INP2" RX1
tinymix set "RX INT4_1 MIX1 INP2" RX1
tinymix set "RX INT5_1 MIX1 INP2" RX1
tinymix set "RX INT6_1 MIX1 INP2" RX1
tinymix set "RX INT7_1 MIX1 INP2" RX1
tinymix set "RX INT8_1 MIX1 INP2" RX1
tinymix set "RX INT8_1 MIX1 INP2" RX0
tinymix set "RX INT7_1 MIX1 INP2" RX0
tinymix set "RX INT6_1 MIX1 INP2" RX0
tinymix set "RX0 Digital Volume" 80
tinymix set "RX1 Digital Volume" 80
tinymix set "RX2 Digital Volume" 80
*/
&sound {
compatible = "qcom,msm8998-sndcard";
model = "Sony-Xperia-Yoshino";
/* Audio routing including WSA amp speakers */
/* audio-routing = "RX_BIAS", "MCLK",
"AMIC2", "MIC BIAS2",
"AMIC3", "MIC BIAS3",
"DMIC0", "MIC BIAS1",
"DMIC4", "MIC BIAS4",
"SpkrLeft IN", "SPK1 OUT",
"SpkrRight IN", "SPK2 OUT",
"MM_DL1", "MultiMedia1 Playback",
"MM_DL2", "MultiMedia2 Playback",
"MultiMedia3 Capture", "MM_UL3";
*/
/* Basic routing, 3.5mm jack only */
audio-routing = "RX_BIAS", "MCLK",
"AMIC2", "MIC BIAS2",
"AMIC3", "MIC BIAS3",
"DMIC0", "MIC BIAS1",
"DMIC4", "MIC BIAS4",
"MM_DL1", "MultiMedia1 Playback",
"MM_DL2", "MultiMedia2 Playback",
"MultiMedia3 Capture", "MM_UL3";
/*
<path name="voicemmode1-call headphones">
<ctl name="SLIM_0_RX_Voice Mixer VoiceMMode1" value="1" />
<ctl name="VoiceMMode1_Tx Mixer SLIM_0_TX_MMode1" value="1" />
</path>
<path name="sidetone-headphones">
<path name="sidetone-iir" />
<!-- 45 % of 124 (range 0 - 124) Register: 0x340 -->
<ctl name="IIR0 INP0 Volume" value="44" />
<ctl name="RX INT1 MIX2 INP" value="SRC0" />
<ctl name="RX INT2 MIX2 INP" value="SRC0" />
</path>
<path name="speaker-and-headphones">
<path name="speaker" />
<ctl name="RX INT1_1 MIX1 INP0" value="RX1" />
<ctl name="RX INT2_1 MIX1 INP0" value="RX1" />
<ctl name="RX INT1 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="RX INT2 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="RX1 Digital Volume" value="55" />
<ctl name="RX2 Digital Volume" value="55" />
<path name="headphones-hpf" />
<ctl name="Set Custom Stereo" value="Mix" />
</path>
<path name="headphones">
<ctl name="SLIM RX0 MUX" value="AIF_MIX1_PB" />
<ctl name="SLIM RX1 MUX" value="AIF_MIX1_PB" />
<ctl name="SLIM_0_RX Channels" value="Two" />
<ctl name="RX INT1_1 MIX1 INP0" value="RX0" />
<ctl name="RX INT2_1 MIX1 INP0" value="RX1" />
<ctl name="RX INT1 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="RX INT2 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="RX1 Digital Volume" value="80" />
<ctl name="RX2 Digital Volume" value="80" />
</path>
<path name="headphones-hpf">
<ctl name="RX INT1_1 HPF cut off" value="CF_NEG_3DB_150HZ" />
<ctl name="RX INT2_1 HPF cut off" value="CF_NEG_3DB_150HZ" />
</path>
<path name="anc-off-headphone">
<ctl name="SLIM RX0 MUX" value="AIF_MIX1_PB" />
<ctl name="SLIM RX1 MUX" value="AIF_MIX1_PB" />
<ctl name="SLIM_0_RX Channels" value="Two" />
<ctl name="RX INT1_1 MIX1 INP0" value="RX0" />
<ctl name="RX INT2_1 MIX1 INP0" value="RX1" />
<ctl name="RX INT1 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="RX INT2 DEM MUX" value="CLSH_DSM_OUT" />
<ctl name="COMP1 Switch" value="0" />
<ctl name="COMP2 Switch" value="0" />
<ctl name="HPHL Volume" value="20" />
<ctl name="HPHR Volume" value="20" />
<ctl name="RX1 Digital Volume" value="77" />
<ctl name="RX2 Digital Volume" value="77" />
</path>
<path name="audio-record">
<ctl name="MultiMedia1 Mixer SLIM_0_TX" value="1" />
</path>
<path name="deep-buffer-playback">
<ctl name="SLIMBUS_0_RX Audio Mixer MultiMedia1" value="1" />
</path>
*/
mm1-dai-link {
/* Deep Buffer playback for SLIM{0,7}, BT, USBAUDIO, AFE, DP, HDMI */
link-name = "MultiMedia1";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
};
};
mm2-dai-link {
/* Multichannel playback for HDMI and DP */
link-name = "MultiMedia2";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>;
};
};
mm3-dai-link {
/* Ultra Low Latency playback for SLIM0, HDMI, and DP */
link-name = "MultiMedia3";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>;
};
};
slim-dai-link {
link-name = "SLIM Playback";
cpu {
sound-dai = <&q6afedai SLIMBUS_0_RX>;
};
platform {
sound-dai = <&q6routing>;
};
codec {
/* Support only sound through 3.5mm for now: soundwire is currently unavailable */
//sound-dai = <&left_spkr>, <&right_spkr>, <&swm 0>, <&wcd9335 0>;
sound-dai = <&wcd9335 0>;
};
};
slimcap-dai-link {
link-name = "SLIM Capture";
cpu {
sound-dai = <&q6afedai SLIMBUS_0_TX>;
};
platform {
sound-dai = <&q6routing>;
};
codec {
sound-dai = <&wcd9335 1>;
};
};
};
&tlmm {
@ -606,6 +1169,14 @@
drive-strength = <2>;
};
tof_int_n: tof-int-n {
pins = "gpio22";
function = "gpio";
bias-pull-up;
drive-strength = <2>;
input-enable;
};
cam1_vdig_default: cam1-vdig-default {
pins = "gpio25";
function = "gpio";
@ -613,6 +1184,81 @@
drive-strength = <2>;
};
tof_rst_n: tof-rst-n {
pins = "gpio27";
function = "gpio";
bias-disable;
drive-strength = <2>;
output-low;
};
cam1_rst_default: cam1-rst-n {
pins = "gpio28";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
cam0_rst_default: cam0-rst-n {
pins = "gpio30";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
wcd_int_n: wcd-int-n {
pins = "gpio54";
function = "gpio";
bias-pull-down;
drive-strength = <2>;
input-enable;
};
cdc_reset_n: cdc-reset-n {
pins = "gpio64";
function = "gpio";
bias-pull-down;
drive-strength = <16>;
output-high;
};
wsa_leftspk_pwr_n: wsa-leftspk-pwr-n {
pins = "gpio65";
function = "gpio";
bias-disable;
drive-strength = <2>;
output-low;
};
wsa_rightspk_pwr_n: wsa-rightspk-pwr-n {
pins = "gpio66";
function = "gpio";
bias-disable;
drive-strength = <2>;
output-low;
};
ts_reset_n: ts-reset-n {
pins = "gpio89";
function = "gpio";
bias-pull-up;
drive-strength = <8>;
};
panel_reset_n: panel-rst-n {
pins = "gpio94";
function = "gpio";
bias-disable;
drive-strength = <2>;
};
usb_extcon_active: usb-extcon-active {
pins = "gpio38";
function = "gpio";
bias-disable;
drive-strength = <16>;
};
hall_sensor0_default: acc-cover-open {
pins = "gpio124";
function = "gpio";
@ -628,6 +1274,14 @@
bias-pull-up;
};
usb_vbus_active: usb-vbus-active {
pins = "gpio128";
function = "gpio";
bias-disable;
drive-strength = <2>;
output-low;
};
ts_vddio_en: ts-vddio-en-default {
pins = "gpio133";
function = "gpio";
@ -658,6 +1312,7 @@
&usb3_dwc3 {
/* Force to peripheral until we have Type-C hooked up */
dr_mode = "peripheral";
extcon = <&extcon_usb>;
};
&usb3phy {

File diff suppressed because it is too large Load diff

View file

@ -28,5 +28,9 @@
reg = <0x5 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
pm8005_regulators: regulators {
compatible = "qcom,pm8005-regulators";
};
};
};

View file

@ -78,6 +78,16 @@
#size-cells = <0>;
#io-channel-cells = <1>;
adc-chan@0 {
reg = <ADC5_REF_GND>;
label = "ref_gnd";
};
adc-chan@1 {
reg = <ADC5_REF_GND>;
label = "vref_1p25";
};
adc-chan@6 {
reg = <ADC5_DIE_TEMP>;
label = "die_temp";

View file

@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <dt-bindings/input/qcom,spmi-haptics.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
@ -9,6 +10,23 @@
#address-cells = <1>;
#size-cells = <0>;
pmi8998_charger: charger@1000 {
compatible = "qcom,pmi8998-charger";
reg = <0x1000>;
interrupts = <0x2 0x13 0x4 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x12 0x2 IRQ_TYPE_EDGE_BOTH>,
<0x2 0x16 0x1 IRQ_TYPE_EDGE_RISING>,
<0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "usb-plugin", "bat-ov", "wdog-bark", "usbin-icl-change";
io-channels = <&pmi8998_rradc 3>,
<&pmi8998_rradc 4>;
io-channel-names = "usbin_i", "usbin_v";
status = "disabled";
};
pmi8998_gpio: gpios@c000 {
compatible = "qcom,pmi8998-gpio", "qcom,spmi-gpio";
reg = <0xc000>;
@ -18,6 +36,14 @@
interrupt-controller;
#interrupt-cells = <2>;
};
pmi8998_rradc: rradc@4500 {
compatible = "qcom,pmi8998-rradc";
reg = <0x4500>;
#io-channel-cells = <1>;
status = "disabled";
};
};
pmi8998_lsid1: pmic@3 {
@ -53,5 +79,29 @@
status = "disabled";
};
pmi8998_haptics: haptics@c000 {
compatible = "qcom,spmi-haptics";
reg = <0xc000>;
interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
<0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
interrupt-names = "short", "play";
qcom,wave-shape = <HAP_WAVE_SINE>;
qcom,play-mode = <HAP_PLAY_BUFFER>;
qcom,brake-pattern = <0x3 0x3 0x2 0x1>;
status = "disabled";
};
pmi8998_lpg: led-controller {
compatible = "qcom,pmi8998-lpg";
#address-cells = <1>;
#size-cells = <0>;
#pwm-cells = <2>;
status = "disabled";
};
};
};

View file

@ -1173,19 +1173,19 @@
<&cpr_efuse_ring2>,
<&cpr_efuse_ring3>,
<&cpr_efuse_revision>;
nvmem-cell-names = "cpr_quotient_offset1",
"cpr_quotient_offset2",
"cpr_quotient_offset3",
"cpr_init_voltage1",
"cpr_init_voltage2",
"cpr_init_voltage3",
"cpr_quotient1",
"cpr_quotient2",
"cpr_quotient3",
"cpr_ring_osc1",
"cpr_ring_osc2",
"cpr_ring_osc3",
"cpr_fuse_revision";
nvmem-cell-names = "cpr0_quotient_offset1",
"cpr0_quotient_offset2",
"cpr0_quotient_offset3",
"cpr0_init_voltage1",
"cpr0_init_voltage2",
"cpr0_init_voltage3",
"cpr0_quotient1",
"cpr0_quotient2",
"cpr0_quotient3",
"cpr0_ring_osc1",
"cpr0_ring_osc2",
"cpr0_ring_osc3",
"cpr0_fuse_revision";
};
timer@b120000 {

View file

@ -2080,6 +2080,7 @@ static struct clk_branch gcc_bimc_gfx_clk = {
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "gcc_bimc_gfx_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
@ -2220,6 +2221,7 @@ static struct clk_rcg2 hmss_gpll0_clk_src = {
.name = "hmss_gpll0_clk_src",
.parent_data = gcc_parent_data_1,
.num_parents = ARRAY_SIZE(gcc_parent_data_1),
.flags = CLK_IS_CRITICAL,
.ops = &clk_rcg2_ops,
},
};
@ -2833,6 +2835,43 @@ static struct clk_branch gcc_rx1_usb2_clkref_clk = {
},
};
static struct clk_branch hlos1_vote_lpass_core_smmu_clk = {
.halt_reg = 0x7D010,
.clkr = {
.enable_reg = 0x7D010,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "hlos1_vote_lpass_core_smmu_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch hlos1_vote_lpass_adsp_smmu_clk = {
.halt_reg = 0x7D014,
.clkr = {
.enable_reg = 0x7D014,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "hlos1_vote_lpass_adsp_smmu_clk",
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
.halt_reg = 0x8A040,
.clkr = {
.enable_reg = 0x8A040,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data) {
.name = "gcc_mss_q6_bimc_axi_clk",
.flags = CLK_IS_CRITICAL,
.ops = &clk_branch2_ops,
},
},
};
static struct gdsc pcie_0_gdsc = {
.gdscr = 0x6b004,
.gds_hw_ctrl = 0x0,
@ -2863,6 +2902,26 @@ static struct gdsc usb_30_gdsc = {
.flags = VOTABLE,
};
static struct gdsc hlos1_vote_lpass_adsp = {
.gdscr = 0x7d034,
.gds_hw_ctrl = 0x0,
.pd = {
.name = "lpass_adsp_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = VOTABLE,
};
static struct gdsc hlos1_vote_lpass_core = {
.gdscr = 0x7d038,
.gds_hw_ctrl = 0x0,
.pd = {
.name = "lpass_core_gdsc",
},
.pwrsts = PWRSTS_OFF_ON,
.flags = ALWAYS_ON,
};
static struct clk_regmap *gcc_msm8998_clocks[] = {
[BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr,
[BLSP1_QUP1_SPI_APPS_CLK_SRC] = &blsp1_qup1_spi_apps_clk_src.clkr,
@ -3036,12 +3095,17 @@ static struct clk_regmap *gcc_msm8998_clocks[] = {
[GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
[GCC_MMSS_GPLL0_CLK] = &gcc_mmss_gpll0_clk.clkr,
[HMSS_GPLL0_CLK_SRC] = &hmss_gpll0_clk_src.clkr,
[GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
[HLOS1_VOTE_LPASS_CORE_SMMU_CLK] = &hlos1_vote_lpass_core_smmu_clk.clkr,
[HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] = &hlos1_vote_lpass_adsp_smmu_clk.clkr,
};
static struct gdsc *gcc_msm8998_gdscs[] = {
[PCIE_0_GDSC] = &pcie_0_gdsc,
[UFS_GDSC] = &ufs_gdsc,
[USB_30_GDSC] = &usb_30_gdsc,
[LPASS_ADSP_GDSC] = &hlos1_vote_lpass_adsp,
[LPASS_CORE_GDSC] = &hlos1_vote_lpass_core,
};
static const struct qcom_reset_map gcc_msm8998_resets[] = {
@ -3191,6 +3255,14 @@ static int gcc_msm8998_probe(struct platform_device *pdev)
if (ret)
return ret;
/*
* GCC_MMSS_MISC - GCC_GPU_MISC:
* 1. Disable the GPLL0 active input to MMSS and GPU
* 2. Select clk division 1 (CLK/2)
*/
regmap_write(regmap, 0x0902C, 0x10003); /* MMSS*/
regmap_write(regmap, 0x71028, 0x10003); /* GPU */
return qcom_cc_really_probe(pdev, &gcc_msm8998_desc, regmap);
}

View file

@ -511,7 +511,7 @@ static struct clk_rcg2 byte0_clk_src = {
.parent_data = mmss_xo_dsibyte,
.num_parents = ARRAY_SIZE(mmss_xo_dsibyte),
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
};
@ -524,7 +524,7 @@ static struct clk_rcg2 byte1_clk_src = {
.parent_data = mmss_xo_dsibyte,
.num_parents = ARRAY_SIZE(mmss_xo_dsibyte),
.ops = &clk_byte2_ops,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
};
@ -1075,7 +1075,7 @@ static struct clk_rcg2 pclk0_clk_src = {
.parent_data = mmss_xo_dsi0pll_dsi1pll,
.num_parents = ARRAY_SIZE(mmss_xo_dsi0pll_dsi1pll),
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
};
@ -1089,7 +1089,7 @@ static struct clk_rcg2 pclk1_clk_src = {
.parent_data = mmss_xo_dsi0pll_dsi1pll,
.num_parents = ARRAY_SIZE(mmss_xo_dsi0pll_dsi1pll),
.ops = &clk_pixel_ops,
.flags = CLK_SET_RATE_PARENT,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
};

View file

@ -137,6 +137,7 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "qcom,apq8096", },
{ .compatible = "qcom,msm8996", },
{ .compatible = "qcom,msm8998", },
{ .compatible = "qcom,qcs404", },
{ .compatible = "qcom,sa8155p" },
{ .compatible = "qcom,sa8540p" },

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@ int __drm_mode_object_add(struct drm_device *dev, struct drm_mode_object *obj,
{
int ret;
WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
//WARN_ON(!dev->driver->load && dev->registered && !obj_free_cb);
mutex_lock(&dev->mode_config.idr_mutex);
ret = idr_alloc(&dev->mode_config.object_idr, register_obj ? obj : NULL,
@ -237,10 +237,10 @@ void drm_object_attach_property(struct drm_mode_object *obj,
if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
struct drm_connector *connector = obj_to_connector(obj);
/*struct drm_connector *connector = obj_to_connector(obj);
WARN_ON(!dev->driver->load &&
connector->registration_state == DRM_CONNECTOR_REGISTERED);
connector->registration_state == DRM_CONNECTOR_REGISTERED);*/
} else {
WARN_ON(!dev->driver->load && dev->registered);
}

View file

@ -104,7 +104,7 @@ config DRM_MSM_DSI_14NM_PHY
Choose this option if DSI PHY on 8996 is used on the platform.
config DRM_MSM_DSI_10NM_PHY
bool "Enable DSI 10nm PHY driver in MSM DRM (used by SDM845)"
bool "Enable DSI 10nm PHY driver in MSM DRM (used by MSM8998/SDM845)"
depends on DRM_MSM_DSI
default y
help

View file

@ -121,6 +121,48 @@ static void a5xx_submit_in_rb(struct msm_gpu *gpu, struct msm_gem_submit *submit
msm_gpu_retire(gpu);
}
static void a5xx_set_pagetable(struct a5xx_gpu *a5xx_gpu,
struct msm_ringbuffer *ring, struct msm_file_private *ctx)
{
phys_addr_t ttbr;
u32 asid;
u64 memptr = rbmemptr(ring, ttbr0);
if (ctx == a5xx_gpu->cur_ctx)
return;
if (msm_iommu_pagetable_params(ctx->aspace->mmu, &ttbr, &asid))
return;
/* Execute the table update */
OUT_PKT7(ring, CP_SMMU_TABLE_UPDATE, 3);
OUT_RING(ring, CP_SMMU_TABLE_UPDATE_0_TTBR0_LO(lower_32_bits(ttbr)));
OUT_RING(ring,
CP_SMMU_TABLE_UPDATE_1_TTBR0_HI(upper_32_bits(ttbr)) |
CP_SMMU_TABLE_UPDATE_1_ASID(asid));
OUT_RING(ring, CP_SMMU_TABLE_UPDATE_2_CONTEXTIDR(0));
/*
* Write the new TTBR0 to the memstore. This is good for debugging.
*/
OUT_PKT7(ring, CP_MEM_WRITE, 4);
OUT_RING(ring, CP_MEM_WRITE_0_ADDR_LO(lower_32_bits(memptr)));
OUT_RING(ring, CP_MEM_WRITE_1_ADDR_HI(upper_32_bits(memptr)));
OUT_RING(ring, lower_32_bits(ttbr));
OUT_RING(ring, (asid << 16) | upper_32_bits(ttbr));
/*
* And finally, trigger a uche flush to be sure there isn't anything
* lingering in that part of the GPU
*/
OUT_PKT7(ring, CP_EVENT_WRITE, 1);
OUT_RING(ring, 0x31);
a5xx_gpu->cur_ctx = ctx;
}
static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@ -151,13 +193,17 @@ static void a5xx_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
OUT_RING(ring, 1);
/* Enable local preemption for finegrain preemption */
OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
OUT_RING(ring, 0x02);
//OUT_PKT7(ring, CP_PREEMPT_ENABLE_GLOBAL, 1);
//OUT_RING(ring, 0x02);
OUT_PKT7(ring, CP_PREEMPT_ENABLE_LOCAL, 1);
OUT_RING(ring, 0x01);
/* Allow CP_CONTEXT_SWITCH_YIELD packets in the IB2 */
OUT_PKT7(ring, CP_YIELD_ENABLE, 1);
OUT_RING(ring, 0x02);
a5xx_set_pagetable(a5xx_gpu, ring, submit->queue->ctx);
/* Submit the commands */
for (i = 0; i < submit->nr_cmds; i++) {
switch (submit->cmd[i].type) {
@ -942,6 +988,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu)
a5xx_preempt_fini(gpu);
gpu->nr_rings = 1;
}
a5xx_gpu->cur_ctx = NULL;
a5xx_preempt_hw_init(gpu);
@ -1697,6 +1744,20 @@ static uint32_t a5xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
return ring->memptrs->rptr = gpu_read(gpu, REG_A5XX_CP_RB_RPTR);
}
static struct msm_gem_address_space *
a5xx_create_private_address_space(struct msm_gpu *gpu)
{
struct msm_mmu *mmu;
mmu = msm_iommu_pagetable_create(gpu->aspace->mmu);
if (IS_ERR(mmu))
return ERR_CAST(mmu);
return msm_gem_address_space_create(mmu,
"gpu", 0x100000000ULL, 0x1ffffffffULL);
}
static const struct adreno_gpu_funcs funcs = {
.base = {
.get_param = adreno_get_param,
@ -1719,6 +1780,7 @@ static const struct adreno_gpu_funcs funcs = {
.gpu_state_get = a5xx_gpu_state_get,
.gpu_state_put = a5xx_gpu_state_put,
.create_address_space = adreno_iommu_create_address_space,
.create_private_address_space = a5xx_create_private_address_space,
.get_rptr = a5xx_get_rptr,
},
.get_timestamp = a5xx_get_timestamp,

View file

@ -29,6 +29,7 @@ struct a5xx_gpu {
struct msm_ringbuffer *cur_ring;
struct msm_ringbuffer *next_ring;
struct msm_file_private *cur_ctx;
struct drm_gem_object *preempt_bo[MSM_GPU_MAX_RINGS];
struct drm_gem_object *preempt_counters_bo[MSM_GPU_MAX_RINGS];

View file

@ -355,6 +355,11 @@ MODULE_FIRMWARE("qcom/a530_zap.mdt");
MODULE_FIRMWARE("qcom/a530_zap.b00");
MODULE_FIRMWARE("qcom/a530_zap.b01");
MODULE_FIRMWARE("qcom/a530_zap.b02");
MODULE_FIRMWARE("qcom/a540_gpmu.fw2");
MODULE_FIRMWARE("qcom/a540_zap.mdt");
MODULE_FIRMWARE("qcom/a540_zap.b00");
MODULE_FIRMWARE("qcom/a540_zap.b01");
MODULE_FIRMWARE("qcom/a540_zap.b02");
MODULE_FIRMWARE("qcom/a630_sqe.fw");
MODULE_FIRMWARE("qcom/a630_gmu.bin");
MODULE_FIRMWARE("qcom/a630_zap.mbn");

View file

@ -743,6 +743,7 @@ struct dpu_mdss_cfg {
const struct dpu_mdp_cfg *mdp;
u32 ctl_count;
bool ctl_no_start_read_quirk;
const struct dpu_ctl_cfg *ctl;
u32 sspp_count;

View file

@ -94,7 +94,7 @@ static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx)
static inline bool dpu_hw_ctl_is_started(struct dpu_hw_ctl *ctx)
{
return !!(DPU_REG_READ(&ctx->hw, CTL_START) & BIT(0));
return !!(DPU_REG_READ(&ctx->hw, CTL_START) & BIT(0)) || ctx->ctl_no_start_read_quirk;
}
static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx)
@ -628,6 +628,7 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx,
c->idx = idx;
c->mixer_count = m->mixer_count;
c->mixer_hw_caps = m->mixer;
c->ctl_no_start_read_quirk = m->ctl_no_start_read_quirk;
return c;
}

View file

@ -203,6 +203,7 @@ struct dpu_hw_ctl {
u32 pending_flush_mask;
u32 pending_intf_flush_mask;
u32 pending_merge_3d_flush_mask;
bool ctl_no_start_read_quirk;
/* ops */
struct dpu_hw_ctl_ops ops;

View file

@ -1072,6 +1072,10 @@ static int dpu_kms_hw_init(struct msm_kms *kms)
goto power_error;
}
if (of_property_read_bool(dpu_kms->pdev->dev.of_node, "qcom,ctl-no-start-read-quirk")) {
dpu_kms->catalog->ctl_no_start_read_quirk = true;
}
/*
* Now we need to read the HW catalog and initialize resources such as
* clocks, regulators, GDSC/MMAGIC, ioremap the register ranges etc

View file

@ -122,7 +122,7 @@ static void dsi_pll_calc_dec_frac(struct dsi_pll_10nm *pll, struct dsi_pll_confi
pll_freq = pll->vco_current_rate;
divider = fref * 2;
divider = fref;
multiplier = 1 << FRAC_BITS;
dec_multiple = div_u64(pll_freq * multiplier, divider);
@ -440,12 +440,11 @@ static unsigned long dsi_pll_10nm_vco_recalc_rate(struct clk_hw *hw,
* 1. Assumes prescaler is disabled
*/
multiplier = 1 << FRAC_BITS;
pll_freq = dec * (ref_clk * 2);
tmp64 = (ref_clk * 2 * frac);
pll_freq = dec * ref_clk;
tmp64 = ref_clk * frac;
pll_freq += div_u64(tmp64, multiplier);
vco_rate = pll_freq;
pll_10nm->vco_current_rate = vco_rate;
DBG("DSI PLL%d returning vco rate = %lu, dec = %x, frac = %x",
pll_10nm->phy->id, (unsigned long)vco_rate, dec, frac);

View file

@ -461,6 +461,36 @@ config DRM_PANEL_SAMSUNG_S6D27A1
This panel can be found in Samsung Galaxy Ace 2
GT-I8160 mobile phone.
config DRM_PANEL_SAMSUNG_S6E3FA5
tristate "Samsung S6E3FA5 DSI command mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
Say Y here if you want to enable support for Samsung S6E3FA5 AMOLED
command mode panel as found in OnePlus 5 (2017) devices. The panel has a
FHD (1080x1920) resolution and uses 24 bit RGB per pixel. It provides a
MIPI DSI interface to the host and has a built-in LED backlight.
To compile this driver as a module, choose M here: the module
will be called panel-samsung-s6e3fa5.
config DRM_PANEL_SAMSUNG_S6E3FC1
tristate "Samsung S6E3FC1 DSI command mode panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
select VIDEOMODE_HELPERS
help
Say Y here if you want to enable support for Samsung S6E3FC1 AMOLED
command mode panel as found in OnePlus 5T (2017) devices. The panel has a
FHD (1080x2160) resolution and uses 24 bit RGB per pixel. It provides a
MIPI DSI interface to the host and has a built-in LED backlight.
To compile this driver as a module, choose M here: the module
will be called panel-samsung-s6e3fc1.
config DRM_PANEL_SAMSUNG_S6E3HA2
tristate "Samsung S6E3HA2 DSI video mode panel"
depends on OF

View file

@ -45,6 +45,8 @@ obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D16D0) += panel-samsung-s6d16d0.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6D27A1) += panel-samsung-s6d27a1.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FA5) += panel-samsung-s6e3fa5.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3FC1) += panel-samsung-s6e3fc1.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2) += panel-samsung-s6e3ha2.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63J0X03) += panel-samsung-s6e63j0x03.o
obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E63M0) += panel-samsung-s6e63m0.o

View file

@ -0,0 +1,351 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2021 Jami Kettunen <jami.kettunen@protonmail.com>
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_connector.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
struct s6e3fa5 {
struct drm_panel panel;
enum drm_panel_orientation orientation;
struct mipi_dsi_device *dsi;
struct regulator *supply;
struct gpio_desc *reset_gpio;
bool prepared;
};
static inline struct s6e3fa5 *to_s6e3fa5_panel(struct drm_panel *panel)
{
return container_of(panel, struct s6e3fa5, panel);
}
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void s6e3fa5_reset(struct s6e3fa5 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(2000, 3000);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(2000, 3000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(2000, 3000);
}
static int s6e3fa5_on(struct s6e3fa5 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(20);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
dev_err(dev, "Failed to set tear on: %d\n", ret);
return ret;
}
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
dsi_dcs_write_seq(dsi, 0xb0, 0x04);
dsi_dcs_write_seq(dsi, 0xb4, 0x06, 0x0c, 0x12);
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
dsi_dcs_write_seq(dsi, 0xc3, 0x01);
dsi_dcs_write_seq(dsi, 0xb0, 0x18);
dsi_dcs_write_seq(dsi, 0xc3, 0x00);
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
return 0;
}
static int s6e3fa5_off(struct s6e3fa5 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
return ret;
}
msleep(40);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(160);
return 0;
}
static int s6e3fa5_prepare(struct drm_panel *panel)
{
struct s6e3fa5 *ctx = to_s6e3fa5_panel(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (ctx->prepared)
return 0;
ret = regulator_enable(ctx->supply);
if (ret < 0) {
dev_err(dev, "Failed to enable regulator: %d\n", ret);
return ret;
}
s6e3fa5_reset(ctx);
ret = s6e3fa5_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->supply);
return ret;
}
ctx->prepared = true;
return 0;
}
static int s6e3fa5_unprepare(struct drm_panel *panel)
{
struct s6e3fa5 *ctx = to_s6e3fa5_panel(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (!ctx->prepared)
return 0;
ret = s6e3fa5_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->supply);
ctx->prepared = false;
return 0;
}
static const struct drm_display_mode s6e3fa5_mode = {
.clock = (1080 + 120 + 19 + 70) * (1920 + 18 + 2 + 4) * 60 / 1000,
.hdisplay = 1080,
.hsync_start = 1080 + 120,
.hsync_end = 1080 + 120 + 19,
.htotal = 1080 + 120 + 19 + 70,
.vdisplay = 1920,
.vsync_start = 1920 + 18,
.vsync_end = 1920 + 18 + 2,
.vtotal = 1920 + 18 + 2 + 4,
.width_mm = 68,
.height_mm = 122,
};
static int s6e3fa5_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
struct s6e3fa5 *ctx;
mode = drm_mode_duplicate(connector->dev, &s6e3fa5_mode);
if (!mode)
return -ENOMEM;
ctx = to_s6e3fa5_panel(panel);
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_connector_set_panel_orientation(connector, ctx->orientation);
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs s6e3fa5_panel_funcs = {
.prepare = s6e3fa5_prepare,
.unprepare = s6e3fa5_unprepare,
.get_modes = s6e3fa5_get_modes,
};
static int s6e3fa5_bl_update_status(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness = backlight_get_brightness(bl);
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return 0;
}
static int s6e3fa5_bl_get_brightness(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return brightness & 0xff;
}
static const struct backlight_ops s6e3fa5_bl_ops = {
.update_status = s6e3fa5_bl_update_status,
.get_brightness = s6e3fa5_bl_get_brightness,
};
static struct backlight_device *
s6e3fa5_create_backlight(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_RAW,
.brightness = 255,
.max_brightness = 255,
};
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
&s6e3fa5_bl_ops, &props);
}
static int s6e3fa5_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct s6e3fa5 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(ctx->supply))
return dev_err_probe(dev, PTR_ERR(ctx->supply),
"Failed to get vddio regulator\n");
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_HSE |
MIPI_DSI_MODE_NO_EOT_PACKET |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret < 0) {
dev_err(dev, "Failed to parse rotation property: %d\n", ret);
return ret;
}
drm_panel_init(&ctx->panel, dev, &s6e3fa5_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.backlight = s6e3fa5_create_backlight(dsi);
if (IS_ERR(ctx->panel.backlight))
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
"Failed to create backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static int s6e3fa5_remove(struct mipi_dsi_device *dsi)
{
struct s6e3fa5 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return 0;
}
static const struct of_device_id s6e3fa5_of_match[] = {
{ .compatible = "samsung,s6e3fa5" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, s6e3fa5_of_match);
static struct mipi_dsi_driver s6e3fa5_driver = {
.probe = s6e3fa5_probe,
.remove = s6e3fa5_remove,
.driver = {
.name = "panel-samsung-s6e3fa5",
.of_match_table = s6e3fa5_of_match,
},
};
module_mipi_dsi_driver(s6e3fa5_driver);
MODULE_AUTHOR("Jami Kettunen <jami.kettunen@protonmail.com>");
MODULE_DESCRIPTION("DRM driver for Samsung S6E3FA5 AMOLED DSI cmd mode panel found on OnePlus 5 phones");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2021 Jami Kettunen <jami.kettunen@protonmail.com>
* Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/swab.h>
#include <video/mipi_display.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
struct s6e3fc1 {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct regulator *supply;
struct gpio_desc *reset_gpio;
bool prepared;
};
static inline struct s6e3fc1 *to_s6e3fc1_panel(struct drm_panel *panel)
{
return container_of(panel, struct s6e3fc1, panel);
}
#define dsi_dcs_write_seq(dsi, seq...) do { \
static const u8 d[] = { seq }; \
int ret; \
ret = mipi_dsi_dcs_write_buffer(dsi, d, ARRAY_SIZE(d)); \
if (ret < 0) \
return ret; \
} while (0)
static void s6e3fc1_reset(struct s6e3fc1 *ctx)
{
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(2000, 3000);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
usleep_range(2000, 3000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
usleep_range(2000, 3000);
}
static int s6e3fc1_on(struct s6e3fc1 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(25);
ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret < 0) {
dev_err(dev, "Failed to set tear on: %d\n", ret);
return ret;
}
dsi_dcs_write_seq(dsi, 0xfc, 0x5a, 0x5a);
dsi_dcs_write_seq(dsi, 0xe8, 0x64, 0x08, 0x0c);
dsi_dcs_write_seq(dsi, 0xfc, 0xa5, 0xa5);
dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a);
dsi_dcs_write_seq(dsi, 0xb0, 0x01);
dsi_dcs_write_seq(dsi, 0xed, 0x04);
dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20);
dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
return 0;
}
static int s6e3fc1_off(struct s6e3fc1 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
return ret;
}
usleep_range(10000, 11000);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(160);
return 0;
}
static int s6e3fc1_prepare(struct drm_panel *panel)
{
struct s6e3fc1 *ctx = to_s6e3fc1_panel(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (ctx->prepared)
return 0;
ret = regulator_enable(ctx->supply);
if (ret < 0) {
dev_err(dev, "Failed to enable regulator: %d\n", ret);
return ret;
}
s6e3fc1_reset(ctx);
ret = s6e3fc1_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->supply);
return ret;
}
ctx->prepared = true;
return 0;
}
static int s6e3fc1_unprepare(struct drm_panel *panel)
{
struct s6e3fc1 *ctx = to_s6e3fc1_panel(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
if (!ctx->prepared)
return 0;
ret = s6e3fc1_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_disable(ctx->supply);
ctx->prepared = false;
return 0;
}
static const struct drm_display_mode s6e3fc1_mode = {
.clock = (1080 + 128 + 16 + 64) * (2160 + 18 + 2 + 4) * 60 / 1000,
.hdisplay = 1080,
.hsync_start = 1080 + 128,
.hsync_end = 1080 + 128 + 16,
.htotal = 1080 + 128 + 16 + 64,
.vdisplay = 2160,
.vsync_start = 2160 + 18,
.vsync_end = 2160 + 18 + 2,
.vtotal = 2160 + 18 + 2 + 4,
.width_mm = 68,
.height_mm = 137,
};
static int s6e3fc1_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, &s6e3fc1_mode);
if (!mode)
return -ENOMEM;
drm_mode_set_name(mode);
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
connector->display_info.width_mm = mode->width_mm;
connector->display_info.height_mm = mode->height_mm;
drm_mode_probed_add(connector, mode);
return 1;
}
static const struct drm_panel_funcs s6e3fc1_panel_funcs = {
.prepare = s6e3fc1_prepare,
.unprepare = s6e3fc1_unprepare,
.get_modes = s6e3fc1_get_modes,
};
static int s6e3fc1_bl_update_status(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
brightness = (u16)backlight_get_brightness(bl);
// This panel needs the high and low bytes swapped for the brightness value
brightness = __swab16(brightness);
ret = mipi_dsi_dcs_set_display_brightness(dsi, brightness);
if (ret < 0)
return ret;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return 0;
}
static int s6e3fc1_bl_get_brightness(struct backlight_device *bl)
{
struct mipi_dsi_device *dsi = bl_get_data(bl);
u16 brightness;
int ret;
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
if (ret < 0)
return ret;
// This panel needs the high and low bytes swapped for the brightness value
brightness = __swab16(brightness);
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
return brightness;
}
static const struct backlight_ops s6e3fc1_bl_ops = {
.update_status = s6e3fc1_bl_update_status,
.get_brightness = s6e3fc1_bl_get_brightness,
};
static struct backlight_device *
s6e3fc1_create_backlight(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_RAW,
.brightness = 1023,
.max_brightness = 1023,
};
return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
&s6e3fc1_bl_ops, &props);
}
static int s6e3fc1_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct s6e3fc1 *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->supply = devm_regulator_get(dev, "vddio");
if (IS_ERR(ctx->supply))
return dev_err_probe(dev, PTR_ERR(ctx->supply),
"Failed to get vddio regulator\n");
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
ctx->dsi = dsi;
mipi_dsi_set_drvdata(dsi, ctx);
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_HSE |
MIPI_DSI_CLOCK_NON_CONTINUOUS;
drm_panel_init(&ctx->panel, dev, &s6e3fc1_panel_funcs,
DRM_MODE_CONNECTOR_DSI);
ctx->panel.backlight = s6e3fc1_create_backlight(dsi);
if (IS_ERR(ctx->panel.backlight))
return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
"Failed to create backlight\n");
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static int s6e3fc1_remove(struct mipi_dsi_device *dsi)
{
struct s6e3fc1 *ctx = mipi_dsi_get_drvdata(dsi);
int ret;
ret = mipi_dsi_detach(dsi);
if (ret < 0)
dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
drm_panel_remove(&ctx->panel);
return 0;
}
static const struct of_device_id s6e3fc1_of_match[] = {
{ .compatible = "samsung,s6e3fc1" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, s6e3fc1_of_match);
static struct mipi_dsi_driver s6e3fc1_driver = {
.probe = s6e3fc1_probe,
.remove = s6e3fc1_remove,
.driver = {
.name = "panel-samsung-s6e3fc1",
.of_match_table = s6e3fc1_of_match,
},
};
module_mipi_dsi_driver(s6e3fc1_driver);
MODULE_AUTHOR("Jami Kettunen <jami.kettunen@protonmail.com>");
MODULE_DESCRIPTION("DRM driver for Samsung S6E3FC1 AMOLED DSI cmd mode panel found on OnePlus 5T phones");
MODULE_LICENSE("GPL v2");

View file

@ -39,6 +39,8 @@
#define QUP_MX_READ_CNT 0x208
#define QUP_IN_FIFO_BASE 0x218
#define QUP_I2C_CLK_CTL 0x400
#define QUP_I2C_CLK_CTL_SDA_NR GENMASK(27, 26)
#define QUP_I2C_CLK_CTL_SCL_NR GENMASK(25, 24)
#define QUP_I2C_STATUS 0x404
#define QUP_I2C_MASTER_GEN 0x408
@ -1663,6 +1665,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
int ret, fs_div, hs_div;
u32 src_clk_freq = DEFAULT_SRC_CLK;
u32 clk_freq = DEFAULT_CLK_FREQ;
u32 noise_reject_scl = 0, noise_reject_sda = 0;
int blocks;
bool is_qup_v1;
@ -1860,6 +1863,19 @@ nodma:
qup->clk_ctl = ((fs_div / 2) << 16) | (hs_div << 8) | (fs_div & 0xff);
}
/* SCL/SDA Noise rejection (optional) */
ret = device_property_read_u32(qup->dev, "qcom,noise-reject-scl",
&noise_reject_scl);
if (ret == 0)
qup->clk_ctl |= FIELD_PREP(QUP_I2C_CLK_CTL_SCL_NR,
noise_reject_scl);
ret = device_property_read_u32(qup->dev, "qcom,noise-reject-sda",
&noise_reject_sda);
if (ret == 0)
qup->clk_ctl |= FIELD_PREP(QUP_I2C_CLK_CTL_SDA_NR,
noise_reject_sda);
/*
* Time it takes for a byte to be clocked out on the bus.
* Each byte takes 9 clock cycles (8 bits + 1 ack).

View file

@ -823,6 +823,18 @@ config QCOM_PM8XXX_XOADC
To compile this driver as a module, choose M here: the module
will be called qcom-pm8xxx-xoadc.
config QCOM_SPMI_RRADC
tristate "Qualcomm SPMI RRADC"
depends on MFD_SPMI_PMIC
help
This is for the PMIC Round Robin ADC driver.
This driver exposes the battery ID resistor, battery thermal, PMIC die
temperature, charger USB in and DC in voltage and current.
To compile this driver as a module, choose M here: the module will
be called qcom-qpmi-rradc.
config QCOM_SPMI_IADC
tristate "Qualcomm SPMI PMIC current ADC"
depends on SPMI

View file

@ -78,6 +78,7 @@ obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_ADC5) += qcom-spmi-adc5.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_RRADC) += qcom-spmi-rradc.o
obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o

File diff suppressed because it is too large Load diff

View file

@ -243,6 +243,19 @@ config KEYBOARD_GPIO
To compile this driver as a module, choose M here: the
module will be called gpio_keys.
config KEYBOARD_GPIO_FASTMATRIX
tristate "GPIO Keyboard"
depends on GPIOLIB
select INPUT_MATRIXKMAP
help
This driver implements support for matrix keypads and/or
keyboards connected directly to GPIO pins of a CPU, made
to also perform with slow I2C GPIO expanders and even
on matrices with no protection diodes.
To compile this driver as a module, choose M here: the
module will be called gpio_fastmatrix
config KEYBOARD_GPIO_POLLED
tristate "Polled GPIO buttons"
depends on GPIOLIB

View file

@ -23,6 +23,7 @@ obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_GPIO_FASTMATRIX) += gpio_fastmatrix.o
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o

View file

@ -0,0 +1,528 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Fast GPIO driven keyboard/keypad matrix driver
*
* Copyright (c) 2020 AngeloGioacchino Del Regno
* <angelogioacchino.delregno@somainline.org>
* Based on matrix_keypad.c
*/
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
struct gpio_keyboard {
struct device *dev;
struct input_dev *input_dev;
unsigned int row_shift;
struct gpio_descs *row_gpios;
struct gpio_descs *col_gpios;
u32 autorescan_ms;
u32 debounce_ms;
u32 col_scan_us;
int clustered_irq;
DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
u32 last_key_state[MATRIX_MAX_COLS];
struct delayed_work work;
struct mutex lock;
bool drive_inactive_cols;
bool gpio_all_disabled;
bool scan_pending;
bool stopped;
};
static int activate_one_column(struct gpio_keyboard *gkb, int col, bool wait)
{
int ret;
ret = gpiod_direction_output(gkb->col_gpios->desc[col], 1);
if (ret)
return ret;
if (wait && gkb->col_scan_us)
udelay(gkb->col_scan_us);
return 0;
}
/*
* NOTE: If drive_inactive_cols is false, then the GPIO has to be put into
* HiZ when de-activated to cause minmal side effect when scanning other
* columns. In that case it is configured here to be input, otherwise it is
* driven with the inactive value.
*/
static int deactivate_one_column(struct gpio_keyboard *gkb, int col)
{
gpiod_set_value_cansleep(gkb->col_gpios->desc[col], 0);
if (!gkb->drive_inactive_cols)
return gpiod_direction_input(gkb->col_gpios->desc[col]);
return 0;
}
static int activate_all_cols(struct gpio_keyboard *gkb)
{
unsigned long val = ULONG_MAX;
int ret, col;
/*
* Shortcut! If we don't have to set direction, we can use
* the way faster gpiod array setting instead.
*/
if (gkb->drive_inactive_cols) {
return gpiod_set_array_value_cansleep(gkb->col_gpios->ndescs,
gkb->col_gpios->desc,
gkb->col_gpios->info,
&val);
}
for (col = 0; col < gkb->col_gpios->ndescs; col++) {
ret = activate_one_column(gkb, col, false);
if (ret)
return ret;
}
return 0;
}
static int deactivate_all_cols(struct gpio_keyboard *gkb)
{
unsigned long val = 0;
int col, ret;
/*
* If the GPIO controller supports setting all pins at once it
* is going to be way faster, otherwise this function will fall
* back to setting all pins one at a time.
*/
ret = gpiod_set_array_value_cansleep(gkb->col_gpios->ndescs,
gkb->col_gpios->desc,
gkb->col_gpios->info, &val);
if (ret)
return ret;
if (!gkb->drive_inactive_cols) {
for (col = 0; col < gkb->col_gpios->ndescs; col++)
gpiod_direction_input(gkb->col_gpios->desc[col]);
}
return ret;
}
static void enable_row_irqs(struct gpio_keyboard *gkb)
{
int i;
if (gkb->clustered_irq > 0)
enable_irq(gkb->clustered_irq);
else {
for (i = 0; i < gkb->row_gpios->ndescs; i++)
enable_irq(gpiod_to_irq(gkb->row_gpios->desc[i]));
}
}
static void disable_row_irqs(struct gpio_keyboard *gkb)
{
int i;
if (gkb->clustered_irq > 0)
disable_irq_nosync(gkb->clustered_irq);
else {
for (i = 0; i < gkb->row_gpios->ndescs; i++)
disable_irq_nosync(gpiod_to_irq(gkb->row_gpios->desc[i]));
}
}
/*
* This gets the keys from keyboard and reports it to input subsystem
*/
static void gpio_keyboard_scan(struct work_struct *work)
{
struct gpio_keyboard *gkb =
container_of(work, struct gpio_keyboard, work.work);
struct input_dev *input_dev = gkb->input_dev;
const unsigned short *keycodes = input_dev->keycode;
u32 *new_state;
unsigned long row_values;
int ret, row, col, code;
u32 keymask = 0;
new_state = kzalloc(gkb->col_gpios->ndescs * sizeof(*new_state),
GFP_KERNEL);
if (!new_state)
return;
/* de-activate all columns for scanning */
deactivate_all_cols(gkb);
/* assert each column and read the row status out */
for (col = 0; col < gkb->col_gpios->ndescs; col++) {
activate_one_column(gkb, col, true);
ret = gpiod_get_array_value_cansleep(gkb->row_gpios->ndescs,
gkb->row_gpios->desc,
gkb->row_gpios->info,
&row_values);
new_state[col] = row_values;
keymask |= new_state[col];
if (deactivate_one_column(gkb, col)) {
activate_all_cols(gkb);
goto end;
}
}
activate_all_cols(gkb);
for (col = 0; col < gkb->col_gpios->ndescs; col++) {
u32 bits_changed = gkb->last_key_state[col] ^ new_state[col];
if (bits_changed == 0)
continue;
for (row = 0; bits_changed; row++, bits_changed >>=1 ) {
if (!(bits_changed & BIT(0)))
continue;
code = MATRIX_SCAN_CODE(row, col, gkb->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keycodes[code],
new_state[col] & (1 << row));
}
}
input_sync(input_dev);
memcpy(gkb->last_key_state, new_state, sizeof(gkb->last_key_state));
kfree(new_state);
/* Avoid missing key release events on quirky hardware */
if (gkb->autorescan_ms && keymask) {
queue_delayed_work(system_highpri_wq, &gkb->work,
msecs_to_jiffies(gkb->autorescan_ms));
return;
}
end:
/* Enable IRQs again */
mutex_lock(&gkb->lock);
gkb->scan_pending = false;
enable_row_irqs(gkb);
mutex_unlock(&gkb->lock);
}
static irqreturn_t gpio_keyboard_interrupt(int irq, void *id)
{
struct gpio_keyboard *gkb = id;
/*
* See if another IRQ beaten us to it and scheduled the
* scan already. In that case we should not try to
* disable IRQs again.
*/
if (unlikely(gkb->scan_pending || gkb->stopped))
goto out;
mutex_lock(&gkb->lock);
disable_row_irqs(gkb);
gkb->scan_pending = true;
mod_delayed_work(system_highpri_wq, &gkb->work,
msecs_to_jiffies(gkb->debounce_ms));
out:
mutex_unlock(&gkb->lock);
return IRQ_HANDLED;
}
static int gpio_keyboard_start(struct input_dev *dev)
{
struct gpio_keyboard *gkb = input_get_drvdata(dev);
gkb->stopped = false;
/*
* Schedule an immediate key scan to capture current key state;
* columns will be activated and IRQs be enabled after the scan.
*/
schedule_delayed_work(&gkb->work, 0);
return 0;
}
static void gpio_keyboard_stop(struct input_dev *dev)
{
struct gpio_keyboard *gkb = input_get_drvdata(dev);
mutex_lock(&gkb->lock);
gkb->stopped = true;
mutex_unlock(&gkb->lock);
flush_delayed_work(&gkb->work);
/*
* gpio_keyboard_scan() will leave IRQs enabled;
* we should disable them now.
*/
disable_row_irqs(gkb);
}
static void __maybe_unused gpio_keyboard_wakeup_en(struct gpio_keyboard *gkb)
{
int irq, i;
if (gkb->clustered_irq > 0) {
if (enable_irq_wake(gkb->clustered_irq) == 0)
gkb->gpio_all_disabled = true;
} else {
for (i = 0; i < gkb->row_gpios->ndescs; i++) {
if (!test_bit(i, gkb->disabled_gpios)) {
irq = gpiod_to_irq(gkb->row_gpios->desc[i]);
if (enable_irq_wake(irq) == 0)
__set_bit(i, gkb->disabled_gpios);
}
}
}
}
static void __maybe_unused gpio_keyboard_wakeup_dis(struct gpio_keyboard *gkb)
{
int irq, i;
if (gkb->clustered_irq > 0) {
if (gkb->gpio_all_disabled) {
disable_irq_wake(gkb->clustered_irq);
gkb->gpio_all_disabled = false;
}
} else {
for (i = 0; i < gkb->row_gpios->ndescs; i++) {
if (test_and_clear_bit(i, gkb->disabled_gpios)) {
irq = gpiod_to_irq(gkb->row_gpios->desc[i]);
disable_irq_wake(irq);
}
}
}
}
static int __maybe_unused gpio_keyboard_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keyboard *gkb = platform_get_drvdata(pdev);
gpio_keyboard_stop(gkb->input_dev);
if (device_may_wakeup(&pdev->dev))
gpio_keyboard_wakeup_en(gkb);
return 0;
}
static int __maybe_unused gpio_keyboard_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_keyboard *gkb = platform_get_drvdata(pdev);
if (device_may_wakeup(&pdev->dev))
gpio_keyboard_wakeup_dis(gkb);
gpio_keyboard_start(gkb->input_dev);
return 0;
}
static SIMPLE_DEV_PM_OPS(gpio_keyboard_pm_ops,
gpio_keyboard_suspend, gpio_keyboard_resume);
static int gpio_keyboard_init_gpio(struct platform_device *pdev,
struct gpio_keyboard *gkb)
{
int i, ret;
if (gkb->clustered_irq > 0) {
ret = devm_request_threaded_irq(gkb->dev, gkb->clustered_irq,
NULL, gpio_keyboard_interrupt,
IRQF_ONESHOT, "gpio-keyboard", gkb);
if (ret < 0) {
dev_err(&pdev->dev,
"Cannot get IRQ %d\n", gkb->clustered_irq);
return ret;
}
} else {
for (i = 0; i < gkb->row_gpios->ndescs; i++) {
ret = devm_request_threaded_irq(
gkb->dev,
gpiod_to_irq(gkb->row_gpios->desc[i]),
NULL, gpio_keyboard_interrupt,
IRQF_TRIGGER_HIGH |
IRQF_TRIGGER_LOW,
"gpio-keyboard", gkb);
if (ret < 0) {
dev_err(&pdev->dev,
"Cannot get IRQ for gpio%d\n",
desc_to_gpio(gkb->row_gpios->desc[i]));
return ret;
}
}
}
/* initialized as disabled - enabled by input->open */
disable_row_irqs(gkb);
return 0;
}
static int gpio_keyboard_parse_dt(struct gpio_keyboard *gkb)
{
struct device *dev = gkb->dev;
int rc;
/*
* Get as GPIOD_ASIS to use the configuration that comes from
* device-tree. Anyway, in many cases the row is configured as
* input, while the column is configured as output-high.
*
* This may vary depending on the hardware.
*/
gkb->row_gpios = devm_gpiod_get_array(dev, "row", GPIOD_ASIS);
if (IS_ERR(gkb->row_gpios))
return PTR_ERR(gkb->row_gpios);
gkb->col_gpios = devm_gpiod_get_array(dev, "col", GPIOD_ASIS);
if (IS_ERR(gkb->col_gpios))
return PTR_ERR(gkb->col_gpios);
/* All of these additional properties are optional */
device_property_read_string(dev, "label", &gkb->input_dev->name);
if (device_property_read_bool(dev, "autorepeat"))
__set_bit(EV_REP, gkb->input_dev->evbit);
gkb->drive_inactive_cols =
device_property_read_bool(dev, "drive-inactive-cols");
rc = device_property_read_u32(dev, "autorescan-ms",
&gkb->autorescan_ms);
if (rc < 0)
gkb->autorescan_ms = 0;
rc = device_property_read_u32(dev, "debounce-delay-ms",
&gkb->debounce_ms);
if (rc < 0)
gkb->debounce_ms = 0;
rc = device_property_read_u32(dev, "col-scan-delay-us",
&gkb->col_scan_us);
if (rc < 0)
gkb->col_scan_us = 0;
return 0;
}
static int gpio_keyboard_probe(struct platform_device *pdev)
{
struct gpio_keyboard *gkb;
bool wake;
int irq, ret;
gkb = devm_kmalloc(&pdev->dev, sizeof(*gkb), GFP_KERNEL);
if (!gkb)
return -ENOMEM;
gkb->dev = &pdev->dev;
gkb->input_dev = devm_input_allocate_device(&pdev->dev);
if (!gkb->input_dev)
return -ENOMEM;
ret = gpio_keyboard_parse_dt(gkb);
if (ret)
return ret;
irq = platform_get_irq_optional(pdev, 0);
gkb->clustered_irq = (irq > 0) ? irq : 0;
gkb->row_shift = get_count_order(gkb->col_gpios->ndescs);
gkb->stopped = true;
INIT_DELAYED_WORK(&gkb->work, gpio_keyboard_scan);
memset(gkb->last_key_state, 0, sizeof(gkb->last_key_state));
mutex_init(&gkb->lock);
if (!gkb->input_dev->name)
gkb->input_dev->name = pdev->name;
gkb->input_dev->id.bustype = BUS_HOST;
gkb->input_dev->dev.parent = &pdev->dev;
gkb->input_dev->open = gpio_keyboard_start;
gkb->input_dev->close = gpio_keyboard_stop;
ret = matrix_keypad_build_keymap(NULL, NULL,
gkb->row_gpios->ndescs,
gkb->col_gpios->ndescs,
NULL, gkb->input_dev);
if (ret) {
dev_err(&pdev->dev, "failed to build keymap\n");
return ret;
}
input_set_capability(gkb->input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(gkb->input_dev, gkb);
ret = gpio_keyboard_init_gpio(pdev, gkb);
if (ret)
return ret;
ret = input_register_device(gkb->input_dev);
if (ret)
return ret;
wake = device_property_read_bool(&pdev->dev, "wakeup-source");
device_init_wakeup(&pdev->dev, wake);
platform_set_drvdata(pdev, gkb);
return 0;
}
static int gpio_keyboard_remove(struct platform_device *pdev)
{
struct gpio_keyboard *gkb = platform_get_drvdata(pdev);
int i;
if (gkb->clustered_irq > 0) {
free_irq(gkb->clustered_irq, gkb);
} else {
for (i = 0; i < gkb->row_gpios->ndescs; i++)
free_irq(gpiod_to_irq(gkb->row_gpios->desc[i]), gkb);
}
input_unregister_device(gkb->input_dev);
return 0;
}
static const struct of_device_id gpio_keyboard_dt_match[] = {
{ .compatible = "gpio-fastmatrix-keyboard" },
{ }
};
MODULE_DEVICE_TABLE(of, gpio_keyboard_dt_match);
static struct platform_driver gpio_keyboard_driver = {
.probe = gpio_keyboard_probe,
.remove = gpio_keyboard_remove,
.driver = {
.name = "gpio-fastmatrix-keyboard",
.pm = &gpio_keyboard_pm_ops,
.of_match_table = gpio_keyboard_dt_match,
},
};
module_platform_driver(gpio_keyboard_driver);
MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@somainline.org>");
MODULE_DESCRIPTION("Fast GPIO driven keyboard/keypad matrix driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:gpio-fastmatrix-keyboard");

View file

@ -186,6 +186,18 @@ config INPUT_PMIC8XXX_PWRKEY
To compile this driver as a module, choose M here: the
module will be called pmic8xxx-pwrkey.
config INPUT_QCOM_SPMI_HAPTICS
tristate "Qualcomm SPMI HAPTICS"
depends on ARCH_QCOM
depends on SPMI
select INPUT_FF_MEMLESS
help
This option enables support for the haptics found in pmi8998 and
related PMICs. Based on the ff-memless interface.
To compile this driver as module, choose M here: the
module will be called qcom_spmi_haptics.
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
depends on PCI && SPARC64

View file

@ -64,6 +64,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o
obj-$(CONFIG_INPUT_QCOM_SPMI_HAPTICS) += qcom-spmi-haptics.o
obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o

View file

@ -0,0 +1,977 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, Caleb Connolly <caleb@connolly.tech>
* Qualcomm QPMI haptics driver for pmi8998 and related PMICs.
*/
#include <dt-bindings/input/qcom,spmi-haptics.h>
#include <linux/atomic.h>
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/types.h>
#define HAP_STATUS_1_REG 0x0A
#define HAP_BUSY_BIT BIT(1)
#define SC_FLAG_BIT BIT(3)
#define AUTO_RES_ERROR_BIT BIT(4)
#define HAP_LRA_AUTO_RES_LO_REG 0x0B
#define HAP_LRA_AUTO_RES_HI_REG 0x0C
#define HAP_EN_CTL_REG 0x46
#define HAP_EN_BIT BIT(7)
#define HAP_EN_CTL2_REG 0x48
#define BRAKE_EN_BIT BIT(0)
#define HAP_AUTO_RES_CTRL_REG 0x4B
#define AUTO_RES_EN_BIT BIT(7)
#define AUTO_RES_ERR_RECOVERY_BIT BIT(3)
#define AUTO_RES_EN_FLAG_BIT BIT(0)
#define HAP_CFG1_REG 0x4C
#define HAP_ACT_TYPE_MASK BIT(0)
#define HAP_CFG2_REG 0x4D
#define HAP_LRA_RES_TYPE_MASK BIT(0)
#define HAP_SEL_REG 0x4E
#define HAP_WF_SOURCE_MASK GENMASK(5, 4)
#define HAP_WF_SOURCE_SHIFT 4
#define HAP_LRA_AUTO_RES_REG 0x4F
#define LRA_AUTO_RES_MODE_MASK GENMASK(6, 4)
#define LRA_AUTO_RES_MODE_SHIFT 4
#define LRA_HIGH_Z_MASK GENMASK(3, 2)
#define LRA_HIGH_Z_SHIFT 2
#define LRA_RES_CAL_MASK GENMASK(1, 0)
#define HAP_RES_CAL_PERIOD_MIN 4
#define HAP_RES_CAL_PERIOD_MAX 32
#define HAP_VMAX_CFG_REG 0x51
#define HAP_VMAX_OVD_BIT BIT(6)
#define HAP_VMAX_MASK GENMASK(5, 1)
#define HAP_VMAX_SHIFT 1
#define HAP_ILIM_CFG_REG 0x52
#define HAP_ILIM_SEL_MASK BIT(0)
#define HAP_ILIM_400_MA 0
#define HAP_ILIM_800_MA 1
#define HAP_SC_DEB_REG 0x53
#define HAP_SC_DEB_MASK GENMASK(2, 0)
#define HAP_SC_DEB_CYCLES_MIN 0
#define HAP_DEF_SC_DEB_CYCLES 8
#define HAP_SC_DEB_CYCLES_MAX 32
#define HAP_RATE_CFG1_REG 0x54
#define HAP_RATE_CFG1_MASK GENMASK(7, 0)
#define HAP_RATE_CFG2_SHIFT 8
#define HAP_RATE_CFG2_REG 0x55
#define HAP_RATE_CFG2_MASK GENMASK(3, 0)
#define HAP_SC_CLR_REG 0x59
#define SC_CLR_BIT BIT(0)
#define HAP_BRAKE_REG 0x5C
#define HAP_BRAKE_PAT_MASK 0x3
#define HAP_WF_REPEAT_REG 0x5E
#define WF_REPEAT_MASK GENMASK(6, 4)
#define WF_REPEAT_SHIFT 4
#define WF_REPEAT_MIN 1
#define WF_REPEAT_MAX 128
#define WF_S_REPEAT_MASK GENMASK(1, 0)
#define WF_S_REPEAT_MIN 1
#define WF_S_REPEAT_MAX 8
#define HAP_WF_S1_REG 0x60
#define HAP_WF_SIGN_BIT BIT(7)
#define HAP_WF_OVD_BIT BIT(6)
#define HAP_WF_SAMP_MAX GENMASK(5, 1)
#define HAP_WF_SAMPLE_LEN 8
#define HAP_PLAY_REG 0x70
#define HAP_PLAY_BIT BIT(7)
#define HAP_PAUSE_BIT BIT(0)
#define HAP_SEC_ACCESS_REG 0xD0
#define HAP_SEC_ACCESS_UNLOCK 0xA5
#define HAP_TEST2_REG 0xE3
#define HAP_VMAX_MIN_MV 116
#define HAP_VMAX_MAX_MV 3596
#define HAP_VMAX_MAX_MV_STRONG 3596
#define HAP_WAVE_PLAY_RATE_MIN_US 0
#define HAP_WAVE_PLAY_RATE_MAX_US 20475
#define HAP_WAVE_PLAY_TIME_MAX_MS 15000
#define AUTO_RES_ERR_POLL_TIME_NS (20 * NSEC_PER_MSEC)
#define HAPTICS_BACK_EMF_DELAY_US 20000
#define HAP_BRAKE_PAT_LEN 4
#define HAP_WAVE_SAMP_LEN 8
#define NUM_WF_SET 4
#define HAP_WAVE_SAMP_SET_LEN (HAP_WAVE_SAMP_LEN * NUM_WF_SET)
#define HAP_RATE_CFG_STEP_US 5
#define SC_MAX_COUNT 5
#define SC_COUNT_RST_DELAY_US 1000000
enum hap_play_control {
HAP_STOP,
HAP_PAUSE,
HAP_PLAY,
};
/**
* struct spmi_haptics - struct for spmi haptics data.
*
* @dev: Our device parent.
* @regmap: Register map for the hardware block.
* @haptics_input_dev: The input device used to receive events.
* @work: Work struct to play effects.
* @base: Base address of the regmap.
* @active: Atomic value used to track if haptics are currently playing.
* @play_irq: Fired to load the next wave pattern.
* @sc_irq: Short circuit irq.
* @last_sc_time: Time since the short circuit IRQ last fired.
* @sc_count: Number of times the short circuit IRQ has fired in this interval.
* @actuator_type: The type of actuator in use.
* @wave_shape: The shape of the waves to use (sine or square).
* @play_mode: The play mode to use (direct, buffer, pwm, audio).
* @magnitude: The strength we should be playing at.
* @vmax: Max voltage to use when playing.
* @current_limit: The current limit for this hardware (400mA or 800mA).
* @play_wave_rate: The wave rate to use for this hardware.
* @wave_samp: The array of wave samples to write for buffer mode.
* @brake_pat: The pattern to apply when braking.
* @play_lock: Lock to be held when updating the hardware state.
*/
struct spmi_haptics {
struct device *dev;
struct regmap *regmap;
struct input_dev *haptics_input_dev;
struct work_struct work;
u32 base;
atomic_t active;
int play_irq;
int sc_irq;
ktime_t last_sc_time;
u8 sc_count;
u8 actuator_type;
u8 wave_shape;
u8 play_mode;
int magnitude;
u32 vmax;
u32 current_limit;
u32 play_wave_rate;
u32 wave_samp[HAP_WAVE_SAMP_SET_LEN];
u8 brake_pat[HAP_BRAKE_PAT_LEN];
struct mutex play_lock;
};
static inline bool is_secure_addr(u16 addr)
{
return (addr & 0xFF) > 0xD0;
}
static int spmi_haptics_read(struct spmi_haptics *haptics,
u16 addr, u8 *val, int len)
{
int ret;
ret = regmap_bulk_read(haptics->regmap, addr, val, len);
if (ret < 0)
dev_err(haptics->dev, "Error reading address: 0x%x, ret %d\n", addr, ret);
return ret;
}
static int spmi_haptics_write(struct spmi_haptics *haptics,
u16 addr, u8 *val, int len)
{
int ret, i;
if (is_secure_addr(addr)) {
for (i = 0; i < len; i++) {
dev_dbg(haptics->dev, "%s: unlocking for addr: 0x%x, val: 0x%x", __func__,
addr, val[i]);
ret = regmap_write(haptics->regmap,
haptics->base + HAP_SEC_ACCESS_REG, HAP_SEC_ACCESS_UNLOCK);
if (ret < 0) {
dev_err(haptics->dev, "Error writing unlock code, ret %d\n",
ret);
return ret;
}
ret = regmap_write(haptics->regmap, addr + i, val[i]);
if (ret < 0) {
dev_err(haptics->dev, "Error writing address 0x%x, ret %d\n",
addr + i, ret);
return ret;
}
}
} else {
if (len > 1)
ret = regmap_bulk_write(haptics->regmap, addr, val, len);
else
ret = regmap_write(haptics->regmap, addr, *val);
}
if (ret < 0)
dev_err(haptics->dev, "%s: Error writing address: 0x%x, ret %d\n",
__func__, addr, ret);
return ret;
}
static int spmi_haptics_write_masked(struct spmi_haptics *haptics,
u16 addr, u8 mask, u8 val)
{
int ret;
if (is_secure_addr(addr)) {
ret = regmap_write(haptics->regmap,
haptics->base + HAP_SEC_ACCESS_REG, HAP_SEC_ACCESS_UNLOCK);
if (ret < 0) {
dev_err(haptics->dev, "Error writing unlock code - ret %d\n", ret);
return ret;
}
}
ret = regmap_update_bits(haptics->regmap, addr, mask, val);
if (ret < 0)
dev_err(haptics->dev, "Error writing address: 0x%x - ret %d\n", addr, ret);
return ret;
}
static bool is_haptics_idle(struct spmi_haptics *haptics)
{
int ret;
u8 val;
if (haptics->play_mode == HAP_PLAY_DIRECT ||
haptics->play_mode == HAP_PLAY_PWM)
return true;
ret = spmi_haptics_read(haptics, haptics->base + HAP_STATUS_1_REG, &val, 1);
if (ret < 0 || (val & HAP_BUSY_BIT))
return false;
return true;
}
static int spmi_haptics_module_enable(struct spmi_haptics *haptics, bool enable)
{
u8 val;
dev_dbg(haptics->dev, "Setting module enable: %d", enable);
val = enable ? HAP_EN_BIT : 0;
return spmi_haptics_write(haptics, haptics->base + HAP_EN_CTL_REG, &val, 1);
}
static int spmi_haptics_write_vmax(struct spmi_haptics *haptics)
{
u8 val = 0;
u32 vmax_mv = haptics->vmax;
vmax_mv = clamp_t(u32, vmax_mv, HAP_VMAX_MIN_MV, HAP_VMAX_MAX_MV);
dev_dbg(haptics->dev, "Setting vmax to: %d", vmax_mv);
val = DIV_ROUND_CLOSEST(vmax_mv, HAP_VMAX_MIN_MV);
val = FIELD_PREP(HAP_VMAX_MASK, val);
// TODO: pm660 can enable overdrive here
return spmi_haptics_write_masked(haptics, haptics->base + HAP_VMAX_CFG_REG,
HAP_VMAX_MASK | HAP_WF_OVD_BIT, val);
}
static int spmi_haptics_write_current_limit(struct spmi_haptics *haptics)
{
haptics->current_limit = clamp_t(u32, haptics->current_limit,
HAP_ILIM_400_MA, HAP_ILIM_800_MA);
dev_dbg(haptics->dev, "Setting current_limit to: 0x%x", haptics->current_limit);
return spmi_haptics_write_masked(haptics, haptics->base + HAP_ILIM_CFG_REG,
HAP_ILIM_SEL_MASK, haptics->current_limit);
}
static int spmi_haptics_write_play_mode(struct spmi_haptics *haptics)
{
u8 val = 0;
if (!is_haptics_idle(haptics))
return -EBUSY;
dev_dbg(haptics->dev, "Setting play_mode to: 0x%x", haptics->play_mode);
val = FIELD_PREP(HAP_WF_SOURCE_MASK, haptics->play_mode);
return spmi_haptics_write_masked(haptics, haptics->base + HAP_SEL_REG,
HAP_WF_SOURCE_MASK, val);
}
static int spmi_haptics_write_play_rate(struct spmi_haptics *haptics, u16 play_rate)
{
u8 val[2];
dev_dbg(haptics->dev, "Setting play_rate to: %d", play_rate);
val[0] = FIELD_PREP(HAP_RATE_CFG1_MASK, play_rate);
val[1] = FIELD_PREP(HAP_RATE_CFG2_MASK, play_rate >> HAP_RATE_CFG2_SHIFT);
return spmi_haptics_write(haptics, haptics->base + HAP_RATE_CFG1_REG, val, 2);
}
/*
* spmi_haptics_set_auto_res() - Auto resonance
* allows the haptics to automatically adjust the
* speed of the oscillation in order to maintain
* the resonant frequency.
*/
static int spmi_haptics_set_auto_res(struct spmi_haptics *haptics, bool enable)
{
u8 val;
// LRAs are the only type to support auto res
if (haptics->actuator_type != HAP_TYPE_LRA)
return 0;
val = enable ? AUTO_RES_EN_BIT : 0;
return spmi_haptics_write_masked(haptics, haptics->base + HAP_TEST2_REG,
AUTO_RES_EN_BIT, val);
}
static int spmi_haptics_write_brake(struct spmi_haptics *haptics)
{
int ret, i;
u8 val;
dev_dbg(haptics->dev, "Configuring brake pattern");
ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_EN_CTL2_REG,
BRAKE_EN_BIT, 1);
if (ret < 0)
return ret;
for (i = HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) {
u8 p = haptics->brake_pat[i] & HAP_BRAKE_PAT_MASK;
val |= p << (i * 2);
}
return spmi_haptics_write(haptics, haptics->base + HAP_BRAKE_REG, &val, 1);
}
static int spmi_haptics_write_buffer_config(struct spmi_haptics *haptics)
{
u8 buf[HAP_WAVE_SAMP_LEN];
int i;
dev_dbg(haptics->dev, "Writing buffer config");
for (i = 0; i < HAP_WAVE_SAMP_LEN; i++)
buf[i] = haptics->wave_samp[i];
return spmi_haptics_write(haptics, haptics->base + HAP_WF_S1_REG, buf,
HAP_WAVE_SAMP_LEN);
}
static int spmi_haptics_write_wave_repeat(struct spmi_haptics *haptics)
{
u8 val, mask;
/* The number of times to repeat each wave */
mask = WF_REPEAT_MASK | WF_S_REPEAT_MASK;
val = FIELD_PREP(WF_REPEAT_MASK, 0) |
FIELD_PREP(WF_S_REPEAT_MASK, 0);
return spmi_haptics_write_masked(haptics, haptics->base + HAP_WF_REPEAT_REG,
mask, val);
}
static int spmi_haptics_write_play_control(struct spmi_haptics *haptics,
enum hap_play_control ctrl)
{
u8 val;
switch (ctrl) {
case HAP_STOP:
val = 0;
break;
case HAP_PAUSE:
val = HAP_PAUSE_BIT;
break;
case HAP_PLAY:
val = HAP_PLAY_BIT;
break;
default:
return 0;
}
dev_dbg(haptics->dev, "haptics play ctrl: %d\n", ctrl);
return spmi_haptics_write(haptics, haptics->base + HAP_PLAY_REG, &val, 1);
}
/*
* This IRQ is fired to tell us to load the next wave sample set.
* As we only currently support a single sample set, it's unused.
*/
static irqreturn_t spmi_haptics_play_irq_handler(int irq, void *data)
{
struct spmi_haptics *haptics = data;
dev_dbg(haptics->dev, "play_irq triggered");
return IRQ_HANDLED;
}
/**
* spmi_haptics_sc_irq_handler() - short circuit irq handler
* Fires every ~50ms whilst the haptics are active.
* If the SC_FLAG_BIT is set then that means there isn't a short circuit
* and we just need to clear the IRQ to indicate that the device should
* keep vibrating.
*
* Otherwise, it means a short circuit situation has occurred.
*
* @irq: irq number
* @data: haptics data
* Returns: IRQ_HANDLED
*/
static irqreturn_t spmi_haptics_sc_irq_handler(int irq, void *data)
{
struct spmi_haptics *haptics = data;
int ret;
u8 val;
s64 sc_delta_time_us;
ktime_t temp;
ret = spmi_haptics_read(haptics, haptics->base + HAP_STATUS_1_REG, &val, 1);
if (ret < 0)
return IRQ_HANDLED;
if (!(val & SC_FLAG_BIT)) {
haptics->sc_count = 0;
return IRQ_HANDLED;
}
temp = ktime_get();
sc_delta_time_us = ktime_us_delta(temp, haptics->last_sc_time);
haptics->last_sc_time = temp;
if (sc_delta_time_us > SC_COUNT_RST_DELAY_US)
haptics->sc_count = 0;
else
haptics->sc_count++;
// Clear the interrupt flag
val = SC_CLR_BIT;
ret = spmi_haptics_write(haptics, haptics->base + HAP_SC_CLR_REG, &val, 1);
if (ret < 0)
return IRQ_HANDLED;
if (haptics->sc_count > SC_MAX_COUNT) {
dev_err(haptics->dev, "Short circuit persists, disabling haptics\n");
ret = spmi_haptics_module_enable(haptics, false);
if (ret < 0)
dev_err(haptics->dev, "Error disabling module, rc=%d\n", ret);
}
return IRQ_HANDLED;
}
/**
* spmi_haptics_init() - Initialise haptics hardware for use
* @haptics: haptics device
* Returns: 0 on success, < 0 on error
*/
static int spmi_haptics_init(struct spmi_haptics *haptics)
{
int ret;
u8 val, mask;
u16 play_rate;
ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_CFG1_REG,
HAP_ACT_TYPE_MASK, haptics->actuator_type);
if (ret < 0)
return ret;
/*
* Configure auto resonance
* see spmi_haptics_lra_auto_res_config downstream
* This is greatly simplified.
*/
val = FIELD_PREP(LRA_RES_CAL_MASK, ilog2(32 / HAP_RES_CAL_PERIOD_MIN)) |
FIELD_PREP(LRA_AUTO_RES_MODE_MASK, HAP_AUTO_RES_ZXD_EOP) |
FIELD_PREP(LRA_HIGH_Z_MASK, 1);
mask = LRA_AUTO_RES_MODE_MASK | LRA_HIGH_Z_MASK | LRA_RES_CAL_MASK;
ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_LRA_AUTO_RES_REG,
mask, val);
/* Configure the PLAY MODE register */
ret = spmi_haptics_write_play_mode(haptics);
if (ret < 0)
return ret;
ret = spmi_haptics_write_vmax(haptics);
if (ret < 0)
return ret;
/* Configure the ILIM register */
ret = spmi_haptics_write_current_limit(haptics);
if (ret < 0)
return ret;
// Configure the debounce for short-circuit detection.
ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_SC_DEB_REG,
HAP_SC_DEB_MASK, HAP_SC_DEB_CYCLES_MAX);
if (ret < 0)
return ret;
// write the wave shape
ret = spmi_haptics_write_masked(haptics, haptics->base + HAP_CFG2_REG,
HAP_LRA_RES_TYPE_MASK, haptics->wave_shape);
if (ret < 0)
return ret;
play_rate = haptics->play_wave_rate / HAP_RATE_CFG_STEP_US;
/*
* Configure RATE_CFG1 and RATE_CFG2 registers.
* Note: For ERM these registers act as play rate and
* for LRA these represent resonance period
*/
ret = spmi_haptics_write_play_rate(haptics, play_rate);
if (ret < 0)
return ret;
ret = spmi_haptics_write_brake(haptics);
if (ret < 0)
return ret;
if (haptics->play_mode == HAP_PLAY_BUFFER) {
ret = spmi_haptics_write_wave_repeat(haptics);
if (ret < 0)
return ret;
ret = spmi_haptics_write_buffer_config(haptics);
if (ret < 0)
return ret;
}
dev_dbg(haptics->dev, "%s: Requesting play IRQ, irq: %d", __func__,
haptics->play_irq);
ret = devm_request_threaded_irq(haptics->dev, haptics->play_irq,
NULL, spmi_haptics_play_irq_handler, IRQF_ONESHOT,
"haptics_play_irq", haptics);
if (ret < 0) {
dev_err(haptics->dev, "Unable to request play IRQ ret=%d\n", ret);
return ret;
}
/* use play_irq only for buffer mode */
if (haptics->play_mode != HAP_PLAY_BUFFER)
disable_irq(haptics->play_irq);
dev_dbg(haptics->dev, "%s: Requesting play IRQ, irq: %d", __func__,
haptics->play_irq);
ret = devm_request_threaded_irq(haptics->dev, haptics->sc_irq,
NULL, spmi_haptics_sc_irq_handler, IRQF_ONESHOT,
"haptics_sc_irq", haptics);
if (ret < 0) {
dev_err(haptics->dev, "Unable to request sc IRQ ret=%d\n", ret);
return ret;
}
return 0;
}
/**
* spmi_haptics_enable - handler to start/stop vibration
* @haptics: pointer to haptics struct
* Returns: 0 on success, < 0 on failure
*/
static int spmi_haptics_enable(struct spmi_haptics *haptics)
{
int ret;
mutex_lock(&haptics->play_lock);
if (haptics->sc_count > SC_MAX_COUNT) {
dev_err(haptics->dev, "Can't play while in short circuit");
ret = -1;
goto out;
}
ret = spmi_haptics_set_auto_res(haptics, false);
if (ret < 0) {
dev_err(haptics->dev, "Error disabling auto_res, ret=%d\n", ret);
goto out;
}
ret = spmi_haptics_module_enable(haptics, true);
if (ret < 0) {
dev_err(haptics->dev, "Error enabling module, ret=%d\n", ret);
goto out;
}
ret = spmi_haptics_write_play_control(haptics, HAP_PLAY);
if (ret < 0) {
dev_err(haptics->dev, "Error enabling play, ret=%d\n", ret);
goto out;
}
ret = spmi_haptics_set_auto_res(haptics, true);
if (ret < 0) {
dev_err(haptics->dev, "Error enabling auto_res, ret=%d\n", ret);
goto out;
}
out:
mutex_unlock(&haptics->play_lock);
return ret;
}
/**
* spmi_haptics_enable - handler to start/stop vibration
* @haptics: pointer to haptics struct
* Returns: 0 on success, < 0 on failure
*/
static int spmi_haptics_disable(struct spmi_haptics *haptics)
{
int ret;
mutex_lock(&haptics->play_lock);
ret = spmi_haptics_write_play_control(haptics, HAP_STOP);
if (ret < 0) {
dev_err(haptics->dev, "Error disabling play, ret=%d\n", ret);
goto out;
}
ret = spmi_haptics_module_enable(haptics, false);
if (ret < 0) {
dev_err(haptics->dev, "Error disabling module, ret=%d\n", ret);
goto out;
}
out:
mutex_unlock(&haptics->play_lock);
return ret;
}
/*
* Threaded function to update the haptics state.
*/
static void spmi_haptics_work(struct work_struct *work)
{
struct spmi_haptics *haptics = container_of(work, struct spmi_haptics, work);
int ret;
bool enable;
enable = atomic_read(&haptics->active);
dev_dbg(haptics->dev, "%s: state: %d\n", __func__, enable);
if (enable)
ret = spmi_haptics_enable(haptics);
else
ret = spmi_haptics_disable(haptics);
if (ret < 0)
dev_err(haptics->dev, "Error setting haptics, ret=%d", ret);
}
/**
* spmi_haptics_close - callback for input device close
* @dev: input device pointer
*
* Turns off the vibrator.
*/
static void spmi_haptics_close(struct input_dev *dev)
{
struct spmi_haptics *haptics = input_get_drvdata(dev);
cancel_work_sync(&haptics->work);
if (atomic_read(&haptics->active)) {
atomic_set(&haptics->active, 0);
schedule_work(&haptics->work);
}
}
/**
* spmi_haptics_play_effect - play haptics effects
* @dev: input device pointer
* @data: data of effect
* @effect: effect to play
*/
static int spmi_haptics_play_effect(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct spmi_haptics *haptics = input_get_drvdata(dev);
dev_dbg(haptics->dev, "%s: Rumbling with strong: %d and weak: %d", __func__,
effect->u.rumble.strong_magnitude, effect->u.rumble.weak_magnitude);
haptics->magnitude = effect->u.rumble.strong_magnitude >> 8;
if (!haptics->magnitude)
haptics->magnitude = effect->u.rumble.weak_magnitude >> 10;
if (!haptics->magnitude) {
atomic_set(&haptics->active, 0);
goto end;
}
atomic_set(&haptics->active, 1);
haptics->vmax = ((HAP_VMAX_MAX_MV - HAP_VMAX_MIN_MV) * haptics->magnitude) / 100 +
HAP_VMAX_MIN_MV;
dev_dbg(haptics->dev, "%s: magnitude: %d, vmax: %d", __func__,
haptics->magnitude, haptics->vmax);
spmi_haptics_write_vmax(haptics);
end:
schedule_work(&haptics->work);
return 0;
}
static int spmi_haptics_probe(struct platform_device *pdev)
{
struct spmi_haptics *haptics;
struct device_node *node;
struct input_dev *input_dev;
int ret;
u32 val;
int i;
haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL);
if (!haptics)
return -ENOMEM;
haptics->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!haptics->regmap)
return -ENODEV;
node = pdev->dev.of_node;
haptics->dev = &pdev->dev;
ret = of_property_read_u32(node, "reg", &haptics->base);
if (ret < 0) {
dev_err(haptics->dev, "Couldn't find reg in node = %s ret = %d\n",
node->full_name, ret);
return ret;
}
haptics->play_irq = platform_get_irq_byname(pdev, "play");
if (haptics->play_irq < 0) {
dev_err(&pdev->dev, "Unable to get play irq\n");
ret = haptics->play_irq;
goto register_fail;
}
haptics->sc_irq = platform_get_irq_byname(pdev, "short");
if (haptics->sc_irq < 0) {
dev_err(&pdev->dev, "Unable to get sc irq\n");
ret = haptics->sc_irq;
goto register_fail;
}
// We only support LRAs for now
haptics->actuator_type = HAP_TYPE_LRA;
ret = of_property_read_u32(node, "qcom,actuator-type", &val);
if (!ret) {
if (val != HAP_TYPE_LRA) {
dev_err(&pdev->dev, "qcom,actuator-type (%d) isn't supported\n", val);
ret = -EINVAL;
goto register_fail;
}
haptics->actuator_type = val;
}
// Only buffer mode is currently supported
haptics->play_mode = HAP_PLAY_BUFFER;
ret = of_property_read_u32(node, "qcom,play-mode", &val);
if (!ret) {
if (val != HAP_PLAY_BUFFER) {
dev_err(&pdev->dev, "qcom,play-mode (%d) isn't supported\n", val);
ret = -EINVAL;
goto register_fail;
}
haptics->play_mode = val;
}
ret = of_property_read_u32(node, "qcom,wave-play-rate-us", &val);
if (!ret) {
haptics->play_wave_rate = val;
} else if (ret != -EINVAL) {
dev_err(haptics->dev, "Unable to read play rate ret=%d\n", ret);
goto register_fail;
}
haptics->play_wave_rate =
clamp_t(u32, haptics->play_wave_rate,
HAP_WAVE_PLAY_RATE_MIN_US, HAP_WAVE_PLAY_RATE_MAX_US);
haptics->wave_shape = HAP_WAVE_SINE;
ret = of_property_read_u32(node, "qcom,wave-shape", &val);
if (!ret) {
if (val != HAP_WAVE_SINE && val != HAP_WAVE_SQUARE) {
dev_err(&pdev->dev, "qcom,wave-shape is invalid: %d\n", val);
ret = -EINVAL;
goto register_fail;
}
haptics->wave_shape = val;
}
haptics->brake_pat[0] = 0x3;
haptics->brake_pat[1] = 0x3;
haptics->brake_pat[2] = 0x2;
haptics->brake_pat[3] = 0x1;
ret = of_property_read_u8_array(node, "qcom,brake-pattern", haptics->brake_pat, 4);
if (ret < 0 && ret != -EINVAL) {
dev_err(&pdev->dev, "qcom,brake-pattern is invalid, ret = %d\n", ret);
goto register_fail;
}
haptics->current_limit = HAP_ILIM_400_MA;
for (i = 0; i < HAP_WAVE_SAMP_LEN; i++)
haptics->wave_samp[i] = HAP_WF_SAMP_MAX;
ret = spmi_haptics_init(haptics);
if (ret < 0) {
dev_err(&pdev->dev, "Error initialising haptics, ret=%d\n",
ret);
goto register_fail;
}
platform_set_drvdata(pdev, haptics);
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
INIT_WORK(&haptics->work, spmi_haptics_work);
haptics->haptics_input_dev = input_dev;
input_dev->name = "spmi_haptics";
input_dev->id.version = 1;
input_dev->close = spmi_haptics_close;
input_set_drvdata(input_dev, haptics);
// Figure out how to make this FF_PERIODIC
input_set_capability(haptics->haptics_input_dev, EV_FF, FF_RUMBLE);
ret = input_ff_create_memless(input_dev, NULL,
spmi_haptics_play_effect);
if (ret) {
dev_err(&pdev->dev,
"couldn't register vibrator as FF device\n");
goto register_fail;
}
ret = input_register_device(input_dev);
if (ret) {
dev_err(&pdev->dev, "couldn't register input device\n");
goto register_fail;
}
return 0;
register_fail:
cancel_work_sync(&haptics->work);
mutex_destroy(&haptics->play_lock);
return ret;
}
static int __maybe_unused spmi_haptics_suspend(struct device *dev)
{
struct spmi_haptics *haptics = dev_get_drvdata(dev);
cancel_work_sync(&haptics->work);
spmi_haptics_disable(haptics);
return 0;
}
static SIMPLE_DEV_PM_OPS(spmi_haptics_pm_ops, spmi_haptics_suspend, NULL);
static int spmi_haptics_remove(struct platform_device *pdev)
{
struct spmi_haptics *haptics = dev_get_drvdata(&pdev->dev);
cancel_work_sync(&haptics->work);
mutex_destroy(&haptics->play_lock);
input_unregister_device(haptics->haptics_input_dev);
return 0;
}
static void spmi_haptics_shutdown(struct platform_device *pdev)
{
struct spmi_haptics *haptics = dev_get_drvdata(&pdev->dev);
cancel_work_sync(&haptics->work);
spmi_haptics_disable(haptics);
}
static const struct of_device_id spmi_haptics_match_table[] = {
{ .compatible = "qcom,spmi-haptics" },
{ }
};
MODULE_DEVICE_TABLE(of, spmi_haptics_match_table);
static struct platform_driver spmi_haptics_driver = {
.probe = spmi_haptics_probe,
.remove = spmi_haptics_remove,
.shutdown = spmi_haptics_shutdown,
.driver = {
.name = "spmi-haptics",
.pm = &spmi_haptics_pm_ops,
.of_match_table = spmi_haptics_match_table,
},
};
module_platform_driver(spmi_haptics_driver);
MODULE_DESCRIPTION("spmi haptics driver using ff-memless framework");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Caleb Connolly <caleb@connolly.tech>");

View file

@ -82,6 +82,14 @@ config RMI4_F12
touchpads. For sensors that support relative pointing, F12 also
provides mouse input.
config RMI4_F1A
bool "RMI4 Function 1A (Simple capacitive buttons)"
depends on OF
help
Say Y here if you want to add support for RMI4 function 1A.
Function 1A provides GPIO capacitive button support for RMI4 devices.
config RMI4_F30
bool "RMI4 Function 30 (GPIO LED)"
help

View file

@ -8,6 +8,7 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F1A) += rmi_f1a.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o

View file

@ -360,6 +360,9 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F12
&rmi_f12_handler,
#endif
#ifdef CONFIG_RMI4_F1A
&rmi_f1a_handler,
#endif
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif

View file

@ -133,6 +133,7 @@ extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f1a_handler;
extern struct rmi_function_handler rmi_f30_handler;
extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f3a_handler;

View file

@ -0,0 +1,190 @@
// FIXME: Too much stuff is hardcoded in currently!
#include <linux/input.h>
#include <linux/rmi.h>
#include <linux/of.h>
#include "rmi_driver.h"
/* Query 1 */
//#define F1A_BUTTONS_COUNT 0b00011111 /* BIT(1) */
#define MAX_NAME_LEN 256
#define F1A_MAX_BUTTONS 8
struct f1a_data {
struct rmi_function *fn;
unsigned char button_count;
u32 button_map[F1A_MAX_BUTTONS];
struct input_dev *input;
char input_name[MAX_NAME_LEN];
char input_phys[MAX_NAME_LEN];
u8 button_data_buffer;
};
static int rmi_f1a_initialize(struct f1a_data *f1a)
{
struct rmi_function *fn = f1a->fn;
struct device *dev = &fn->dev;
//u8 query[2];
int error;
/*error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, query, 2);
if (error) {
dev_err(dev, "Failed to read query register (%d).\n", error);
return error;
}
printk("%s: query0: 0x%x, query1: 0x%x\n", __func__, query[0], query[1]);*/
error = of_property_read_variable_u32_array(dev_of_node(dev),
"syna,codes", f1a->button_map, 1, F1A_MAX_BUTTONS);
if (error < 0) {
dev_err(dev, "Failed to parse syna,codes from OF device tree (%d).\n", error);
return error;
}
// FIXME: button_count = query[1] & F1A_BUTTONS_COUNT;
f1a->button_count = 0;
for (f1a->button_count = 0; f1a->button_count < F1A_MAX_BUTTONS; f1a->button_count++)
if (f1a->button_map[f1a->button_count] == 0)
break;
rmi_dbg(RMI_DEBUG_FN, dev, "%s: %d button codes defined\n", __func__, f1a->button_count);
return 0;
}
static int rmi_f1a_register_device(struct f1a_data *f1a)
{
struct rmi_function *fn = f1a->fn;
struct device *dev = &fn->dev;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct input_dev *input_dev;
int i, rc;
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(dev, "Failed to allocate input device.\n");
return -ENOMEM;
}
f1a->input = input_dev;
snprintf(f1a->input_name, MAX_NAME_LEN, "%s.fn%02x",
dev_name(&rmi_dev->dev), fn->fd.function_number);
input_dev->name = f1a->input_name;
snprintf(f1a->input_phys, MAX_NAME_LEN, "%s/input0", input_dev->name);
input_dev->phys = f1a->input_phys;
input_dev->dev.parent = &rmi_dev->dev;
input_set_drvdata(input_dev, f1a);
/* set up any input events */
set_bit(EV_SYN, input_dev->evbit);
set_bit(EV_KEY, input_dev->evbit);
/* manage button map using input subsystem */
input_dev->keycode = f1a->button_map;
input_dev->keycodesize = sizeof(f1a->button_map); /* f1a->button_count */
input_dev->keycodemax = f1a->button_count;
/* set bits for each button */
for (i = 0; i < f1a->button_count; i++) {
set_bit(f1a->button_map[i], input_dev->keybit);
input_set_capability(input_dev, EV_KEY, f1a->button_map[i]);
}
rc = input_register_device(input_dev);
if (rc < 0) {
dev_err(dev, "Failed to register input device.\n");
goto error_free_device;
}
return 0;
error_free_device:
input_free_device(input_dev);
return rc;
}
static int rmi_f1a_probe(struct rmi_function *fn)
{
struct device *dev = &fn->dev;
struct f1a_data *f1a;
int error;
rmi_dbg(RMI_DEBUG_FN, dev, "%s\n", __func__);
if (!fn->dev.of_node) {
/*
* Some quirky devices (e.g. OnePlus 5T) report supporting F1A
* (Simple capacitive buttons) despite not having the hardware,
* so in case there isn't an associated device-tree node present
* just pretend we probed successfully.
*/
return 0;
}
f1a = devm_kzalloc(dev, sizeof(struct f1a_data), GFP_KERNEL);
if (!f1a)
return -ENOMEM;
f1a->fn = fn;
error = rmi_f1a_initialize(f1a);
if (error < 0)
return error;
error = rmi_f1a_register_device(f1a);
if (error < 0)
return error;
dev_set_drvdata(dev, f1a);
return 0;
}
static int rmi_f1a_config(struct rmi_function *fn)
{
fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
return 0;
}
static irqreturn_t rmi_f1a_attention(int irq, void *ctx)
{
struct rmi_function *fn = ctx;
struct device *dev = &fn->dev;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f1a_data *f1a = dev_get_drvdata(dev);
int error, button;
// TODO: use rmi_read_block() to accomodate up to 8 buttons?
error = rmi_read(rmi_dev, fn->fd.data_base_addr, &(f1a->button_data_buffer));
if (error < 0) {
dev_err(dev, "Failed to read button data registers (%d).\n", error);
return error;
}
/*rmi_dbg(RMI_DEBUG_FN, dev, "%s: button_data=0x%x\n", __func__, f1a->button_data_buffer);*/
/* generate events for buttons that change state */
// TODO: Implement button_data_buffer as array + button_reg = button / 8
for (button = 0; button < f1a->button_count; button++) {
int button_shift;
bool button_status;
/* bit shift to get button's status */
button_shift = button % 8;
button_status = ((f1a->button_data_buffer >> button_shift) & 0x01) != 0;
rmi_dbg(RMI_DEBUG_FN, dev, "button %d (code %d) -> %d\n",
button, f1a->button_map[button], button_status);
/* generate an event here */
input_report_key(f1a->input, f1a->button_map[button], button_status);
}
input_sync(f1a->input); /* sync after groups of events */
return IRQ_HANDLED;
}
struct rmi_function_handler rmi_f1a_handler = {
.driver = {
.name = "rmi4_f1a",
},
.func = 0x1a,
.probe = rmi_f1a_probe,
.config = rmi_f1a_config,
.attention = rmi_f1a_attention,
};

View file

@ -44,6 +44,15 @@ config INTERCONNECT_QCOM_MSM8996
This is a driver for the Qualcomm Network-on-Chip on msm8996-based
platforms.
config INTERCONNECT_QCOM_MSM8998
tristate "Qualcomm MSM8998 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8998-based
platforms.
config INTERCONNECT_QCOM_OSM_L3
tristate "Qualcomm OSM L3 interconnect driver"
depends on INTERCONNECT_QCOM || COMPILE_TEST

View file

@ -5,6 +5,7 @@ qnoc-msm8916-objs := msm8916.o
qnoc-msm8939-objs := msm8939.o
qnoc-msm8974-objs := msm8974.o
qnoc-msm8996-objs := msm8996.o
qnoc-msm8998-objs := msm8998.o
icc-osm-l3-objs := osm-l3.o
qnoc-qcm2290-objs := qcm2290.o
qnoc-qcs404-objs := qcs404.o
@ -26,6 +27,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8998) += qnoc-msm8998.o
obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o

View file

@ -0,0 +1,981 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Qualcomm MSM8998 Network-on-Chip (NoC) QoS driver
* Copyright (c) 2020, AngeloGioacchino Del Regno
* <angelogioacchino.delregno@somainline.org>
* Copyright (C) 2020, Konrad Dybcio <konrad.dybcio@somainline.org>
*
*/
#include <dt-bindings/interconnect/qcom,msm8998.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include "smd-rpm.h"
#define RPM_BUS_MASTER_REQ 0x73616d62
#define RPM_BUS_SLAVE_REQ 0x766c7362
/* BIMC QoS */
#define M_BKE_REG_BASE(n) (0x300 + (0x4000 * n))
#define M_BKE_EN_ADDR(n) (M_BKE_REG_BASE(n))
#define M_BKE_HEALTH_CFG_ADDR(i, n) (M_BKE_REG_BASE(n) + 0x40 + (0x4 * i))
#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK 0x80000000
#define M_BKE_HEALTH_CFG_AREQPRIO_MASK 0x300
#define M_BKE_HEALTH_CFG_PRIOLVL_MASK 0x3
#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT 0x8
#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f
#define M_BKE_EN_EN_BMASK 0x1
/* Valid for both NoC and BIMC */
#define NOC_QOS_MODE_FIXED 0x0
#define NOC_QOS_MODE_LIMITER 0x1
#define NOC_QOS_MODE_BYPASS 0x2
/* NoC QoS */
#define NOC_PERM_MODE_FIXED 1
#define NOC_PERM_MODE_BYPASS (1 << NOC_QOS_MODE_BYPASS)
#define NOC_QOS_PRIORITYn_ADDR(n) (0x8 + (n * 0x1000))
#define NOC_QOS_PRIORITY_MASK 0xf
#define NOC_QOS_PRIORITY_P1_SHIFT 0x2
#define NOC_QOS_PRIORITY_P0_SHIFT 0x3
#define NOC_QOS_MODEn_ADDR(n) (0xc + (n * 0x1000))
#define NOC_QOS_MODEn_MASK 0x3
enum {
MSM8998_MASTER_IPA = 1,
MSM8998_MASTER_CNOC_A2NOC,
MSM8998_MASTER_SDCC_2,
MSM8998_MASTER_SDCC_4,
MSM8998_MASTER_BLSP_1,
MSM8998_MASTER_BLSP_2,
MSM8998_MASTER_UFS,
MSM8998_MASTER_USB_HS,
MSM8998_MASTER_USB3,
MSM8998_MASTER_CRYPTO_C0,
MSM8998_MASTER_GNOC_BIMC,
MSM8998_MASTER_OXILI,
MSM8998_MASTER_MNOC_BIMC,
MSM8998_MASTER_SNOC_BIMC,
MSM8998_MASTER_PIMEM,
MSM8998_MASTER_SNOC_CNOC,
MSM8998_MASTER_QDSS_DAP,
MSM8998_MASTER_APPS_PROC,
MSM8998_MASTER_CNOC_MNOC_MMSS_CFG,
MSM8998_MASTER_CNOC_MNOC_CFG,
MSM8998_MASTER_CPP,
MSM8998_MASTER_JPEG,
MSM8998_MASTER_MDP_P0,
MSM8998_MASTER_MDP_P1,
MSM8998_MASTER_VENUS,
MSM8998_MASTER_VFE,
MSM8998_MASTER_QDSS_ETR,
MSM8998_MASTER_QDSS_BAM,
MSM8998_MASTER_SNOC_CFG,
MSM8998_MASTER_BIMC_SNOC,
MSM8998_MASTER_A1NOC_SNOC,
MSM8998_MASTER_A2NOC_SNOC,
MSM8998_MASTER_GNOC_SNOC,
MSM8998_MASTER_PCIE_0,
MSM8998_MASTER_A2NOC_TSIF,
MSM8998_MASTER_CRVIRT_A2NOC,
MSM8998_MASTER_ROTATOR,
MSM8998_MASTER_VENUS_VMEM,
MSM8998_MASTER_HMSS,
MSM8998_MASTER_BIMC_SNOC_0,
MSM8998_MASTER_BIMC_SNOC_1,
MSM8998_SLAVE_A1NOC_SNOC,
MSM8998_SLAVE_A2NOC_SNOC,
MSM8998_SLAVE_EBI,
MSM8998_SLAVE_HMSS_L3,
MSM8998_SLAVE_CNOC_A2NOC,
MSM8998_SLAVE_MPM,
MSM8998_SLAVE_PMIC_ARB,
MSM8998_SLAVE_TLMM_NORTH,
MSM8998_SLAVE_TCSR,
MSM8998_SLAVE_PIMEM_CFG,
MSM8998_SLAVE_IMEM_CFG,
MSM8998_SLAVE_MESSAGE_RAM,
MSM8998_SLAVE_GLM,
MSM8998_SLAVE_BIMC_CFG,
MSM8998_SLAVE_PRNG,
MSM8998_SLAVE_SPDM,
MSM8998_SLAVE_QDSS_CFG,
MSM8998_SLAVE_CNOC_MNOC_CFG,
MSM8998_SLAVE_SNOC_CFG,
MSM8998_SLAVE_QM_CFG,
MSM8998_SLAVE_CLK_CTL,
MSM8998_SLAVE_MSS_CFG,
MSM8998_SLAVE_UFS_CFG,
MSM8998_SLAVE_A2NOC_CFG,
MSM8998_SLAVE_A2NOC_SMMU_CFG,
MSM8998_SLAVE_GPUSS_CFG,
MSM8998_SLAVE_AHB2PHY,
MSM8998_SLAVE_BLSP_1,
MSM8998_SLAVE_SDCC_2,
MSM8998_SLAVE_SDCC_4,
MSM8998_SLAVE_BLSP_2,
MSM8998_SLAVE_PDM,
MSM8998_SLAVE_CNOC_MNOC_MMSS_CFG,
MSM8998_SLAVE_USB_HS,
MSM8998_SLAVE_USB3_0,
MSM8998_SLAVE_SRVC_CNOC,
MSM8998_SLAVE_GNOC_BIMC,
MSM8998_SLAVE_GNOC_SNOC,
MSM8998_SLAVE_CAMERA_CFG,
MSM8998_SLAVE_CAMERA_THROTTLE_CFG,
MSM8998_SLAVE_MISC_CFG,
MSM8998_SLAVE_VENUS_THROTTLE_CFG,
MSM8998_SLAVE_VENUS_CFG,
MSM8998_SLAVE_MMSS_CLK_XPU_CFG,
MSM8998_SLAVE_MMSS_CLK_CFG,
MSM8998_SLAVE_MNOC_MPU_CFG,
MSM8998_SLAVE_DISPLAY_CFG,
MSM8998_SLAVE_CSI_PHY_CFG,
MSM8998_SLAVE_DISPLAY_THROTTLE_CFG,
MSM8998_SLAVE_SMMU_CFG,
MSM8998_SLAVE_MNOC_BIMC,
MSM8998_SLAVE_SRVC_MNOC,
MSM8998_SLAVE_HMSS,
MSM8998_SLAVE_LPASS,
MSM8998_SLAVE_WLAN,
MSM8998_SLAVE_CDSP,
MSM8998_SLAVE_IPA,
MSM8998_SLAVE_SNOC_BIMC,
MSM8998_SLAVE_SNOC_CNOC,
MSM8998_SLAVE_IMEM,
MSM8998_SLAVE_PIMEM,
MSM8998_SLAVE_QDSS_STM,
MSM8998_SLAVE_SRVC_SNOC,
MSM8998_SLAVE_BIMC_SNOC_0,
MSM8998_SLAVE_BIMC_SNOC_1,
MSM8998_SLAVE_SSC_CFG,
MSM8998_SLAVE_SKL,
MSM8998_SLAVE_TLMM_WEST,
MSM8998_SLAVE_A1NOC_CFG,
MSM8998_SLAVE_A1NOC_SMMU_CFG,
MSM8998_SLAVE_TSIF,
MSM8998_SLAVE_TLMM_EAST,
MSM8998_SLAVE_CRVIRT_A2NOC,
MSM8998_SLAVE_VMEM_CFG,
MSM8998_SLAVE_VMEM,
MSM8998_SLAVE_PCIE_0,
};
#define to_qcom_provider(_provider) \
container_of(_provider, struct qcom_icc_provider, provider)
static const struct clk_bulk_data bus_clocks[] = {
{ .id = "bus" },
{ .id = "bus_a" },
};
static const struct clk_bulk_data bus_mm_clocks[] = {
{ .id = "bus" },
{ .id = "bus_a" },
{ .id = "iface" },
};
/**
* struct qcom_icc_provider - Qualcomm specific interconnect provider
* @provider: generic interconnect provider
* @bus_clks: the clk_bulk_data table of bus clocks
* @num_clks: the total number of clk_bulk_data entries
* @is_bimc_node: indicates whether to use bimc specific setting
* @mmio: NoC base iospace
*/
struct qcom_icc_provider {
struct icc_provider provider;
struct clk_bulk_data *bus_clks;
int num_clks;
bool is_bimc_node;
struct regmap *regmap;
void __iomem *mmio;
};
#define MSM8998_MAX_LINKS 38
/**
* struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters
* @areq_prio: node requests priority
* @prio_level: priority level for bus communication
* @limit_commands: activate/deactivate limiter mode during runtime
* @ap_owned: indicates if the node is owned by the AP or by the RPM
* @qos_mode: default qos mode for this node
* @qos_port: qos port number for finding qos registers of this node
*/
struct qcom_icc_qos {
u32 areq_prio;
u32 prio_level;
bool limit_commands;
bool ap_owned;
int qos_mode;
int qos_port;
};
/**
* struct qcom_icc_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
* @id: a unique node identifier
* @links: an array of nodes where we can go next while traversing
* @num_links: the total number of @links
* @buswidth: width of the interconnect between a node and the bus (bytes)
* @mas_rpm_id: RPM id for devices that are bus masters
* @slv_rpm_id: RPM id for devices that are bus slaves
* @qos: NoC QoS setting parameters
* @rate: current bus clock rate in Hz
*/
struct qcom_icc_node {
unsigned char *name;
u16 id;
u16 links[MSM8998_MAX_LINKS];
u16 num_links;
u16 buswidth;
int mas_rpm_id;
int slv_rpm_id;
struct qcom_icc_qos qos;
u64 rate;
};
struct qcom_icc_desc {
struct qcom_icc_node **nodes;
size_t num_nodes;
const struct regmap_config *regmap_cfg;
};
#define DEFINE_QNODE(_name, _id, _buswidth, _mas_rpm_id, _slv_rpm_id, \
_ap_owned, _qos_mode, _qos_prio, _qos_port, ...) \
static struct qcom_icc_node _name = { \
.name = #_name, \
.id = _id, \
.buswidth = _buswidth, \
.mas_rpm_id = _mas_rpm_id, \
.slv_rpm_id = _slv_rpm_id, \
.qos.ap_owned = _ap_owned, \
.qos.qos_mode = _qos_mode, \
.qos.areq_prio = _qos_prio, \
.qos.prio_level = _qos_prio, \
.qos.qos_port = _qos_port, \
.num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })), \
.links = { __VA_ARGS__ }, \
}
/* masters */
DEFINE_QNODE(mas_pcie_0, MSM8998_MASTER_PCIE_0, 16, 45, -1, true, NOC_QOS_MODE_FIXED, 1, 1, MSM8998_SLAVE_A1NOC_SNOC);
DEFINE_QNODE(mas_usb3, MSM8998_MASTER_USB3, 16, 32, -1, true, NOC_QOS_MODE_FIXED, 1, 2, MSM8998_SLAVE_A1NOC_SNOC);
DEFINE_QNODE(mas_ufs, MSM8998_MASTER_UFS, 16, 68, -1, true, NOC_QOS_MODE_FIXED, 1, 2, MSM8998_SLAVE_A1NOC_SNOC);
DEFINE_QNODE(mas_blsp_2, MSM8998_MASTER_BLSP_2, 16, 39, -1, false, NOC_QOS_MODE_FIXED, 0, 4, MSM8998_SLAVE_A1NOC_SNOC);
DEFINE_QNODE(mas_cnoc_a2noc, MSM8998_MASTER_CNOC_A2NOC, 8, 146, -1, true, -1, 0, -1, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_ipa, MSM8998_MASTER_IPA, 8, 59, -1, true, NOC_QOS_MODE_FIXED, 1, 1, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_sdcc_2, MSM8998_MASTER_SDCC_2, 8, 35, -1, false, NOC_QOS_MODE_FIXED, 0, 6, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_sdcc_4, MSM8998_MASTER_SDCC_4, 8, 36, -1, false, NOC_QOS_MODE_FIXED, 0, 7, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_tsif, MSM8998_MASTER_A2NOC_TSIF, 4, 37, -1, true, -1, 0, -1, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_blsp_1, MSM8998_MASTER_BLSP_1, 16, 41, -1, false, NOC_QOS_MODE_FIXED, 0, 8, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_crvirt_a2noc, MSM8998_MASTER_CRVIRT_A2NOC, 8, 145, -1, false, NOC_QOS_MODE_FIXED, 0, 9, MSM8998_SLAVE_A2NOC_SNOC);
DEFINE_QNODE(mas_gnoc_bimc, MSM8998_MASTER_GNOC_BIMC, 8, 144, -1, true, NOC_QOS_MODE_FIXED, 0, 0, MSM8998_SLAVE_EBI, MSM8998_SLAVE_BIMC_SNOC_0);
DEFINE_QNODE(mas_oxili, MSM8998_MASTER_OXILI, 8, 6, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, MSM8998_SLAVE_BIMC_SNOC_1, MSM8998_SLAVE_HMSS_L3, MSM8998_SLAVE_EBI, MSM8998_SLAVE_BIMC_SNOC_0);
DEFINE_QNODE(mas_mnoc_bimc, MSM8998_MASTER_MNOC_BIMC, 8, 2, -1, true, NOC_QOS_MODE_BYPASS, 0, 2, MSM8998_SLAVE_BIMC_SNOC_1, MSM8998_SLAVE_HMSS_L3, MSM8998_SLAVE_EBI, MSM8998_SLAVE_BIMC_SNOC_0);
DEFINE_QNODE(mas_snoc_bimc, MSM8998_MASTER_SNOC_BIMC, 8, 3, -1, false, NOC_QOS_MODE_BYPASS, 0, 3, MSM8998_SLAVE_HMSS_L3, MSM8998_SLAVE_EBI);
DEFINE_QNODE(mas_snoc_cnoc, MSM8998_MASTER_SNOC_CNOC, 8, 52, -1, true, -1, 0, -1, MSM8998_SLAVE_SKL, MSM8998_SLAVE_BLSP_2, MSM8998_SLAVE_MESSAGE_RAM, MSM8998_SLAVE_TLMM_WEST, MSM8998_SLAVE_TSIF, MSM8998_SLAVE_MPM, MSM8998_SLAVE_BIMC_CFG, MSM8998_SLAVE_TLMM_EAST, MSM8998_SLAVE_SPDM, MSM8998_SLAVE_PIMEM_CFG, MSM8998_SLAVE_A1NOC_SMMU_CFG, MSM8998_SLAVE_BLSP_1, MSM8998_SLAVE_CLK_CTL, MSM8998_SLAVE_PRNG, MSM8998_SLAVE_USB3_0, MSM8998_SLAVE_QDSS_CFG, MSM8998_SLAVE_QM_CFG, MSM8998_SLAVE_A2NOC_CFG, MSM8998_SLAVE_PMIC_ARB, MSM8998_SLAVE_UFS_CFG, MSM8998_SLAVE_SRVC_CNOC, MSM8998_SLAVE_AHB2PHY, MSM8998_SLAVE_IPA, MSM8998_SLAVE_GLM, MSM8998_SLAVE_SNOC_CFG, MSM8998_SLAVE_SSC_CFG, MSM8998_SLAVE_SDCC_2, MSM8998_SLAVE_SDCC_4, MSM8998_SLAVE_PDM, MSM8998_SLAVE_CNOC_MNOC_MMSS_CFG, MSM8998_SLAVE_CNOC_MNOC_CFG, MSM8998_SLAVE_MSS_CFG, MSM8998_SLAVE_IMEM_CFG, MSM8998_SLAVE_A1NOC_CFG, MSM8998_SLAVE_GPUSS_CFG, MSM8998_SLAVE_TCSR, MSM8998_SLAVE_TLMM_NORTH);
DEFINE_QNODE(mas_qdss_dap, MSM8998_MASTER_QDSS_DAP, 8, 49, -1, true, -1, 0, -1, MSM8998_SLAVE_SKL, MSM8998_SLAVE_BLSP_2, MSM8998_SLAVE_MESSAGE_RAM, MSM8998_SLAVE_TLMM_WEST, MSM8998_SLAVE_TSIF, MSM8998_SLAVE_MPM, MSM8998_SLAVE_BIMC_CFG, MSM8998_SLAVE_TLMM_EAST, MSM8998_SLAVE_SPDM, MSM8998_SLAVE_PIMEM_CFG, MSM8998_SLAVE_A1NOC_SMMU_CFG, MSM8998_SLAVE_BLSP_1, MSM8998_SLAVE_CLK_CTL, MSM8998_SLAVE_PRNG, MSM8998_SLAVE_USB3_0, MSM8998_SLAVE_QDSS_CFG, MSM8998_SLAVE_QM_CFG, MSM8998_SLAVE_A2NOC_CFG, MSM8998_SLAVE_PMIC_ARB, MSM8998_SLAVE_UFS_CFG, MSM8998_SLAVE_SRVC_CNOC, MSM8998_SLAVE_AHB2PHY, MSM8998_SLAVE_IPA, MSM8998_SLAVE_GLM, MSM8998_SLAVE_SNOC_CFG, MSM8998_SLAVE_SDCC_2, MSM8998_SLAVE_SDCC_4, MSM8998_SLAVE_PDM, MSM8998_SLAVE_CNOC_MNOC_MMSS_CFG, MSM8998_SLAVE_CNOC_MNOC_CFG, MSM8998_SLAVE_MSS_CFG, MSM8998_SLAVE_IMEM_CFG, MSM8998_SLAVE_A1NOC_CFG, MSM8998_SLAVE_GPUSS_CFG, MSM8998_SLAVE_SSC_CFG, MSM8998_SLAVE_TCSR, MSM8998_SLAVE_TLMM_NORTH, MSM8998_SLAVE_CNOC_A2NOC);
DEFINE_QNODE(mas_crypto, MSM8998_MASTER_CRYPTO_C0, 650, 23, -1, false, -1, 0, -1, MSM8998_MASTER_CRVIRT_A2NOC);
DEFINE_QNODE(mas_apss_proc, MSM8998_MASTER_APPS_PROC, 32, 0, -1, true, -1, 0, -1, MSM8998_SLAVE_GNOC_BIMC);
DEFINE_QNODE(mas_cnoc_mnoc_mmss_cfg, MSM8998_MASTER_CNOC_MNOC_MMSS_CFG, 8, 4, -1, true, -1, 0, -1, MSM8998_SLAVE_CAMERA_THROTTLE_CFG, MSM8998_SLAVE_VENUS_CFG, MSM8998_SLAVE_MISC_CFG, MSM8998_SLAVE_CAMERA_CFG, MSM8998_SLAVE_DISPLAY_THROTTLE_CFG, MSM8998_SLAVE_VENUS_THROTTLE_CFG, MSM8998_SLAVE_DISPLAY_CFG, MSM8998_SLAVE_MMSS_CLK_CFG, MSM8998_SLAVE_VMEM_CFG, MSM8998_SLAVE_MMSS_CLK_XPU_CFG, MSM8998_SLAVE_SMMU_CFG);
DEFINE_QNODE(mas_cnoc_mnoc_cfg, MSM8998_MASTER_CNOC_MNOC_CFG, 8, 5, -1, true, -1, 0, -1, MSM8998_SLAVE_SRVC_MNOC);
DEFINE_QNODE(mas_cpp, MSM8998_MASTER_CPP, 32, 115, -1, true, NOC_QOS_MODE_BYPASS, 0, 5, MSM8998_SLAVE_MNOC_BIMC);
DEFINE_QNODE(mas_jpeg, MSM8998_MASTER_JPEG, 32, 7, -1, true, NOC_QOS_MODE_BYPASS, 0, 7, MSM8998_SLAVE_MNOC_BIMC);
DEFINE_QNODE(mas_mdp_p0, MSM8998_MASTER_MDP_P0, 32, 8, -1, true, NOC_QOS_MODE_BYPASS, 0, 1, MSM8998_SLAVE_MNOC_BIMC); /* vrail-comp???? */
DEFINE_QNODE(mas_mdp_p1, MSM8998_MASTER_MDP_P1, 32, 61, -1, true, NOC_QOS_MODE_BYPASS, 0, 2, MSM8998_SLAVE_MNOC_BIMC); /* vrail-comp??? */
DEFINE_QNODE(mas_rotator, MSM8998_MASTER_ROTATOR, 32, 120, -1, true, NOC_QOS_MODE_BYPASS, 0, 0, MSM8998_SLAVE_MNOC_BIMC);
DEFINE_QNODE(mas_venus, MSM8998_MASTER_VENUS, 32, 9, -1, true, NOC_QOS_MODE_BYPASS, 0, 3, MSM8998_SLAVE_MNOC_BIMC);
DEFINE_QNODE(mas_vfe, MSM8998_MASTER_VFE, 32, 11, -1, true, NOC_QOS_MODE_BYPASS, 0, 6, MSM8998_SLAVE_MNOC_BIMC);
DEFINE_QNODE(mas_venus_vmem, MSM8998_MASTER_VENUS_VMEM, 32, 121, -1, true, -1, 0, -1, MSM8998_SLAVE_VMEM);
DEFINE_QNODE(mas_hmss, MSM8998_MASTER_HMSS, 16, 118, -1, true, NOC_QOS_MODE_FIXED, 1, 3, MSM8998_SLAVE_PIMEM, MSM8998_SLAVE_IMEM, MSM8998_SLAVE_SNOC_BIMC);
DEFINE_QNODE(mas_qdss_bam, MSM8998_MASTER_QDSS_BAM, 16, 19, -1, true, NOC_QOS_MODE_FIXED, 1, 1, MSM8998_SLAVE_IMEM, MSM8998_SLAVE_PIMEM, MSM8998_SLAVE_SNOC_CNOC, MSM8998_SLAVE_SNOC_BIMC);
DEFINE_QNODE(mas_snoc_cfg, MSM8998_MASTER_SNOC_CFG, 16, 20, -1, false, -1, 0, -1, MSM8998_SLAVE_SRVC_SNOC);
DEFINE_QNODE(mas_bimc_snoc_0, MSM8998_MASTER_BIMC_SNOC_0, 16, 21, -1, false, -1, 0, -1, MSM8998_SLAVE_PIMEM, MSM8998_SLAVE_LPASS, MSM8998_SLAVE_HMSS, MSM8998_SLAVE_WLAN, MSM8998_SLAVE_SNOC_CNOC, MSM8998_SLAVE_IMEM, MSM8998_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_bimc_snoc_1, MSM8998_MASTER_BIMC_SNOC_1, 16, 109, -1, true, -1, 0, -1, MSM8998_SLAVE_PCIE_0);
DEFINE_QNODE(mas_a1noc_snoc, MSM8998_MASTER_A1NOC_SNOC, 16, 111, -1, false, -1, 0, -1, MSM8998_SLAVE_PIMEM, MSM8998_SLAVE_PCIE_0, MSM8998_SLAVE_LPASS, MSM8998_SLAVE_HMSS, MSM8998_SLAVE_SNOC_BIMC, MSM8998_SLAVE_SNOC_CNOC, MSM8998_SLAVE_IMEM, MSM8998_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_a2noc_snoc, MSM8998_MASTER_A2NOC_SNOC, 16, 112, -1, false, -1, 0, -1, MSM8998_SLAVE_PIMEM, MSM8998_SLAVE_PCIE_0, MSM8998_SLAVE_LPASS, MSM8998_SLAVE_HMSS, MSM8998_SLAVE_SNOC_BIMC, MSM8998_SLAVE_WLAN, MSM8998_SLAVE_SNOC_CNOC, MSM8998_SLAVE_IMEM, MSM8998_SLAVE_QDSS_STM);
DEFINE_QNODE(mas_qdss_etr, MSM8998_MASTER_QDSS_ETR, 16, 31, -1, true, NOC_QOS_MODE_FIXED, 1, 2, MSM8998_SLAVE_IMEM, MSM8998_MASTER_PIMEM, MSM8998_SLAVE_SNOC_CNOC, MSM8998_SLAVE_SNOC_BIMC);
/* slaves */
DEFINE_QNODE(slv_a1noc_snoc, MSM8998_SLAVE_A1NOC_SNOC, 16, -1, 142, false, -1, 0, -1, MSM8998_MASTER_A1NOC_SNOC);
DEFINE_QNODE(slv_a2noc_snoc, MSM8998_SLAVE_A2NOC_SNOC, 16, -1, 143, false, -1, 0, -1, MSM8998_MASTER_A2NOC_SNOC);
DEFINE_QNODE(slv_ebi, MSM8998_SLAVE_EBI, 8, -1, 0, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_hmss_l3, MSM8998_SLAVE_HMSS_L3, 8, -1, 160, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_bimc_snoc_0, MSM8998_SLAVE_BIMC_SNOC_0, 8, -1, 2, false, -1, 0, -1, MSM8998_MASTER_BIMC_SNOC_0);
DEFINE_QNODE(slv_bimc_snoc_1, MSM8998_SLAVE_BIMC_SNOC_1, 8, -1, 138, true, -1, 0, -1, MSM8998_MASTER_BIMC_SNOC_1);
DEFINE_QNODE(slv_cnoc_a2noc, MSM8998_SLAVE_CNOC_A2NOC, 4, -1, 208, true, -1, 0, -1, MSM8998_MASTER_CNOC_A2NOC);
DEFINE_QNODE(slv_ssc_cfg, MSM8998_SLAVE_SSC_CFG, 4, -1, 177, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_mpm, MSM8998_SLAVE_MPM, 4, -1, 62, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_pmic_arb, MSM8998_SLAVE_PMIC_ARB, 4, -1, 59, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_tlmm_north, MSM8998_SLAVE_TLMM_NORTH, 4, -1, 214, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_pimem_cfg, MSM8998_SLAVE_PIMEM_CFG, 4, -1, 167, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_imem_cfg, MSM8998_SLAVE_IMEM_CFG, 4, -1, 54, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_message_ram, MSM8998_SLAVE_MESSAGE_RAM, 4, -1, 55, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_skl, MSM8998_SLAVE_SKL, 4, -1, 196, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_bimc_cfg, MSM8998_SLAVE_BIMC_CFG, 4, -1, 56, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_prng, MSM8998_SLAVE_PRNG, 4, -1, 44, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_a2noc_cfg, MSM8998_SLAVE_A2NOC_CFG, 4, -1, 150, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_ipa, MSM8998_SLAVE_IPA, 4, -1, 183, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_tcsr, MSM8998_SLAVE_TCSR, 4, -1, 50, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_snoc_cfg, MSM8998_SLAVE_SNOC_CFG, 4, -1, 70, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_clk_ctl, MSM8998_SLAVE_CLK_CTL, 4, -1, 47, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_glm, MSM8998_SLAVE_GLM, 4, -1, 209, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_spdm, MSM8998_SLAVE_SPDM, 4, -1, 60, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_gpuss_cfg, MSM8998_SLAVE_GPUSS_CFG, 4, -1, 11, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_cnoc_mnoc_cfg, MSM8998_SLAVE_CNOC_MNOC_CFG, 4, -1, 66, true, -1, 0, -1, MSM8998_MASTER_CNOC_MNOC_CFG);
DEFINE_QNODE(slv_qm_cfg, MSM8998_SLAVE_QM_CFG, 4, -1, 212, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_mss_cfg, MSM8998_SLAVE_MSS_CFG, 4, -1, 48, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_ufs_cfg, MSM8998_SLAVE_UFS_CFG, 4, -1, 92, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_tlmm_west, MSM8998_SLAVE_TLMM_WEST, 4, -1, 215, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_a1noc_cfg, MSM8998_SLAVE_A1NOC_CFG, 4, -1, 147, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_ahb2phy, MSM8998_SLAVE_AHB2PHY, 4, -1, 163, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_blsp_2, MSM8998_SLAVE_BLSP_2, 4, -1, 37, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_pdm, MSM8998_SLAVE_PDM, 4, -1, 41, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_usb3_0, MSM8998_SLAVE_USB3_0, 4, -1, 22, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_a1noc_smmu_cfg, MSM8998_SLAVE_A1NOC_SMMU_CFG, 8, -1, 149, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_blsp_1, MSM8998_SLAVE_BLSP_1, 4, -1, 39, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_sdcc_2, MSM8998_SLAVE_SDCC_2, 4, -1, 33, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_sdcc_4, MSM8998_SLAVE_SDCC_4, 4, -1, 34, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_tsif, MSM8998_SLAVE_TSIF, 4, -1, 35, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_qdss_cfg, MSM8998_SLAVE_QDSS_CFG, 4, -1, 63, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_tlmm_east, MSM8998_SLAVE_TLMM_EAST, 4, -1, 213, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, MSM8998_SLAVE_CNOC_MNOC_MMSS_CFG, 8, -1, 58, true, -1, 0, -1, MSM8998_MASTER_CNOC_MNOC_MMSS_CFG);
DEFINE_QNODE(slv_srvc_cnoc, MSM8998_SLAVE_SRVC_CNOC, 4, -1, 76, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_crvirt_a2noc, MSM8998_SLAVE_CRVIRT_A2NOC, 8, -1, 207, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_gnoc_bimc, MSM8998_SLAVE_GNOC_BIMC, 32, -1, 210, true, -1, 0, -1, MSM8998_MASTER_GNOC_BIMC);
DEFINE_QNODE(slv_camera_cfg, MSM8998_SLAVE_CAMERA_CFG, 8, -1, 3, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_camera_throttle_cfg, MSM8998_SLAVE_CAMERA_THROTTLE_CFG, 8, -1, 154, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_misc_cfg, MSM8998_SLAVE_MISC_CFG, 8, -1, 8, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_venus_throttle_cfg, MSM8998_SLAVE_VENUS_THROTTLE_CFG, 8, -1, 178, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_venus_cfg, MSM8998_SLAVE_VENUS_CFG, 8, -1, 10, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_vmem_cfg, MSM8998_SLAVE_VMEM_CFG, 8, -1, 180, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_mmss_clk_xpu_cfg, MSM8998_SLAVE_MMSS_CLK_XPU_CFG, 8, -1, 13, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_mmss_clk_cfg, MSM8998_SLAVE_MMSS_CLK_CFG, 8, -1, 12, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_display_cfg, MSM8998_SLAVE_DISPLAY_CFG, 8, -1, 4, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_display_throttle_cfg, MSM8998_SLAVE_DISPLAY_THROTTLE_CFG, 4, -1, 156, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_smmu_cfg, MSM8998_SLAVE_SMMU_CFG, 8, -1, 205, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_mnoc_bimc, MSM8998_SLAVE_MNOC_BIMC, 32, -1, 16, true, -1, 0, -1, MSM8998_MASTER_MNOC_BIMC);
DEFINE_QNODE(slv_vmem, MSM8998_SLAVE_VMEM, 32, -1, 179, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_srvc_mnoc, MSM8998_SLAVE_SRVC_MNOC, 8, -1, 17, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_hmss, MSM8998_SLAVE_HMSS, 16, -1, 20, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_lpass, MSM8998_SLAVE_LPASS, 16, -1, 21, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_wlan, MSM8998_SLAVE_WLAN, 16, -1, 206, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_snoc_bimc, MSM8998_SLAVE_SNOC_BIMC, 32, -1, 24, false, -1, 0, -1, MSM8998_MASTER_SNOC_BIMC);
DEFINE_QNODE(slv_snoc_cnoc, MSM8998_SLAVE_SNOC_CNOC, 16, -1, 25, false, -1, 0, -1, MSM8998_MASTER_SNOC_CNOC);
DEFINE_QNODE(slv_imem, MSM8998_SLAVE_IMEM, 16, -1, 26, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_pimem, MSM8998_SLAVE_PIMEM, 16, -1, 166, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_qdss_stm, MSM8998_SLAVE_QDSS_STM, 16, -1, 30, false, -1, 0, -1, 0);
DEFINE_QNODE(slv_pcie_0, MSM8998_SLAVE_PCIE_0, 16, -1, 84, true, -1, 0, -1, 0);
DEFINE_QNODE(slv_srvc_snoc, MSM8998_SLAVE_SRVC_SNOC, 16, -1, 29, false, -1, 0, -1, 0);
static struct qcom_icc_node *msm8998_a1noc_nodes[] = {
[MASTER_PCIE_0] = &mas_pcie_0,
[MASTER_USB3] = &mas_usb3,
[MASTER_UFS] = &mas_ufs,
[MASTER_BLSP_2] = &mas_blsp_2,
[SLAVE_A1NOC_SNOC] = &slv_a1noc_snoc,
};
static const struct regmap_config msm8998_a1noc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x60000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_a1noc = {
.nodes = msm8998_a1noc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_a1noc_nodes),
.regmap_cfg = &msm8998_a1noc_regmap_config,
};
static struct qcom_icc_node *msm8998_a2noc_nodes[] = {
[MASTER_IPA] = &mas_ipa,
[MASTER_CNOC_A2NOC] = &mas_cnoc_a2noc,
[MASTER_SDCC_2] = &mas_sdcc_2,
[MASTER_SDCC_4] = &mas_sdcc_4,
[MASTER_TSIF] = &mas_tsif,
[MASTER_BLSP_1] = &mas_blsp_1,
[MASTER_CRVIRT_A2NOC] = &mas_crvirt_a2noc,
[MASTER_CRYPTO_C0] = &mas_crypto,
[SLAVE_A2NOC_SNOC] = &slv_a2noc_snoc,
[SLAVE_CRVIRT_A2NOC] = &slv_crvirt_a2noc,
};
static const struct regmap_config msm8998_a2noc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x60000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_a2noc = {
.nodes = msm8998_a2noc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_a2noc_nodes),
.regmap_cfg = &msm8998_a2noc_regmap_config,
};
static struct qcom_icc_node *msm8998_bimc_nodes[] = {
[MASTER_GNOC_BIMC] = &mas_gnoc_bimc,
[MASTER_OXILI] = &mas_oxili,
[MASTER_MNOC_BIMC] = &mas_mnoc_bimc,
[MASTER_SNOC_BIMC] = &mas_snoc_bimc,
[SLAVE_EBI] = &slv_ebi,
[SLAVE_HMSS_L3] = &slv_hmss_l3,
[SLAVE_BIMC_SNOC_0] = &slv_bimc_snoc_0,
[SLAVE_BIMC_SNOC_1] = &slv_bimc_snoc_1,
};
static const struct regmap_config msm8998_bimc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x80000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_bimc = {
.nodes = msm8998_bimc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_bimc_nodes),
.regmap_cfg = &msm8998_bimc_regmap_config,
};
static struct qcom_icc_node *msm8998_cnoc_nodes[] = {
[MASTER_SNOC_CNOC] = &mas_snoc_cnoc,
[MASTER_QDSS_DAP] = &mas_qdss_dap,
[SLAVE_CNOC_A2NOC] = &slv_cnoc_a2noc,
[SLAVE_SSC_CFG] = &slv_ssc_cfg,
[SLAVE_MPM] = &slv_mpm,
[SLAVE_PMIC_ARB] = &slv_pmic_arb,
[SLAVE_TLMM_NORTH] = &slv_tlmm_north,
[SLAVE_PIMEM_CFG] = &slv_pimem_cfg,
[SLAVE_IMEM_CFG] = &slv_imem_cfg,
[SLAVE_MESSAGE_RAM] = &slv_message_ram,
[SLAVE_SKL] = &slv_skl,
[SLAVE_BIMC_CFG] = &slv_bimc_cfg,
[SLAVE_PRNG] = &slv_prng,
[SLAVE_A2NOC_CFG] = &slv_a2noc_cfg,
[SLAVE_IPA] = &slv_ipa,
[SLAVE_TCSR] = &slv_tcsr,
[SLAVE_SNOC_CFG] = &slv_snoc_cfg,
[SLAVE_CLK_CTL] = &slv_clk_ctl,
[SLAVE_GLM] = &slv_glm,
[SLAVE_SPDM] = &slv_spdm,
[SLAVE_GPUSS_CFG] = &slv_gpuss_cfg,
[SLAVE_CNOC_MNOC_CFG] = &slv_cnoc_mnoc_cfg,
[SLAVE_QM_CFG] = &slv_qm_cfg,
[SLAVE_MSS_CFG] = &slv_mss_cfg,
[SLAVE_UFS_CFG] = &slv_ufs_cfg,
[SLAVE_TLMM_WEST] = &slv_tlmm_west,
[SLAVE_A1NOC_CFG] = &slv_a1noc_cfg,
[SLAVE_AHB2PHY] = &slv_ahb2phy,
[SLAVE_BLSP_2] = &slv_blsp_2,
[SLAVE_PDM] = &slv_pdm,
[SLAVE_USB3_0] = &slv_usb3_0,
[SLAVE_A1NOC_SMMU_CFG] = &slv_a1noc_smmu_cfg,
[SLAVE_BLSP_1] = &slv_blsp_1,
[SLAVE_SDCC_2] = &slv_sdcc_2,
[SLAVE_SDCC_4] = &slv_sdcc_4,
[SLAVE_TSIF] = &slv_tsif,
[SLAVE_QDSS_CFG] = &slv_qdss_cfg,
[SLAVE_TLMM_EAST] = &slv_tlmm_east,
[SLAVE_CNOC_MNOC_MMSS_CFG] = &slv_cnoc_mnoc_mmss_cfg,
[SLAVE_SRVC_CNOC] = &slv_srvc_cnoc,
};
static const struct regmap_config msm8998_cnoc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x10000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_cnoc = {
.nodes = msm8998_cnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_cnoc_nodes),
.regmap_cfg = &msm8998_cnoc_regmap_config,
};
static struct qcom_icc_node *msm8998_gnoc_nodes[] = {
[MASTER_APSS_PROC] = &mas_apss_proc,
[SLAVE_GNOC_BIMC] = &slv_gnoc_bimc,
};
static const struct regmap_config msm8998_gnoc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x10000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_gnoc = {
.nodes = msm8998_gnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_gnoc_nodes),
.regmap_cfg = &msm8998_gnoc_regmap_config,
};
static struct qcom_icc_node *msm8998_mnoc_nodes[] = {
[MASTER_CNOC_MNOC_CFG] = &mas_cnoc_mnoc_cfg,
[MASTER_CPP] = &mas_cpp,
[MASTER_JPEG] = &mas_jpeg,
[MASTER_MDP_P0] = &mas_mdp_p0,
[MASTER_MDP_P1] = &mas_mdp_p1,
[MASTER_ROTATOR] = &mas_rotator,
[MASTER_VENUS] = &mas_venus,
[MASTER_VFE] = &mas_vfe,
[MASTER_VENUS_VMEM] = &mas_venus_vmem,
[SLAVE_MNOC_BIMC] = &slv_mnoc_bimc,
[SLAVE_VMEM] = &slv_vmem,
[SLAVE_SRVC_MNOC] = &slv_srvc_mnoc,
[MASTER_CNOC_MNOC_MMSS_CFG] = &mas_cnoc_mnoc_mmss_cfg,
[SLAVE_CAMERA_CFG] = &slv_camera_cfg,
[SLAVE_CAMERA_THROTTLE_CFG] = &slv_camera_throttle_cfg,
[SLAVE_MISC_CFG] = &slv_misc_cfg,
[SLAVE_VENUS_THROTTLE_CFG] = &slv_venus_throttle_cfg,
[SLAVE_VENUS_CFG] = &slv_venus_cfg,
[SLAVE_VMEM_CFG] = &slv_vmem_cfg,
[SLAVE_MMSS_CLK_XPU_CFG] = &slv_mmss_clk_xpu_cfg,
[SLAVE_MMSS_CLK_CFG] = &slv_mmss_clk_cfg,
[SLAVE_DISPLAY_CFG] = &slv_display_cfg,
[SLAVE_DISPLAY_THROTTLE_CFG] = &slv_display_throttle_cfg,
[SLAVE_SMMU_CFG] = &slv_smmu_cfg,
};
static const struct regmap_config msm8998_mnoc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x10000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_mnoc = {
.nodes = msm8998_mnoc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_mnoc_nodes),
.regmap_cfg = &msm8998_mnoc_regmap_config,
};
static struct qcom_icc_node *msm8998_snoc_nodes[] = {
[MASTER_HMSS] = &mas_hmss,
[MASTER_QDSS_BAM] = &mas_qdss_bam,
[MASTER_SNOC_CFG] = &mas_snoc_cfg,
[MASTER_BIMC_SNOC_0] = &mas_bimc_snoc_0,
[MASTER_BIMC_SNOC_1] = &mas_bimc_snoc_1,
[MASTER_A1NOC_SNOC] = &mas_a1noc_snoc,
[MASTER_A2NOC_SNOC] = &mas_a2noc_snoc,
[MASTER_QDSS_ETR] = &mas_qdss_etr,
[SLAVE_HMSS] = &slv_hmss,
[SLAVE_LPASS] = &slv_lpass,
[SLAVE_WLAN] = &slv_wlan,
[SLAVE_SNOC_BIMC] = &slv_snoc_bimc,
[SLAVE_SNOC_CNOC] = &slv_snoc_cnoc,
[SLAVE_IMEM] = &slv_imem,
[SLAVE_PIMEM] = &slv_pimem,
[SLAVE_QDSS_STM] = &slv_qdss_stm,
[SLAVE_PCIE_0] = &slv_pcie_0,
[SLAVE_SRVC_SNOC] = &slv_srvc_snoc,
};
static const struct regmap_config msm8998_snoc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0x40000,
.fast_io = true,
};
static struct qcom_icc_desc msm8998_snoc = {
.nodes = msm8998_snoc_nodes,
.num_nodes = ARRAY_SIZE(msm8998_snoc_nodes),
.regmap_cfg = &msm8998_snoc_regmap_config,
};
static int qcom_icc_bimc_set_qos_health(struct regmap *rmap,
struct qcom_icc_qos *qos,
int regnum)
{
u32 val;
u32 mask;
val = qos->prio_level;
mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK;
val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT;
mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK;
/* LIMITCMDS is not present on M_BKE_HEALTH_3 */
if (regnum != 3) {
val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT;
mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK;
}
return regmap_update_bits(rmap,
M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port),
mask, val);
}
static int qcom_icc_set_bimc_qos(struct icc_node *src, u64 max_bw,
bool bypass_mode)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_provider *provider;
u32 mode = NOC_QOS_MODE_BYPASS;
u32 val = 0;
int i, rc = 0;
qn = src->data;
provider = src->provider;
qp = to_qcom_provider(provider);
if (qn->qos.qos_mode != -1)
mode = qn->qos.qos_mode;
/*
* QoS Priority: The QoS Health parameters are getting considered
* only if we are NOT in Bypass Mode.
*/
if (mode != NOC_QOS_MODE_BYPASS) {
for (i = 3; i >= 0; i--) {
rc = qcom_icc_bimc_set_qos_health(qp->regmap,
&qn->qos, i);
if (rc)
return rc;
}
/* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */
val = 1;
}
return regmap_update_bits(qp->regmap, M_BKE_EN_ADDR(qn->qos.qos_port),
M_BKE_EN_EN_BMASK, val);
}
static int qcom_icc_noc_set_qos_priority(struct regmap *rmap,
struct qcom_icc_qos *qos)
{
u32 val;
int rc;
/* Must be updated one at a time, P1 first, P0 last */
val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT;
rc = regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
NOC_QOS_PRIORITY_MASK, val);
if (rc)
return rc;
val = qos->prio_level << NOC_QOS_PRIORITY_P0_SHIFT;
return regmap_update_bits(rmap, NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
NOC_QOS_PRIORITY_MASK, val);
}
static int qcom_icc_set_noc_qos(struct icc_node *src, u64 max_bw)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_provider *provider;
u32 mode = NOC_QOS_MODE_BYPASS;
int rc = 0;
qn = src->data;
provider = src->provider;
qp = to_qcom_provider(provider);
if (qn->qos.qos_port < 0) {
dev_dbg(src->provider->dev,
"NoC QoS: Skipping %s: vote aggregated on parent.\n",
qn->name);
return 0;
}
if (qn->qos.qos_mode != -1)
mode = qn->qos.qos_mode;
if (mode == NOC_QOS_MODE_FIXED) {
dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n",
qn->name);
rc = qcom_icc_noc_set_qos_priority(qp->regmap, &qn->qos);
if (rc)
return rc;
} else if (mode == NOC_QOS_MODE_BYPASS) {
dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n",
qn->name);
}
return regmap_update_bits(qp->regmap,
NOC_QOS_MODEn_ADDR(qn->qos.qos_port),
NOC_QOS_MODEn_MASK, mode);
}
static int qcom_icc_qos_set(struct icc_node *node, u64 sum_bw)
{
struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
struct qcom_icc_node *qn = node->data;
dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name);
if (qp->is_bimc_node)
return qcom_icc_set_bimc_qos(node, sum_bw,
(qn->qos.qos_mode == NOC_QOS_MODE_BYPASS));
return qcom_icc_set_noc_qos(node, sum_bw);
}
static int qcom_icc_rpm_set(int mas_rpm_id, int slv_rpm_id, u64 sum_bw)
{
int ret = 0;
if (mas_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
RPM_BUS_MASTER_REQ,
mas_rpm_id,
sum_bw);
if (ret) {
pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
mas_rpm_id, ret);
return ret;
}
}
if (slv_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
RPM_BUS_SLAVE_REQ,
slv_rpm_id,
sum_bw);
if (ret) {
pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
slv_rpm_id, ret);
return ret;
}
}
return ret;
}
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_provider *provider;
struct icc_node *n;
u64 sum_bw;
u64 max_peak_bw;
u64 rate;
u32 agg_avg = 0;
u32 agg_peak = 0;
int ret, i;
qn = src->data;
provider = src->provider;
qp = to_qcom_provider(provider);
list_for_each_entry(n, &provider->nodes, node_list)
provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
&agg_avg, &agg_peak);
sum_bw = icc_units_to_bps(agg_avg);
max_peak_bw = icc_units_to_bps(agg_peak);
if (!qn->qos.ap_owned) {
/* send bandwidth request message to the RPM processor */
ret = qcom_icc_rpm_set(qn->mas_rpm_id, qn->slv_rpm_id, sum_bw);
if (ret)
return ret;
} else if (qn->qos.qos_mode != -1) {
/* set bandwidth directly from the AP */
ret = qcom_icc_qos_set(src, sum_bw);
if (ret)
return ret;
}
rate = max(sum_bw, max_peak_bw);
do_div(rate, qn->buswidth);
if (qn->rate == rate)
return 0;
for (i = 0; i < qp->num_clks; i++) {
ret = clk_set_rate(qp->bus_clks[i].clk, rate);
if (ret) {
pr_err("%s clk_set_rate error: %d\n",
qp->bus_clks[i].id, ret);
return ret;
}
}
qn->rate = rate;
return 0;
}
static int qnoc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct qcom_icc_desc *desc;
struct icc_onecell_data *data;
struct icc_provider *provider;
struct qcom_icc_node **qnodes;
struct qcom_icc_provider *qp;
struct icc_node *node;
struct resource *res;
size_t num_nodes, i;
int ret;
/* wait for the RPM proxy */
if (!qcom_icc_rpm_smd_available())
return -EPROBE_DEFER;
desc = of_device_get_match_data(dev);
if (!desc)
return -EINVAL;
qnodes = desc->nodes;
num_nodes = desc->num_nodes;
qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
GFP_KERNEL);
if (!data)
return -ENOMEM;
if (of_device_is_compatible(dev->of_node, "qcom,msm8998-mnoc")) {
qp->bus_clks = devm_kmemdup(dev, bus_mm_clocks,
sizeof(bus_mm_clocks), GFP_KERNEL);
qp->num_clks = ARRAY_SIZE(bus_mm_clocks);
} else {
if (of_device_is_compatible(dev->of_node, "qcom,msm8998-bimc"))
qp->is_bimc_node = true;
qp->bus_clks = devm_kmemdup(dev, bus_clocks, sizeof(bus_clocks),
GFP_KERNEL);
qp->num_clks = ARRAY_SIZE(bus_clocks);
}
if (!qp->bus_clks)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
qp->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(qp->mmio)) {
dev_err(dev, "Cannot ioremap interconnect bus resource\n");
return PTR_ERR(qp->mmio);
}
qp->regmap = devm_regmap_init_mmio(dev, qp->mmio, desc->regmap_cfg);
if (IS_ERR(qp->regmap)) {
dev_err(dev, "Cannot regmap interconnect bus resource\n");
return PTR_ERR(qp->regmap);
}
ret = devm_clk_bulk_get(dev, qp->num_clks, qp->bus_clks);
if (ret)
return ret;
ret = clk_bulk_prepare_enable(qp->num_clks, qp->bus_clks);
if (ret)
return ret;
provider = &qp->provider;
INIT_LIST_HEAD(&provider->nodes);
provider->dev = dev;
provider->set = qcom_icc_set;
provider->aggregate = icc_std_aggregate;
provider->xlate = of_icc_xlate_onecell;
provider->data = data;
ret = icc_provider_add(provider);
if (ret) {
dev_err(dev, "error adding interconnect provider: %d\n", ret);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
return ret;
}
for (i = 0; i < num_nodes; i++) {
size_t j;
node = icc_node_create(qnodes[i]->id);
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err;
}
node->name = qnodes[i]->name;
node->data = qnodes[i];
icc_node_add(node, provider);
for (j = 0; j < qnodes[i]->num_links; j++)
icc_link_create(node, qnodes[i]->links[j]);
data->nodes[i] = node;
}
data->num_nodes = num_nodes;
platform_set_drvdata(pdev, qp);
return 0;
err:
icc_nodes_remove(provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
icc_provider_del(provider);
return ret;
}
static int qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_nodes_remove(&qp->provider);
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
return icc_provider_del(&qp->provider);
}
static const struct of_device_id msm8998_noc_of_match[] = {
{ .compatible = "qcom,msm8998-a1noc", .data = &msm8998_a1noc },
{ .compatible = "qcom,msm8998-a2noc", .data = &msm8998_a2noc },
{ .compatible = "qcom,msm8998-bimc", .data = &msm8998_bimc },
{ .compatible = "qcom,msm8998-cnoc", .data = &msm8998_cnoc },
{ .compatible = "qcom,msm8998-gnoc", .data = &msm8998_gnoc },
{ .compatible = "qcom,msm8998-mnoc", .data = &msm8998_mnoc },
{ .compatible = "qcom,msm8998-snoc", .data = &msm8998_snoc },
{ },
};
MODULE_DEVICE_TABLE(of, msm8998_noc_of_match);
static struct platform_driver msm8998_noc_driver = {
.probe = qnoc_probe,
.remove = qnoc_remove,
.driver = {
.name = "qnoc-msm8998",
.of_match_table = msm8998_noc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(msm8998_noc_driver);
MODULE_DESCRIPTION("Qualcomm msm8998 NoC driver");
MODULE_LICENSE("GPL v2");

View file

@ -5,6 +5,7 @@
#include <linux/acpi.h>
#include <linux/adreno-smmu-priv.h>
#include <linux/bitmap.h>
#include <linux/of_device.h>
#include <linux/qcom_scm.h>
@ -12,6 +13,7 @@
struct qcom_smmu {
struct arm_smmu_device smmu;
DECLARE_BITMAP(reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS);
bool bypass_quirk;
u8 bypass_cbndx;
u32 stall_enabled;
@ -180,11 +182,13 @@ static int qcom_adreno_smmu_alloc_context_bank(struct arm_smmu_domain *smmu_doma
static bool qcom_adreno_can_do_ttbr1(struct arm_smmu_device *smmu)
{
/*
const struct device_node *np = smmu->dev->of_node;
if (of_device_is_compatible(np, "qcom,msm8996-smmu-v2"))
if (of_device_is_compatible(np, "qcom,msm8996-smmu-v2") ||
of_device_is_compatible(np, "qcom,msm8998-smmu-v2") ||
of_device_is_compatible(np, "qcom,sdm630-smmu-v2"))
return false;
*/
return true;
}
@ -228,11 +232,13 @@ static const struct of_device_id qcom_smmu_client_of_match[] __maybe_unused = {
{ .compatible = "qcom,adreno" },
{ .compatible = "qcom,mdp4" },
{ .compatible = "qcom,mdss" },
{ .compatible = "qcom,msm8998-mss-pil" },
{ .compatible = "qcom,sc7180-mdss" },
{ .compatible = "qcom,sc7180-mss-pil" },
{ .compatible = "qcom,sc7280-mdss" },
{ .compatible = "qcom,sc7280-mss-pil" },
{ .compatible = "qcom,sc8180x-mdss" },
{ .compatible = "qcom,sdm660-mss-pil" },
{ .compatible = "qcom,sdm845-mdss" },
{ .compatible = "qcom,sdm845-mss-pil" },
{ }
@ -267,7 +273,8 @@ static int qcom_smmu_cfg_probe(struct arm_smmu_device *smmu)
reg = arm_smmu_gr0_read(smmu, last_s2cr);
if (FIELD_GET(ARM_SMMU_S2CR_TYPE, reg) != S2CR_TYPE_BYPASS) {
qsmmu->bypass_quirk = true;
qsmmu->bypass_cbndx = smmu->num_context_banks - 1;
if (qsmmu->bypass_cbndx == 0xff)
qsmmu->bypass_cbndx = smmu->num_context_banks - 1;
set_bit(qsmmu->bypass_cbndx, smmu->context_map);
@ -359,8 +366,15 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
static int qcom_smmu500_reset(struct arm_smmu_device *smmu)
{
const struct device_node *np = smmu->dev->of_node;
struct qcom_smmu *qsmmu = to_qcom_smmu(smmu);
arm_mmu500_reset(smmu);
/*
* Execute the mmu-500 reset implementation detail only if there
* are no secured untouchable contexts in this iommu, otherwise
* the system will crash.
*/
if (bitmap_empty(qsmmu->reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS))
arm_mmu500_reset(smmu);
if (of_device_is_compatible(np, "qcom,sdm845-smmu-500"))
return qcom_sdm845_smmu500_reset(smmu);
@ -368,11 +382,20 @@ static int qcom_smmu500_reset(struct arm_smmu_device *smmu)
return 0;
}
static bool qcom_smmu500_reset_cb_nodisable(struct arm_smmu_device *smmu,
int cbndx)
{
struct qcom_smmu *qsmmu = to_qcom_smmu(smmu);
return test_bit(cbndx, qsmmu->reset_cb_nodisable_mask);
}
static const struct arm_smmu_impl qcom_smmu_impl = {
.init_context = qcom_smmu_init_context,
.cfg_probe = qcom_smmu_cfg_probe,
.def_domain_type = qcom_smmu_def_domain_type,
.reset = qcom_smmu500_reset,
.reset_cb_nodisable = qcom_smmu500_reset_cb_nodisable,
.write_s2cr = qcom_smmu_write_s2cr,
};
@ -380,6 +403,7 @@ static const struct arm_smmu_impl qcom_adreno_smmu_impl = {
.init_context = qcom_adreno_smmu_init_context,
.def_domain_type = qcom_smmu_def_domain_type,
.reset = qcom_smmu500_reset,
.reset_cb_nodisable = qcom_smmu500_reset_cb_nodisable,
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
.write_sctlr = qcom_adreno_smmu_write_sctlr,
};
@ -387,7 +411,10 @@ static const struct arm_smmu_impl qcom_adreno_smmu_impl = {
static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
const struct arm_smmu_impl *impl)
{
const struct device_node *np = smmu->dev->of_node;
struct qcom_smmu *qsmmu;
u8 reset_nodisable_cbs[ARM_SMMU_MAX_CBS];
int i, sz;
/* Check to make sure qcom_scm has finished probing */
if (!qcom_scm_is_available())
@ -398,6 +425,34 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
return ERR_PTR(-ENOMEM);
qsmmu->smmu.impl = impl;
qsmmu->bypass_cbndx = 0xff;
bitmap_zero(qsmmu->reset_cb_nodisable_mask, ARM_SMMU_MAX_CBS);
if (np != NULL) {
/*
* This property is optional and we expect to fail finding it if:
* - Using the default bypass_cbndx (in the .cfg_probe cb) is fine; or
* - We are booting on ACPI
*/
of_property_read_u8(np, "qcom,bypass-cbndx", &qsmmu->bypass_cbndx);
/*
* Some context banks may not be disabled because they are
* secured: read from DT a list of secured contexts that cannot
* be disabled without crashing the system.
* This list is optional, as not all firmware configurations do
* require us skipping disablement of context banks.
*/
sz = of_property_read_variable_u8_array(np, "qcom,reset-nodisable-cbs",
reset_nodisable_cbs,
1, ARM_SMMU_MAX_CBS);
if (sz > 0) {
for (i = 0; i < sz; i++) {
__set_bit(reset_nodisable_cbs[i],
qsmmu->reset_cb_nodisable_mask);
}
}
}
return &qsmmu->smmu;
}

View file

@ -1624,6 +1624,16 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
/* Make sure all context banks are disabled and clear CB_FSR */
for (i = 0; i < smmu->num_context_banks; ++i) {
/*
* Some context banks cannot be disabled due to hypervisor
* configuration on some systems; if this is the case,
* skip disabling and writing FAULT on the CB FSR in order
* to avoid a system crash.
*/
if (smmu->impl && smmu->impl->reset_cb_nodisable &&
smmu->impl->reset_cb_nodisable(smmu, i)) {
continue;
}
arm_smmu_write_context_bank(smmu, i);
arm_smmu_cb_write(smmu, i, ARM_SMMU_CB_FSR, ARM_SMMU_FSR_FAULT);
}

View file

@ -429,6 +429,7 @@ struct arm_smmu_impl {
u64 val);
int (*cfg_probe)(struct arm_smmu_device *smmu);
int (*reset)(struct arm_smmu_device *smmu);
bool (*reset_cb_nodisable)(struct arm_smmu_device *smmu, int cbndx);
int (*init_context)(struct arm_smmu_domain *smmu_domain,
struct io_pgtable_cfg *cfg, struct device *dev);
void (*tlb_sync)(struct arm_smmu_device *smmu, int page, int sync,

View file

@ -869,6 +869,9 @@ source "drivers/leds/blink/Kconfig"
comment "Flash and Torch LED drivers"
source "drivers/leds/flash/Kconfig"
comment "RGB LED drivers"
source "drivers/leds/rgb/Kconfig"
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"

View file

@ -99,6 +99,9 @@ obj-$(CONFIG_LEDS_USER) += uleds.o
# Flash and Torch LED Drivers
obj-$(CONFIG_LEDS_CLASS_FLASH) += flash/
# RGB LED Drivers
obj-$(CONFIG_LEDS_CLASS_MULTICOLOR) += rgb/
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGERS) += trigger/

18
drivers/leds/rgb/Kconfig Normal file
View file

@ -0,0 +1,18 @@
# SPDX-License-Identifier: GPL-2.0
if LEDS_CLASS_MULTICOLOR
config LEDS_QCOM_LPG
tristate "LED support for Qualcomm LPG"
depends on OF
depends on SPMI
help
This option enables support for the Light Pulse Generator found in a
wide variety of Qualcomm PMICs. The LPG consists of a number of PWM
channels and typically a shared pattern lookup table and a current
sink, intended to drive RGB LEDs. Each channel can either be used as
a LED, grouped to represent a RGB LED or exposed as PWM channels.
If compiled as a module, the module will be named leds-qcom-lpg.
endif # LEDS_CLASS_MULTICOLOR

View file

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_LEDS_QCOM_LPG) += leds-qcom-lpg.o

File diff suppressed because it is too large Load diff

View file

@ -126,7 +126,8 @@ static int pattern_trig_start_pattern(struct led_classdev *led_cdev)
if (data->is_hw_pattern) {
return led_cdev->pattern_set(led_cdev, data->patterns,
data->npatterns, data->repeat);
data->npatterns,
data->last_repeat);
}
/* At least 2 tuples for software pattern. */

View file

@ -2038,6 +2038,18 @@ config MFD_WCD934X
This driver provides common support WCD934x audio codec and its
associated Pin Controller, Soundwire Controller and Audio codec.
config MFD_WCD9335
tristate "Support for WCD9335 Codec"
depends on SLIMBUS
select REGMAP
select REGMAP_SLIMBUS
select REGMAP_IRQ
select MFD_CORE
help
Support for the Qualcomm WCD9335 Codec.
This driver provides common support WCD9335 audio codec and its
associated Pin Controller, Soundwire Controller and Audio codec.
config MFD_ATC260X
tristate
select MFD_CORE

View file

@ -61,6 +61,7 @@ ifeq ($(CONFIG_MFD_CS47L24),y)
arizona-objs += cs47l24-tables.o
endif
obj-$(CONFIG_MFD_WCD934X) += wcd934x.o
obj-$(CONFIG_MFD_WCD9335) += wcd9335.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
wm831x-objs += wm831x-auxadc.o

View file

@ -3,137 +3,213 @@
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*/
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spmi.h>
#include <linux/types.h>
#include <linux/regmap.h>
#include <linux/of_platform.h>
#include <soc/qcom/qcom-spmi-pmic.h>
#define PMIC_REV2 0x101
#define PMIC_REV3 0x102
#define PMIC_REV4 0x103
#define PMIC_TYPE 0x104
#define PMIC_SUBTYPE 0x105
#define PMIC_FAB_ID 0x1f2
#define PMIC_TYPE_VALUE 0x51
#define COMMON_SUBTYPE 0x00
#define PM8941_SUBTYPE 0x01
#define PM8841_SUBTYPE 0x02
#define PM8019_SUBTYPE 0x03
#define PM8226_SUBTYPE 0x04
#define PM8110_SUBTYPE 0x05
#define PMA8084_SUBTYPE 0x06
#define PMI8962_SUBTYPE 0x07
#define PMD9635_SUBTYPE 0x08
#define PM8994_SUBTYPE 0x09
#define PMI8994_SUBTYPE 0x0a
#define PM8916_SUBTYPE 0x0b
#define PM8004_SUBTYPE 0x0c
#define PM8909_SUBTYPE 0x0d
#define PM8028_SUBTYPE 0x0e
#define PM8901_SUBTYPE 0x0f
#define PM8950_SUBTYPE 0x10
#define PMI8950_SUBTYPE 0x11
#define PM8998_SUBTYPE 0x14
#define PMI8998_SUBTYPE 0x15
#define PM8005_SUBTYPE 0x18
#define PM660L_SUBTYPE 0x1A
#define PM660_SUBTYPE 0x1B
#define PM8150_SUBTYPE 0x1E
#define PM8150L_SUBTYPE 0x1f
#define PM8150B_SUBTYPE 0x20
#define PMK8002_SUBTYPE 0x21
#define PM8009_SUBTYPE 0x24
#define PM8150C_SUBTYPE 0x26
#define SMB2351_SUBTYPE 0x29
struct qcom_spmi_dev {
int num_usids;
struct qcom_spmi_pmic pmic;
};
#define N_USIDS(n) ((void *)n)
static const struct of_device_id pmic_spmi_id_table[] = {
{ .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE },
{ .compatible = "qcom,pm660l", .data = (void *)PM660L_SUBTYPE },
{ .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE },
{ .compatible = "qcom,pm8005", .data = (void *)PM8005_SUBTYPE },
{ .compatible = "qcom,pm8019", .data = (void *)PM8019_SUBTYPE },
{ .compatible = "qcom,pm8028", .data = (void *)PM8028_SUBTYPE },
{ .compatible = "qcom,pm8110", .data = (void *)PM8110_SUBTYPE },
{ .compatible = "qcom,pm8150", .data = (void *)PM8150_SUBTYPE },
{ .compatible = "qcom,pm8150b", .data = (void *)PM8150B_SUBTYPE },
{ .compatible = "qcom,pm8150c", .data = (void *)PM8150C_SUBTYPE },
{ .compatible = "qcom,pm8150l", .data = (void *)PM8150L_SUBTYPE },
{ .compatible = "qcom,pm8226", .data = (void *)PM8226_SUBTYPE },
{ .compatible = "qcom,pm8841", .data = (void *)PM8841_SUBTYPE },
{ .compatible = "qcom,pm8901", .data = (void *)PM8901_SUBTYPE },
{ .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE },
{ .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE },
{ .compatible = "qcom,pm8941", .data = (void *)PM8941_SUBTYPE },
{ .compatible = "qcom,pm8950", .data = (void *)PM8950_SUBTYPE },
{ .compatible = "qcom,pm8994", .data = (void *)PM8994_SUBTYPE },
{ .compatible = "qcom,pm8998", .data = (void *)PM8998_SUBTYPE },
{ .compatible = "qcom,pma8084", .data = (void *)PMA8084_SUBTYPE },
{ .compatible = "qcom,pmd9635", .data = (void *)PMD9635_SUBTYPE },
{ .compatible = "qcom,pmi8950", .data = (void *)PMI8950_SUBTYPE },
{ .compatible = "qcom,pmi8962", .data = (void *)PMI8962_SUBTYPE },
{ .compatible = "qcom,pmi8994", .data = (void *)PMI8994_SUBTYPE },
{ .compatible = "qcom,pmi8998", .data = (void *)PMI8998_SUBTYPE },
{ .compatible = "qcom,pmk8002", .data = (void *)PMK8002_SUBTYPE },
{ .compatible = "qcom,smb2351", .data = (void *)SMB2351_SUBTYPE },
{ .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE },
{ .compatible = "qcom,pm660", .data = N_USIDS(2) },
{ .compatible = "qcom,pm660l", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8004", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8005", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8019", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8028", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8110", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8150", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8150b", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8150c", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8150l", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8226", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8841", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8901", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8909", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8916", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8941", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8950", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8994", .data = N_USIDS(2) },
{ .compatible = "qcom,pm8998", .data = N_USIDS(2) },
{ .compatible = "qcom,pma8084", .data = N_USIDS(2) },
{ .compatible = "qcom,pmd9635", .data = N_USIDS(2) },
{ .compatible = "qcom,pmi8950", .data = N_USIDS(2) },
{ .compatible = "qcom,pmi8962", .data = N_USIDS(2) },
{ .compatible = "qcom,pmi8994", .data = N_USIDS(2) },
{ .compatible = "qcom,pmi8998", .data = N_USIDS(2) },
{ .compatible = "qcom,pmk8002", .data = N_USIDS(2) },
{ .compatible = "qcom,smb2351", .data = N_USIDS(2) },
{ .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) },
{ }
};
static void pmic_spmi_show_revid(struct regmap *map, struct device *dev)
#undef N_USIDS
/*
* A PMIC can be represented by multiple SPMI devices, but
* only the base PMIC device will contain a reference to
* the revision information.
*
* This function takes a pointer to a function device and
* returns a pointer to the base PMIC device.
*
* This only supports PMICs with 1 or 2 USIDs.
*/
static struct spmi_device *qcom_pmic_get_base_usid(struct device *dev)
{
unsigned int rev2, minor, major, type, subtype;
const char *name = "unknown";
int ret, i;
struct spmi_device *sdev;
struct qcom_spmi_dev *ctx;
struct device_node *spmi_bus;
struct device_node *other_usid = NULL;
int function_parent_usid, ret;
u32 pmic_addr;
ret = regmap_read(map, PMIC_TYPE, &type);
if (!of_match_device(pmic_spmi_id_table, dev))
return ERR_PTR(-EINVAL);
sdev = to_spmi_device(dev);
ctx = spmi_device_get_drvdata(sdev);
/*
* Quick return if the function device is already in the base
* USID. This will always be hit for PMICs with only 1 USID.
*/
if (sdev->usid % ctx->num_usids == 0)
return sdev;
function_parent_usid = sdev->usid;
/*
* Walk through the list of PMICs until we find the sibling USID.
* The goal is to find the first USID which is less than the
* number of USIDs in the PMIC away, e.g. for a PMIC with 2 USIDs
* where the function device is under USID 3, we want to find the
* device for USID 2.
*/
spmi_bus = of_get_parent(sdev->dev.of_node);
do {
other_usid = of_get_next_child(spmi_bus, other_usid);
ret = of_property_read_u32_index(other_usid, "reg", 0, &pmic_addr);
if (ret)
return ERR_PTR(ret);
sdev = spmi_device_from_of(other_usid);
if (sdev == NULL) {
/*
* If the base USID for this PMIC hasn't probed yet
* but the secondary USID has, then we need to defer
* the function driver so that it will attempt to
* probe again when the base USID is ready.
*/
if (pmic_addr == function_parent_usid - (ctx->num_usids - 1))
return ERR_PTR(-EPROBE_DEFER);
continue;
}
if (pmic_addr == function_parent_usid - (ctx->num_usids - 1))
return sdev;
} while (other_usid->sibling);
return ERR_PTR(-ENODATA);
}
static inline void pmic_print_info(struct device *dev, struct qcom_spmi_pmic *pmic)
{
dev_dbg(dev, "%x: %s v%d.%d\n",
pmic->subtype, pmic->name, pmic->major, pmic->minor);
}
static int pmic_spmi_load_revid(struct regmap *map, struct device *dev,
struct qcom_spmi_pmic *pmic)
{
int ret;
ret = regmap_read(map, PMIC_TYPE, &pmic->type);
if (ret < 0)
return;
return ret;
if (type != PMIC_TYPE_VALUE)
return;
if (pmic->type != PMIC_TYPE_VALUE)
return ret;
ret = regmap_read(map, PMIC_SUBTYPE, &subtype);
ret = regmap_read(map, PMIC_SUBTYPE, &pmic->subtype);
if (ret < 0)
return;
return ret;
for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) {
if (subtype == (unsigned long)pmic_spmi_id_table[i].data)
break;
pmic->name = of_match_device(pmic_spmi_id_table, dev)->compatible;
ret = regmap_read(map, PMIC_REV2, &pmic->rev2);
if (ret < 0)
return ret;
ret = regmap_read(map, PMIC_REV3, &pmic->minor);
if (ret < 0)
return ret;
ret = regmap_read(map, PMIC_REV4, &pmic->major);
if (ret < 0)
return ret;
if (pmic->subtype == PMI8998_SUBTYPE || pmic->subtype == PM660_SUBTYPE) {
ret = regmap_read(map, PMIC_FAB_ID, &pmic->fab_id);
if (ret < 0)
return ret;
}
if (i != ARRAY_SIZE(pmic_spmi_id_table))
name = pmic_spmi_id_table[i].compatible;
ret = regmap_read(map, PMIC_REV2, &rev2);
if (ret < 0)
return;
ret = regmap_read(map, PMIC_REV3, &minor);
if (ret < 0)
return;
ret = regmap_read(map, PMIC_REV4, &major);
if (ret < 0)
return;
/*
* In early versions of PM8941 and PM8226, the major revision number
* started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
* Increment the major revision number here if the chip is an early
* version of PM8941 or PM8226.
*/
if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) &&
major < 0x02)
major++;
if ((pmic->subtype == PM8941_SUBTYPE || pmic->subtype == PM8226_SUBTYPE) &&
pmic->major < 0x02)
pmic->major++;
if (subtype == PM8110_SUBTYPE)
minor = rev2;
if (pmic->subtype == PM8110_SUBTYPE)
pmic->minor = pmic->rev2;
dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor);
pmic_print_info(dev, pmic);
return 0;
}
/**
* qcom_pmic_get() - Get a pointer to the base PMIC device
*
* @dev: the pmic function device
* @return: the struct qcom_spmi_pmic* pointer associated with the function device
*/
inline const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev)
{
struct spmi_device *sdev = qcom_pmic_get_base_usid(dev->parent);
if (IS_ERR(sdev))
return ERR_CAST(sdev);
return &((struct qcom_spmi_dev *)spmi_device_get_drvdata(sdev))->pmic;
}
EXPORT_SYMBOL(qcom_pmic_get);
static const struct regmap_config spmi_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
@ -144,14 +220,26 @@ static const struct regmap_config spmi_regmap_config = {
static int pmic_spmi_probe(struct spmi_device *sdev)
{
struct regmap *regmap;
struct qcom_spmi_dev *ctx;
int ret;
regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
ctx = devm_kzalloc(&sdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->num_usids = (long)of_device_get_match_data(&sdev->dev);
/* Only the first slave id for a PMIC contains this information */
if (sdev->usid % 2 == 0)
pmic_spmi_show_revid(regmap, &sdev->dev);
if (sdev->usid % ctx->num_usids == 0) {
ret = pmic_spmi_load_revid(regmap, &sdev->dev, &ctx->pmic);
if (ret < 0)
return ret;
}
spmi_device_set_drvdata(sdev, ctx);
return devm_of_platform_populate(&sdev->dev);
}

300
drivers/mfd/wcd9335.c Normal file
View file

@ -0,0 +1,300 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wcd9335/registers.h>
#include <linux/mfd/wcd9335/wcd9335.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slimbus.h>
#define WCD9335_REGMAP_IRQ_REG(_irq, _off, _mask) \
[_irq] = { \
.reg_offset = (_off), \
.mask = (_mask), \
.type = { \
.type_reg_offset = (_off), \
.types_supported = IRQ_TYPE_EDGE_BOTH, \
.type_reg_mask = (_mask), \
.type_level_low_val = (_mask), \
.type_level_high_val = (_mask), \
.type_falling_val = 0, \
.type_rising_val = 0, \
}, \
}
static const struct mfd_cell wcd9335_devices[] = {
{
.name = "wcd9335-codec",
}, {
.name = "wcd9335-gpio",
.of_compatible = "qcom,wcd9340-gpio",
}, {
.name = "wcd9335-soundwire",
.of_compatible = "qcom,soundwire-v1.3.0",
},
};
static const struct regmap_irq wcd9335_irqs[] = {
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_SLIMBUS, 0, BIT(0)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPL_FAULT, 0, BIT(2)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPR_FAULT, 0, BIT(3)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_SW_DET, 1, BIT(0)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, 1, BIT(1)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, 1, BIT(2)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, 1, BIT(3)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 1, BIT(4)),
WCD9335_REGMAP_IRQ_REG(WCD9335_IRQ_SOUNDWIRE, 2, BIT(4)),
};
static const struct regmap_irq_chip wcd9335_regmap_irq_chip = {
.name = "wcd9335_irq",
.status_base = WCD9335_INTR_PIN1_STATUS0,
.mask_base = WCD9335_INTR_PIN1_MASK0,
.ack_base = WCD9335_INTR_PIN1_CLEAR0,
.type_base = WCD9335_INTR_LEVEL0,
.num_type_reg = 4,
.type_in_mask = false,
.num_regs = 4,
.irqs = wcd9335_irqs,
.num_irqs = ARRAY_SIZE(wcd9335_irqs),
};
static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WCD9335_INTR_PIN1_STATUS0...WCD9335_INTR_PIN2_CLEAR3:
case WCD9335_SWR_AHB_BRIDGE_RD_DATA_0:
case WCD9335_SWR_AHB_BRIDGE_RD_DATA_1:
case WCD9335_SWR_AHB_BRIDGE_RD_DATA_2:
case WCD9335_SWR_AHB_BRIDGE_RD_DATA_3:
case WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS:
case WCD9335_ANA_MBHC_RESULT_3:
case WCD9335_ANA_MBHC_RESULT_2:
case WCD9335_ANA_MBHC_RESULT_1:
case WCD9335_ANA_MBHC_MECH:
case WCD9335_ANA_MBHC_ELECT:
case WCD9335_ANA_MBHC_ZDET:
case WCD9335_ANA_MICB2:
case WCD9335_ANA_RCO:
case WCD9335_ANA_BIAS:
return true;
default:
return false;
}
};
static const struct regmap_range_cfg wcd9335_ranges[] = {
{ .name = "WCD9335",
.range_min = 0x0,
.range_max = WCD9335_MAX_REGISTER,
.selector_reg = WCD9335_SEL_REGISTER,
.selector_mask = WCD9335_SEL_MASK,
.selector_shift = WCD9335_SEL_SHIFT,
.window_start = WCD9335_WINDOW_START,
.window_len = WCD9335_WINDOW_LENGTH,
},
};
static struct regmap_config wcd9335_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.max_register = 0xffff,
.can_multi_write = true,
.ranges = wcd9335_ranges,
.num_ranges = ARRAY_SIZE(wcd9335_ranges),
.volatile_reg = wcd9335_is_volatile_register,
};
static int wcd9335_bring_up(struct wcd9335_ddata *ddata)
{
struct regmap *regmap = ddata->regmap;
u16 id_minor, id_major;
int ret;
ret = regmap_bulk_read(regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
(u8 *)&id_minor, sizeof(u16));
if (ret)
return ret;
ret = regmap_bulk_read(regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
(u8 *)&id_major, sizeof(u16));
if (ret)
return ret;
dev_info(ddata->dev, "WCD934x chip id major 0x%x, minor 0x%x\n",
id_major, id_minor);
regmap_write(regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
regmap_write(regmap, WCD9335_SIDO_NEW_VOUT_A_STARTUP, 0x19);
regmap_write(regmap, WCD9335_SIDO_NEW_VOUT_D_STARTUP, 0x15);
/* Add 1msec delay for VOUT to settle */
usleep_range(1000, 1100);
regmap_write(regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
regmap_write(regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
regmap_write(regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
regmap_write(regmap, WCD9335_CODEC_RPM_RST_CTL, 0x7);
regmap_write(regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
return 0;
}
static int wcd9335_slim_status_up(struct slim_device *sdev)
{
struct device *dev = &sdev->dev;
struct wcd9335_ddata *ddata;
int ret;
ddata = dev_get_drvdata(dev);
ddata->regmap = regmap_init_slimbus(sdev, &wcd9335_regmap_config);
if (IS_ERR(ddata->regmap)) {
dev_err(dev, "Error allocating slim regmap\n");
return PTR_ERR(ddata->regmap);
}
ret = wcd9335_bring_up(ddata);
if (ret) {
dev_err(dev, "Failed to bring up WCD9335: err = %d\n", ret);
return ret;
}
ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq,
IRQF_TRIGGER_HIGH, 0,
&wcd9335_regmap_irq_chip,
&ddata->irq_data);
if (ret) {
dev_err(dev, "Failed to add IRQ chip: err = %d\n", ret);
return ret;
}
ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, wcd9335_devices,
ARRAY_SIZE(wcd9335_devices), NULL, 0, NULL);
if (ret) {
dev_err(dev, "Failed to add child devices: err = %d\n",
ret);
return ret;
}
return ret;
}
static int wcd9335_slim_status(struct slim_device *sdev,
enum slim_device_status status)
{
switch (status) {
case SLIM_DEVICE_STATUS_UP:
return wcd9335_slim_status_up(sdev);
case SLIM_DEVICE_STATUS_DOWN:
mfd_remove_devices(&sdev->dev);
break;
default:
return -EINVAL;
}
return 0;
}
static int wcd9335_slim_probe(struct slim_device *sdev)
{
struct device *dev = &sdev->dev;
struct device_node *np = dev->of_node;
struct wcd9335_ddata *ddata;
int reset_gpio, ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
ddata->irq = of_irq_get(np, 0);
if (ddata->irq < 0)
return dev_err_probe(ddata->dev, ddata->irq,
"Failed to get IRQ\n");
reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (reset_gpio < 0) {
dev_err(dev, "Failed to get reset gpio: err = %d\n",
reset_gpio);
return reset_gpio;
}
ddata->extclk = devm_clk_get(dev, "extclk");
if (IS_ERR(ddata->extclk)) {
dev_err(dev, "Failed to get extclk");
return PTR_ERR(ddata->extclk);
}
ddata->supplies[0].supply = "vdd-buck";
ddata->supplies[1].supply = "vdd-buck-sido";
ddata->supplies[2].supply = "vdd-tx";
ddata->supplies[3].supply = "vdd-rx";
ddata->supplies[4].supply = "vdd-io";
ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, ddata->supplies);
if (ret) {
dev_err(dev, "Failed to get supplies: err = %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, ddata->supplies);
if (ret) {
dev_err(dev, "Failed to enable supplies: err = %d\n", ret);
return ret;
}
/*
* For WCD9335, it takes about 600us for the Vout_A and
* Vout_D to be ready after BUCK_SIDO is powered up.
* SYS_RST_N shouldn't be pulled high during this time
*/
usleep_range(600, 650);
gpio_direction_output(reset_gpio, 0);
msleep(20);
gpio_set_value(reset_gpio, 1);
msleep(20);
ddata->dev = dev;
dev_set_drvdata(dev, ddata);
return 0;
}
static void wcd9335_slim_remove(struct slim_device *sdev)
{
struct wcd9335_ddata *ddata = dev_get_drvdata(&sdev->dev);
regulator_bulk_disable(WCD9335_MAX_SUPPLY, ddata->supplies);
mfd_remove_devices(&sdev->dev);
}
static const struct slim_device_id wcd9335_slim_id[] = {
{ SLIM_MANF_ID_QCOM, SLIM_PROD_CODE_WCD9340,
SLIM_DEV_IDX_WCD9340, SLIM_DEV_INSTANCE_ID_WCD9340 },
{}
};
static struct slim_driver wcd9335_slim_driver = {
.driver = {
.name = "wcd9335-slim",
},
.probe = wcd9335_slim_probe,
.remove = wcd9335_slim_remove,
.device_status = wcd9335_slim_status,
.id_table = wcd9335_slim_id,
};
module_slim_driver(wcd9335_slim_driver);
MODULE_DESCRIPTION("WCD9335 slim driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("slim:217:250:*");
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");

View file

@ -395,6 +395,7 @@ ipa_power_init(struct device *dev, const struct ipa_power_data *data)
pm_runtime_set_autosuspend_delay(dev, IPA_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_forbid(dev);
pm_runtime_enable(dev);
return power;

View file

@ -1004,6 +1004,8 @@ static void ath10k_qmi_driver_event_work(struct work_struct *work)
switch (event->type) {
case ATH10K_QMI_EVENT_SERVER_ARRIVE:
ath10k_qmi_event_server_arrive(qmi);
// HACK: Fake MSA being ready
ath10k_qmi_event_msa_ready(qmi);
break;
case ATH10K_QMI_EVENT_SERVER_EXIT:
ath10k_qmi_event_server_exit(qmi);

View file

@ -127,6 +127,23 @@ config PINCTRL_AXP209
selected.
Say Y to enable pinctrl and GPIO support for the AXP209 PMIC.
config PINCTRL_AW9523
bool "Awinic AW9523/AW9523B I2C GPIO expander pinctrl driver"
depends on OF && I2C
select PINMUX
select PINCONF
select GENERIC_PINCONF
select GPIOLIB
select GPIOLIB_IRQCHIP
select REGMAP_I2C
help
The Awinic AW9523/AW9523B is a multi-function I2C GPIO
expander with PWM functionality. This driver bundles a
pinctrl driver to select the function muxing and a GPIO
driver to handle GPIO, when the GPIO function is selected.
Say yes to enable pinctrl and GPIO support for the AW9523(B).
config PINCTRL_BM1880
bool "Bitmain BM1880 Pinctrl driver"
depends on OF && (ARCH_BITMAIN || COMPILE_TEST)

View file

@ -15,6 +15,7 @@ obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o
obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o
obj-$(CONFIG_PINCTRL_AW9523) += pinctrl-aw9523.o
obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o
obj-$(CONFIG_PINCTRL_BM1880) += pinctrl-bm1880.o
obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o

File diff suppressed because it is too large Load diff

View file

@ -897,4 +897,23 @@ config BATTERY_UG3105
device is off or suspended, the functionality of this driver is
limited to reporting capacity only.
config BATTERY_QCOM_FG
tristate "Qualcomm PMIC fuel gauge driver"
depends on MFD_SPMI_PMIC
help
Say Y here to enable the Qualcomm PMIC Fuel Gauge driver. This
adds support for battery fuel gauging and state of charge of
battery connected to the fuel gauge. The state of charge is
reported through a BMS power supply property and also sends
uevents when the capacity is updated.
config CHARGER_QCOM_SMB2
tristate "Qualcomm PMI8998 PMIC charger driver"
depends on MFD_SPMI_PMIC
depends on IIO
help
Say Y here to enable the Qualcomm PMIC Charger driver. This
adds support for the SMB2 switch mode battery charger found
in PMI8998 and related PMICs.
endif # POWER_SUPPLY

View file

@ -108,3 +108,5 @@ 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_UG3105) += ug3105_battery.o
obj-$(CONFIG_BATTERY_QCOM_FG) += qcom_fg.o
obj-$(CONFIG_CHARGER_QCOM_SMB2) += qcom_pmi8998_charger.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,176 @@
// #define FG_PARAM_MAX 49
/**** Registers *****/
#define PMIC_SUBTYPE 0x105
#define PMI8994_SUBTYPE 0x0a
#define PMI8996_SUBTYPE 0x13
#define PM8998_SUBTYPE 0x14
#define PMI8998_SUBTYPE 0x15
/* SRAM */
#define MEM_INTF_STS 0x10
#define MEM_INTF_CFG 0x50
#define MEM_INTF_CTL 0x51
#define MEM_INTF_IMA_CFG 0x52
#define MEM_INTF_IMA_OPR_STS 0x54
#define MEM_INTF_IMA_EXP_STS 0x55
#define MEM_INTF_IMA_HW_STS 0x56
#define MEM_INTF_BEAT_COUNT 0x57
#define MEM_INTF_IMA_ERR_STS 0x5f
#define MEM_INTF_IMA_BYTE_EN 0x60
#define MEM_INTF_ADDR_LSB 0x61
#define MEM_INTF_RD_DATA0 0x67
#define MEM_INTF_WR_DATA0 0x63
#define MEM_INTF_AVAIL BIT(0)
#define MEM_INTF_CTL_BURST BIT(7)
#define MEM_INTF_CTL_WR_EN BIT(6)
#define RIF_MEM_ACCESS_REQ BIT(7)
/* Battery info */
#define BATT_INFO_CHARGE_MAX_DESIGN 0x4a
#define BATT_INFO_THERM_C1 0x5c
#define BATT_INFO_VBATT_LSB 0xa0
#define BATT_INFO_VBATT_MSB 0xa1
#define BATT_INFO_IBATT_LSB 0xa2
#define BATT_INFO_IBATT_MSB 0xa3
#define BATT_INFO_BATT_TEMP_LSB 0x50
#define BATT_INFO_BATT_TEMP_MSB 0x51
#define BATT_MONOTONIC_SOC 0x09
#define BATT_TEMP_LSB_MASK GENMASK(7, 0)
#define BATT_TEMP_MSB_MASK GENMASK(2, 0)
/* Base addresses */
#define REG_BASE 0x4000
#define REG_BATT 0x4100
#define REG_MEM 0x4400
/* Interrupt offsets */
#define INT_RT_STS 0x10
#define INT_EN_CLR 0x16
/* Param addresses */
#define PARAM_ADDR_BATT_TEMP 0x50
#define PARAM_ADDR_BATT_VOLTAGE 0xa0
#define PARAM_ADDR_BATT_CURRENT 0xa2
#define MISC_BASE 0x1600
#define USBIN_BASE 0x1300
#define BATT_INFO_JEITA_COLD(chip) (REG_BATT + 0x62)
#define BATT_INFO_JEITA_COOL(chip) (REG_BATT + 0x63)
#define BATT_INFO_JEITA_WARM(chip) (REG_BATT + 0x64)
#define BATT_INFO_JEITA_HOT(chip) (REG_BATT + 0x65)
#define BATT_TEMP_JEITA_COLD 100
#define BATT_TEMP_JEITA_COOL 50
#define BATT_TEMP_JEITA_WARM 400
#define BATT_TEMP_JEITA_HOT 450
#define BATTERY_CHARGER_STATUS_REG(chip) (chip->chg_base + 0x06)
#define BATTERY_HEALTH_STATUS_REG(chip) (chip->chg_base + 0x07)
#define BATTERY_CHARGER_STATUS_MASK GENMASK(2, 0)
#define POWER_PATH_STATUS_REG (MISC_BASE + 0x0B)
#define MEM_IF_TIMEOUT_MS 5000
enum wa_flags {
PMI8998_V1_REV_WA,
PMI8998_V2_REV_WA,
};
enum pmic_rev_offsets {
DIG_MINOR = 0x0,
DIG_MAJOR = 0x1,
ANA_MINOR = 0x2,
ANA_MAJOR = 0x3,
};
enum pmic_rev {
DIG_REV_1 = 0x1,
DIG_REV_2 = 0x2,
DIG_REV_3 = 0x3,
};
enum charger_status{
TRICKLE_CHARGE = 0,
PRE_CHARGE,
FAST_CHARGE,
FULLON_CHARGE,
TAPER_CHARGE,
TERMINATE_CHARGE,
INHIBIT_CHARGE,
DISABLE_CHARGE,
};
static enum power_supply_property fg_properties[] = {
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_VOLTAGE_MIN,
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_MIN,
POWER_SUPPLY_PROP_TEMP_MAX,
POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
};
struct qcom_fg_chip;
struct qcom_fg_ops {
int (*get_capacity)(struct qcom_fg_chip *chip, int *);
int (*get_temperature)(struct qcom_fg_chip *chip, int *);
int (*get_current)(struct qcom_fg_chip *chip, int *);
int (*get_voltage)(struct qcom_fg_chip *chip, int *);
int (*get_batt_status)(struct qcom_fg_chip *chip, int *);
int (*get_health_status)(struct qcom_fg_chip *chip, int *);
int (*get_temp_threshold)(struct qcom_fg_chip *chip,
enum power_supply_property psp, int *);
int (*set_temp_threshold)(struct qcom_fg_chip *chip,
enum power_supply_property psp, int);
};
struct qcom_fg_chip {
struct device *dev;
unsigned int base;
unsigned int chg_base;
struct regmap *regmap;
struct mutex lock;
unsigned int subtype;
const struct qcom_fg_ops *ops;
struct power_supply *bms_psy;
u8 revision[4];
bool ima_supported;
struct completion sram_access_granted;
int batt_cap_uah;
int batt_max_voltage_uv;
int batt_min_voltage_uv;
int health;
int status;
bool online;
};

File diff suppressed because it is too large Load diff

View file

@ -279,12 +279,6 @@ static irqreturn_t qcom_labibb_ocp_isr(int irq, void *chip)
}
vreg->ocp_irq_count++;
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync(irq);
/* Warn the user for overcurrent */
dev_warn(vreg->dev, "Over-Current interrupt fired!\n");
@ -304,6 +298,12 @@ end:
if (ret)
return IRQ_NONE;
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync(irq);
return IRQ_HANDLED;
}
@ -316,8 +316,11 @@ static int qcom_labibb_set_ocp(struct regulator_dev *rdev, int lim,
int irq_trig_low, ret;
/*
* labibb supports only protection - and does not support setting
* limit. Furthermore, we don't support disabling protection.
* labibb does not support specifying a current limit that is
* special to over-current protection, but only a global one
* that will be used for both current limiting and protection;
* for this reason, we only support enabling the OCP here.
* Furthermore, we don't support disabling protection.
*/
if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
return -EINVAL;
@ -540,12 +543,6 @@ static irqreturn_t qcom_labibb_sc_isr(int irq, void *chip)
/* Warn the user for short circuit */
dev_warn(vreg->dev, "Short-Circuit interrupt fired!\n");
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync(irq);
/* Signal out of regulation event to drivers */
regulator_notifier_call_chain(vreg->rdev,
REGULATOR_EVENT_REGULATION_OUT, NULL);
@ -553,6 +550,13 @@ static irqreturn_t qcom_labibb_sc_isr(int irq, void *chip)
/* Schedule the short-circuit handling as high-priority work */
mod_delayed_work(system_highpri_wq, &vreg->sc_recovery_work,
msecs_to_jiffies(SC_RECOVERY_INTERVAL_MS));
/*
* Disable the interrupt temporarily, or it will fire continuously;
* we will re-enable it in the recovery worker function.
*/
disable_irq_nosync(irq);
return IRQ_HANDLED;
}

View file

@ -42,6 +42,23 @@ config QCOM_CPR
To compile this driver as a module, choose M here: the module will
be called qcom-cpr
config QCOM_CPR3
tristate "QCOM Core Power Reduction (CPR v3/v4/Hardened) support"
depends on ARCH_QCOM && HAS_IOMEM
select PM_OPP
select REGMAP
help
Say Y here to enable support for the CPR hardware found on a broad
variety of Qualcomm SoCs like MSM8996, MSM8998, SDM630, SDM660,
SDM845 and others.
This driver populates OPP tables and makes adjustments to them
based on feedback from the CPR hardware. If you want to do CPU
and/or GPU frequency scaling say Y here.
To compile this driver as a module, choose M here: the module will
be called qcom-cpr3
config QCOM_GENI_SE
tristate "QCOM GENI Serial Engine Driver"
depends on ARCH_QCOM || COMPILE_TEST

View file

@ -3,7 +3,8 @@ CFLAGS_rpmh-rsc.o := -I$(src)
obj-$(CONFIG_QCOM_AOSS_QMP) += qcom_aoss.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_CPR) += cpr.o
obj-$(CONFIG_QCOM_CPR) += cpr-common.o cpr.o
obj-$(CONFIG_QCOM_CPR3) += cpr-common.o cpr3.o
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
obj-$(CONFIG_QCOM_OCMEM) += ocmem.o

View file

@ -0,0 +1,372 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2019, Linaro Limited
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
#include <linux/nvmem-consumer.h>
#include "cpr-common.h"
int cpr_populate_ring_osc_idx(struct device *dev,
struct fuse_corner *fuse_corner,
const struct cpr_fuse *cpr_fuse,
int num_fuse_corners)
{
struct fuse_corner *end = fuse_corner + num_fuse_corners;
u32 data;
int ret;
for (; fuse_corner < end; fuse_corner++, cpr_fuse++) {
ret = nvmem_cell_read_variable_le_u32(dev, cpr_fuse->ring_osc, &data);
if (ret)
return ret;
fuse_corner->ring_osc_idx = data;
}
return 0;
}
int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV,
int adj, int step_volt, const char *init_v_efuse,
struct device *dev)
{
int steps, uV;
u32 bits = 0;
int ret;
ret = nvmem_cell_read_variable_le_u32(dev, init_v_efuse, &bits);
if (ret)
return ret;
steps = bits & (BIT(init_v_width - 1) - 1);
/* Not two's complement.. instead highest bit is sign bit */
if (bits & BIT(init_v_width - 1))
steps = -steps;
uV = ref_uV + steps * step_size_uV;
/* Apply open-loop fixed adjustments to fused values */
uV += adj;
return DIV_ROUND_UP(uV, step_volt) * step_volt;
}
const struct cpr_fuse *cpr_get_fuses(struct device *dev, int tid,
int num_fuse_corners)
{
struct cpr_fuse *fuses;
int i;
fuses = devm_kcalloc(dev, num_fuse_corners,
sizeof(struct cpr_fuse),
GFP_KERNEL);
if (!fuses)
return ERR_PTR(-ENOMEM);
for (i = 0; i < num_fuse_corners; i++) {
char tbuf[50];
snprintf(tbuf, sizeof(tbuf), "cpr%d_ring_osc%d", tid, i + 1);
fuses[i].ring_osc = devm_kstrdup(dev, tbuf, GFP_KERNEL);
if (!fuses[i].ring_osc)
return ERR_PTR(-ENOMEM);
snprintf(tbuf, sizeof(tbuf),
"cpr%d_init_voltage%d", tid, i + 1);
fuses[i].init_voltage = devm_kstrdup(dev, tbuf,
GFP_KERNEL);
if (!fuses[i].init_voltage)
return ERR_PTR(-ENOMEM);
snprintf(tbuf, sizeof(tbuf), "cpr%d_quotient%d", tid, i + 1);
fuses[i].quotient = devm_kstrdup(dev, tbuf, GFP_KERNEL);
if (!fuses[i].quotient)
return ERR_PTR(-ENOMEM);
snprintf(tbuf, sizeof(tbuf),
"cpr%d_quotient_offset%d", tid, i + 1);
fuses[i].quotient_offset = devm_kstrdup(dev, tbuf,
GFP_KERNEL);
if (!fuses[i].quotient_offset)
return ERR_PTR(-ENOMEM);
}
return fuses;
}
int cpr_populate_fuse_common(struct device *dev,
struct fuse_corner_data *fdata,
const struct cpr_fuse *cpr_fuse,
struct fuse_corner *fuse_corner,
int step_volt, int init_v_width,
int init_v_step)
{
int uV, ret;
/* Populate uV */
uV = cpr_read_fuse_uV(init_v_width, init_v_step,
fdata->ref_uV, fdata->volt_oloop_adjust,
step_volt, cpr_fuse->init_voltage, dev);
if (uV < 0)
return uV;
/*
* Update SoC voltages: platforms might choose a different
* regulators than the one used to characterize the algorithms
* (ie, init_voltage_step).
*/
fdata->min_uV = roundup(fdata->min_uV, step_volt);
fdata->max_uV = roundup(fdata->max_uV, step_volt);
fuse_corner->min_uV = fdata->min_uV;
fuse_corner->max_uV = fdata->max_uV;
fuse_corner->uV = clamp(uV, fuse_corner->min_uV, fuse_corner->max_uV);
/* Populate target quotient by scaling */
ret = nvmem_cell_read_variable_le_u32(dev, cpr_fuse->quotient, &fuse_corner->quot);
if (ret)
return ret;
fuse_corner->quot *= fdata->quot_scale;
fuse_corner->quot += fdata->quot_offset;
fuse_corner->quot += fdata->quot_adjust;
return 0;
}
/*
* Returns: Index of the initial corner or negative number for error.
*/
int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk,
struct corner *corners, int num_corners)
{
unsigned long rate;
struct corner *iter, *corner;
const struct corner *end;
unsigned int ret = 0;
if (!cpu_clk)
return -EINVAL;
end = &corners[num_corners - 1];
rate = clk_get_rate(cpu_clk);
/*
* Some bootloaders set a CPU clock frequency that is not defined
* in the OPP table. When running at an unlisted frequency,
* cpufreq_online() will change to the OPP which has the lowest
* frequency, at or above the unlisted frequency.
* Since cpufreq_online() always "rounds up" in the case of an
* unlisted frequency, this function always "rounds down" in case
* of an unlisted frequency. That way, when cpufreq_online()
* triggers the first ever call to cpr_set_performance_state(),
* it will correctly determine the direction as UP.
*/
for (iter = corners; iter <= end; iter++) {
if (iter->freq > rate)
break;
ret++;
if (iter->freq == rate) {
corner = iter;
break;
}
if (iter->freq < rate)
corner = iter;
}
if (!corner) {
dev_err(dev, "boot up corner not found\n");
return -EINVAL;
}
dev_dbg(dev, "boot up perf state: %u\n", ret);
return ret;
}
u32 cpr_get_fuse_corner(struct dev_pm_opp *opp, u32 tid)
{
struct device_node *np;
u32 fc;
np = dev_pm_opp_get_of_node(opp);
if (of_property_read_u32_index(np, "qcom,opp-fuse-level", tid, &fc)) {
pr_debug("%s: missing 'qcom,opp-fuse-level' property\n",
__func__);
fc = 0;
}
of_node_put(np);
return fc;
}
void cpr_get_corner_post_vadj(struct dev_pm_opp *opp, u32 tid,
s32 *open_loop, s32 *closed_loop)
{
struct device_node *np;
/*
* There is no of_property_read_s32_index, so we just store the
* result into a s32 variable. After all, the OF API is doing
* the exact same for of_property_read_s32...
*/
np = dev_pm_opp_get_of_node(opp);
if (of_property_read_u32_index(np, "qcom,opp-oloop-vadj", tid,
open_loop))
*open_loop = 0;
if (of_property_read_u32_index(np, "qcom,opp-cloop-vadj", tid,
closed_loop))
*closed_loop = 0;
of_node_put(np);
}
unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
struct device *cpu_dev)
{
u64 rate = 0;
struct device_node *ref_np;
struct device_node *desc_np;
struct device_node *child_np = NULL;
struct device_node *child_req_np = NULL;
desc_np = dev_pm_opp_of_get_opp_desc_node(cpu_dev);
if (!desc_np)
return 0;
ref_np = dev_pm_opp_get_of_node(ref);
if (!ref_np)
goto out_ref;
do {
of_node_put(child_req_np);
child_np = of_get_next_available_child(desc_np, child_np);
child_req_np = of_parse_phandle(child_np, "required-opps", 0);
} while (child_np && child_req_np != ref_np);
if (child_np && child_req_np == ref_np)
of_property_read_u64(child_np, "opp-hz", &rate);
of_node_put(child_req_np);
of_node_put(child_np);
of_node_put(ref_np);
out_ref:
of_node_put(desc_np);
return (unsigned long) rate;
}
int cpr_calculate_scaling(const char *quot_offset,
struct device *dev,
const struct fuse_corner_data *fdata,
const struct corner *corner)
{
u64 freq_diff;
const struct fuse_corner *fuse, *prev_fuse;
u32 quot_diff;
int scaling, ret;
fuse = corner->fuse_corner;
prev_fuse = fuse - 1;
if (quot_offset) {
ret = nvmem_cell_read_variable_le_u32(dev, quot_offset, &quot_diff);
if (ret)
return ret;
quot_diff *= fdata->quot_offset_scale;
quot_diff += fdata->quot_offset_adjust;
} else {
quot_diff = fuse->quot - prev_fuse->quot;
}
freq_diff = fuse->max_freq - prev_fuse->max_freq;
freq_diff = div_u64(freq_diff, 1000000); /* Convert to MHz */
scaling = 1000 * quot_diff;
do_div(scaling, freq_diff);
return min(scaling, fdata->max_quot_scale);
}
int cpr_interpolate(const struct corner *corner, int step_volt,
const struct fuse_corner_data *fdata)
{
unsigned long f_high, f_low, f_diff;
int uV_high, uV_low, uV;
u64 temp, temp_limit;
const struct fuse_corner *fuse, *prev_fuse;
fuse = corner->fuse_corner;
prev_fuse = fuse - 1;
f_high = fuse->max_freq;
f_low = prev_fuse->max_freq;
uV_high = fuse->uV;
uV_low = prev_fuse->uV;
f_diff = fuse->max_freq - corner->freq;
/*
* Don't interpolate in the wrong direction. This could happen
* if the adjusted fuse voltage overlaps with the previous fuse's
* adjusted voltage.
*/
if (f_high <= f_low || uV_high <= uV_low || f_high <= corner->freq)
return corner->uV;
temp = f_diff * (uV_high - uV_low);
temp = div64_ul(temp, f_high - f_low);
/*
* max_volt_scale has units of uV/MHz while freq values
* have units of Hz. Divide by 1000000 to convert to.
*/
temp_limit = f_diff * fdata->max_volt_scale;
do_div(temp_limit, 1000000);
uV = uV_high - min(temp, temp_limit);
return roundup(uV, step_volt);
}
int cpr_check_vreg_constraints(struct device *dev, struct regulator *vreg,
struct fuse_corner *f)
{
int ret;
ret = regulator_is_supported_voltage(vreg, f->min_uV, f->min_uV);
if (!ret) {
dev_err(dev, "min uV: %d not supported by regulator\n",
f->min_uV);
return -EINVAL;
}
ret = regulator_is_supported_voltage(vreg, f->max_uV, f->max_uV);
if (!ret) {
dev_err(dev, "max uV: %d not supported by regulator\n",
f->max_uV);
return -EINVAL;
}
return 0;
}

View file

@ -0,0 +1,117 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
enum voltage_change_dir {
NO_CHANGE,
DOWN,
UP,
};
struct fuse_corner_data {
int ref_uV;
int max_uV;
int min_uV;
int range_uV;
/* fuse volt: closed/open loop */
int volt_cloop_adjust;
int volt_oloop_adjust;
int max_volt_scale;
int max_quot_scale;
/* fuse quot */
int quot_offset;
int quot_scale;
int quot_adjust;
/* fuse quot_offset */
int quot_offset_scale;
int quot_offset_adjust;
};
struct cpr_fuse {
char *ring_osc;
char *init_voltage;
char *quotient;
char *quotient_offset;
};
struct fuse_corner {
int min_uV;
int max_uV;
int uV;
int quot;
int step_quot;
const struct reg_sequence *accs;
int num_accs;
unsigned long max_freq;
u8 ring_osc_idx;
};
struct corner {
int min_uV;
int max_uV;
int uV;
int last_uV;
int quot_adjust;
u32 save_ctl;
u32 save_irq;
unsigned long freq;
bool is_open_loop;
struct fuse_corner *fuse_corner;
};
struct corner_data {
unsigned int fuse_corner;
unsigned long freq;
int oloop_vadj;
int cloop_vadj;
};
struct acc_desc {
unsigned int enable_reg;
u32 enable_mask;
struct reg_sequence *config;
struct reg_sequence *settings;
int num_regs_per_fuse;
};
struct cpr_acc_desc {
const struct cpr_desc *cpr_desc;
const struct acc_desc *acc_desc;
};
int cpr_read_efuse(struct device *dev, const char *cname, u32 *data);
int cpr_populate_ring_osc_idx(struct device *dev,
struct fuse_corner *fuse_corner,
const struct cpr_fuse *cpr_fuse,
int num_fuse_corners);
int cpr_read_fuse_uV(int init_v_width, int step_size_uV, int ref_uV,
int adj, int step_volt, const char *init_v_efuse,
struct device *dev);
const struct cpr_fuse *cpr_get_fuses(struct device *dev, int tid,
int num_fuse_corners);
int cpr_populate_fuse_common(struct device *dev,
struct fuse_corner_data *fdata,
const struct cpr_fuse *cpr_fuse,
struct fuse_corner *fuse_corner,
int step_volt, int init_v_width,
int init_v_step);
int cpr_find_initial_corner(struct device *dev, struct clk *cpu_clk,
struct corner *corners, int num_corners);
u32 cpr_get_fuse_corner(struct dev_pm_opp *opp, u32 tid);
void cpr_get_corner_post_vadj(struct dev_pm_opp *opp, u32 tid,
s32 *open_loop, s32 *closed_loop);
unsigned long cpr_get_opp_hz_for_req(struct dev_pm_opp *ref,
struct device *cpu_dev);
int cpr_calculate_scaling(const char *quot_offset,
struct device *dev,
const struct fuse_corner_data *fdata,
const struct corner *corner);
int cpr_interpolate(const struct corner *corner, int step_volt,
const struct fuse_corner_data *fdata);
int cpr_check_vreg_constraints(struct device *dev, struct regulator *vreg,
struct fuse_corner *f);

Some files were not shown because too many files have changed in this diff Show more