All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/13] Add MediaTek MT6370 PMIC support
@ 2022-07-22 10:23 ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

This patch series add MediaTek MT6370 PMIC support. The MT6370 is a
highly-integrated smart power management IC, which includes a single
cell Li-Ion/Li-Polymer switching battery charger, a USB
Type-C & Power Delivery (PD) controller, dual Flash LED current sources,
a RGB LED driver, a backlight WLED driver, a display bias driver and a
general LDO for portable devices.

In this series of patches, we based on Andy Shevchenko's mfd patch used to
adjust the Makefile order.
(https://lore.kernel.org/all/20220616182524.7956-2-andriy.shevchenko@linux.intel.com/)
Among with this, we took some changes for MT6370 and refined the MT6370 device
tree files to comply with DT specifications.

"[PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370" depends on previous
DT binding patches, so before applying this patch, please apply other DT
patches first. Thanks!

Thank you,
ChiaEn Wu

---
Changes in v6:
- In Patch 03/13:
	- Add 'reg' property of led of multi-led to prevent checking
	  error.

- In Patch 08/13:
	- Convert tcpci as device resource managed with
	   'devm_add_action_or_reset' api.
	- Refine remvoe callback.
	- Refine the commit text from 'this commit add' to 'add'.

- In Patch 09/13:
	- Using 'struct device *dev = &pdev->dev' in probe()
	- Revise the sixth parameter of regmap_read_poll_timeout() by
	   replacing '1000' with 'MILLI'
	- Revise the units of three macros
	- MT6370_AICR_400MA --> MT6370_AICR_400_mA
	- MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
	- MT6370_ICHG_900MA --> MT6370_ICHG_900_mA

- In patch 10/13:
	- Remove the varable (*psy_desc) of struct mt6370_priv
	- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
	   POWER_SUPPLY_TYPE_USB_DCP)
	- Remove useless remove()
	- Revise all units from mini- to micro-
	- Revise get/set power_supply_prop (change to directly return get/set
	   regmap_field)
	- Revise probe() and use devm_add_action_or_reset() for handling of the
	   workqueue/delayed_work/mutex
	- Revise mt6370_chg_psy_desc
	   - Add '.name = "mt6370-charger"'
	   - Use 'static const'

- In patch 11/13:
	- Remove the 'ko' from mt6370 led Kconfig description.
	- Add both authors for Alice and ChiYuan.
	- Use pdata to distinguish the code from mt6370/71 to mt6372.
	- Instead of 'state' define, use the 'state' enum.
	- Fix the typo for 'MT6372_PMW_DUTY'.
	- For pwm_duty define, replace with bit macro - 1.
	- Refine all the labels from 'out' to 'out_unlock'.
	- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
	- Revise for the array initialization from {0} to {}.
	- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
	- Refine the 'comma' usage in struct/enum.

- In patch 12/13:
	- Use 'GENMASK' instead of 'BIT'.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine the return of _mt6370_flash_brightness_set function.
	- Refine the descriptions.
	- Use mt6370_clamp() instead of clamp_align().
	- Use device resource managed API for v4l2 flash_release.


Changes in v5:
- In patch 07/13:
	- Add the comma in the last REGMAP_IRQ_REG_LINE(),
	   DEFINE_RES_IRQ_NAMED() and MFD_CELL_RES()
	- Add the prefix in the first parameter of all mfd_cell
	- Move enum and struct mt6370_info to mt6370.h
	- Remove struct device *dev in struct mt6370_info
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 08/13:
	- Add comma for the last index of mt6370_reg_init.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine kconfig text.
	- Remove both 'else' in set_vbus callback.
	- Remove comma for of_device_id if the assigned member is only one.

- In patch 09/13:
	- Replace using snprintf() with sysfs_emit() in mt6370_adc_read_label()
	- Remove macro ADC_CONV_TIME_US
	- Revise all variable ordering
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 10/13:
	- Replace unsigned int type of pwr_rdy with bool in
	   mt6370_chg_set_online()
	- Remove redundant 'else' in mt6370_chg_field_get()
	- Revise 'if-else' in mt6370_chg_field_set()
	- Revise 'if' condition in mt6370_chg_enable_irq()
	- Revise all text 'otg' --> 'OTG'
	- Revise MT6370_MIVR_IBUS_TH_100_MA --> MT6370_MIVR_IBUS_TH_100_mA
	- Revise the description of Kconfig help text

- In patch 12/13:
	- Refine the coding style.
	- Use "dev" instead of "&pdev->dev".

- In patch 13/13:
	- Add missed <mod_devicetable.h>
	- Add struct device *dev in probe() to make code cleaning
	- Remove useless including header file <gpio/driver.h>, <of.h>
	- Remove useless variable uasage in mt6370_init_backlight_properties()
	- Remove redundant checking enable_gpio in mt6370_bl_update_status()
	- Remove redundant parentheses in mt6370_bl_get_brightness()
	- Revise the description of Kconfig help text
	- Revise the calculation of hys_th_steps


Changes in v4:
- In patch 02/13:
	- Add minItems of "io-channel-names"
	- Replace text "Mediatek" with "MediaTek"

- In patch 06/13:
	- Roll back all "$ref: " to v2 patch style (using "/schemas/...")

- In patch 07/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first break and then return" with "return directly"
	   in "mt6370_check_vendor_info()"
	- Add module name related description in Kconfig helptext
	- Add Copyright in the source code
	- Add header file "mt6370.h" for all "#define IRQ"
	- Adjust Makefile order of MT6370
	- Refine "bank_idx" and "bank_addr" in
	  "mt6375_regmap_read()" / "mt6375_regmap_write()"
	- Refine redundant "else if" in "mt6370_regmap_read()"

- In patch 08/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first ret=regulator_(dis/en)able and then return"
	   with "return directly" in "mt6370_tcpc_set_vbus()"
	- Replace header file <linux/of.h> with <linux/mod_devicetable.h>
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Remove header file <linux/of.h>
	- Refine all probe error by using dev_err_probe()

- In patch 09/13:
	- Replace text "Mediatek" with "MediaTek"
	- Replace all "first dev_err() and then return" with
	   "return dev_err_probe()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig
	- Add unit suffix of macro "ADC_CONV_POLLING_TIME"
	- Add new macro "ADC_CONV_TIME_MS"
	- Adjust the position of include file <mediatek,mt6370_adc.h>
	- Adjust the postions between <linux/module.h> and
	   <linux/mod_devicetable.h>
	- Fix some incorrect characters

- In patch 10/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig and
	   MODULE_DESCRIPTION()
	- Replace "mt6370_chg_val_to_reg" and "mt6370_chg_reg_to_val"
	   with "linear_range" API
	- Replace "first break and then return" with "return directly"
	   in all cases of get/set power_supply_property
	- Replace all "first dev_err() and then return" with "return
	   dev_err_probe()"
	- Replace all "return IS_ERR(priv->rdev) ? PTR_ERR(priv->rdev) : 0"
	   with "PTR_ERR_OR_ZERO()"
	- Replace "priv->dev->of_node" with "dev_of_node()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Add proper unit of "MT6370_MIVR_IBUS_TH"
	- Add error check in "mt6370_chg_get_status"
	- Remove including <mediatek,mt6370_adc.h> header file
	- Remove redundant comma of every enum terminator line
	- Remove unwanted blank lines
	- Remove the useless label (toggle_cfo_exit:)
	- Remove using atomic
	- Remove using of_match_ptr()
	- Fix some incorrect characters
	- Fix updating wrong bits when using ena_gpiod of OTG regulator
	- Adjust the probe order in probe()

- In patch 11/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace text "const" with "constant" in Kconfig
	- Add Copyright in the source code

- In patch 12/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code

- In patch 13/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code
	- Revise the comment of "PWM HYS STEPS"


Changes in v3:
- Remove ADC ABI file, which is added in v2 Patch 7
- In patch 02/14:
	- Add items and remove maxItems of io-channels
	- Add io-channel-names and describe each item
	- Add "unevaluatedProperties: false" in "usb-otg-vbus-regulator"
	- Rename "enable-gpio" to "enable-gpios" in "usb-otg-vbus-regulator"
- In patch 03/14:
	- Use leds-class-multicolor.yaml instead of common.yaml.
	- Split multi-led and led node.
	- Add subdevice "led" in "multi-led".
- In patch 04/14:
	- Remove the description of enum.
- In patch 05/14:
	- Rename "mediatek,bled-pwm-hys-input-threshold-steps" to
	  "mediatek,bled-pwm-hys-input-th-steps"
	- Refine "bled-pwm-hys-input-th-steps", "bled-ovp-microvolt",
	  "bled-ocp-microamp" enum values
- In patch 06/14:
	- Use " in entire patchset
	- Refine ADC description
	- Rename "enable-gpio" to "enable-gpios" in "regualtor"
- In patch 07/14:
	- Refine Kconfig help text
	- Refine error message of unknown vendor ID in
	  mt6370_check_vendor_info()
	- Refine return value handling of mt6370_regmap_read()
	- Refine all probe error by using dev_err_probe()
	- Refine "bank_idx" and "bank_addr" in mt6370_regmap_read() and
	  mt6370_regmap_write()
	- Add "#define VENID*" and drop the comments in
	  mt6370_check_vendor_info()
	- Drop "MFD" in MODULE_DESCRIPTION()
- In patch 09/14:
	- Refine Kconfig help text
- In patch 10/14:
	- Refine Kconfig help text
	- Refine all channel value in read_scale()
		a. current: uA --> mA
		b. voltage: uV --> mV
		c. temperature: degrees Celsius --> milli degrees Celsius
	- Add "default:" condition of switch statement in read_scale() and read_raw()
	- Add error message for reading ADC register failed
	- Add the comment for adc_lock
	- Add <linux/mod_devicetable.h> header file for struct of_device_id
	- Replace "adc" text with "ADC" in all of the error messages
- In patch 12/14:
	- Refine the grammer of the Kconfig.
	- Change reg mode to the const current mode.
- In patch 14/14:
	- Refine bool properties parsing (pwm-enable, ovp-shutdown, ocp-shutdown) in DT
	  parsing function
	- Refine u32 and u8 properties parsing (pwm-hys-input-th-steps, ovp-microvolt,
	  ocp-microamp), from using register value to using actual value
	- Refine error string of "channle-use" parsing failed
	- Refine Kconfig help text


Changes in v2:
- In patch 01/15:
	- Add "unevaluatedProperties: false".
	- Delete "DT bindings".
	- Refine the description to fit in 80 columns.
	- Skip the connector description.
- In patch 02/15:
	- Refine items description of interrupt-name
	- Rename "usb-otg-vbus" to "usb-otg-vbus-regulator"
	- Add constraint properties for ADC
- In patch 03/15:
	- Skip not useful description of "^(multi-)?led@[0-3]$"
	  and reg.
	- Due to the dependency, remove the mention of mfd
	  document directory.
	- Delete Soft-start property. In design aspect, we think
	  soft-restart should always be enabled, our new chip
	  has deleted the related setting register , also, we don’t
	  allow user adjust this parameter in this chip.
	- Refine the commit message.
- In patch 04/15:
	- Skip not useful description of "^led@[0-1]$" and reg.
	- Add apace after '#'.
	- Refine the commit message.
- In patch 05/15:
	- Remove "binding documentation" in subject title
	- Refine description of mt6370 backlight binding
	  document
	- Refine properties name(bled-pwm-hys-input-bit,
	  bled-ovp-microvolt, bled-ocp-microamp) and their
	  description
- In patch 06/15:
	- Refine ADC and Regulator descriptions
	- Refine include header usage in example
	- Refine node name to generic node name("pmic@34")
	- Refine led example indentation
	- Refine license of mediatek,mt6370_adc.h
	- Rename the dts example from IRQ define to number.
	- Remove mediatek,mt6370.h
- In patch 07/15:
	- Add ABI documentation for mt6370 non-standard ADC
	  sysfs interfaces.
- In patch 08/15:
	- Add all IRQ define into mt6370.c.
	- Refine include header usage
- In patch 09/15:
	- No changes.
- In patch 10/15:
	- Use 'gpiod_get_from_of_node' to replace
	  'fwnode_gpiod_get_index'.
- In patch 11/15:
	- Refine Kconfig mt6370 help text
	- Refine mask&shift to FIELD_PREP()
	- Refine mutex lock name ("lock" -> "adc_lock")
	- Refine mt6370_adc_read_scale()
	- Refine mt6370_adc_read_offset()
	- Refine mt6370_channel_labels[] by using enum to index
	  chan spec
	- Refine MT6370_ADC_CHAN()
	- Refine indio_dev->name
	- Remove useless include header files
- In patch 12/15:
	- Refine mt6370_chg_otg_rdesc.of_match
	  ("mt6370,otg-vbus" -> "usb-otg-vbus-regulator") to match
	  DT binding
- In patch 13/15:
	- Refine Kconfig description.
	- Remove include "linux/of.h" and use
	  "linux/mod_devicetable.h".
	- Place a comma for the last element of the const
	  unsigned int array.
	- Add a comment line for the mutex 'lock'.
	- In probe function, use 'dev_err_probe' in some
	  judgement to reduce the LOC.
	- Refine include header usage.
	  BIT/GENMASK -> linux/bits.h
	  FIELD_GET -> linux/bitfield.h
- In patch 14/15:
	- Add blank line.
	- Replace container_of() with to_mt6370_led() .
	- Refine description of ramping.
	- Refine the mt6370_init_common_properties function.
	- Refine the probe return.
- In patch 15/15:
	- Refine MT6370 help text in Kconfig
	- Refine DT Parse function
	- Remove useless enum
	- Add comment for 6372 backward compatible in
	  bl_update_status() and
	  check_vendor_info()
	- Using dev_err_probe(); insteads dev_err()&return; in
	  the probe()

Alice Chen (2):
  dt-bindings: leds: Add MediaTek MT6370 flashlight
  leds: flash: mt6370: Add MediaTek MT6370 flashlight support

ChiYuan Huang (7):
  dt-bindings: usb: Add MediaTek MT6370 TCPC
  dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED
    indicator
  dt-bindings: backlight: Add MediaTek MT6370 backlight
  dt-bindings: mfd: Add MediaTek MT6370
  mfd: mt6370: Add MediaTek MT6370 support
  usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator
    support

ChiaEn Wu (4):
  dt-bindings: power: supply: Add MediaTek MT6370 Charger
  iio: adc: mt6370: Add MediaTek MT6370 support
  power: supply: mt6370: Add MediaTek MT6370 charger driver
  video: backlight: mt6370: Add MediaTek MT6370 support

 .../leds/backlight/mediatek,mt6370-backlight.yaml  |   92 ++
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  |   41 +
 .../bindings/leds/mediatek,mt6370-indicator.yaml   |   81 ++
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   |  280 ++++++
 .../power/supply/mediatek,mt6370-charger.yaml      |   88 ++
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         |   36 +
 drivers/iio/adc/Kconfig                            |   12 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6370-adc.c                       |  274 ++++++
 drivers/leds/flash/Kconfig                         |   12 +
 drivers/leds/flash/Makefile                        |    1 +
 drivers/leds/flash/leds-mt6370-flash.c             |  633 ++++++++++++
 drivers/leds/rgb/Kconfig                           |   13 +
 drivers/leds/rgb/Makefile                          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c                 | 1004 ++++++++++++++++++++
 drivers/mfd/Kconfig                                |   16 +
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/mt6370.c                               |  281 ++++++
 drivers/mfd/mt6370.h                               |   99 ++
 drivers/power/supply/Kconfig                       |   14 +
 drivers/power/supply/Makefile                      |    1 +
 drivers/power/supply/mt6370-charger.c              |  973 +++++++++++++++++++
 drivers/usb/typec/tcpm/Kconfig                     |   11 +
 drivers/usb/typec/tcpm/Makefile                    |    1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c              |  208 ++++
 drivers/video/backlight/Kconfig                    |   12 +
 drivers/video/backlight/Makefile                   |    1 +
 drivers/video/backlight/mt6370-backlight.c         |  339 +++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |   18 +
 29 files changed, 4544 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
 create mode 100644 drivers/iio/adc/mt6370-adc.c
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h
 create mode 100644 drivers/power/supply/mt6370-charger.c
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
 create mode 100644 drivers/video/backlight/mt6370-backlight.c
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 154+ messages in thread

* [PATCH v6 00/13] Add MediaTek MT6370 PMIC support
@ 2022-07-22 10:23 ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiaEn Wu <chiaen_wu@richtek.com>

This patch series add MediaTek MT6370 PMIC support. The MT6370 is a
highly-integrated smart power management IC, which includes a single
cell Li-Ion/Li-Polymer switching battery charger, a USB
Type-C & Power Delivery (PD) controller, dual Flash LED current sources,
a RGB LED driver, a backlight WLED driver, a display bias driver and a
general LDO for portable devices.

In this series of patches, we based on Andy Shevchenko's mfd patch used to
adjust the Makefile order.
(https://lore.kernel.org/all/20220616182524.7956-2-andriy.shevchenko@linux.intel.com/)
Among with this, we took some changes for MT6370 and refined the MT6370 device
tree files to comply with DT specifications.

"[PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370" depends on previous
DT binding patches, so before applying this patch, please apply other DT
patches first. Thanks!

Thank you,
ChiaEn Wu

---
Changes in v6:
- In Patch 03/13:
	- Add 'reg' property of led of multi-led to prevent checking
	  error.

- In Patch 08/13:
	- Convert tcpci as device resource managed with
	   'devm_add_action_or_reset' api.
	- Refine remvoe callback.
	- Refine the commit text from 'this commit add' to 'add'.

- In Patch 09/13:
	- Using 'struct device *dev = &pdev->dev' in probe()
	- Revise the sixth parameter of regmap_read_poll_timeout() by
	   replacing '1000' with 'MILLI'
	- Revise the units of three macros
	- MT6370_AICR_400MA --> MT6370_AICR_400_mA
	- MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
	- MT6370_ICHG_900MA --> MT6370_ICHG_900_mA

- In patch 10/13:
	- Remove the varable (*psy_desc) of struct mt6370_priv
	- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
	   POWER_SUPPLY_TYPE_USB_DCP)
	- Remove useless remove()
	- Revise all units from mini- to micro-
	- Revise get/set power_supply_prop (change to directly return get/set
	   regmap_field)
	- Revise probe() and use devm_add_action_or_reset() for handling of the
	   workqueue/delayed_work/mutex
	- Revise mt6370_chg_psy_desc
	   - Add '.name = "mt6370-charger"'
	   - Use 'static const'

- In patch 11/13:
	- Remove the 'ko' from mt6370 led Kconfig description.
	- Add both authors for Alice and ChiYuan.
	- Use pdata to distinguish the code from mt6370/71 to mt6372.
	- Instead of 'state' define, use the 'state' enum.
	- Fix the typo for 'MT6372_PMW_DUTY'.
	- For pwm_duty define, replace with bit macro - 1.
	- Refine all the labels from 'out' to 'out_unlock'.
	- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
	- Revise for the array initialization from {0} to {}.
	- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
	- Refine the 'comma' usage in struct/enum.

- In patch 12/13:
	- Use 'GENMASK' instead of 'BIT'.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine the return of _mt6370_flash_brightness_set function.
	- Refine the descriptions.
	- Use mt6370_clamp() instead of clamp_align().
	- Use device resource managed API for v4l2 flash_release.


Changes in v5:
- In patch 07/13:
	- Add the comma in the last REGMAP_IRQ_REG_LINE(),
	   DEFINE_RES_IRQ_NAMED() and MFD_CELL_RES()
	- Add the prefix in the first parameter of all mfd_cell
	- Move enum and struct mt6370_info to mt6370.h
	- Remove struct device *dev in struct mt6370_info
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 08/13:
	- Add comma for the last index of mt6370_reg_init.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine kconfig text.
	- Remove both 'else' in set_vbus callback.
	- Remove comma for of_device_id if the assigned member is only one.

- In patch 09/13:
	- Replace using snprintf() with sysfs_emit() in mt6370_adc_read_label()
	- Remove macro ADC_CONV_TIME_US
	- Revise all variable ordering
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 10/13:
	- Replace unsigned int type of pwr_rdy with bool in
	   mt6370_chg_set_online()
	- Remove redundant 'else' in mt6370_chg_field_get()
	- Revise 'if-else' in mt6370_chg_field_set()
	- Revise 'if' condition in mt6370_chg_enable_irq()
	- Revise all text 'otg' --> 'OTG'
	- Revise MT6370_MIVR_IBUS_TH_100_MA --> MT6370_MIVR_IBUS_TH_100_mA
	- Revise the description of Kconfig help text

- In patch 12/13:
	- Refine the coding style.
	- Use "dev" instead of "&pdev->dev".

- In patch 13/13:
	- Add missed <mod_devicetable.h>
	- Add struct device *dev in probe() to make code cleaning
	- Remove useless including header file <gpio/driver.h>, <of.h>
	- Remove useless variable uasage in mt6370_init_backlight_properties()
	- Remove redundant checking enable_gpio in mt6370_bl_update_status()
	- Remove redundant parentheses in mt6370_bl_get_brightness()
	- Revise the description of Kconfig help text
	- Revise the calculation of hys_th_steps


Changes in v4:
- In patch 02/13:
	- Add minItems of "io-channel-names"
	- Replace text "Mediatek" with "MediaTek"

- In patch 06/13:
	- Roll back all "$ref: " to v2 patch style (using "/schemas/...")

- In patch 07/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first break and then return" with "return directly"
	   in "mt6370_check_vendor_info()"
	- Add module name related description in Kconfig helptext
	- Add Copyright in the source code
	- Add header file "mt6370.h" for all "#define IRQ"
	- Adjust Makefile order of MT6370
	- Refine "bank_idx" and "bank_addr" in
	  "mt6375_regmap_read()" / "mt6375_regmap_write()"
	- Refine redundant "else if" in "mt6370_regmap_read()"

- In patch 08/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first ret=regulator_(dis/en)able and then return"
	   with "return directly" in "mt6370_tcpc_set_vbus()"
	- Replace header file <linux/of.h> with <linux/mod_devicetable.h>
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Remove header file <linux/of.h>
	- Refine all probe error by using dev_err_probe()

- In patch 09/13:
	- Replace text "Mediatek" with "MediaTek"
	- Replace all "first dev_err() and then return" with
	   "return dev_err_probe()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig
	- Add unit suffix of macro "ADC_CONV_POLLING_TIME"
	- Add new macro "ADC_CONV_TIME_MS"
	- Adjust the position of include file <mediatek,mt6370_adc.h>
	- Adjust the postions between <linux/module.h> and
	   <linux/mod_devicetable.h>
	- Fix some incorrect characters

- In patch 10/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig and
	   MODULE_DESCRIPTION()
	- Replace "mt6370_chg_val_to_reg" and "mt6370_chg_reg_to_val"
	   with "linear_range" API
	- Replace "first break and then return" with "return directly"
	   in all cases of get/set power_supply_property
	- Replace all "first dev_err() and then return" with "return
	   dev_err_probe()"
	- Replace all "return IS_ERR(priv->rdev) ? PTR_ERR(priv->rdev) : 0"
	   with "PTR_ERR_OR_ZERO()"
	- Replace "priv->dev->of_node" with "dev_of_node()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Add proper unit of "MT6370_MIVR_IBUS_TH"
	- Add error check in "mt6370_chg_get_status"
	- Remove including <mediatek,mt6370_adc.h> header file
	- Remove redundant comma of every enum terminator line
	- Remove unwanted blank lines
	- Remove the useless label (toggle_cfo_exit:)
	- Remove using atomic
	- Remove using of_match_ptr()
	- Fix some incorrect characters
	- Fix updating wrong bits when using ena_gpiod of OTG regulator
	- Adjust the probe order in probe()

- In patch 11/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace text "const" with "constant" in Kconfig
	- Add Copyright in the source code

- In patch 12/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code

- In patch 13/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code
	- Revise the comment of "PWM HYS STEPS"


Changes in v3:
- Remove ADC ABI file, which is added in v2 Patch 7
- In patch 02/14:
	- Add items and remove maxItems of io-channels
	- Add io-channel-names and describe each item
	- Add "unevaluatedProperties: false" in "usb-otg-vbus-regulator"
	- Rename "enable-gpio" to "enable-gpios" in "usb-otg-vbus-regulator"
- In patch 03/14:
	- Use leds-class-multicolor.yaml instead of common.yaml.
	- Split multi-led and led node.
	- Add subdevice "led" in "multi-led".
- In patch 04/14:
	- Remove the description of enum.
- In patch 05/14:
	- Rename "mediatek,bled-pwm-hys-input-threshold-steps" to
	  "mediatek,bled-pwm-hys-input-th-steps"
	- Refine "bled-pwm-hys-input-th-steps", "bled-ovp-microvolt",
	  "bled-ocp-microamp" enum values
- In patch 06/14:
	- Use " in entire patchset
	- Refine ADC description
	- Rename "enable-gpio" to "enable-gpios" in "regualtor"
- In patch 07/14:
	- Refine Kconfig help text
	- Refine error message of unknown vendor ID in
	  mt6370_check_vendor_info()
	- Refine return value handling of mt6370_regmap_read()
	- Refine all probe error by using dev_err_probe()
	- Refine "bank_idx" and "bank_addr" in mt6370_regmap_read() and
	  mt6370_regmap_write()
	- Add "#define VENID*" and drop the comments in
	  mt6370_check_vendor_info()
	- Drop "MFD" in MODULE_DESCRIPTION()
- In patch 09/14:
	- Refine Kconfig help text
- In patch 10/14:
	- Refine Kconfig help text
	- Refine all channel value in read_scale()
		a. current: uA --> mA
		b. voltage: uV --> mV
		c. temperature: degrees Celsius --> milli degrees Celsius
	- Add "default:" condition of switch statement in read_scale() and read_raw()
	- Add error message for reading ADC register failed
	- Add the comment for adc_lock
	- Add <linux/mod_devicetable.h> header file for struct of_device_id
	- Replace "adc" text with "ADC" in all of the error messages
- In patch 12/14:
	- Refine the grammer of the Kconfig.
	- Change reg mode to the const current mode.
- In patch 14/14:
	- Refine bool properties parsing (pwm-enable, ovp-shutdown, ocp-shutdown) in DT
	  parsing function
	- Refine u32 and u8 properties parsing (pwm-hys-input-th-steps, ovp-microvolt,
	  ocp-microamp), from using register value to using actual value
	- Refine error string of "channle-use" parsing failed
	- Refine Kconfig help text


Changes in v2:
- In patch 01/15:
	- Add "unevaluatedProperties: false".
	- Delete "DT bindings".
	- Refine the description to fit in 80 columns.
	- Skip the connector description.
- In patch 02/15:
	- Refine items description of interrupt-name
	- Rename "usb-otg-vbus" to "usb-otg-vbus-regulator"
	- Add constraint properties for ADC
- In patch 03/15:
	- Skip not useful description of "^(multi-)?led@[0-3]$"
	  and reg.
	- Due to the dependency, remove the mention of mfd
	  document directory.
	- Delete Soft-start property. In design aspect, we think
	  soft-restart should always be enabled, our new chip
	  has deleted the related setting register , also, we don’t
	  allow user adjust this parameter in this chip.
	- Refine the commit message.
- In patch 04/15:
	- Skip not useful description of "^led@[0-1]$" and reg.
	- Add apace after '#'.
	- Refine the commit message.
- In patch 05/15:
	- Remove "binding documentation" in subject title
	- Refine description of mt6370 backlight binding
	  document
	- Refine properties name(bled-pwm-hys-input-bit,
	  bled-ovp-microvolt, bled-ocp-microamp) and their
	  description
- In patch 06/15:
	- Refine ADC and Regulator descriptions
	- Refine include header usage in example
	- Refine node name to generic node name("pmic@34")
	- Refine led example indentation
	- Refine license of mediatek,mt6370_adc.h
	- Rename the dts example from IRQ define to number.
	- Remove mediatek,mt6370.h
- In patch 07/15:
	- Add ABI documentation for mt6370 non-standard ADC
	  sysfs interfaces.
- In patch 08/15:
	- Add all IRQ define into mt6370.c.
	- Refine include header usage
- In patch 09/15:
	- No changes.
- In patch 10/15:
	- Use 'gpiod_get_from_of_node' to replace
	  'fwnode_gpiod_get_index'.
- In patch 11/15:
	- Refine Kconfig mt6370 help text
	- Refine mask&shift to FIELD_PREP()
	- Refine mutex lock name ("lock" -> "adc_lock")
	- Refine mt6370_adc_read_scale()
	- Refine mt6370_adc_read_offset()
	- Refine mt6370_channel_labels[] by using enum to index
	  chan spec
	- Refine MT6370_ADC_CHAN()
	- Refine indio_dev->name
	- Remove useless include header files
- In patch 12/15:
	- Refine mt6370_chg_otg_rdesc.of_match
	  ("mt6370,otg-vbus" -> "usb-otg-vbus-regulator") to match
	  DT binding
- In patch 13/15:
	- Refine Kconfig description.
	- Remove include "linux/of.h" and use
	  "linux/mod_devicetable.h".
	- Place a comma for the last element of the const
	  unsigned int array.
	- Add a comment line for the mutex 'lock'.
	- In probe function, use 'dev_err_probe' in some
	  judgement to reduce the LOC.
	- Refine include header usage.
	  BIT/GENMASK -> linux/bits.h
	  FIELD_GET -> linux/bitfield.h
- In patch 14/15:
	- Add blank line.
	- Replace container_of() with to_mt6370_led() .
	- Refine description of ramping.
	- Refine the mt6370_init_common_properties function.
	- Refine the probe return.
- In patch 15/15:
	- Refine MT6370 help text in Kconfig
	- Refine DT Parse function
	- Remove useless enum
	- Add comment for 6372 backward compatible in
	  bl_update_status() and
	  check_vendor_info()
	- Using dev_err_probe(); insteads dev_err()&return; in
	  the probe()

Alice Chen (2):
  dt-bindings: leds: Add MediaTek MT6370 flashlight
  leds: flash: mt6370: Add MediaTek MT6370 flashlight support

ChiYuan Huang (7):
  dt-bindings: usb: Add MediaTek MT6370 TCPC
  dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED
    indicator
  dt-bindings: backlight: Add MediaTek MT6370 backlight
  dt-bindings: mfd: Add MediaTek MT6370
  mfd: mt6370: Add MediaTek MT6370 support
  usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator
    support

ChiaEn Wu (4):
  dt-bindings: power: supply: Add MediaTek MT6370 Charger
  iio: adc: mt6370: Add MediaTek MT6370 support
  power: supply: mt6370: Add MediaTek MT6370 charger driver
  video: backlight: mt6370: Add MediaTek MT6370 support

 .../leds/backlight/mediatek,mt6370-backlight.yaml  |   92 ++
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  |   41 +
 .../bindings/leds/mediatek,mt6370-indicator.yaml   |   81 ++
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   |  280 ++++++
 .../power/supply/mediatek,mt6370-charger.yaml      |   88 ++
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         |   36 +
 drivers/iio/adc/Kconfig                            |   12 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6370-adc.c                       |  274 ++++++
 drivers/leds/flash/Kconfig                         |   12 +
 drivers/leds/flash/Makefile                        |    1 +
 drivers/leds/flash/leds-mt6370-flash.c             |  633 ++++++++++++
 drivers/leds/rgb/Kconfig                           |   13 +
 drivers/leds/rgb/Makefile                          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c                 | 1004 ++++++++++++++++++++
 drivers/mfd/Kconfig                                |   16 +
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/mt6370.c                               |  281 ++++++
 drivers/mfd/mt6370.h                               |   99 ++
 drivers/power/supply/Kconfig                       |   14 +
 drivers/power/supply/Makefile                      |    1 +
 drivers/power/supply/mt6370-charger.c              |  973 +++++++++++++++++++
 drivers/usb/typec/tcpm/Kconfig                     |   11 +
 drivers/usb/typec/tcpm/Makefile                    |    1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c              |  208 ++++
 drivers/video/backlight/Kconfig                    |   12 +
 drivers/video/backlight/Makefile                   |    1 +
 drivers/video/backlight/mt6370-backlight.c         |  339 +++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |   18 +
 29 files changed, 4544 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
 create mode 100644 drivers/iio/adc/mt6370-adc.c
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h
 create mode 100644 drivers/power/supply/mt6370-charger.c
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
 create mode 100644 drivers/video/backlight/mt6370-backlight.c
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 154+ messages in thread

* [PATCH v6 00/13] Add MediaTek MT6370 PMIC support
@ 2022-07-22 10:23 ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

This patch series add MediaTek MT6370 PMIC support. The MT6370 is a
highly-integrated smart power management IC, which includes a single
cell Li-Ion/Li-Polymer switching battery charger, a USB
Type-C & Power Delivery (PD) controller, dual Flash LED current sources,
a RGB LED driver, a backlight WLED driver, a display bias driver and a
general LDO for portable devices.

In this series of patches, we based on Andy Shevchenko's mfd patch used to
adjust the Makefile order.
(https://lore.kernel.org/all/20220616182524.7956-2-andriy.shevchenko@linux.intel.com/)
Among with this, we took some changes for MT6370 and refined the MT6370 device
tree files to comply with DT specifications.

"[PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370" depends on previous
DT binding patches, so before applying this patch, please apply other DT
patches first. Thanks!

Thank you,
ChiaEn Wu

---
Changes in v6:
- In Patch 03/13:
	- Add 'reg' property of led of multi-led to prevent checking
	  error.

- In Patch 08/13:
	- Convert tcpci as device resource managed with
	   'devm_add_action_or_reset' api.
	- Refine remvoe callback.
	- Refine the commit text from 'this commit add' to 'add'.

- In Patch 09/13:
	- Using 'struct device *dev = &pdev->dev' in probe()
	- Revise the sixth parameter of regmap_read_poll_timeout() by
	   replacing '1000' with 'MILLI'
	- Revise the units of three macros
	- MT6370_AICR_400MA --> MT6370_AICR_400_mA
	- MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
	- MT6370_ICHG_900MA --> MT6370_ICHG_900_mA

- In patch 10/13:
	- Remove the varable (*psy_desc) of struct mt6370_priv
	- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
	   POWER_SUPPLY_TYPE_USB_DCP)
	- Remove useless remove()
	- Revise all units from mini- to micro-
	- Revise get/set power_supply_prop (change to directly return get/set
	   regmap_field)
	- Revise probe() and use devm_add_action_or_reset() for handling of the
	   workqueue/delayed_work/mutex
	- Revise mt6370_chg_psy_desc
	   - Add '.name = "mt6370-charger"'
	   - Use 'static const'

- In patch 11/13:
	- Remove the 'ko' from mt6370 led Kconfig description.
	- Add both authors for Alice and ChiYuan.
	- Use pdata to distinguish the code from mt6370/71 to mt6372.
	- Instead of 'state' define, use the 'state' enum.
	- Fix the typo for 'MT6372_PMW_DUTY'.
	- For pwm_duty define, replace with bit macro - 1.
	- Refine all the labels from 'out' to 'out_unlock'.
	- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
	- Revise for the array initialization from {0} to {}.
	- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
	- Refine the 'comma' usage in struct/enum.

- In patch 12/13:
	- Use 'GENMASK' instead of 'BIT'.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine the return of _mt6370_flash_brightness_set function.
	- Refine the descriptions.
	- Use mt6370_clamp() instead of clamp_align().
	- Use device resource managed API for v4l2 flash_release.


Changes in v5:
- In patch 07/13:
	- Add the comma in the last REGMAP_IRQ_REG_LINE(),
	   DEFINE_RES_IRQ_NAMED() and MFD_CELL_RES()
	- Add the prefix in the first parameter of all mfd_cell
	- Move enum and struct mt6370_info to mt6370.h
	- Remove struct device *dev in struct mt6370_info
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 08/13:
	- Add comma for the last index of mt6370_reg_init.
	- Use dev_err_probe to decrease LOC.
	- Use 'dev' variable to make probe function more clean.
	- Refine kconfig text.
	- Remove both 'else' in set_vbus callback.
	- Remove comma for of_device_id if the assigned member is only one.

- In patch 09/13:
	- Replace using snprintf() with sysfs_emit() in mt6370_adc_read_label()
	- Remove macro ADC_CONV_TIME_US
	- Revise all variable ordering
	- Revise the description of Kconfig help text
	- Revise MODULE_DESCRIPTION()

- In patch 10/13:
	- Replace unsigned int type of pwr_rdy with bool in
	   mt6370_chg_set_online()
	- Remove redundant 'else' in mt6370_chg_field_get()
	- Revise 'if-else' in mt6370_chg_field_set()
	- Revise 'if' condition in mt6370_chg_enable_irq()
	- Revise all text 'otg' --> 'OTG'
	- Revise MT6370_MIVR_IBUS_TH_100_MA --> MT6370_MIVR_IBUS_TH_100_mA
	- Revise the description of Kconfig help text

- In patch 12/13:
	- Refine the coding style.
	- Use "dev" instead of "&pdev->dev".

- In patch 13/13:
	- Add missed <mod_devicetable.h>
	- Add struct device *dev in probe() to make code cleaning
	- Remove useless including header file <gpio/driver.h>, <of.h>
	- Remove useless variable uasage in mt6370_init_backlight_properties()
	- Remove redundant checking enable_gpio in mt6370_bl_update_status()
	- Remove redundant parentheses in mt6370_bl_get_brightness()
	- Revise the description of Kconfig help text
	- Revise the calculation of hys_th_steps


Changes in v4:
- In patch 02/13:
	- Add minItems of "io-channel-names"
	- Replace text "Mediatek" with "MediaTek"

- In patch 06/13:
	- Roll back all "$ref: " to v2 patch style (using "/schemas/...")

- In patch 07/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first break and then return" with "return directly"
	   in "mt6370_check_vendor_info()"
	- Add module name related description in Kconfig helptext
	- Add Copyright in the source code
	- Add header file "mt6370.h" for all "#define IRQ"
	- Adjust Makefile order of MT6370
	- Refine "bank_idx" and "bank_addr" in
	  "mt6375_regmap_read()" / "mt6375_regmap_write()"
	- Refine redundant "else if" in "mt6370_regmap_read()"

- In patch 08/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace "first ret=regulator_(dis/en)able and then return"
	   with "return directly" in "mt6370_tcpc_set_vbus()"
	- Replace header file <linux/of.h> with <linux/mod_devicetable.h>
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Remove header file <linux/of.h>
	- Refine all probe error by using dev_err_probe()

- In patch 09/13:
	- Replace text "Mediatek" with "MediaTek"
	- Replace all "first dev_err() and then return" with
	   "return dev_err_probe()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig
	- Add unit suffix of macro "ADC_CONV_POLLING_TIME"
	- Add new macro "ADC_CONV_TIME_MS"
	- Adjust the position of include file <mediatek,mt6370_adc.h>
	- Adjust the postions between <linux/module.h> and
	   <linux/mod_devicetable.h>
	- Fix some incorrect characters

- In patch 10/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig and
	   MODULE_DESCRIPTION()
	- Replace "mt6370_chg_val_to_reg" and "mt6370_chg_reg_to_val"
	   with "linear_range" API
	- Replace "first break and then return" with "return directly"
	   in all cases of get/set power_supply_property
	- Replace all "first dev_err() and then return" with "return
	   dev_err_probe()"
	- Replace all "return IS_ERR(priv->rdev) ? PTR_ERR(priv->rdev) : 0"
	   with "PTR_ERR_OR_ZERO()"
	- Replace "priv->dev->of_node" with "dev_of_node()"
	- Add Copyright in the source code
	- Add module name related description in Kconfig helptext
	- Add proper unit of "MT6370_MIVR_IBUS_TH"
	- Add error check in "mt6370_chg_get_status"
	- Remove including <mediatek,mt6370_adc.h> header file
	- Remove redundant comma of every enum terminator line
	- Remove unwanted blank lines
	- Remove the useless label (toggle_cfo_exit:)
	- Remove using atomic
	- Remove using of_match_ptr()
	- Fix some incorrect characters
	- Fix updating wrong bits when using ena_gpiod of OTG regulator
	- Adjust the probe order in probe()

- In patch 11/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Replace text "const" with "constant" in Kconfig
	- Add Copyright in the source code

- In patch 12/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code

- In patch 13/13:
	- Replace text "Mediatek" with "MediaTek" in Kconfig
	- Add Copyright in the source code
	- Revise the comment of "PWM HYS STEPS"


Changes in v3:
- Remove ADC ABI file, which is added in v2 Patch 7
- In patch 02/14:
	- Add items and remove maxItems of io-channels
	- Add io-channel-names and describe each item
	- Add "unevaluatedProperties: false" in "usb-otg-vbus-regulator"
	- Rename "enable-gpio" to "enable-gpios" in "usb-otg-vbus-regulator"
- In patch 03/14:
	- Use leds-class-multicolor.yaml instead of common.yaml.
	- Split multi-led and led node.
	- Add subdevice "led" in "multi-led".
- In patch 04/14:
	- Remove the description of enum.
- In patch 05/14:
	- Rename "mediatek,bled-pwm-hys-input-threshold-steps" to
	  "mediatek,bled-pwm-hys-input-th-steps"
	- Refine "bled-pwm-hys-input-th-steps", "bled-ovp-microvolt",
	  "bled-ocp-microamp" enum values
- In patch 06/14:
	- Use " in entire patchset
	- Refine ADC description
	- Rename "enable-gpio" to "enable-gpios" in "regualtor"
- In patch 07/14:
	- Refine Kconfig help text
	- Refine error message of unknown vendor ID in
	  mt6370_check_vendor_info()
	- Refine return value handling of mt6370_regmap_read()
	- Refine all probe error by using dev_err_probe()
	- Refine "bank_idx" and "bank_addr" in mt6370_regmap_read() and
	  mt6370_regmap_write()
	- Add "#define VENID*" and drop the comments in
	  mt6370_check_vendor_info()
	- Drop "MFD" in MODULE_DESCRIPTION()
- In patch 09/14:
	- Refine Kconfig help text
- In patch 10/14:
	- Refine Kconfig help text
	- Refine all channel value in read_scale()
		a. current: uA --> mA
		b. voltage: uV --> mV
		c. temperature: degrees Celsius --> milli degrees Celsius
	- Add "default:" condition of switch statement in read_scale() and read_raw()
	- Add error message for reading ADC register failed
	- Add the comment for adc_lock
	- Add <linux/mod_devicetable.h> header file for struct of_device_id
	- Replace "adc" text with "ADC" in all of the error messages
- In patch 12/14:
	- Refine the grammer of the Kconfig.
	- Change reg mode to the const current mode.
- In patch 14/14:
	- Refine bool properties parsing (pwm-enable, ovp-shutdown, ocp-shutdown) in DT
	  parsing function
	- Refine u32 and u8 properties parsing (pwm-hys-input-th-steps, ovp-microvolt,
	  ocp-microamp), from using register value to using actual value
	- Refine error string of "channle-use" parsing failed
	- Refine Kconfig help text


Changes in v2:
- In patch 01/15:
	- Add "unevaluatedProperties: false".
	- Delete "DT bindings".
	- Refine the description to fit in 80 columns.
	- Skip the connector description.
- In patch 02/15:
	- Refine items description of interrupt-name
	- Rename "usb-otg-vbus" to "usb-otg-vbus-regulator"
	- Add constraint properties for ADC
- In patch 03/15:
	- Skip not useful description of "^(multi-)?led@[0-3]$"
	  and reg.
	- Due to the dependency, remove the mention of mfd
	  document directory.
	- Delete Soft-start property. In design aspect, we think
	  soft-restart should always be enabled, our new chip
	  has deleted the related setting register , also, we don’t
	  allow user adjust this parameter in this chip.
	- Refine the commit message.
- In patch 04/15:
	- Skip not useful description of "^led@[0-1]$" and reg.
	- Add apace after '#'.
	- Refine the commit message.
- In patch 05/15:
	- Remove "binding documentation" in subject title
	- Refine description of mt6370 backlight binding
	  document
	- Refine properties name(bled-pwm-hys-input-bit,
	  bled-ovp-microvolt, bled-ocp-microamp) and their
	  description
- In patch 06/15:
	- Refine ADC and Regulator descriptions
	- Refine include header usage in example
	- Refine node name to generic node name("pmic@34")
	- Refine led example indentation
	- Refine license of mediatek,mt6370_adc.h
	- Rename the dts example from IRQ define to number.
	- Remove mediatek,mt6370.h
- In patch 07/15:
	- Add ABI documentation for mt6370 non-standard ADC
	  sysfs interfaces.
- In patch 08/15:
	- Add all IRQ define into mt6370.c.
	- Refine include header usage
- In patch 09/15:
	- No changes.
- In patch 10/15:
	- Use 'gpiod_get_from_of_node' to replace
	  'fwnode_gpiod_get_index'.
- In patch 11/15:
	- Refine Kconfig mt6370 help text
	- Refine mask&shift to FIELD_PREP()
	- Refine mutex lock name ("lock" -> "adc_lock")
	- Refine mt6370_adc_read_scale()
	- Refine mt6370_adc_read_offset()
	- Refine mt6370_channel_labels[] by using enum to index
	  chan spec
	- Refine MT6370_ADC_CHAN()
	- Refine indio_dev->name
	- Remove useless include header files
- In patch 12/15:
	- Refine mt6370_chg_otg_rdesc.of_match
	  ("mt6370,otg-vbus" -> "usb-otg-vbus-regulator") to match
	  DT binding
- In patch 13/15:
	- Refine Kconfig description.
	- Remove include "linux/of.h" and use
	  "linux/mod_devicetable.h".
	- Place a comma for the last element of the const
	  unsigned int array.
	- Add a comment line for the mutex 'lock'.
	- In probe function, use 'dev_err_probe' in some
	  judgement to reduce the LOC.
	- Refine include header usage.
	  BIT/GENMASK -> linux/bits.h
	  FIELD_GET -> linux/bitfield.h
- In patch 14/15:
	- Add blank line.
	- Replace container_of() with to_mt6370_led() .
	- Refine description of ramping.
	- Refine the mt6370_init_common_properties function.
	- Refine the probe return.
- In patch 15/15:
	- Refine MT6370 help text in Kconfig
	- Refine DT Parse function
	- Remove useless enum
	- Add comment for 6372 backward compatible in
	  bl_update_status() and
	  check_vendor_info()
	- Using dev_err_probe(); insteads dev_err()&return; in
	  the probe()

Alice Chen (2):
  dt-bindings: leds: Add MediaTek MT6370 flashlight
  leds: flash: mt6370: Add MediaTek MT6370 flashlight support

ChiYuan Huang (7):
  dt-bindings: usb: Add MediaTek MT6370 TCPC
  dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED
    indicator
  dt-bindings: backlight: Add MediaTek MT6370 backlight
  dt-bindings: mfd: Add MediaTek MT6370
  mfd: mt6370: Add MediaTek MT6370 support
  usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator
    support

ChiaEn Wu (4):
  dt-bindings: power: supply: Add MediaTek MT6370 Charger
  iio: adc: mt6370: Add MediaTek MT6370 support
  power: supply: mt6370: Add MediaTek MT6370 charger driver
  video: backlight: mt6370: Add MediaTek MT6370 support

 .../leds/backlight/mediatek,mt6370-backlight.yaml  |   92 ++
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  |   41 +
 .../bindings/leds/mediatek,mt6370-indicator.yaml   |   81 ++
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   |  280 ++++++
 .../power/supply/mediatek,mt6370-charger.yaml      |   88 ++
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         |   36 +
 drivers/iio/adc/Kconfig                            |   12 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/mt6370-adc.c                       |  274 ++++++
 drivers/leds/flash/Kconfig                         |   12 +
 drivers/leds/flash/Makefile                        |    1 +
 drivers/leds/flash/leds-mt6370-flash.c             |  633 ++++++++++++
 drivers/leds/rgb/Kconfig                           |   13 +
 drivers/leds/rgb/Makefile                          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c                 | 1004 ++++++++++++++++++++
 drivers/mfd/Kconfig                                |   16 +
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/mt6370.c                               |  281 ++++++
 drivers/mfd/mt6370.h                               |   99 ++
 drivers/power/supply/Kconfig                       |   14 +
 drivers/power/supply/Makefile                      |    1 +
 drivers/power/supply/mt6370-charger.c              |  973 +++++++++++++++++++
 drivers/usb/typec/tcpm/Kconfig                     |   11 +
 drivers/usb/typec/tcpm/Makefile                    |    1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c              |  208 ++++
 drivers/video/backlight/Kconfig                    |   12 +
 drivers/video/backlight/Makefile                   |    1 +
 drivers/video/backlight/mt6370-backlight.c         |  339 +++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |   18 +
 29 files changed, 4544 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
 create mode 100644 drivers/iio/adc/mt6370-adc.c
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h
 create mode 100644 drivers/power/supply/mt6370-charger.c
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
 create mode 100644 drivers/video/backlight/mt6370-backlight.c
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* [PATCH v6 01/13] dt-bindings: usb: Add MediaTek MT6370 TCPC
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:23   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 TCPC binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml

diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
new file mode 100644
index 0000000..72f56cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MediaTek MT6370 is a multi-functional device.
+  It integrates charger, ADC, flash, RGB indicators,
+  regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller.
+  This document only describes MT6370 Type-C Port Switch and
+  Power Delivery controller.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6370-tcpc
+
+  interrupts:
+    maxItems: 1
+
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - interrupts
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 01/13] dt-bindings: usb: Add MediaTek MT6370 TCPC
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	Krzysztof Kozlowski, chiaen_wu, linux-mediatek, linux-arm-kernel,
	linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 TCPC binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml

diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
new file mode 100644
index 0000000..72f56cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MediaTek MT6370 is a multi-functional device.
+  It integrates charger, ADC, flash, RGB indicators,
+  regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller.
+  This document only describes MT6370 Type-C Port Switch and
+  Power Delivery controller.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6370-tcpc
+
+  interrupts:
+    maxItems: 1
+
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - interrupts
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 01/13] dt-bindings: usb: Add MediaTek MT6370 TCPC
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 TCPC binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/usb/mediatek,mt6370-tcpc.yaml         | 36 ++++++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml

diff --git a/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
new file mode 100644
index 0000000..72f56cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/mediatek,mt6370-tcpc.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/usb/mediatek,mt6370-tcpc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: MediatTek MT6370 Type-C Port Switch and Power Delivery controller
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MediaTek MT6370 is a multi-functional device.
+  It integrates charger, ADC, flash, RGB indicators,
+  regulators (DSV/VIBLDO), and TypeC Port Switch with Power Delivery controller.
+  This document only describes MT6370 Type-C Port Switch and
+  Power Delivery controller.
+
+properties:
+  compatible:
+    enum:
+      - mediatek,mt6370-tcpc
+
+  interrupts:
+    maxItems: 1
+
+  connector:
+    type: object
+    $ref: /schemas/connector/usb-connector.yaml#
+    unevaluatedProperties: false
+
+additionalProperties: false
+
+required:
+  - compatible
+  - interrupts
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 02/13] dt-bindings: power: supply: Add MediaTek MT6370 Charger
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:23   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiaEn Wu <chiaen_wu@richtek.com>

Add MediaTek MT6370 Charger binding documentation.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../power/supply/mediatek,mt6370-charger.yaml      | 88 ++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
new file mode 100644
index 0000000..bd09a0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Battery Charger
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Provides Battery Charger, Boost for OTG devices and BC1.2 detection.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-charger
+
+  interrupts:
+    description: |
+      Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ
+      "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D"
+      are required.
+    items:
+      - description: BC1.2 done irq
+      - description: usb plug in irq
+      - description: mivr irq
+
+  interrupt-names:
+    items:
+      - const: attach_i
+      - const: uvp_d_evt
+      - const: mivr
+
+  io-channels:
+    description: |
+      Use ADC channel to read VBUS, IBUS, IBAT, etc., info.
+    minItems: 1
+    items:
+      - description: |
+          VBUS voltage with lower accuracy (+-75mV) but higher measure
+          range (1~22V)
+      - description: |
+          VBUS voltage with higher accuracy (+-30mV) but lower measure
+          range (1~9.76V)
+      - description: the main system input voltage
+      - description: battery voltage
+      - description: battery temperature-sense input voltage
+      - description: IBUS current (required)
+      - description: battery current
+      - description: |
+          regulated output voltage to supply for the PWM low-side gate driver
+          and the bootstrap capacitor
+      - description: IC junction temperature
+
+  io-channel-names:
+    minItems: 1
+    items:
+      - const: vbusdiv5
+      - const: vbusdiv2
+      - const: vsys
+      - const: vbat
+      - const: ts_bat
+      - const: ibus
+      - const: ibat
+      - const: chg_vddp
+      - const: temp_jc
+
+  usb-otg-vbus-regulator:
+    type: object
+    description: OTG boost regulator.
+    unevaluatedProperties: false
+    $ref: /schemas/regulator/regulator.yaml#
+
+    properties:
+      enable-gpios:
+        maxItems: 1
+
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - io-channels
+
+additionalProperties: false
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 02/13] dt-bindings: power: supply: Add MediaTek MT6370 Charger
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	Krzysztof Kozlowski, chiaen_wu, linux-mediatek, linux-arm-kernel,
	linux-leds

From: ChiaEn Wu <chiaen_wu@richtek.com>

Add MediaTek MT6370 Charger binding documentation.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../power/supply/mediatek,mt6370-charger.yaml      | 88 ++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
new file mode 100644
index 0000000..bd09a0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Battery Charger
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Provides Battery Charger, Boost for OTG devices and BC1.2 detection.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-charger
+
+  interrupts:
+    description: |
+      Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ
+      "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D"
+      are required.
+    items:
+      - description: BC1.2 done irq
+      - description: usb plug in irq
+      - description: mivr irq
+
+  interrupt-names:
+    items:
+      - const: attach_i
+      - const: uvp_d_evt
+      - const: mivr
+
+  io-channels:
+    description: |
+      Use ADC channel to read VBUS, IBUS, IBAT, etc., info.
+    minItems: 1
+    items:
+      - description: |
+          VBUS voltage with lower accuracy (+-75mV) but higher measure
+          range (1~22V)
+      - description: |
+          VBUS voltage with higher accuracy (+-30mV) but lower measure
+          range (1~9.76V)
+      - description: the main system input voltage
+      - description: battery voltage
+      - description: battery temperature-sense input voltage
+      - description: IBUS current (required)
+      - description: battery current
+      - description: |
+          regulated output voltage to supply for the PWM low-side gate driver
+          and the bootstrap capacitor
+      - description: IC junction temperature
+
+  io-channel-names:
+    minItems: 1
+    items:
+      - const: vbusdiv5
+      - const: vbusdiv2
+      - const: vsys
+      - const: vbat
+      - const: ts_bat
+      - const: ibus
+      - const: ibat
+      - const: chg_vddp
+      - const: temp_jc
+
+  usb-otg-vbus-regulator:
+    type: object
+    description: OTG boost regulator.
+    unevaluatedProperties: false
+    $ref: /schemas/regulator/regulator.yaml#
+
+    properties:
+      enable-gpios:
+        maxItems: 1
+
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - io-channels
+
+additionalProperties: false
+
+...
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 02/13] dt-bindings: power: supply: Add MediaTek MT6370 Charger
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiaEn Wu <chiaen_wu@richtek.com>

Add MediaTek MT6370 Charger binding documentation.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../power/supply/mediatek,mt6370-charger.yaml      | 88 ++++++++++++++++++++++
 1 file changed, 88 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml

diff --git a/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
new file mode 100644
index 0000000..bd09a0a
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/supply/mediatek,mt6370-charger.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/power/supply/mediatek,mt6370-charger.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Battery Charger
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Provides Battery Charger, Boost for OTG devices and BC1.2 detection.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-charger
+
+  interrupts:
+    description: |
+      Specify what irqs are needed to be handled by MT6370 Charger driver. IRQ
+      "MT6370_IRQ_CHG_MIVR", "MT6370_IRQ_ATTACH" and "MT6370_IRQ_OVPCTRL_UVP_D"
+      are required.
+    items:
+      - description: BC1.2 done irq
+      - description: usb plug in irq
+      - description: mivr irq
+
+  interrupt-names:
+    items:
+      - const: attach_i
+      - const: uvp_d_evt
+      - const: mivr
+
+  io-channels:
+    description: |
+      Use ADC channel to read VBUS, IBUS, IBAT, etc., info.
+    minItems: 1
+    items:
+      - description: |
+          VBUS voltage with lower accuracy (+-75mV) but higher measure
+          range (1~22V)
+      - description: |
+          VBUS voltage with higher accuracy (+-30mV) but lower measure
+          range (1~9.76V)
+      - description: the main system input voltage
+      - description: battery voltage
+      - description: battery temperature-sense input voltage
+      - description: IBUS current (required)
+      - description: battery current
+      - description: |
+          regulated output voltage to supply for the PWM low-side gate driver
+          and the bootstrap capacitor
+      - description: IC junction temperature
+
+  io-channel-names:
+    minItems: 1
+    items:
+      - const: vbusdiv5
+      - const: vbusdiv2
+      - const: vsys
+      - const: vbat
+      - const: ts_bat
+      - const: ibus
+      - const: ibat
+      - const: chg_vddp
+      - const: temp_jc
+
+  usb-otg-vbus-regulator:
+    type: object
+    description: OTG boost regulator.
+    unevaluatedProperties: false
+    $ref: /schemas/regulator/regulator.yaml#
+
+    properties:
+      enable-gpios:
+        maxItems: 1
+
+required:
+  - compatible
+  - interrupts
+  - interrupt-names
+  - io-channels
+
+additionalProperties: false
+
+...
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 03/13] dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED indicator
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:23   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 current sink type LED indicator binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---

v6
- Add 'reg' property of led of multi-led to prevent checking error.
---
 .../bindings/leds/mediatek,mt6370-indicator.yaml   | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
new file mode 100644
index 0000000..204b103
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-indicator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode
+
+allOf:
+  - $ref: leds-class-multicolor.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-indicator
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^multi-led@[0-3]$":
+    type: object
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-2]$":
+        type: object
+        $ref: common.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          reg:
+            enum: [0, 1, 2]
+
+        required:
+          - reg
+          - color
+
+    required:
+      - reg
+      - color
+      - "#address-cells"
+      - "#size-cells"
+
+  "^led@[0-3]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+    required:
+      - reg
+      - color
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 03/13] dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED indicator
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	Krzysztof Kozlowski, chiaen_wu, linux-mediatek, linux-arm-kernel,
	linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 current sink type LED indicator binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---

v6
- Add 'reg' property of led of multi-led to prevent checking error.
---
 .../bindings/leds/mediatek,mt6370-indicator.yaml   | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
new file mode 100644
index 0000000..204b103
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-indicator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode
+
+allOf:
+  - $ref: leds-class-multicolor.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-indicator
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^multi-led@[0-3]$":
+    type: object
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-2]$":
+        type: object
+        $ref: common.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          reg:
+            enum: [0, 1, 2]
+
+        required:
+          - reg
+          - color
+
+    required:
+      - reg
+      - color
+      - "#address-cells"
+      - "#size-cells"
+
+  "^led@[0-3]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+    required:
+      - reg
+      - color
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 03/13] dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED indicator
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 current sink type LED indicator binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---

v6
- Add 'reg' property of led of multi-led to prevent checking error.
---
 .../bindings/leds/mediatek,mt6370-indicator.yaml   | 81 ++++++++++++++++++++++
 1 file changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
new file mode 100644
index 0000000..204b103
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-indicator.yaml
@@ -0,0 +1,81 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-indicator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 LED driver include 4-channel RGB LED support Register/PWM/Breath Mode
+
+allOf:
+  - $ref: leds-class-multicolor.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-indicator
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^multi-led@[0-3]$":
+    type: object
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+    patternProperties:
+      "^led@[0-2]$":
+        type: object
+        $ref: common.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          reg:
+            enum: [0, 1, 2]
+
+        required:
+          - reg
+          - color
+
+    required:
+      - reg
+      - color
+      - "#address-cells"
+      - "#size-cells"
+
+  "^led@[0-3]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1, 2, 3]
+
+    required:
+      - reg
+      - color
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:23   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: Alice Chen <alice_chen@richtek.com>

Add MediaTek MT6370 flashlight binding documentation.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
new file mode 100644
index 0000000..e9d02ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-flashlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Flash LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 flash LED driver include 2-channel flash LED support Torch/Strobe Mode.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-flashlight
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^led@[0-1]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1]
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	Krzysztof Kozlowski, chiaen_wu, linux-mediatek, linux-arm-kernel,
	linux-leds

From: Alice Chen <alice_chen@richtek.com>

Add MediaTek MT6370 flashlight binding documentation.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
new file mode 100644
index 0000000..e9d02ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-flashlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Flash LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 flash LED driver include 2-channel flash LED support Torch/Strobe Mode.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-flashlight
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^led@[0-1]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1]
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: Alice Chen <alice_chen@richtek.com>

Add MediaTek MT6370 flashlight binding documentation.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../bindings/leds/mediatek,mt6370-flashlight.yaml  | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
new file mode 100644
index 0000000..e9d02ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/mediatek,mt6370-flashlight.yaml
@@ -0,0 +1,41 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/mediatek,mt6370-flashlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Flash LED driver for MT6370 PMIC from MediaTek Integrated.
+
+maintainers:
+  - Alice Chen <alice_chen@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  Add MT6370 flash LED driver include 2-channel flash LED support Torch/Strobe Mode.
+
+properties:
+  compatible:
+    const: mediatek,mt6370-flashlight
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^led@[0-1]$":
+    type: object
+    $ref: common.yaml#
+    unevaluatedProperties: false
+
+    properties:
+      reg:
+        enum: [0, 1]
+
+required:
+  - compatible
+  - "#address-cells"
+  - "#size-cells"
+
+additionalProperties: false
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:23   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

Add MT6370 backlight binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../leds/backlight/mediatek,mt6370-backlight.yaml  | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
new file mode 100644
index 0000000..d674212
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Backlight
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  The MT6370 Backlight WLED driver supports up to a 29V output voltage for
+  4 channels of 8 series WLEDs. Each channel supports up to 30mA of current
+  capability with 2048 current steps (11 bits) in exponential or linear
+  mapping curves.
+
+allOf:
+  - $ref: common.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-backlight
+
+  default-brightness:
+    minimum: 0
+    maximum: 2048
+
+  max-brightness:
+    minimum: 0
+    maximum: 2048
+
+  enable-gpios:
+    description: External backlight 'enable' pin
+    maxItems: 1
+
+  mediatek,bled-pwm-enable:
+    description: |
+      Enable external PWM input for backlight dimming
+    type: boolean
+
+  mediatek,bled-pwm-hys-enable:
+    description: |
+      Enable the backlight input-hysteresis for PWM mode
+    type: boolean
+
+  mediatek,bled-pwm-hys-input-th-steps:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    enum: [1, 4, 16, 64]
+    description: |
+      The selection of the upper and lower bounds threshold of backlight
+      PWM resolution. If we choose selection 64, the variation of PWM
+      resolution needs more than 64 steps.
+
+  mediatek,bled-ovp-shutdown:
+    description: |
+      Enable the backlight shutdown when OVP level triggered
+    type: boolean
+
+  mediatek,bled-ovp-microvolt:
+    enum: [17000000, 21000000, 25000000, 29000000]
+    description: |
+      Backlight OVP level selection.
+
+  mediatek,bled-ocp-shutdown:
+    description: |
+      Enable the backlight shutdown when OCP level triggerred.
+    type: boolean
+
+  mediatek,bled-ocp-microamp:
+    enum: [900000, 1200000, 1500000, 1800000]
+    description: |
+      Backlight OC level selection.
+
+  mediatek,bled-channel-use:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      Backlight LED channel to be used.
+      Each bit mapping to:
+        - 0: CH4
+        - 1: CH3
+        - 2: CH2
+        - 3: CH1
+    minimum: 1
+    maximum: 15
+
+required:
+  - compatible
+  - mediatek,bled-channel-use
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Rob Herring

From: ChiYuan Huang <cy_huang@richtek.com>

Add MT6370 backlight binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../leds/backlight/mediatek,mt6370-backlight.yaml  | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
new file mode 100644
index 0000000..d674212
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Backlight
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  The MT6370 Backlight WLED driver supports up to a 29V output voltage for
+  4 channels of 8 series WLEDs. Each channel supports up to 30mA of current
+  capability with 2048 current steps (11 bits) in exponential or linear
+  mapping curves.
+
+allOf:
+  - $ref: common.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-backlight
+
+  default-brightness:
+    minimum: 0
+    maximum: 2048
+
+  max-brightness:
+    minimum: 0
+    maximum: 2048
+
+  enable-gpios:
+    description: External backlight 'enable' pin
+    maxItems: 1
+
+  mediatek,bled-pwm-enable:
+    description: |
+      Enable external PWM input for backlight dimming
+    type: boolean
+
+  mediatek,bled-pwm-hys-enable:
+    description: |
+      Enable the backlight input-hysteresis for PWM mode
+    type: boolean
+
+  mediatek,bled-pwm-hys-input-th-steps:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    enum: [1, 4, 16, 64]
+    description: |
+      The selection of the upper and lower bounds threshold of backlight
+      PWM resolution. If we choose selection 64, the variation of PWM
+      resolution needs more than 64 steps.
+
+  mediatek,bled-ovp-shutdown:
+    description: |
+      Enable the backlight shutdown when OVP level triggered
+    type: boolean
+
+  mediatek,bled-ovp-microvolt:
+    enum: [17000000, 21000000, 25000000, 29000000]
+    description: |
+      Backlight OVP level selection.
+
+  mediatek,bled-ocp-shutdown:
+    description: |
+      Enable the backlight shutdown when OCP level triggerred.
+    type: boolean
+
+  mediatek,bled-ocp-microamp:
+    enum: [900000, 1200000, 1500000, 1800000]
+    description: |
+      Backlight OC level selection.
+
+  mediatek,bled-channel-use:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      Backlight LED channel to be used.
+      Each bit mapping to:
+        - 0: CH4
+        - 1: CH3
+        - 2: CH2
+        - 3: CH1
+    minimum: 1
+    maximum: 15
+
+required:
+  - compatible
+  - mediatek,bled-channel-use
+
+additionalProperties: false
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight
@ 2022-07-22 10:23   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:23 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Rob Herring

From: ChiYuan Huang <cy_huang@richtek.com>

Add MT6370 backlight binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../leds/backlight/mediatek,mt6370-backlight.yaml  | 92 ++++++++++++++++++++++
 1 file changed, 92 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml

diff --git a/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
new file mode 100644
index 0000000..d674212
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/backlight/mediatek,mt6370-backlight.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 Backlight
+
+maintainers:
+  - ChiaEn Wu <chiaen_wu@richtek.com>
+
+description: |
+  This module is part of the MT6370 MFD device.
+  The MT6370 Backlight WLED driver supports up to a 29V output voltage for
+  4 channels of 8 series WLEDs. Each channel supports up to 30mA of current
+  capability with 2048 current steps (11 bits) in exponential or linear
+  mapping curves.
+
+allOf:
+  - $ref: common.yaml#
+
+properties:
+  compatible:
+    const: mediatek,mt6370-backlight
+
+  default-brightness:
+    minimum: 0
+    maximum: 2048
+
+  max-brightness:
+    minimum: 0
+    maximum: 2048
+
+  enable-gpios:
+    description: External backlight 'enable' pin
+    maxItems: 1
+
+  mediatek,bled-pwm-enable:
+    description: |
+      Enable external PWM input for backlight dimming
+    type: boolean
+
+  mediatek,bled-pwm-hys-enable:
+    description: |
+      Enable the backlight input-hysteresis for PWM mode
+    type: boolean
+
+  mediatek,bled-pwm-hys-input-th-steps:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    enum: [1, 4, 16, 64]
+    description: |
+      The selection of the upper and lower bounds threshold of backlight
+      PWM resolution. If we choose selection 64, the variation of PWM
+      resolution needs more than 64 steps.
+
+  mediatek,bled-ovp-shutdown:
+    description: |
+      Enable the backlight shutdown when OVP level triggered
+    type: boolean
+
+  mediatek,bled-ovp-microvolt:
+    enum: [17000000, 21000000, 25000000, 29000000]
+    description: |
+      Backlight OVP level selection.
+
+  mediatek,bled-ocp-shutdown:
+    description: |
+      Enable the backlight shutdown when OCP level triggerred.
+    type: boolean
+
+  mediatek,bled-ocp-microamp:
+    enum: [900000, 1200000, 1500000, 1800000]
+    description: |
+      Backlight OC level selection.
+
+  mediatek,bled-channel-use:
+    $ref: /schemas/types.yaml#/definitions/uint8
+    description: |
+      Backlight LED channel to be used.
+      Each bit mapping to:
+        - 0: CH4
+        - 1: CH3
+        - 2: CH2
+        - 3: CH1
+    minimum: 1
+    maximum: 15
+
+required:
+  - compatible
+  - mediatek,bled-channel-use
+
+additionalProperties: false
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	Krzysztof Kozlowski, chiaen_wu, linux-mediatek, linux-arm-kernel,
	linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   | 280 +++++++++++++++++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |  18 ++
 2 files changed, 298 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
new file mode 100644
index 0000000..410e2d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
@@ -0,0 +1,280 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 SubPMIC
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MT6370 is a highly-integrated smart power management IC, which includes a
+  single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C &
+  Power Delivery (PD) controller, dual flash LED current sources, a RGB LED
+  driver, a backlight WLED driver, a display bias driver and a general LDO for
+  portable devices.
+
+properties:
+  compatible:
+    const: mediatek,mt6370
+
+  reg:
+    maxItems: 1
+
+  wakeup-source: true
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 1
+
+  adc:
+    type: object
+    description: |
+      Provides 9 channels for system monitoring, including VBUSDIV5 (lower
+      accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower
+      measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC.
+
+    properties:
+      compatible:
+        const: mediatek,mt6370-adc
+
+      "#io-channel-cells":
+        const: 1
+
+    required:
+      - compatible
+      - "#io-channel-cells"
+
+  backlight:
+    type: object
+    $ref: /schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+
+  charger:
+    type: object
+    $ref: /schemas/power/supply/mediatek,mt6370-charger.yaml#
+
+  tcpc:
+    type: object
+    $ref: /schemas/usb/mediatek,mt6370-tcpc.yaml#
+
+  indicator:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-indicator.yaml#
+
+  flashlight:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-flashlight.yaml#
+
+  regulators:
+    type: object
+    description: |
+      List all supported regulators, which support the control for DisplayBias
+      voltages and one general purpose LDO which commonly used to drive the
+      vibrator.
+
+    patternProperties:
+      "^(dsvbst|vibldo)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+      "^(dsvpos|dsvneg)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+        properties:
+          enable-gpios:
+            maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+  - regulators
+  - adc
+  - backlight
+  - indicator
+  - tcpc
+  - charger
+  - flashlight
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    #include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+    #include <dt-bindings/usb/pd.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+        pmic@34 {
+        compatible = "mediatek,mt6370";
+        reg = <0x34>;
+        wakeup-source;
+        interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+
+        mt6370_adc: adc {
+          compatible = "mediatek,mt6370-adc";
+          #io-channel-cells = <1>;
+        };
+
+        backlight {
+          compatible = "mediatek,mt6370-backlight";
+          mediatek,bled-channel-use = /bits/ 8 <15>;
+        };
+
+        charger {
+          compatible = "mediatek,mt6370-charger";
+          interrupts = <48>, <68>, <6>;
+          interrupt-names = "attach_i", "uvp_d_evt", "mivr";
+          io-channels = <&mt6370_adc MT6370_CHAN_IBUS>;
+
+          mt6370_otg_vbus: usb-otg-vbus-regulator {
+            regulator-name = "mt6370-usb-otg-vbus";
+            regulator-min-microvolt = <4350000>;
+            regulator-max-microvolt = <5800000>;
+            regulator-min-microamp = <500000>;
+            regulator-max-microamp = <3000000>;
+          };
+        };
+
+        indicator {
+          compatible = "mediatek,mt6370-indicator";
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          multi-led@0 {
+            reg = <0>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_RGB>;
+            led-max-microamp = <24000>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            led@0 {
+              reg = <0>;
+              color = <LED_COLOR_ID_RED>;
+            };
+            led@1 {
+              reg = <1>;
+              color = <LED_COLOR_ID_GREEN>;
+            };
+            led@2 {
+              reg = <2>;
+              color = <LED_COLOR_ID_BLUE>;
+            };
+          };
+          led@3 {
+            reg = <3>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_WHITE>;
+            led-max-microamp = <6000>;
+          };
+        };
+
+        flashlight {
+          compatible = "mediatek,mt6370-flashlight";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          led@0 {
+            reg = <0>;
+            led-sources = <0>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <1>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+          led@1 {
+            reg = <1>;
+            led-sources = <1>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <2>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+        };
+
+        tcpc {
+          compatible = "mediatek,mt6370-tcpc";
+          interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>;
+
+          connector {
+            compatible = "usb-c-connector";
+            label = "USB-C";
+            vbus-supply = <&mt6370_otg_vbus>;
+            data-role = "dual";
+            power-role = "dual";
+            try-power-role = "sink";
+            source-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            op-sink-microwatt = <10000000>;
+
+            ports {
+              #address-cells = <1>;
+              #size-cells = <0>;
+
+              port@0 {
+                reg = <0>;
+                endpoint {
+                  remote-endpoint = <&usb_hs>;
+                };
+              };
+              port@1 {
+                reg = <1>;
+                endpoint {
+                  remote-endpoint = <&usb_ss>;
+                };
+              };
+              port@2 {
+                reg = <2>;
+                endpoint {
+                  remote-endpoint = <&dp_aux>;
+                };
+              };
+            };
+          };
+        };
+
+        regulators {
+          dsvbst {
+            regulator-name = "mt6370-dsv-vbst";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6200000>;
+          };
+          dsvpos {
+            regulator-name = "mt6370-dsv-vpos";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          dsvneg {
+            regulator-name = "mt6370-dsv-vneg";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          vibldo {
+            regulator-name = "mt6370-vib-ldo";
+            regulator-min-microvolt = <1600000>;
+            regulator-max-microvolt = <4000000>;
+          };
+        };
+      };
+    };
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
new file mode 100644
index 0000000..6ee7255
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+
+/* ADC Channel Index */
+#define MT6370_CHAN_VBUSDIV5	0
+#define MT6370_CHAN_VBUSDIV2	1
+#define MT6370_CHAN_VSYS	2
+#define MT6370_CHAN_VBAT	3
+#define MT6370_CHAN_TS_BAT	4
+#define MT6370_CHAN_IBUS	5
+#define MT6370_CHAN_IBAT	6
+#define MT6370_CHAN_CHG_VDDP	7
+#define MT6370_CHAN_TEMP_JC	8
+#define MT6370_CHAN_MAX		9
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   | 280 +++++++++++++++++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |  18 ++
 2 files changed, 298 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
new file mode 100644
index 0000000..410e2d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
@@ -0,0 +1,280 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 SubPMIC
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MT6370 is a highly-integrated smart power management IC, which includes a
+  single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C &
+  Power Delivery (PD) controller, dual flash LED current sources, a RGB LED
+  driver, a backlight WLED driver, a display bias driver and a general LDO for
+  portable devices.
+
+properties:
+  compatible:
+    const: mediatek,mt6370
+
+  reg:
+    maxItems: 1
+
+  wakeup-source: true
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 1
+
+  adc:
+    type: object
+    description: |
+      Provides 9 channels for system monitoring, including VBUSDIV5 (lower
+      accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower
+      measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC.
+
+    properties:
+      compatible:
+        const: mediatek,mt6370-adc
+
+      "#io-channel-cells":
+        const: 1
+
+    required:
+      - compatible
+      - "#io-channel-cells"
+
+  backlight:
+    type: object
+    $ref: /schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+
+  charger:
+    type: object
+    $ref: /schemas/power/supply/mediatek,mt6370-charger.yaml#
+
+  tcpc:
+    type: object
+    $ref: /schemas/usb/mediatek,mt6370-tcpc.yaml#
+
+  indicator:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-indicator.yaml#
+
+  flashlight:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-flashlight.yaml#
+
+  regulators:
+    type: object
+    description: |
+      List all supported regulators, which support the control for DisplayBias
+      voltages and one general purpose LDO which commonly used to drive the
+      vibrator.
+
+    patternProperties:
+      "^(dsvbst|vibldo)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+      "^(dsvpos|dsvneg)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+        properties:
+          enable-gpios:
+            maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+  - regulators
+  - adc
+  - backlight
+  - indicator
+  - tcpc
+  - charger
+  - flashlight
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    #include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+    #include <dt-bindings/usb/pd.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+        pmic@34 {
+        compatible = "mediatek,mt6370";
+        reg = <0x34>;
+        wakeup-source;
+        interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+
+        mt6370_adc: adc {
+          compatible = "mediatek,mt6370-adc";
+          #io-channel-cells = <1>;
+        };
+
+        backlight {
+          compatible = "mediatek,mt6370-backlight";
+          mediatek,bled-channel-use = /bits/ 8 <15>;
+        };
+
+        charger {
+          compatible = "mediatek,mt6370-charger";
+          interrupts = <48>, <68>, <6>;
+          interrupt-names = "attach_i", "uvp_d_evt", "mivr";
+          io-channels = <&mt6370_adc MT6370_CHAN_IBUS>;
+
+          mt6370_otg_vbus: usb-otg-vbus-regulator {
+            regulator-name = "mt6370-usb-otg-vbus";
+            regulator-min-microvolt = <4350000>;
+            regulator-max-microvolt = <5800000>;
+            regulator-min-microamp = <500000>;
+            regulator-max-microamp = <3000000>;
+          };
+        };
+
+        indicator {
+          compatible = "mediatek,mt6370-indicator";
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          multi-led@0 {
+            reg = <0>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_RGB>;
+            led-max-microamp = <24000>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            led@0 {
+              reg = <0>;
+              color = <LED_COLOR_ID_RED>;
+            };
+            led@1 {
+              reg = <1>;
+              color = <LED_COLOR_ID_GREEN>;
+            };
+            led@2 {
+              reg = <2>;
+              color = <LED_COLOR_ID_BLUE>;
+            };
+          };
+          led@3 {
+            reg = <3>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_WHITE>;
+            led-max-microamp = <6000>;
+          };
+        };
+
+        flashlight {
+          compatible = "mediatek,mt6370-flashlight";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          led@0 {
+            reg = <0>;
+            led-sources = <0>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <1>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+          led@1 {
+            reg = <1>;
+            led-sources = <1>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <2>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+        };
+
+        tcpc {
+          compatible = "mediatek,mt6370-tcpc";
+          interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>;
+
+          connector {
+            compatible = "usb-c-connector";
+            label = "USB-C";
+            vbus-supply = <&mt6370_otg_vbus>;
+            data-role = "dual";
+            power-role = "dual";
+            try-power-role = "sink";
+            source-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            op-sink-microwatt = <10000000>;
+
+            ports {
+              #address-cells = <1>;
+              #size-cells = <0>;
+
+              port@0 {
+                reg = <0>;
+                endpoint {
+                  remote-endpoint = <&usb_hs>;
+                };
+              };
+              port@1 {
+                reg = <1>;
+                endpoint {
+                  remote-endpoint = <&usb_ss>;
+                };
+              };
+              port@2 {
+                reg = <2>;
+                endpoint {
+                  remote-endpoint = <&dp_aux>;
+                };
+              };
+            };
+          };
+        };
+
+        regulators {
+          dsvbst {
+            regulator-name = "mt6370-dsv-vbst";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6200000>;
+          };
+          dsvpos {
+            regulator-name = "mt6370-dsv-vpos";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          dsvneg {
+            regulator-name = "mt6370-dsv-vneg";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          vibldo {
+            regulator-name = "mt6370-vib-ldo";
+            regulator-min-microvolt = <1600000>;
+            regulator-max-microvolt = <4000000>;
+          };
+        };
+      };
+    };
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
new file mode 100644
index 0000000..6ee7255
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+
+/* ADC Channel Index */
+#define MT6370_CHAN_VBUSDIV5	0
+#define MT6370_CHAN_VBUSDIV2	1
+#define MT6370_CHAN_VSYS	2
+#define MT6370_CHAN_VBAT	3
+#define MT6370_CHAN_TS_BAT	4
+#define MT6370_CHAN_IBUS	5
+#define MT6370_CHAN_IBAT	6
+#define MT6370_CHAN_CHG_VDDP	7
+#define MT6370_CHAN_TEMP_JC	8
+#define MT6370_CHAN_MAX		9
+
+#endif
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	Krzysztof Kozlowski

From: ChiYuan Huang <cy_huang@richtek.com>

Add MediaTek MT6370 binding documentation.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
---
 .../devicetree/bindings/mfd/mediatek,mt6370.yaml   | 280 +++++++++++++++++++++
 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h  |  18 ++
 2 files changed, 298 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
 create mode 100644 include/dt-bindings/iio/adc/mediatek,mt6370_adc.h

diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
new file mode 100644
index 0000000..410e2d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6370.yaml
@@ -0,0 +1,280 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/mediatek,mt6370.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT6370 SubPMIC
+
+maintainers:
+  - ChiYuan Huang <cy_huang@richtek.com>
+
+description: |
+  MT6370 is a highly-integrated smart power management IC, which includes a
+  single cell Li-Ion/Li-Polymer switching battery charger, a USB Type-C &
+  Power Delivery (PD) controller, dual flash LED current sources, a RGB LED
+  driver, a backlight WLED driver, a display bias driver and a general LDO for
+  portable devices.
+
+properties:
+  compatible:
+    const: mediatek,mt6370
+
+  reg:
+    maxItems: 1
+
+  wakeup-source: true
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 1
+
+  adc:
+    type: object
+    description: |
+      Provides 9 channels for system monitoring, including VBUSDIV5 (lower
+      accuracy, higher measure range), VBUSDIV2 (higher accuracy, lower
+      measure range), VBAT, VSYS, CHG_VDDP, TS_BAT, IBUS, IBAT, and TEMP_JC.
+
+    properties:
+      compatible:
+        const: mediatek,mt6370-adc
+
+      "#io-channel-cells":
+        const: 1
+
+    required:
+      - compatible
+      - "#io-channel-cells"
+
+  backlight:
+    type: object
+    $ref: /schemas/leds/backlight/mediatek,mt6370-backlight.yaml#
+
+  charger:
+    type: object
+    $ref: /schemas/power/supply/mediatek,mt6370-charger.yaml#
+
+  tcpc:
+    type: object
+    $ref: /schemas/usb/mediatek,mt6370-tcpc.yaml#
+
+  indicator:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-indicator.yaml#
+
+  flashlight:
+    type: object
+    $ref: /schemas/leds/mediatek,mt6370-flashlight.yaml#
+
+  regulators:
+    type: object
+    description: |
+      List all supported regulators, which support the control for DisplayBias
+      voltages and one general purpose LDO which commonly used to drive the
+      vibrator.
+
+    patternProperties:
+      "^(dsvbst|vibldo)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+      "^(dsvpos|dsvneg)$":
+        $ref: /schemas/regulator/regulator.yaml#
+        type: object
+        unevaluatedProperties: false
+
+        properties:
+          enable-gpios:
+            maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - "#interrupt-cells"
+  - regulators
+  - adc
+  - backlight
+  - indicator
+  - tcpc
+  - charger
+  - flashlight
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/leds/common.h>
+    #include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+    #include <dt-bindings/usb/pd.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+        pmic@34 {
+        compatible = "mediatek,mt6370";
+        reg = <0x34>;
+        wakeup-source;
+        interrupts-extended = <&gpio26 3 IRQ_TYPE_LEVEL_LOW>;
+        interrupt-controller;
+        #interrupt-cells = <1>;
+
+        mt6370_adc: adc {
+          compatible = "mediatek,mt6370-adc";
+          #io-channel-cells = <1>;
+        };
+
+        backlight {
+          compatible = "mediatek,mt6370-backlight";
+          mediatek,bled-channel-use = /bits/ 8 <15>;
+        };
+
+        charger {
+          compatible = "mediatek,mt6370-charger";
+          interrupts = <48>, <68>, <6>;
+          interrupt-names = "attach_i", "uvp_d_evt", "mivr";
+          io-channels = <&mt6370_adc MT6370_CHAN_IBUS>;
+
+          mt6370_otg_vbus: usb-otg-vbus-regulator {
+            regulator-name = "mt6370-usb-otg-vbus";
+            regulator-min-microvolt = <4350000>;
+            regulator-max-microvolt = <5800000>;
+            regulator-min-microamp = <500000>;
+            regulator-max-microamp = <3000000>;
+          };
+        };
+
+        indicator {
+          compatible = "mediatek,mt6370-indicator";
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          multi-led@0 {
+            reg = <0>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_RGB>;
+            led-max-microamp = <24000>;
+            #address-cells = <1>;
+            #size-cells = <0>;
+            led@0 {
+              reg = <0>;
+              color = <LED_COLOR_ID_RED>;
+            };
+            led@1 {
+              reg = <1>;
+              color = <LED_COLOR_ID_GREEN>;
+            };
+            led@2 {
+              reg = <2>;
+              color = <LED_COLOR_ID_BLUE>;
+            };
+          };
+          led@3 {
+            reg = <3>;
+            function = LED_FUNCTION_INDICATOR;
+            color = <LED_COLOR_ID_WHITE>;
+            led-max-microamp = <6000>;
+          };
+        };
+
+        flashlight {
+          compatible = "mediatek,mt6370-flashlight";
+          #address-cells = <1>;
+          #size-cells = <0>;
+          led@0 {
+            reg = <0>;
+            led-sources = <0>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <1>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+          led@1 {
+            reg = <1>;
+            led-sources = <1>;
+            function = LED_FUNCTION_FLASH;
+            color = <LED_COLOR_ID_WHITE>;
+            function-enumerator = <2>;
+            led-max-microamp = <200000>;
+            flash-max-microamp = <500000>;
+            flash-max-timeout-us = <1248000>;
+          };
+        };
+
+        tcpc {
+          compatible = "mediatek,mt6370-tcpc";
+          interrupts-extended = <&gpio26 4 IRQ_TYPE_LEVEL_LOW>;
+
+          connector {
+            compatible = "usb-c-connector";
+            label = "USB-C";
+            vbus-supply = <&mt6370_otg_vbus>;
+            data-role = "dual";
+            power-role = "dual";
+            try-power-role = "sink";
+            source-pdos = <PDO_FIXED(5000, 1000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP)>;
+            op-sink-microwatt = <10000000>;
+
+            ports {
+              #address-cells = <1>;
+              #size-cells = <0>;
+
+              port@0 {
+                reg = <0>;
+                endpoint {
+                  remote-endpoint = <&usb_hs>;
+                };
+              };
+              port@1 {
+                reg = <1>;
+                endpoint {
+                  remote-endpoint = <&usb_ss>;
+                };
+              };
+              port@2 {
+                reg = <2>;
+                endpoint {
+                  remote-endpoint = <&dp_aux>;
+                };
+              };
+            };
+          };
+        };
+
+        regulators {
+          dsvbst {
+            regulator-name = "mt6370-dsv-vbst";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6200000>;
+          };
+          dsvpos {
+            regulator-name = "mt6370-dsv-vpos";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          dsvneg {
+            regulator-name = "mt6370-dsv-vneg";
+            regulator-min-microvolt = <4000000>;
+            regulator-max-microvolt = <6000000>;
+            regulator-boot-on;
+          };
+          vibldo {
+            regulator-name = "mt6370-vib-ldo";
+            regulator-min-microvolt = <1600000>;
+            regulator-max-microvolt = <4000000>;
+          };
+        };
+      };
+    };
diff --git a/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
new file mode 100644
index 0000000..6ee7255
--- /dev/null
+++ b/include/dt-bindings/iio/adc/mediatek,mt6370_adc.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+#define __DT_BINDINGS_MEDIATEK_MT6370_ADC_H__
+
+/* ADC Channel Index */
+#define MT6370_CHAN_VBUSDIV5	0
+#define MT6370_CHAN_VBUSDIV2	1
+#define MT6370_CHAN_VSYS	2
+#define MT6370_CHAN_VBAT	3
+#define MT6370_CHAN_TS_BAT	4
+#define MT6370_CHAN_IBUS	5
+#define MT6370_CHAN_IBAT	6
+#define MT6370_CHAN_CHG_VDDP	7
+#define MT6370_CHAN_TEMP_JC	8
+#define MT6370_CHAN_MAX		9
+
+#endif
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiYuan Huang <cy_huang@richtek.com>

This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
SubPMIC consisting of a single cell battery charger with ADC monitoring,
RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
voltage supply, one general purpose LDO, and the USB Type-C & PD controller
complies with the latest USB Type-C and PD standards.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/mfd/Kconfig  |  16 +++
 drivers/mfd/Makefile |   1 +
 drivers/mfd/mt6370.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/mt6370.h |  99 ++++++++++++++++++
 4 files changed, 397 insertions(+)
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3b59456..a9bcae3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -937,6 +937,22 @@ config MFD_MT6360
 	  PMIC part includes 2-channel BUCKs and 2-channel LDOs
 	  LDO part includes 4-channel LDOs
 
+config MFD_MT6370
+	tristate "MediaTek MT6370 SubPMIC"
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	depends on I2C
+	help
+	  Say Y here to enable MT6370 SubPMIC functional support.
+	  It consists of a single cell battery charger with ADC monitoring, RGB
+	  LEDs, dual channel flashlight, WLED backlight driver, display bias
+	  voltage supply, one general purpose LDO, and the USB Type-C & PD
+	  controller complies with the latest USB Type-C and PD standards.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370".
+
 config MFD_MT6397
 	tristate "MediaTek MT6397 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8c69867..81dbed3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_MAX8998)	+= max8998.o max8998-irq.o
 obj-$(CONFIG_MFD_MP2629)	+= mp2629.o
 
 obj-$(CONFIG_MFD_MT6360)	+= mt6360-core.o
+obj-$(CONFIG_MFD_MT6370)	+= mt6370.o
 mt6397-objs			:= mt6397-core.o mt6397-irq.o mt6358-irq.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397.o
 
diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c
new file mode 100644
index 0000000..070c1c7
--- /dev/null
+++ b/drivers/mfd/mt6370.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mt6370.h"
+
+#define MT6370_REG_DEV_INFO	0x100
+#define MT6370_REG_CHG_IRQ1	0x1C0
+#define MT6370_REG_CHG_MASK1	0x1E0
+
+#define MT6370_VENID_MASK	GENMASK(7, 4)
+
+#define MT6370_NUM_IRQREGS	16
+#define MT6370_USBC_I2CADDR	0x4E
+#define MT6370_REG_ADDRLEN	2
+#define MT6370_REG_MAXADDR	0x1FF
+
+#define MT6370_VENID_RT5081	0x8
+#define MT6370_VENID_RT5081A	0xA
+#define MT6370_VENID_MT6370	0xE
+#define MT6370_VENID_MT6371	0xF
+#define MT6370_VENID_MT6372P	0x9
+#define MT6370_VENID_MT6372CP	0xB
+
+static const struct regmap_irq mt6370_irqs[] = {
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8),
+	REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8),
+};
+
+static const struct regmap_irq_chip mt6370_irq_chip = {
+	.name		= "mt6370-irqs",
+	.status_base	= MT6370_REG_CHG_IRQ1,
+	.mask_base	= MT6370_REG_CHG_MASK1,
+	.num_regs	= MT6370_NUM_IRQREGS,
+	.irqs		= mt6370_irqs,
+	.num_irqs	= ARRAY_SIZE(mt6370_irqs),
+};
+
+static const struct resource mt6370_regulator_irqs[] = {
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"),
+};
+
+static const struct mfd_cell mt6370_devices[] = {
+	MFD_CELL_OF("mt6370-adc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-adc"),
+	MFD_CELL_OF("mt6370-charger",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-charger"),
+	MFD_CELL_OF("mt6370-backlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-backlight"),
+	MFD_CELL_OF("mt6370-flashlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"),
+	MFD_CELL_OF("mt6370-indicator",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-indicator"),
+	MFD_CELL_OF("mt6370-tcpc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"),
+	MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs),
+};
+
+static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap)
+{
+	unsigned int devinfo;
+	int ret;
+
+	ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) {
+	case MT6370_VENID_RT5081:
+	case MT6370_VENID_RT5081A:
+	case MT6370_VENID_MT6370:
+	case MT6370_VENID_MT6371:
+	case MT6370_VENID_MT6372P:
+	case MT6370_VENID_MT6372CP:
+		return 0;
+	default:
+		dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo);
+		return -ENODEV;
+	}
+}
+
+static int mt6370_regmap_read(void *context, const void *reg_buf,
+			      size_t reg_size, void *val_buf, size_t val_size)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = reg_buf;
+	u8 bank_idx, bank_addr;
+	int ret;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					    val_size, val_buf);
+	if (ret < 0)
+		return ret;
+
+	if (ret != val_size)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt6370_regmap_write(void *context, const void *data, size_t count)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = data;
+	u8 bank_idx, bank_addr;
+	int len = count - MT6370_REG_ADDRLEN;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					      len, data + MT6370_REG_ADDRLEN);
+}
+
+static const struct regmap_bus mt6370_regmap_bus = {
+	.read		= mt6370_regmap_read,
+	.write		= mt6370_regmap_write,
+};
+
+static const struct regmap_config mt6370_regmap_config = {
+	.reg_bits		= 16,
+	.val_bits		= 8,
+	.reg_format_endian	= REGMAP_ENDIAN_BIG,
+	.max_register		= MT6370_REG_MAXADDR,
+};
+
+static int mt6370_probe(struct i2c_client *i2c)
+{
+	struct mt6370_info *info;
+	struct i2c_client *usbc_i2c;
+	struct regmap *regmap;
+	struct device *dev = &i2c->dev;
+	int ret;
+
+	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter,
+					     MT6370_USBC_I2CADDR);
+	if (IS_ERR(usbc_i2c))
+		return dev_err_probe(dev, PTR_ERR(usbc_i2c),
+				     "Failed to register USBC I2C client\n");
+
+	/* Assign I2C client for PMU and TypeC */
+	info->i2c[MT6370_PMU_I2C] = i2c;
+	info->i2c[MT6370_USBC_I2C] = usbc_i2c;
+
+	regmap = devm_regmap_init(dev, &mt6370_regmap_bus,
+				  info, &mt6370_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(dev, regmap);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
+				       IRQF_ONESHOT, -1, &mt6370_irq_chip,
+				       &info->irq_data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add irq chip\n");
+
+	return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+				    mt6370_devices, ARRAY_SIZE(mt6370_devices),
+				    NULL, 0,
+				    regmap_irq_get_domain(info->irq_data));
+}
+
+static const struct of_device_id mt6370_match_table[] = {
+	{ .compatible = "mediatek,mt6370" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_match_table);
+
+static struct i2c_driver mt6370_driver = {
+	.driver = {
+		.name = "mt6370",
+		.of_match_table = mt6370_match_table,
+	},
+	.probe_new = mt6370_probe,
+};
+module_i2c_driver(mt6370_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/mt6370.h b/drivers/mfd/mt6370.h
new file mode 100644
index 0000000..094e59e
--- /dev/null
+++ b/drivers/mfd/mt6370.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#ifndef __MFD_MT6370_H__
+#define __MFD_MT6370_H__
+
+/* IRQ definitions */
+#define MT6370_IRQ_DIRCHGON		0
+#define MT6370_IRQ_CHG_TREG		4
+#define MT6370_IRQ_CHG_AICR		5
+#define MT6370_IRQ_CHG_MIVR		6
+#define MT6370_IRQ_PWR_RDY		7
+#define MT6370_IRQ_FL_CHG_VINOVP	11
+#define MT6370_IRQ_CHG_VSYSUV		12
+#define MT6370_IRQ_CHG_VSYSOV		13
+#define MT6370_IRQ_CHG_VBATOV		14
+#define MT6370_IRQ_CHG_VINOVPCHG	15
+#define MT6370_IRQ_TS_BAT_COLD		20
+#define MT6370_IRQ_TS_BAT_COOL		21
+#define MT6370_IRQ_TS_BAT_WARM		22
+#define MT6370_IRQ_TS_BAT_HOT		23
+#define MT6370_IRQ_TS_STATC		24
+#define MT6370_IRQ_CHG_FAULT		25
+#define MT6370_IRQ_CHG_STATC		26
+#define MT6370_IRQ_CHG_TMR		27
+#define MT6370_IRQ_CHG_BATABS		28
+#define MT6370_IRQ_CHG_ADPBAD		29
+#define MT6370_IRQ_CHG_RVP		30
+#define MT6370_IRQ_TSHUTDOWN		31
+#define MT6370_IRQ_CHG_IINMEAS		32
+#define MT6370_IRQ_CHG_ICCMEAS		33
+#define MT6370_IRQ_CHGDET_DONE		34
+#define MT6370_IRQ_WDTMR		35
+#define MT6370_IRQ_SSFINISH		36
+#define MT6370_IRQ_CHG_RECHG		37
+#define MT6370_IRQ_CHG_TERM		38
+#define MT6370_IRQ_CHG_IEOC		39
+#define MT6370_IRQ_ADC_DONE		40
+#define MT6370_IRQ_PUMPX_DONE		41
+#define MT6370_IRQ_BST_BATUV		45
+#define MT6370_IRQ_BST_MIDOV		46
+#define MT6370_IRQ_BST_OLP		47
+#define MT6370_IRQ_ATTACH		48
+#define MT6370_IRQ_DETACH		49
+#define MT6370_IRQ_HVDCP_STPDONE	51
+#define MT6370_IRQ_HVDCP_VBUSDET_DONE	52
+#define MT6370_IRQ_HVDCP_DET		53
+#define MT6370_IRQ_CHGDET		54
+#define MT6370_IRQ_DCDT			55
+#define MT6370_IRQ_DIRCHG_VGOK		59
+#define MT6370_IRQ_DIRCHG_WDTMR		60
+#define MT6370_IRQ_DIRCHG_UC		61
+#define MT6370_IRQ_DIRCHG_OC		62
+#define MT6370_IRQ_DIRCHG_OV		63
+#define MT6370_IRQ_OVPCTRL_SWON		67
+#define MT6370_IRQ_OVPCTRL_UVP_D	68
+#define MT6370_IRQ_OVPCTRL_UVP		69
+#define MT6370_IRQ_OVPCTRL_OVP_D	70
+#define MT6370_IRQ_OVPCTRL_OVP		71
+#define MT6370_IRQ_FLED_STRBPIN		72
+#define MT6370_IRQ_FLED_TORPIN		73
+#define MT6370_IRQ_FLED_TX		74
+#define MT6370_IRQ_FLED_LVF		75
+#define MT6370_IRQ_FLED2_SHORT		78
+#define MT6370_IRQ_FLED1_SHORT		79
+#define MT6370_IRQ_FLED2_STRB		80
+#define MT6370_IRQ_FLED1_STRB		81
+#define mT6370_IRQ_FLED2_STRB_TO	82
+#define MT6370_IRQ_FLED1_STRB_TO	83
+#define MT6370_IRQ_FLED2_TOR		84
+#define MT6370_IRQ_FLED1_TOR		85
+#define MT6370_IRQ_OTP			93
+#define MT6370_IRQ_VDDA_OVP		94
+#define MT6370_IRQ_VDDA_UV		95
+#define MT6370_IRQ_LDO_OC		103
+#define MT6370_IRQ_BLED_OCP		118
+#define MT6370_IRQ_BLED_OVP		119
+#define MT6370_IRQ_DSV_VNEG_OCP		123
+#define MT6370_IRQ_DSV_VPOS_OCP		124
+#define MT6370_IRQ_DSV_BST_OCP		125
+#define MT6370_IRQ_DSV_VNEG_SCP		126
+#define MT6370_IRQ_DSV_VPOS_SCP		127
+
+enum {
+	MT6370_USBC_I2C = 0,
+	MT6370_PMU_I2C,
+	MT6370_MAX_I2C
+};
+
+struct mt6370_info {
+	struct i2c_client *i2c[MT6370_MAX_I2C];
+	struct regmap_irq_chip_data *irq_data;
+};
+
+#endif /* __MFD_MT6375_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
SubPMIC consisting of a single cell battery charger with ADC monitoring,
RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
voltage supply, one general purpose LDO, and the USB Type-C & PD controller
complies with the latest USB Type-C and PD standards.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/mfd/Kconfig  |  16 +++
 drivers/mfd/Makefile |   1 +
 drivers/mfd/mt6370.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/mt6370.h |  99 ++++++++++++++++++
 4 files changed, 397 insertions(+)
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3b59456..a9bcae3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -937,6 +937,22 @@ config MFD_MT6360
 	  PMIC part includes 2-channel BUCKs and 2-channel LDOs
 	  LDO part includes 4-channel LDOs
 
+config MFD_MT6370
+	tristate "MediaTek MT6370 SubPMIC"
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	depends on I2C
+	help
+	  Say Y here to enable MT6370 SubPMIC functional support.
+	  It consists of a single cell battery charger with ADC monitoring, RGB
+	  LEDs, dual channel flashlight, WLED backlight driver, display bias
+	  voltage supply, one general purpose LDO, and the USB Type-C & PD
+	  controller complies with the latest USB Type-C and PD standards.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370".
+
 config MFD_MT6397
 	tristate "MediaTek MT6397 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8c69867..81dbed3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_MAX8998)	+= max8998.o max8998-irq.o
 obj-$(CONFIG_MFD_MP2629)	+= mp2629.o
 
 obj-$(CONFIG_MFD_MT6360)	+= mt6360-core.o
+obj-$(CONFIG_MFD_MT6370)	+= mt6370.o
 mt6397-objs			:= mt6397-core.o mt6397-irq.o mt6358-irq.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397.o
 
diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c
new file mode 100644
index 0000000..070c1c7
--- /dev/null
+++ b/drivers/mfd/mt6370.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mt6370.h"
+
+#define MT6370_REG_DEV_INFO	0x100
+#define MT6370_REG_CHG_IRQ1	0x1C0
+#define MT6370_REG_CHG_MASK1	0x1E0
+
+#define MT6370_VENID_MASK	GENMASK(7, 4)
+
+#define MT6370_NUM_IRQREGS	16
+#define MT6370_USBC_I2CADDR	0x4E
+#define MT6370_REG_ADDRLEN	2
+#define MT6370_REG_MAXADDR	0x1FF
+
+#define MT6370_VENID_RT5081	0x8
+#define MT6370_VENID_RT5081A	0xA
+#define MT6370_VENID_MT6370	0xE
+#define MT6370_VENID_MT6371	0xF
+#define MT6370_VENID_MT6372P	0x9
+#define MT6370_VENID_MT6372CP	0xB
+
+static const struct regmap_irq mt6370_irqs[] = {
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8),
+	REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8),
+};
+
+static const struct regmap_irq_chip mt6370_irq_chip = {
+	.name		= "mt6370-irqs",
+	.status_base	= MT6370_REG_CHG_IRQ1,
+	.mask_base	= MT6370_REG_CHG_MASK1,
+	.num_regs	= MT6370_NUM_IRQREGS,
+	.irqs		= mt6370_irqs,
+	.num_irqs	= ARRAY_SIZE(mt6370_irqs),
+};
+
+static const struct resource mt6370_regulator_irqs[] = {
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"),
+};
+
+static const struct mfd_cell mt6370_devices[] = {
+	MFD_CELL_OF("mt6370-adc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-adc"),
+	MFD_CELL_OF("mt6370-charger",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-charger"),
+	MFD_CELL_OF("mt6370-backlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-backlight"),
+	MFD_CELL_OF("mt6370-flashlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"),
+	MFD_CELL_OF("mt6370-indicator",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-indicator"),
+	MFD_CELL_OF("mt6370-tcpc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"),
+	MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs),
+};
+
+static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap)
+{
+	unsigned int devinfo;
+	int ret;
+
+	ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) {
+	case MT6370_VENID_RT5081:
+	case MT6370_VENID_RT5081A:
+	case MT6370_VENID_MT6370:
+	case MT6370_VENID_MT6371:
+	case MT6370_VENID_MT6372P:
+	case MT6370_VENID_MT6372CP:
+		return 0;
+	default:
+		dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo);
+		return -ENODEV;
+	}
+}
+
+static int mt6370_regmap_read(void *context, const void *reg_buf,
+			      size_t reg_size, void *val_buf, size_t val_size)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = reg_buf;
+	u8 bank_idx, bank_addr;
+	int ret;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					    val_size, val_buf);
+	if (ret < 0)
+		return ret;
+
+	if (ret != val_size)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt6370_regmap_write(void *context, const void *data, size_t count)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = data;
+	u8 bank_idx, bank_addr;
+	int len = count - MT6370_REG_ADDRLEN;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					      len, data + MT6370_REG_ADDRLEN);
+}
+
+static const struct regmap_bus mt6370_regmap_bus = {
+	.read		= mt6370_regmap_read,
+	.write		= mt6370_regmap_write,
+};
+
+static const struct regmap_config mt6370_regmap_config = {
+	.reg_bits		= 16,
+	.val_bits		= 8,
+	.reg_format_endian	= REGMAP_ENDIAN_BIG,
+	.max_register		= MT6370_REG_MAXADDR,
+};
+
+static int mt6370_probe(struct i2c_client *i2c)
+{
+	struct mt6370_info *info;
+	struct i2c_client *usbc_i2c;
+	struct regmap *regmap;
+	struct device *dev = &i2c->dev;
+	int ret;
+
+	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter,
+					     MT6370_USBC_I2CADDR);
+	if (IS_ERR(usbc_i2c))
+		return dev_err_probe(dev, PTR_ERR(usbc_i2c),
+				     "Failed to register USBC I2C client\n");
+
+	/* Assign I2C client for PMU and TypeC */
+	info->i2c[MT6370_PMU_I2C] = i2c;
+	info->i2c[MT6370_USBC_I2C] = usbc_i2c;
+
+	regmap = devm_regmap_init(dev, &mt6370_regmap_bus,
+				  info, &mt6370_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(dev, regmap);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
+				       IRQF_ONESHOT, -1, &mt6370_irq_chip,
+				       &info->irq_data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add irq chip\n");
+
+	return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+				    mt6370_devices, ARRAY_SIZE(mt6370_devices),
+				    NULL, 0,
+				    regmap_irq_get_domain(info->irq_data));
+}
+
+static const struct of_device_id mt6370_match_table[] = {
+	{ .compatible = "mediatek,mt6370" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_match_table);
+
+static struct i2c_driver mt6370_driver = {
+	.driver = {
+		.name = "mt6370",
+		.of_match_table = mt6370_match_table,
+	},
+	.probe_new = mt6370_probe,
+};
+module_i2c_driver(mt6370_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/mt6370.h b/drivers/mfd/mt6370.h
new file mode 100644
index 0000000..094e59e
--- /dev/null
+++ b/drivers/mfd/mt6370.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#ifndef __MFD_MT6370_H__
+#define __MFD_MT6370_H__
+
+/* IRQ definitions */
+#define MT6370_IRQ_DIRCHGON		0
+#define MT6370_IRQ_CHG_TREG		4
+#define MT6370_IRQ_CHG_AICR		5
+#define MT6370_IRQ_CHG_MIVR		6
+#define MT6370_IRQ_PWR_RDY		7
+#define MT6370_IRQ_FL_CHG_VINOVP	11
+#define MT6370_IRQ_CHG_VSYSUV		12
+#define MT6370_IRQ_CHG_VSYSOV		13
+#define MT6370_IRQ_CHG_VBATOV		14
+#define MT6370_IRQ_CHG_VINOVPCHG	15
+#define MT6370_IRQ_TS_BAT_COLD		20
+#define MT6370_IRQ_TS_BAT_COOL		21
+#define MT6370_IRQ_TS_BAT_WARM		22
+#define MT6370_IRQ_TS_BAT_HOT		23
+#define MT6370_IRQ_TS_STATC		24
+#define MT6370_IRQ_CHG_FAULT		25
+#define MT6370_IRQ_CHG_STATC		26
+#define MT6370_IRQ_CHG_TMR		27
+#define MT6370_IRQ_CHG_BATABS		28
+#define MT6370_IRQ_CHG_ADPBAD		29
+#define MT6370_IRQ_CHG_RVP		30
+#define MT6370_IRQ_TSHUTDOWN		31
+#define MT6370_IRQ_CHG_IINMEAS		32
+#define MT6370_IRQ_CHG_ICCMEAS		33
+#define MT6370_IRQ_CHGDET_DONE		34
+#define MT6370_IRQ_WDTMR		35
+#define MT6370_IRQ_SSFINISH		36
+#define MT6370_IRQ_CHG_RECHG		37
+#define MT6370_IRQ_CHG_TERM		38
+#define MT6370_IRQ_CHG_IEOC		39
+#define MT6370_IRQ_ADC_DONE		40
+#define MT6370_IRQ_PUMPX_DONE		41
+#define MT6370_IRQ_BST_BATUV		45
+#define MT6370_IRQ_BST_MIDOV		46
+#define MT6370_IRQ_BST_OLP		47
+#define MT6370_IRQ_ATTACH		48
+#define MT6370_IRQ_DETACH		49
+#define MT6370_IRQ_HVDCP_STPDONE	51
+#define MT6370_IRQ_HVDCP_VBUSDET_DONE	52
+#define MT6370_IRQ_HVDCP_DET		53
+#define MT6370_IRQ_CHGDET		54
+#define MT6370_IRQ_DCDT			55
+#define MT6370_IRQ_DIRCHG_VGOK		59
+#define MT6370_IRQ_DIRCHG_WDTMR		60
+#define MT6370_IRQ_DIRCHG_UC		61
+#define MT6370_IRQ_DIRCHG_OC		62
+#define MT6370_IRQ_DIRCHG_OV		63
+#define MT6370_IRQ_OVPCTRL_SWON		67
+#define MT6370_IRQ_OVPCTRL_UVP_D	68
+#define MT6370_IRQ_OVPCTRL_UVP		69
+#define MT6370_IRQ_OVPCTRL_OVP_D	70
+#define MT6370_IRQ_OVPCTRL_OVP		71
+#define MT6370_IRQ_FLED_STRBPIN		72
+#define MT6370_IRQ_FLED_TORPIN		73
+#define MT6370_IRQ_FLED_TX		74
+#define MT6370_IRQ_FLED_LVF		75
+#define MT6370_IRQ_FLED2_SHORT		78
+#define MT6370_IRQ_FLED1_SHORT		79
+#define MT6370_IRQ_FLED2_STRB		80
+#define MT6370_IRQ_FLED1_STRB		81
+#define mT6370_IRQ_FLED2_STRB_TO	82
+#define MT6370_IRQ_FLED1_STRB_TO	83
+#define MT6370_IRQ_FLED2_TOR		84
+#define MT6370_IRQ_FLED1_TOR		85
+#define MT6370_IRQ_OTP			93
+#define MT6370_IRQ_VDDA_OVP		94
+#define MT6370_IRQ_VDDA_UV		95
+#define MT6370_IRQ_LDO_OC		103
+#define MT6370_IRQ_BLED_OCP		118
+#define MT6370_IRQ_BLED_OVP		119
+#define MT6370_IRQ_DSV_VNEG_OCP		123
+#define MT6370_IRQ_DSV_VPOS_OCP		124
+#define MT6370_IRQ_DSV_BST_OCP		125
+#define MT6370_IRQ_DSV_VNEG_SCP		126
+#define MT6370_IRQ_DSV_VPOS_SCP		127
+
+enum {
+	MT6370_USBC_I2C = 0,
+	MT6370_PMU_I2C,
+	MT6370_MAX_I2C
+};
+
+struct mt6370_info {
+	struct i2c_client *i2c[MT6370_MAX_I2C];
+	struct regmap_irq_chip_data *irq_data;
+};
+
+#endif /* __MFD_MT6375_H__ */
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiYuan Huang <cy_huang@richtek.com>

This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
SubPMIC consisting of a single cell battery charger with ADC monitoring,
RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
voltage supply, one general purpose LDO, and the USB Type-C & PD controller
complies with the latest USB Type-C and PD standards.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
---
 drivers/mfd/Kconfig  |  16 +++
 drivers/mfd/Makefile |   1 +
 drivers/mfd/mt6370.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/mfd/mt6370.h |  99 ++++++++++++++++++
 4 files changed, 397 insertions(+)
 create mode 100644 drivers/mfd/mt6370.c
 create mode 100644 drivers/mfd/mt6370.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3b59456..a9bcae3 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -937,6 +937,22 @@ config MFD_MT6360
 	  PMIC part includes 2-channel BUCKs and 2-channel LDOs
 	  LDO part includes 4-channel LDOs
 
+config MFD_MT6370
+	tristate "MediaTek MT6370 SubPMIC"
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	depends on I2C
+	help
+	  Say Y here to enable MT6370 SubPMIC functional support.
+	  It consists of a single cell battery charger with ADC monitoring, RGB
+	  LEDs, dual channel flashlight, WLED backlight driver, display bias
+	  voltage supply, one general purpose LDO, and the USB Type-C & PD
+	  controller complies with the latest USB Type-C and PD standards.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370".
+
 config MFD_MT6397
 	tristate "MediaTek MT6397 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8c69867..81dbed3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -173,6 +173,7 @@ obj-$(CONFIG_MFD_MAX8998)	+= max8998.o max8998-irq.o
 obj-$(CONFIG_MFD_MP2629)	+= mp2629.o
 
 obj-$(CONFIG_MFD_MT6360)	+= mt6360-core.o
+obj-$(CONFIG_MFD_MT6370)	+= mt6370.o
 mt6397-objs			:= mt6397-core.o mt6397-irq.o mt6358-irq.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397.o
 
diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c
new file mode 100644
index 0000000..070c1c7
--- /dev/null
+++ b/drivers/mfd/mt6370.c
@@ -0,0 +1,281 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "mt6370.h"
+
+#define MT6370_REG_DEV_INFO	0x100
+#define MT6370_REG_CHG_IRQ1	0x1C0
+#define MT6370_REG_CHG_MASK1	0x1E0
+
+#define MT6370_VENID_MASK	GENMASK(7, 4)
+
+#define MT6370_NUM_IRQREGS	16
+#define MT6370_USBC_I2CADDR	0x4E
+#define MT6370_REG_ADDRLEN	2
+#define MT6370_REG_MAXADDR	0x1FF
+
+#define MT6370_VENID_RT5081	0x8
+#define MT6370_VENID_RT5081A	0xA
+#define MT6370_VENID_MT6370	0xE
+#define MT6370_VENID_MT6371	0xF
+#define MT6370_VENID_MT6372P	0x9
+#define MT6370_VENID_MT6372CP	0xB
+
+static const struct regmap_irq mt6370_irqs[] = {
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8),
+	REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8),
+	REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8),
+};
+
+static const struct regmap_irq_chip mt6370_irq_chip = {
+	.name		= "mt6370-irqs",
+	.status_base	= MT6370_REG_CHG_IRQ1,
+	.mask_base	= MT6370_REG_CHG_MASK1,
+	.num_regs	= MT6370_NUM_IRQREGS,
+	.irqs		= mt6370_irqs,
+	.num_irqs	= ARRAY_SIZE(mt6370_irqs),
+};
+
+static const struct resource mt6370_regulator_irqs[] = {
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"),
+	DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"),
+};
+
+static const struct mfd_cell mt6370_devices[] = {
+	MFD_CELL_OF("mt6370-adc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-adc"),
+	MFD_CELL_OF("mt6370-charger",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-charger"),
+	MFD_CELL_OF("mt6370-backlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-backlight"),
+	MFD_CELL_OF("mt6370-flashlight",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"),
+	MFD_CELL_OF("mt6370-indicator",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-indicator"),
+	MFD_CELL_OF("mt6370-tcpc",
+		    NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"),
+	MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs),
+};
+
+static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap)
+{
+	unsigned int devinfo;
+	int ret;
+
+	ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MT6370_VENID_MASK, devinfo)) {
+	case MT6370_VENID_RT5081:
+	case MT6370_VENID_RT5081A:
+	case MT6370_VENID_MT6370:
+	case MT6370_VENID_MT6371:
+	case MT6370_VENID_MT6372P:
+	case MT6370_VENID_MT6372CP:
+		return 0;
+	default:
+		dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo);
+		return -ENODEV;
+	}
+}
+
+static int mt6370_regmap_read(void *context, const void *reg_buf,
+			      size_t reg_size, void *val_buf, size_t val_size)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = reg_buf;
+	u8 bank_idx, bank_addr;
+	int ret;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					    val_size, val_buf);
+	if (ret < 0)
+		return ret;
+
+	if (ret != val_size)
+		return -EIO;
+
+	return 0;
+}
+
+static int mt6370_regmap_write(void *context, const void *data, size_t count)
+{
+	struct mt6370_info *info = context;
+	const u8 *u8_buf = data;
+	u8 bank_idx, bank_addr;
+	int len = count - MT6370_REG_ADDRLEN;
+
+	bank_idx = u8_buf[0];
+	bank_addr = u8_buf[1];
+
+	return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr,
+					      len, data + MT6370_REG_ADDRLEN);
+}
+
+static const struct regmap_bus mt6370_regmap_bus = {
+	.read		= mt6370_regmap_read,
+	.write		= mt6370_regmap_write,
+};
+
+static const struct regmap_config mt6370_regmap_config = {
+	.reg_bits		= 16,
+	.val_bits		= 8,
+	.reg_format_endian	= REGMAP_ENDIAN_BIG,
+	.max_register		= MT6370_REG_MAXADDR,
+};
+
+static int mt6370_probe(struct i2c_client *i2c)
+{
+	struct mt6370_info *info;
+	struct i2c_client *usbc_i2c;
+	struct regmap *regmap;
+	struct device *dev = &i2c->dev;
+	int ret;
+
+	info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter,
+					     MT6370_USBC_I2CADDR);
+	if (IS_ERR(usbc_i2c))
+		return dev_err_probe(dev, PTR_ERR(usbc_i2c),
+				     "Failed to register USBC I2C client\n");
+
+	/* Assign I2C client for PMU and TypeC */
+	info->i2c[MT6370_PMU_I2C] = i2c;
+	info->i2c[MT6370_USBC_I2C] = usbc_i2c;
+
+	regmap = devm_regmap_init(dev, &mt6370_regmap_bus,
+				  info, &mt6370_regmap_config);
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap),
+				     "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(dev, regmap);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq,
+				       IRQF_ONESHOT, -1, &mt6370_irq_chip,
+				       &info->irq_data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add irq chip\n");
+
+	return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO,
+				    mt6370_devices, ARRAY_SIZE(mt6370_devices),
+				    NULL, 0,
+				    regmap_irq_get_domain(info->irq_data));
+}
+
+static const struct of_device_id mt6370_match_table[] = {
+	{ .compatible = "mediatek,mt6370" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_match_table);
+
+static struct i2c_driver mt6370_driver = {
+	.driver = {
+		.name = "mt6370",
+		.of_match_table = mt6370_match_table,
+	},
+	.probe_new = mt6370_probe,
+};
+module_i2c_driver(mt6370_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/mt6370.h b/drivers/mfd/mt6370.h
new file mode 100644
index 0000000..094e59e
--- /dev/null
+++ b/drivers/mfd/mt6370.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#ifndef __MFD_MT6370_H__
+#define __MFD_MT6370_H__
+
+/* IRQ definitions */
+#define MT6370_IRQ_DIRCHGON		0
+#define MT6370_IRQ_CHG_TREG		4
+#define MT6370_IRQ_CHG_AICR		5
+#define MT6370_IRQ_CHG_MIVR		6
+#define MT6370_IRQ_PWR_RDY		7
+#define MT6370_IRQ_FL_CHG_VINOVP	11
+#define MT6370_IRQ_CHG_VSYSUV		12
+#define MT6370_IRQ_CHG_VSYSOV		13
+#define MT6370_IRQ_CHG_VBATOV		14
+#define MT6370_IRQ_CHG_VINOVPCHG	15
+#define MT6370_IRQ_TS_BAT_COLD		20
+#define MT6370_IRQ_TS_BAT_COOL		21
+#define MT6370_IRQ_TS_BAT_WARM		22
+#define MT6370_IRQ_TS_BAT_HOT		23
+#define MT6370_IRQ_TS_STATC		24
+#define MT6370_IRQ_CHG_FAULT		25
+#define MT6370_IRQ_CHG_STATC		26
+#define MT6370_IRQ_CHG_TMR		27
+#define MT6370_IRQ_CHG_BATABS		28
+#define MT6370_IRQ_CHG_ADPBAD		29
+#define MT6370_IRQ_CHG_RVP		30
+#define MT6370_IRQ_TSHUTDOWN		31
+#define MT6370_IRQ_CHG_IINMEAS		32
+#define MT6370_IRQ_CHG_ICCMEAS		33
+#define MT6370_IRQ_CHGDET_DONE		34
+#define MT6370_IRQ_WDTMR		35
+#define MT6370_IRQ_SSFINISH		36
+#define MT6370_IRQ_CHG_RECHG		37
+#define MT6370_IRQ_CHG_TERM		38
+#define MT6370_IRQ_CHG_IEOC		39
+#define MT6370_IRQ_ADC_DONE		40
+#define MT6370_IRQ_PUMPX_DONE		41
+#define MT6370_IRQ_BST_BATUV		45
+#define MT6370_IRQ_BST_MIDOV		46
+#define MT6370_IRQ_BST_OLP		47
+#define MT6370_IRQ_ATTACH		48
+#define MT6370_IRQ_DETACH		49
+#define MT6370_IRQ_HVDCP_STPDONE	51
+#define MT6370_IRQ_HVDCP_VBUSDET_DONE	52
+#define MT6370_IRQ_HVDCP_DET		53
+#define MT6370_IRQ_CHGDET		54
+#define MT6370_IRQ_DCDT			55
+#define MT6370_IRQ_DIRCHG_VGOK		59
+#define MT6370_IRQ_DIRCHG_WDTMR		60
+#define MT6370_IRQ_DIRCHG_UC		61
+#define MT6370_IRQ_DIRCHG_OC		62
+#define MT6370_IRQ_DIRCHG_OV		63
+#define MT6370_IRQ_OVPCTRL_SWON		67
+#define MT6370_IRQ_OVPCTRL_UVP_D	68
+#define MT6370_IRQ_OVPCTRL_UVP		69
+#define MT6370_IRQ_OVPCTRL_OVP_D	70
+#define MT6370_IRQ_OVPCTRL_OVP		71
+#define MT6370_IRQ_FLED_STRBPIN		72
+#define MT6370_IRQ_FLED_TORPIN		73
+#define MT6370_IRQ_FLED_TX		74
+#define MT6370_IRQ_FLED_LVF		75
+#define MT6370_IRQ_FLED2_SHORT		78
+#define MT6370_IRQ_FLED1_SHORT		79
+#define MT6370_IRQ_FLED2_STRB		80
+#define MT6370_IRQ_FLED1_STRB		81
+#define mT6370_IRQ_FLED2_STRB_TO	82
+#define MT6370_IRQ_FLED1_STRB_TO	83
+#define MT6370_IRQ_FLED2_TOR		84
+#define MT6370_IRQ_FLED1_TOR		85
+#define MT6370_IRQ_OTP			93
+#define MT6370_IRQ_VDDA_OVP		94
+#define MT6370_IRQ_VDDA_UV		95
+#define MT6370_IRQ_LDO_OC		103
+#define MT6370_IRQ_BLED_OCP		118
+#define MT6370_IRQ_BLED_OVP		119
+#define MT6370_IRQ_DSV_VNEG_OCP		123
+#define MT6370_IRQ_DSV_VPOS_OCP		124
+#define MT6370_IRQ_DSV_BST_OCP		125
+#define MT6370_IRQ_DSV_VNEG_SCP		126
+#define MT6370_IRQ_DSV_VPOS_SCP		127
+
+enum {
+	MT6370_USBC_I2C = 0,
+	MT6370_PMU_I2C,
+	MT6370_MAX_I2C
+};
+
+struct mt6370_info {
+	struct i2c_client *i2c[MT6370_MAX_I2C];
+	struct regmap_irq_chip_data *irq_data;
+};
+
+#endif /* __MFD_MT6375_H__ */
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

Add support for the Type-C & Power Delivery controller in
MediaTek MT6370 IC.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
- Refine remvoe callback.
- Refine the commit text from 'This commit add' to 'Add'.
---
 drivers/usb/typec/tcpm/Kconfig        |  11 ++
 drivers/usb/typec/tcpm/Makefile       |   1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
 3 files changed, 220 insertions(+)
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c

diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
index 073fd2e..e6b88ca 100644
--- a/drivers/usb/typec/tcpm/Kconfig
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -35,6 +35,17 @@ config TYPEC_MT6360
 	  USB Type-C. It works with Type-C Port Controller Manager
 	  to provide USB PD and USB Type-C functionalities.
 
+config TYPEC_TCPCI_MT6370
+	tristate "MediaTek MT6370 Type-C driver"
+	depends on MFD_MT6370
+	help
+	  MediaTek MT6370 is a multi-functional IC that includes
+	  USB Type-C. It works with Type-C Port Controller Manager
+	  to provide USB PD and USB Type-C functionalities.
+
+	  This driver can also be built as a module. The module
+	  will be called "tcpci_mt6370".
+
 config TYPEC_TCPCI_MAXIM
 	tristate "Maxim TCPCI based Type-C chip driver"
 	help
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 7d499f3..906d9dc 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
 obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
 obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
 obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
+obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
 obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
new file mode 100644
index 0000000..4f53319
--- /dev/null
+++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/tcpm.h>
+#include "tcpci.h"
+
+#define MT6370_REG_SYSCTRL8	0x9B
+
+#define MT6370_AUTOIDLE_MASK	BIT(3)
+
+#define MT6370_VENDOR_ID	0x29CF
+#define MT6370_TCPC_DID_A	0x2170
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regulator *vbus;
+	struct tcpci *tcpci;
+	struct tcpci_data tcpci_data;
+};
+
+static const struct reg_sequence mt6370_reg_init[] = {
+	REG_SEQ(0xA0, 0x1, 1000),
+	REG_SEQ(0x81, 0x38, 0),
+	REG_SEQ(0x82, 0x82, 0),
+	REG_SEQ(0xBA, 0xFC, 0),
+	REG_SEQ(0xBB, 0x50, 0),
+	REG_SEQ(0x9E, 0x8F, 0),
+	REG_SEQ(0xA1, 0x5, 0),
+	REG_SEQ(0xA2, 0x4, 0),
+	REG_SEQ(0xA3, 0x4A, 0),
+	REG_SEQ(0xA4, 0x01, 0),
+	REG_SEQ(0x95, 0x01, 0),
+	REG_SEQ(0x80, 0x71, 0),
+	REG_SEQ(0x9B, 0x3A, 1000),
+};
+
+static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
+{
+	u16 did;
+	int ret;
+
+	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
+				    ARRAY_SIZE(mt6370_reg_init));
+	if (ret)
+		return ret;
+
+	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (did == MT6370_TCPC_DID_A)
+		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
+
+	return 0;
+}
+
+static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
+				 bool enable)
+{
+	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
+				  MT6370_AUTOIDLE_MASK,
+				  !enable ? MT6370_AUTOIDLE_MASK : 0);
+}
+
+static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
+				bool source, bool sink)
+{
+	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
+						tcpci_data);
+	int ret;
+
+	ret = regulator_is_enabled(priv->vbus);
+	if (ret < 0)
+		return ret;
+
+	if (ret && !source)
+		return regulator_disable(priv->vbus);
+
+	if (!ret && source)
+		return regulator_enable(priv->vbus);
+
+	return 0;
+}
+
+static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
+{
+	struct mt6370_priv *priv = dev_id;
+
+	return tcpci_irq(priv->tcpci);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	struct regmap *regmap = priv->tcpci_data.regmap;
+	u16 vid;
+	int ret;
+
+	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (vid != MT6370_VENDOR_ID)
+		return dev_err_probe(priv->dev, -ENODEV,
+				     "Vendor ID not correct 0x%02x\n", vid);
+
+	return 0;
+}
+
+static void mt6370_unregister_tcpci_port(void *tcpci)
+{
+	tcpci_unregister_port(tcpci);
+}
+
+static int mt6370_tcpc_probe(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv;
+	struct device *dev = &pdev->dev;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->tcpci_data.regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get irq\n");
+
+	/* Assign TCPCI feature and ops */
+	priv->tcpci_data.auto_discharge_disconnect = 1;
+	priv->tcpci_data.init = mt6370_tcpc_init;
+	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
+
+	priv->vbus = devm_regulator_get_optional(dev, "vbus");
+	if (!IS_ERR(priv->vbus))
+		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
+
+	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
+	if (IS_ERR(priv->tcpci))
+		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
+				     "Failed to register tcpci port\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
+				       priv->tcpci);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
+					IRQF_ONESHOT, dev_name(dev), priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
+
+	device_init_wakeup(dev, true);
+	dev_pm_set_wake_irq(dev, irq);
+
+	return 0;
+}
+
+static int mt6370_tcpc_remove(struct platform_device *pdev)
+{
+	dev_pm_clear_wake_irq(&pdev->dev);
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_tcpc_devid_table[] = {
+	{ .compatible = "mediatek,mt6370-tcpc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
+
+static struct platform_driver mt6370_tcpc_driver = {
+	.driver = {
+		.name = "mt6370-tcpc",
+		.of_match_table = mt6370_tcpc_devid_table,
+	},
+	.probe = mt6370_tcpc_probe,
+	.remove = mt6370_tcpc_remove,
+};
+module_platform_driver(mt6370_tcpc_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds,
	AngeloGioacchino Del Regno

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

Add support for the Type-C & Power Delivery controller in
MediaTek MT6370 IC.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
- Refine remvoe callback.
- Refine the commit text from 'This commit add' to 'Add'.
---
 drivers/usb/typec/tcpm/Kconfig        |  11 ++
 drivers/usb/typec/tcpm/Makefile       |   1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
 3 files changed, 220 insertions(+)
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c

diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
index 073fd2e..e6b88ca 100644
--- a/drivers/usb/typec/tcpm/Kconfig
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -35,6 +35,17 @@ config TYPEC_MT6360
 	  USB Type-C. It works with Type-C Port Controller Manager
 	  to provide USB PD and USB Type-C functionalities.
 
+config TYPEC_TCPCI_MT6370
+	tristate "MediaTek MT6370 Type-C driver"
+	depends on MFD_MT6370
+	help
+	  MediaTek MT6370 is a multi-functional IC that includes
+	  USB Type-C. It works with Type-C Port Controller Manager
+	  to provide USB PD and USB Type-C functionalities.
+
+	  This driver can also be built as a module. The module
+	  will be called "tcpci_mt6370".
+
 config TYPEC_TCPCI_MAXIM
 	tristate "Maxim TCPCI based Type-C chip driver"
 	help
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 7d499f3..906d9dc 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
 obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
 obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
 obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
+obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
 obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
new file mode 100644
index 0000000..4f53319
--- /dev/null
+++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/tcpm.h>
+#include "tcpci.h"
+
+#define MT6370_REG_SYSCTRL8	0x9B
+
+#define MT6370_AUTOIDLE_MASK	BIT(3)
+
+#define MT6370_VENDOR_ID	0x29CF
+#define MT6370_TCPC_DID_A	0x2170
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regulator *vbus;
+	struct tcpci *tcpci;
+	struct tcpci_data tcpci_data;
+};
+
+static const struct reg_sequence mt6370_reg_init[] = {
+	REG_SEQ(0xA0, 0x1, 1000),
+	REG_SEQ(0x81, 0x38, 0),
+	REG_SEQ(0x82, 0x82, 0),
+	REG_SEQ(0xBA, 0xFC, 0),
+	REG_SEQ(0xBB, 0x50, 0),
+	REG_SEQ(0x9E, 0x8F, 0),
+	REG_SEQ(0xA1, 0x5, 0),
+	REG_SEQ(0xA2, 0x4, 0),
+	REG_SEQ(0xA3, 0x4A, 0),
+	REG_SEQ(0xA4, 0x01, 0),
+	REG_SEQ(0x95, 0x01, 0),
+	REG_SEQ(0x80, 0x71, 0),
+	REG_SEQ(0x9B, 0x3A, 1000),
+};
+
+static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
+{
+	u16 did;
+	int ret;
+
+	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
+				    ARRAY_SIZE(mt6370_reg_init));
+	if (ret)
+		return ret;
+
+	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (did == MT6370_TCPC_DID_A)
+		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
+
+	return 0;
+}
+
+static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
+				 bool enable)
+{
+	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
+				  MT6370_AUTOIDLE_MASK,
+				  !enable ? MT6370_AUTOIDLE_MASK : 0);
+}
+
+static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
+				bool source, bool sink)
+{
+	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
+						tcpci_data);
+	int ret;
+
+	ret = regulator_is_enabled(priv->vbus);
+	if (ret < 0)
+		return ret;
+
+	if (ret && !source)
+		return regulator_disable(priv->vbus);
+
+	if (!ret && source)
+		return regulator_enable(priv->vbus);
+
+	return 0;
+}
+
+static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
+{
+	struct mt6370_priv *priv = dev_id;
+
+	return tcpci_irq(priv->tcpci);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	struct regmap *regmap = priv->tcpci_data.regmap;
+	u16 vid;
+	int ret;
+
+	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (vid != MT6370_VENDOR_ID)
+		return dev_err_probe(priv->dev, -ENODEV,
+				     "Vendor ID not correct 0x%02x\n", vid);
+
+	return 0;
+}
+
+static void mt6370_unregister_tcpci_port(void *tcpci)
+{
+	tcpci_unregister_port(tcpci);
+}
+
+static int mt6370_tcpc_probe(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv;
+	struct device *dev = &pdev->dev;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->tcpci_data.regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get irq\n");
+
+	/* Assign TCPCI feature and ops */
+	priv->tcpci_data.auto_discharge_disconnect = 1;
+	priv->tcpci_data.init = mt6370_tcpc_init;
+	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
+
+	priv->vbus = devm_regulator_get_optional(dev, "vbus");
+	if (!IS_ERR(priv->vbus))
+		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
+
+	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
+	if (IS_ERR(priv->tcpci))
+		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
+				     "Failed to register tcpci port\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
+				       priv->tcpci);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
+					IRQF_ONESHOT, dev_name(dev), priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
+
+	device_init_wakeup(dev, true);
+	dev_pm_set_wake_irq(dev, irq);
+
+	return 0;
+}
+
+static int mt6370_tcpc_remove(struct platform_device *pdev)
+{
+	dev_pm_clear_wake_irq(&pdev->dev);
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_tcpc_devid_table[] = {
+	{ .compatible = "mediatek,mt6370-tcpc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
+
+static struct platform_driver mt6370_tcpc_driver = {
+	.driver = {
+		.name = "mt6370-tcpc",
+		.of_match_table = mt6370_tcpc_devid_table,
+	},
+	.probe = mt6370_tcpc_probe,
+	.remove = mt6370_tcpc_remove,
+};
+module_platform_driver(mt6370_tcpc_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

Add support for the Type-C & Power Delivery controller in
MediaTek MT6370 IC.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
- Refine remvoe callback.
- Refine the commit text from 'This commit add' to 'Add'.
---
 drivers/usb/typec/tcpm/Kconfig        |  11 ++
 drivers/usb/typec/tcpm/Makefile       |   1 +
 drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
 3 files changed, 220 insertions(+)
 create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c

diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
index 073fd2e..e6b88ca 100644
--- a/drivers/usb/typec/tcpm/Kconfig
+++ b/drivers/usb/typec/tcpm/Kconfig
@@ -35,6 +35,17 @@ config TYPEC_MT6360
 	  USB Type-C. It works with Type-C Port Controller Manager
 	  to provide USB PD and USB Type-C functionalities.
 
+config TYPEC_TCPCI_MT6370
+	tristate "MediaTek MT6370 Type-C driver"
+	depends on MFD_MT6370
+	help
+	  MediaTek MT6370 is a multi-functional IC that includes
+	  USB Type-C. It works with Type-C Port Controller Manager
+	  to provide USB PD and USB Type-C functionalities.
+
+	  This driver can also be built as a module. The module
+	  will be called "tcpci_mt6370".
+
 config TYPEC_TCPCI_MAXIM
 	tristate "Maxim TCPCI based Type-C chip driver"
 	help
diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
index 7d499f3..906d9dc 100644
--- a/drivers/usb/typec/tcpm/Makefile
+++ b/drivers/usb/typec/tcpm/Makefile
@@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
 obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
 obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
 obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
+obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
 obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
new file mode 100644
index 0000000..4f53319
--- /dev/null
+++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
@@ -0,0 +1,208 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeup.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/usb/tcpm.h>
+#include "tcpci.h"
+
+#define MT6370_REG_SYSCTRL8	0x9B
+
+#define MT6370_AUTOIDLE_MASK	BIT(3)
+
+#define MT6370_VENDOR_ID	0x29CF
+#define MT6370_TCPC_DID_A	0x2170
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regulator *vbus;
+	struct tcpci *tcpci;
+	struct tcpci_data tcpci_data;
+};
+
+static const struct reg_sequence mt6370_reg_init[] = {
+	REG_SEQ(0xA0, 0x1, 1000),
+	REG_SEQ(0x81, 0x38, 0),
+	REG_SEQ(0x82, 0x82, 0),
+	REG_SEQ(0xBA, 0xFC, 0),
+	REG_SEQ(0xBB, 0x50, 0),
+	REG_SEQ(0x9E, 0x8F, 0),
+	REG_SEQ(0xA1, 0x5, 0),
+	REG_SEQ(0xA2, 0x4, 0),
+	REG_SEQ(0xA3, 0x4A, 0),
+	REG_SEQ(0xA4, 0x01, 0),
+	REG_SEQ(0x95, 0x01, 0),
+	REG_SEQ(0x80, 0x71, 0),
+	REG_SEQ(0x9B, 0x3A, 1000),
+};
+
+static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
+{
+	u16 did;
+	int ret;
+
+	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
+				    ARRAY_SIZE(mt6370_reg_init));
+	if (ret)
+		return ret;
+
+	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (did == MT6370_TCPC_DID_A)
+		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
+
+	return 0;
+}
+
+static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
+				 bool enable)
+{
+	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
+				  MT6370_AUTOIDLE_MASK,
+				  !enable ? MT6370_AUTOIDLE_MASK : 0);
+}
+
+static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
+				bool source, bool sink)
+{
+	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
+						tcpci_data);
+	int ret;
+
+	ret = regulator_is_enabled(priv->vbus);
+	if (ret < 0)
+		return ret;
+
+	if (ret && !source)
+		return regulator_disable(priv->vbus);
+
+	if (!ret && source)
+		return regulator_enable(priv->vbus);
+
+	return 0;
+}
+
+static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
+{
+	struct mt6370_priv *priv = dev_id;
+
+	return tcpci_irq(priv->tcpci);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	struct regmap *regmap = priv->tcpci_data.regmap;
+	u16 vid;
+	int ret;
+
+	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
+	if (ret)
+		return ret;
+
+	if (vid != MT6370_VENDOR_ID)
+		return dev_err_probe(priv->dev, -ENODEV,
+				     "Vendor ID not correct 0x%02x\n", vid);
+
+	return 0;
+}
+
+static void mt6370_unregister_tcpci_port(void *tcpci)
+{
+	tcpci_unregister_port(tcpci);
+}
+
+static int mt6370_tcpc_probe(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv;
+	struct device *dev = &pdev->dev;
+	int irq, ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->tcpci_data.regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return dev_err_probe(dev, irq, "Failed to get irq\n");
+
+	/* Assign TCPCI feature and ops */
+	priv->tcpci_data.auto_discharge_disconnect = 1;
+	priv->tcpci_data.init = mt6370_tcpc_init;
+	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
+
+	priv->vbus = devm_regulator_get_optional(dev, "vbus");
+	if (!IS_ERR(priv->vbus))
+		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
+
+	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
+	if (IS_ERR(priv->tcpci))
+		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
+				     "Failed to register tcpci port\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
+				       priv->tcpci);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
+					IRQF_ONESHOT, dev_name(dev), priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
+
+	device_init_wakeup(dev, true);
+	dev_pm_set_wake_irq(dev, irq);
+
+	return 0;
+}
+
+static int mt6370_tcpc_remove(struct platform_device *pdev)
+{
+	dev_pm_clear_wake_irq(&pdev->dev);
+	device_init_wakeup(&pdev->dev, false);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_tcpc_devid_table[] = {
+	{ .compatible = "mediatek,mt6370-tcpc" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
+
+static struct platform_driver mt6370_tcpc_driver = {
+	.driver = {
+		.name = "mt6370-tcpc",
+		.of_match_table = mt6370_tcpc_devid_table,
+	},
+	.probe = mt6370_tcpc_probe,
+	.remove = mt6370_tcpc_remove,
+};
+module_platform_driver(mt6370_tcpc_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds,
	AngeloGioacchino Del Regno

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

Add a support the MT6370 ADC driver for system monitoring, including
charger current, voltage, and temperature.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Using 'struct device *dev = &pdev->dev' in probe()
- Revise the sixth parameter of regmap_read_poll_timeout() by
  replacing '1000' with 'MILLI'
- Revise the units of three macros
  - MT6370_AICR_400MA --> MT6370_AICR_400_mA
  - MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
  - MT6370_ICHG_900MA --> MT6370_ICHG_900_mA
---
 drivers/iio/adc/Kconfig      |  12 ++
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/mt6370-adc.c | 274 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/iio/adc/mt6370-adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 48ace74..60bcc28 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -737,6 +737,18 @@ config MEDIATEK_MT6360_ADC
 	  is used in smartphones and tablets and supports a 11 channel
 	  general purpose ADC.
 
+config MEDIATEK_MT6370_ADC
+	tristate "MediaTek MT6370 ADC driver"
+	depends on MFD_MT6370
+	help
+	  Say yes here to enable MediaTek MT6370 ADC support.
+
+	  This ADC driver provides 9 channels for system monitoring (charger
+	  current, voltage, and temperature).
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-adc".
+
 config MEDIATEK_MT6577_AUXADC
 	tristate "MediaTek AUXADC driver"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 39d806f..0ce285c 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MCP3911) += mcp3911.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644
index 0000000..c665de9
--- /dev/null
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3		0x113 /* AICR */
+#define MT6370_REG_CHG_CTRL7		0x117 /* ICHG */
+#define MT6370_REG_CHG_ADC		0x121
+#define MT6370_REG_ADC_DATA_H		0x14C
+
+#define MT6370_ADC_START_MASK		BIT(0)
+#define MT6370_ADC_IN_SEL_MASK		GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK		GENMASK(7, 2)
+
+#define MT6370_AICR_400_mA		0x6
+#define MT6370_ICHG_500_mA		0x4
+#define MT6370_ICHG_900_mA		0x8
+
+#define ADC_CONV_TIME_MS		35
+#define ADC_CONV_POLLING_TIME_US	1000
+
+struct mt6370_adc_data {
+	struct device *dev;
+	struct regmap *regmap;
+	/*
+	 * This mutex lock is for preventing the different ADC channels
+	 * from being read at the same time.
+	 */
+	struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+				   unsigned long addr, int *val)
+{
+	unsigned int reg_val;
+	__be16 be_val;
+	int ret;
+
+	mutex_lock(&priv->adc_lock);
+
+	reg_val = MT6370_ADC_START_MASK |
+		  FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+	if (ret)
+		goto adc_unlock;
+
+	msleep(ADC_CONV_TIME_MS);
+
+	ret = regmap_read_poll_timeout(priv->regmap,
+				       MT6370_REG_CHG_ADC, reg_val,
+				       !(reg_val & MT6370_ADC_START_MASK),
+				       ADC_CONV_POLLING_TIME_US,
+				       ADC_CONV_TIME_MS * MILLI * 3);
+	if (ret) {
+		dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+		goto adc_unlock;
+	}
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+			      &be_val, sizeof(be_val));
+	if (ret)
+		goto adc_unlock;
+
+	*val = be16_to_cpu(be_val);
+	ret = IIO_VAL_INT;
+
+adc_unlock:
+	mutex_unlock(&priv->adc_lock);
+
+	return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+				 int chan, int *val1, int *val2)
+{
+	unsigned int reg_val;
+	int ret;
+
+	switch (chan) {
+	case MT6370_CHAN_VBAT:
+	case MT6370_CHAN_VSYS:
+	case MT6370_CHAN_CHG_VDDP:
+		*val1 = 5;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_IBUS:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_AICR_400_mA)
+			*val1 = 3350;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_IBAT:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_ICHG_500_mA)
+			*val1 = 2375;
+		else if (reg_val >= MT6370_ICHG_500_mA &&
+			 reg_val < MT6370_ICHG_900_mA)
+			*val1 = 2680;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_VBUSDIV5:
+		*val1 = 25;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_VBUSDIV2:
+		*val1 = 50;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_TS_BAT:
+		*val1 = 25;
+		*val2 = 10000;
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_TEMP_JC:
+		*val1 = 2000;
+		return IIO_VAL_FRACTIONAL;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+				  int chan, int *val)
+{
+	*val = -20;
+
+	return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+			       const struct iio_chan_spec *chan,
+			       int *val, int *val2, long mask)
+{
+	struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return mt6370_adc_read_channel(priv, chan->channel,
+					       chan->address, val);
+	case IIO_CHAN_INFO_SCALE:
+		return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+	case IIO_CHAN_INFO_OFFSET:
+		return mt6370_adc_read_offset(priv, chan->channel, val);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+	[MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+	[MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+	[MT6370_CHAN_VSYS] = "vsys",
+	[MT6370_CHAN_VBAT] = "vbat",
+	[MT6370_CHAN_TS_BAT] = "ts_bat",
+	[MT6370_CHAN_IBUS] = "ibus",
+	[MT6370_CHAN_IBAT] = "ibat",
+	[MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+	[MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+				 struct iio_chan_spec const *chan, char *label)
+{
+	return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+	.read_raw = mt6370_adc_read_raw,
+	.read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) {	\
+	.type = _type,						\
+	.channel = MT6370_CHAN_##_idx,				\
+	.address = _addr,					\
+	.scan_index = MT6370_CHAN_##_idx,			\
+	.indexed = 1,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+			      BIT(IIO_CHAN_INFO_SCALE) |	\
+			      _extra_info,			\
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+	MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+	MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+	MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+	MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+	MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+	MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+	MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+	MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+	MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_adc_data *priv;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	priv = iio_priv(indio_dev);
+	priv->dev = dev;
+	priv->regmap = regmap;
+	mutex_init(&priv->adc_lock);
+
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+	indio_dev->name = "mt6370-adc";
+	indio_dev->info = &mt6370_adc_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6370_adc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+	{ .compatible = "mediatek,mt6370-adc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+	.driver = {
+		.name = "mt6370-adc",
+		.of_match_table = mt6370_adc_of_id,
+	},
+	.probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

Add a support the MT6370 ADC driver for system monitoring, including
charger current, voltage, and temperature.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Using 'struct device *dev = &pdev->dev' in probe()
- Revise the sixth parameter of regmap_read_poll_timeout() by
  replacing '1000' with 'MILLI'
- Revise the units of three macros
  - MT6370_AICR_400MA --> MT6370_AICR_400_mA
  - MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
  - MT6370_ICHG_900MA --> MT6370_ICHG_900_mA
---
 drivers/iio/adc/Kconfig      |  12 ++
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/mt6370-adc.c | 274 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/iio/adc/mt6370-adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 48ace74..60bcc28 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -737,6 +737,18 @@ config MEDIATEK_MT6360_ADC
 	  is used in smartphones and tablets and supports a 11 channel
 	  general purpose ADC.
 
+config MEDIATEK_MT6370_ADC
+	tristate "MediaTek MT6370 ADC driver"
+	depends on MFD_MT6370
+	help
+	  Say yes here to enable MediaTek MT6370 ADC support.
+
+	  This ADC driver provides 9 channels for system monitoring (charger
+	  current, voltage, and temperature).
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-adc".
+
 config MEDIATEK_MT6577_AUXADC
 	tristate "MediaTek AUXADC driver"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 39d806f..0ce285c 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MCP3911) += mcp3911.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644
index 0000000..c665de9
--- /dev/null
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3		0x113 /* AICR */
+#define MT6370_REG_CHG_CTRL7		0x117 /* ICHG */
+#define MT6370_REG_CHG_ADC		0x121
+#define MT6370_REG_ADC_DATA_H		0x14C
+
+#define MT6370_ADC_START_MASK		BIT(0)
+#define MT6370_ADC_IN_SEL_MASK		GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK		GENMASK(7, 2)
+
+#define MT6370_AICR_400_mA		0x6
+#define MT6370_ICHG_500_mA		0x4
+#define MT6370_ICHG_900_mA		0x8
+
+#define ADC_CONV_TIME_MS		35
+#define ADC_CONV_POLLING_TIME_US	1000
+
+struct mt6370_adc_data {
+	struct device *dev;
+	struct regmap *regmap;
+	/*
+	 * This mutex lock is for preventing the different ADC channels
+	 * from being read at the same time.
+	 */
+	struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+				   unsigned long addr, int *val)
+{
+	unsigned int reg_val;
+	__be16 be_val;
+	int ret;
+
+	mutex_lock(&priv->adc_lock);
+
+	reg_val = MT6370_ADC_START_MASK |
+		  FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+	if (ret)
+		goto adc_unlock;
+
+	msleep(ADC_CONV_TIME_MS);
+
+	ret = regmap_read_poll_timeout(priv->regmap,
+				       MT6370_REG_CHG_ADC, reg_val,
+				       !(reg_val & MT6370_ADC_START_MASK),
+				       ADC_CONV_POLLING_TIME_US,
+				       ADC_CONV_TIME_MS * MILLI * 3);
+	if (ret) {
+		dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+		goto adc_unlock;
+	}
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+			      &be_val, sizeof(be_val));
+	if (ret)
+		goto adc_unlock;
+
+	*val = be16_to_cpu(be_val);
+	ret = IIO_VAL_INT;
+
+adc_unlock:
+	mutex_unlock(&priv->adc_lock);
+
+	return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+				 int chan, int *val1, int *val2)
+{
+	unsigned int reg_val;
+	int ret;
+
+	switch (chan) {
+	case MT6370_CHAN_VBAT:
+	case MT6370_CHAN_VSYS:
+	case MT6370_CHAN_CHG_VDDP:
+		*val1 = 5;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_IBUS:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_AICR_400_mA)
+			*val1 = 3350;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_IBAT:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_ICHG_500_mA)
+			*val1 = 2375;
+		else if (reg_val >= MT6370_ICHG_500_mA &&
+			 reg_val < MT6370_ICHG_900_mA)
+			*val1 = 2680;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_VBUSDIV5:
+		*val1 = 25;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_VBUSDIV2:
+		*val1 = 50;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_TS_BAT:
+		*val1 = 25;
+		*val2 = 10000;
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_TEMP_JC:
+		*val1 = 2000;
+		return IIO_VAL_FRACTIONAL;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+				  int chan, int *val)
+{
+	*val = -20;
+
+	return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+			       const struct iio_chan_spec *chan,
+			       int *val, int *val2, long mask)
+{
+	struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return mt6370_adc_read_channel(priv, chan->channel,
+					       chan->address, val);
+	case IIO_CHAN_INFO_SCALE:
+		return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+	case IIO_CHAN_INFO_OFFSET:
+		return mt6370_adc_read_offset(priv, chan->channel, val);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+	[MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+	[MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+	[MT6370_CHAN_VSYS] = "vsys",
+	[MT6370_CHAN_VBAT] = "vbat",
+	[MT6370_CHAN_TS_BAT] = "ts_bat",
+	[MT6370_CHAN_IBUS] = "ibus",
+	[MT6370_CHAN_IBAT] = "ibat",
+	[MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+	[MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+				 struct iio_chan_spec const *chan, char *label)
+{
+	return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+	.read_raw = mt6370_adc_read_raw,
+	.read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) {	\
+	.type = _type,						\
+	.channel = MT6370_CHAN_##_idx,				\
+	.address = _addr,					\
+	.scan_index = MT6370_CHAN_##_idx,			\
+	.indexed = 1,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+			      BIT(IIO_CHAN_INFO_SCALE) |	\
+			      _extra_info,			\
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+	MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+	MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+	MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+	MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+	MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+	MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+	MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+	MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+	MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_adc_data *priv;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	priv = iio_priv(indio_dev);
+	priv->dev = dev;
+	priv->regmap = regmap;
+	mutex_init(&priv->adc_lock);
+
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+	indio_dev->name = "mt6370-adc";
+	indio_dev->info = &mt6370_adc_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6370_adc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+	{ .compatible = "mediatek,mt6370-adc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+	.driver = {
+		.name = "mt6370-adc",
+		.of_match_table = mt6370_adc_of_id,
+	},
+	.probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

Add a support the MT6370 ADC driver for system monitoring, including
charger current, voltage, and temperature.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---

v6
- Using 'struct device *dev = &pdev->dev' in probe()
- Revise the sixth parameter of regmap_read_poll_timeout() by
  replacing '1000' with 'MILLI'
- Revise the units of three macros
  - MT6370_AICR_400MA --> MT6370_AICR_400_mA
  - MT6370_ICHG_500MA --> MT6370_ICHG_500_mA
  - MT6370_ICHG_900MA --> MT6370_ICHG_900_mA
---
 drivers/iio/adc/Kconfig      |  12 ++
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/mt6370-adc.c | 274 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/iio/adc/mt6370-adc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 48ace74..60bcc28 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -737,6 +737,18 @@ config MEDIATEK_MT6360_ADC
 	  is used in smartphones and tablets and supports a 11 channel
 	  general purpose ADC.
 
+config MEDIATEK_MT6370_ADC
+	tristate "MediaTek MT6370 ADC driver"
+	depends on MFD_MT6370
+	help
+	  Say yes here to enable MediaTek MT6370 ADC support.
+
+	  This ADC driver provides 9 channels for system monitoring (charger
+	  current, voltage, and temperature).
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-adc".
+
 config MEDIATEK_MT6577_AUXADC
 	tristate "MediaTek AUXADC driver"
 	depends on ARCH_MEDIATEK || COMPILE_TEST
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 39d806f..0ce285c 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
 obj-$(CONFIG_MCP3422) += mcp3422.o
 obj-$(CONFIG_MCP3911) += mcp3911.o
 obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o
+obj-$(CONFIG_MEDIATEK_MT6370_ADC) += mt6370-adc.o
 obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
 obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c
new file mode 100644
index 0000000..c665de9
--- /dev/null
+++ b/drivers/iio/adc/mt6370-adc.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/units.h>
+
+#include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
+
+#define MT6370_REG_CHG_CTRL3		0x113 /* AICR */
+#define MT6370_REG_CHG_CTRL7		0x117 /* ICHG */
+#define MT6370_REG_CHG_ADC		0x121
+#define MT6370_REG_ADC_DATA_H		0x14C
+
+#define MT6370_ADC_START_MASK		BIT(0)
+#define MT6370_ADC_IN_SEL_MASK		GENMASK(7, 4)
+#define MT6370_AICR_ICHG_MASK		GENMASK(7, 2)
+
+#define MT6370_AICR_400_mA		0x6
+#define MT6370_ICHG_500_mA		0x4
+#define MT6370_ICHG_900_mA		0x8
+
+#define ADC_CONV_TIME_MS		35
+#define ADC_CONV_POLLING_TIME_US	1000
+
+struct mt6370_adc_data {
+	struct device *dev;
+	struct regmap *regmap;
+	/*
+	 * This mutex lock is for preventing the different ADC channels
+	 * from being read at the same time.
+	 */
+	struct mutex adc_lock;
+};
+
+static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
+				   unsigned long addr, int *val)
+{
+	unsigned int reg_val;
+	__be16 be_val;
+	int ret;
+
+	mutex_lock(&priv->adc_lock);
+
+	reg_val = MT6370_ADC_START_MASK |
+		  FIELD_PREP(MT6370_ADC_IN_SEL_MASK, addr);
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, reg_val);
+	if (ret)
+		goto adc_unlock;
+
+	msleep(ADC_CONV_TIME_MS);
+
+	ret = regmap_read_poll_timeout(priv->regmap,
+				       MT6370_REG_CHG_ADC, reg_val,
+				       !(reg_val & MT6370_ADC_START_MASK),
+				       ADC_CONV_POLLING_TIME_US,
+				       ADC_CONV_TIME_MS * MILLI * 3);
+	if (ret) {
+		dev_err(priv->dev, "Failed to read ADC register (%d)\n", ret);
+		goto adc_unlock;
+	}
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_ADC_DATA_H,
+			      &be_val, sizeof(be_val));
+	if (ret)
+		goto adc_unlock;
+
+	*val = be16_to_cpu(be_val);
+	ret = IIO_VAL_INT;
+
+adc_unlock:
+	mutex_unlock(&priv->adc_lock);
+
+	return ret;
+}
+
+static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
+				 int chan, int *val1, int *val2)
+{
+	unsigned int reg_val;
+	int ret;
+
+	switch (chan) {
+	case MT6370_CHAN_VBAT:
+	case MT6370_CHAN_VSYS:
+	case MT6370_CHAN_CHG_VDDP:
+		*val1 = 5;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_IBUS:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL3, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_AICR_400_mA)
+			*val1 = 3350;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_IBAT:
+		ret = regmap_read(priv->regmap, MT6370_REG_CHG_CTRL7, &reg_val);
+		if (ret)
+			return ret;
+
+		reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
+		if (reg_val < MT6370_ICHG_500_mA)
+			*val1 = 2375;
+		else if (reg_val >= MT6370_ICHG_500_mA &&
+			 reg_val < MT6370_ICHG_900_mA)
+			*val1 = 2680;
+		else
+			*val1 = 5000;
+
+		*val2 = 100;
+
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_VBUSDIV5:
+		*val1 = 25;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_VBUSDIV2:
+		*val1 = 50;
+		return IIO_VAL_INT;
+	case MT6370_CHAN_TS_BAT:
+		*val1 = 25;
+		*val2 = 10000;
+		return IIO_VAL_FRACTIONAL;
+	case MT6370_CHAN_TEMP_JC:
+		*val1 = 2000;
+		return IIO_VAL_FRACTIONAL;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_adc_read_offset(struct mt6370_adc_data *priv,
+				  int chan, int *val)
+{
+	*val = -20;
+
+	return IIO_VAL_INT;
+}
+
+static int mt6370_adc_read_raw(struct iio_dev *iio_dev,
+			       const struct iio_chan_spec *chan,
+			       int *val, int *val2, long mask)
+{
+	struct mt6370_adc_data *priv = iio_priv(iio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return mt6370_adc_read_channel(priv, chan->channel,
+					       chan->address, val);
+	case IIO_CHAN_INFO_SCALE:
+		return mt6370_adc_read_scale(priv, chan->channel, val, val2);
+	case IIO_CHAN_INFO_OFFSET:
+		return mt6370_adc_read_offset(priv, chan->channel, val);
+	default:
+		return -EINVAL;
+	}
+}
+
+static const char * const mt6370_channel_labels[MT6370_CHAN_MAX] = {
+	[MT6370_CHAN_VBUSDIV5] = "vbusdiv5",
+	[MT6370_CHAN_VBUSDIV2] = "vbusdiv2",
+	[MT6370_CHAN_VSYS] = "vsys",
+	[MT6370_CHAN_VBAT] = "vbat",
+	[MT6370_CHAN_TS_BAT] = "ts_bat",
+	[MT6370_CHAN_IBUS] = "ibus",
+	[MT6370_CHAN_IBAT] = "ibat",
+	[MT6370_CHAN_CHG_VDDP] = "chg_vddp",
+	[MT6370_CHAN_TEMP_JC] = "temp_jc",
+};
+
+static int mt6370_adc_read_label(struct iio_dev *iio_dev,
+				 struct iio_chan_spec const *chan, char *label)
+{
+	return sysfs_emit(label, "%s\n", mt6370_channel_labels[chan->channel]);
+}
+
+static const struct iio_info mt6370_adc_iio_info = {
+	.read_raw = mt6370_adc_read_raw,
+	.read_label = mt6370_adc_read_label,
+};
+
+#define MT6370_ADC_CHAN(_idx, _type, _addr, _extra_info) {	\
+	.type = _type,						\
+	.channel = MT6370_CHAN_##_idx,				\
+	.address = _addr,					\
+	.scan_index = MT6370_CHAN_##_idx,			\
+	.indexed = 1,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
+			      BIT(IIO_CHAN_INFO_SCALE) |	\
+			      _extra_info,			\
+}
+
+static const struct iio_chan_spec mt6370_adc_channels[] = {
+	MT6370_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE, 1, 0),
+	MT6370_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE, 2, 0),
+	MT6370_ADC_CHAN(VSYS, IIO_VOLTAGE, 3, 0),
+	MT6370_ADC_CHAN(VBAT, IIO_VOLTAGE, 4, 0),
+	MT6370_ADC_CHAN(TS_BAT, IIO_VOLTAGE, 6, 0),
+	MT6370_ADC_CHAN(IBUS, IIO_CURRENT, 8, 0),
+	MT6370_ADC_CHAN(IBAT, IIO_CURRENT, 9, 0),
+	MT6370_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE, 11, 0),
+	MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
+};
+
+static int mt6370_adc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_adc_data *priv;
+	struct iio_dev *indio_dev;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	priv = iio_priv(indio_dev);
+	priv->dev = dev;
+	priv->regmap = regmap;
+	mutex_init(&priv->adc_lock);
+
+	ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to reset ADC\n");
+
+	indio_dev->name = "mt6370-adc";
+	indio_dev->info = &mt6370_adc_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = mt6370_adc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(mt6370_adc_channels);
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id mt6370_adc_of_id[] = {
+	{ .compatible = "mediatek,mt6370-adc", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_adc_of_id);
+
+static struct platform_driver mt6370_adc_driver = {
+	.driver = {
+		.name = "mt6370-adc",
+		.of_match_table = mt6370_adc_of_id,
+	},
+	.probe = mt6370_adc_probe,
+};
+module_platform_driver(mt6370_adc_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MT6370 ADC Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds MediaTek MT6370 Charger driver support. The charger module
of MT6370 supports High-Accuracy Voltage/Current Regulation,
Average Input Current Regulation, Battery Temperature Sensing,
Over-Temperature Protection, DPDM Detection for BC1.2.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---

v6
- Remove the varable (*psy_desc) of struct mt6370_priv
- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
  POWER_SUPPLY_TYPE_USB_DCP)
- Remove useless remove()
- Revise all units from mini- to micro-
- Revise get/set power_supply_prop (change to directly return get/set
  regmap_field)
- Revise probe() and use devm_add_action_or_reset() for handling of the
  workqueue/delayed_work/mutex
- Revise mt6370_chg_psy_desc
  - Add '.name = "mt6370-charger"'
  - Use 'static const'

---

uevent dump:
vim3l:/sys/class/power_supply/mt6370-charger # cat uevent
POWER_SUPPLY_NAME=mt6370-charger
POWER_SUPPLY_TYPE=USB
POWER_SUPPLY_ONLINE=0
POWER_SUPPLY_STATUS=Discharging
POWER_SUPPLY_CHARGE_TYPE=N/A
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT=900000
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT_MAX=5000000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE=4200000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE_MAX=4710000
POWER_SUPPLY_INPUT_CURRENT_LIMIT=500000
POWER_SUPPLY_INPUT_VOLTAGE_LIMIT=4400000
POWER_SUPPLY_PRECHARGE_CURRENT=150000
POWER_SUPPLY_CHARGE_TERM_CURRENT=250000
POWER_SUPPLY_USB_TYPE=[Unknown] SDP CDP DCP
---
 drivers/power/supply/Kconfig          |  14 +
 drivers/power/supply/Makefile         |   1 +
 drivers/power/supply/mt6370-charger.c | 973 ++++++++++++++++++++++++++++++++++
 3 files changed, 988 insertions(+)
 create mode 100644 drivers/power/supply/mt6370-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 1aa8323..591deb8 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -619,6 +619,20 @@ config CHARGER_MT6360
 	  Average Input Current Regulation, Battery Temperature Sensing,
 	  Over-Temperature Protection, DPDM Detection for BC1.2.
 
+config CHARGER_MT6370
+	tristate "MediaTek MT6370 Charger Driver"
+	depends on MFD_MT6370
+	depends on REGULATOR
+	select LINEAR_RANGES
+	help
+	  Say Y here to enable MT6370 Charger Part.
+	  The device supports High-Accuracy Voltage/Current Regulation,
+	  Average Input Current Regulation, Battery Temperature Sensing,
+	  Over-Temperature Protection, DPDM Detection for BC1.2.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-charger".
+
 config CHARGER_QCOM_SMBB
 	tristate "Qualcomm Switch-Mode Battery Charger and Boost"
 	depends on MFD_SPMI_PMIC || COMPILE_TEST
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7f02f36..8c95276 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_MP2629)	+= mp2629_charger.o
 obj-$(CONFIG_CHARGER_MT6360)	+= mt6360_charger.o
+obj-$(CONFIG_CHARGER_MT6370)	+= mt6370-charger.o
 obj-$(CONFIG_CHARGER_QCOM_SMBB)	+= qcom_smbb.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
 obj-$(CONFIG_CHARGER_BQ24190)	+= bq24190_charger.o
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
new file mode 100644
index 0000000..84f1436
--- /dev/null
+++ b/drivers/power/supply/mt6370-charger.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/workqueue.h>
+
+#define MT6370_REG_CHG_CTRL1		0x111
+#define MT6370_REG_CHG_CTRL2		0x112
+#define MT6370_REG_CHG_CTRL3		0x113
+#define MT6370_REG_CHG_CTRL4		0x114
+#define MT6370_REG_CHG_CTRL5		0x115
+#define MT6370_REG_CHG_CTRL6		0x116
+#define MT6370_REG_CHG_CTRL7		0x117
+#define MT6370_REG_CHG_CTRL8		0x118
+#define MT6370_REG_CHG_CTRL9		0x119
+#define MT6370_REG_CHG_CTRL10		0x11A
+#define MT6370_REG_DEVICE_TYPE		0x122
+#define MT6370_REG_USB_STATUS1		0x127
+#define MT6370_REG_CHG_STAT		0x14A
+#define MT6370_REG_FLED_EN		0x17E
+#define MT6370_REG_CHG_STAT1		0X1D0
+#define MT6370_REG_OVPCTRL_STAT		0x1D8
+
+#define MT6370_VOBST_MASK		GENMASK(7, 2)
+#define MT6370_OTG_PIN_EN_MASK		BIT(1)
+#define MT6370_OPA_MODE_MASK		BIT(0)
+#define MT6370_OTG_OC_MASK		GENMASK(2, 0)
+
+#define MT6370_MIVR_IBUS_TH_100_mA	100000
+#define MT6370_ADC_CHAN_IBUS		5
+#define MT6370_ADC_CHAN_MAX		9
+
+enum mt6370_chg_reg_field {
+	/* MT6370_REG_CHG_CTRL2 */
+	F_IINLMTSEL, F_CFO_EN, F_CHG_EN,
+	/* MT6370_REG_CHG_CTRL3 */
+	F_IAICR, F_AICR_EN, F_ILIM_EN,
+	/* MT6370_REG_CHG_CTRL4 */
+	F_VOREG,
+	/* MT6370_REG_CHG_CTRL6 */
+	F_VMIVR,
+	/* MT6370_REG_CHG_CTRL7 */
+	F_ICHG,
+	/* MT6370_REG_CHG_CTRL8 */
+	F_IPREC,
+	/* MT6370_REG_CHG_CTRL9 */
+	F_IEOC,
+	/* MT6370_REG_DEVICE_TYPE */
+	F_USBCHGEN,
+	/* MT6370_REG_USB_STATUS1 */
+	F_USB_STAT, F_CHGDET,
+	/* MT6370_REG_CHG_STAT */
+	F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL,
+	/* MT6370_REG_FLED_EN */
+	F_FL_STROBE,
+	/* MT6370_REG_CHG_STAT1 */
+	F_CHG_MIVR_STAT,
+	/* MT6370_REG_OVPCTRL_STAT */
+	F_UVP_D_STAT,
+	F_MAX
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct iio_channel *iio_adcs;
+	struct mutex attach_lock;
+	struct power_supply *psy;
+	struct regmap *regmap;
+	struct regmap_field *rmap_fields[F_MAX];
+	struct regulator_dev *rdev;
+	struct workqueue_struct *wq;
+	struct work_struct bc12_work;
+	struct delayed_work mivr_dwork;
+	int attach;
+	int psy_usb_type;
+	bool pwr_rdy;
+};
+
+enum mt6370_usb_status {
+	MT6370_USB_STAT_NO_VBUS = 0,
+	MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING,
+	MT6370_USB_STAT_SDP,
+	MT6370_USB_STAT_SDP_NSTD,
+	MT6370_USB_STAT_DCP,
+	MT6370_USB_STAT_CDP,
+	MT6370_USB_STAT_MAX
+};
+
+struct mt6370_chg_field {
+	const char *name;
+	const struct linear_range *range;
+	struct reg_field field;
+};
+
+enum {
+	MT6370_RANGE_F_IAICR = 0,
+	MT6370_RANGE_F_VOREG,
+	MT6370_RANGE_F_VMIVR,
+	MT6370_RANGE_F_ICHG,
+	MT6370_RANGE_F_IPREC,
+	MT6370_RANGE_F_IEOC,
+	MT6370_RANGE_F_MAX
+};
+
+#define MT6370_CHG_LINEAR_RANGE(_rfd, _min, _min_sel, _max_sel, _step)	\
+[_rfd] = {								\
+	.min = _min,							\
+	.min_sel = _min_sel,						\
+	.max_sel = _max_sel,						\
+	.step = _step,							\
+}
+
+static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = {
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IAICR, 100000, 0x0, 0x3F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VOREG, 3900000, 0x0, 0x51, 10000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VMIVR, 3900000, 0x0, 0x5F, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_ICHG, 900000, 0x08, 0x31, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IPREC, 100000, 0x0, 0x0F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IEOC, 100000, 0x0, 0x0F, 50000),
+};
+
+#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb)				\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = NULL,							\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb)			\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = &mt6370_chg_ranges[MT6370_RANGE_##_fd],		\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = {
+	MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3),
+	MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1),
+	MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7),
+	MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1),
+	MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7),
+	MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3),
+	MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7),
+	MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7),
+	MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6),
+	MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3),
+	MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7),
+	MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3),
+	MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5),
+	MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2),
+	MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6),
+	MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4),
+};
+
+static inline int mt6370_chg_field_get(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int *val)
+{
+	int ret;
+	unsigned int reg_val;
+
+	ret = regmap_field_read(priv->rmap_fields[fd], &reg_val);
+	if (ret < 0)
+		return ret;
+
+	if (mt6370_chg_fields[fd].range)
+		return linear_range_get_value(mt6370_chg_fields[fd].range,
+					      reg_val, val);
+
+	*val = reg_val;
+	return 0;
+}
+
+static inline int mt6370_chg_field_set(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int val)
+{
+	int ret;
+	bool f;
+	const struct linear_range *r;
+
+	if (mt6370_chg_fields[fd].range) {
+		r = mt6370_chg_fields[fd].range;
+
+		if (fd == F_VMIVR) {
+			ret = linear_range_get_selector_high(r, val, &val, &f);
+			if (!ret)
+				val = r->max_sel;
+		} else {
+			linear_range_get_selector_within(r, val, &val);
+		}
+	}
+
+	return regmap_field_write(priv->rmap_fields[fd], val);
+}
+
+enum {
+	MT6370_CHG_STAT_READY = 0,
+	MT6370_CHG_STAT_CHARGE_IN_PROGRESS,
+	MT6370_CHG_STAT_DONE,
+	MT6370_CHG_STAT_FAULT,
+	MT6370_CHG_STAT_MAX
+};
+
+enum {
+	MT6370_ATTACH_STAT_DETACH = 0,
+	MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE,
+	MT6370_ATTACH_STAT_ATTACH_BC12_DONE,
+	MT6370_ATTACH_STAT_ATTACH_MAX
+};
+
+static int mt6370_chg_otg_of_parse_cb(struct device_node *of,
+				      const struct regulator_desc *rdesc,
+				      struct regulator_config *rcfg)
+{
+	struct mt6370_priv *priv = rcfg->driver_data;
+
+	rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of),
+						 "enable", 0, GPIOD_OUT_LOW |
+						 GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+						 rdesc->name);
+	if (IS_ERR(rcfg->ena_gpiod)) {
+		rcfg->ena_gpiod = NULL;
+		return 0;
+	}
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1,
+				  MT6370_OTG_PIN_EN_MASK,
+				  MT6370_OTG_PIN_EN_MASK);
+}
+
+static void mt6370_chg_bc12_work_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						bc12_work);
+	int ret;
+	bool rpt_psy = false;
+	unsigned int attach, usb_stat;
+
+	mutex_lock(&priv->attach_lock);
+	attach = priv->attach;
+
+	switch (attach) {
+	case MT6370_ATTACH_STAT_DETACH:
+		usb_stat = 0;
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_DONE:
+		ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat);
+		if (ret < 0) {
+			dev_err(priv->dev, "Failed to get USB status\n");
+			goto bc12_work_func_out;
+		}
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE:
+		ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach);
+		if (ret < 0)
+			dev_err(priv->dev, "Failed to enable USB CHG EN\n");
+		goto bc12_work_func_out;
+	default:
+		dev_err(priv->dev, "Invalid attach state\n");
+		goto bc12_work_func_out;
+	}
+
+	rpt_psy = true;
+
+	switch (usb_stat) {
+	case MT6370_USB_STAT_SDP:
+	case MT6370_USB_STAT_SDP_NSTD:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
+		break;
+	case MT6370_USB_STAT_DCP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+		break;
+	case MT6370_USB_STAT_CDP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
+		break;
+	case MT6370_USB_STAT_NO_VBUS:
+	case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING:
+	default:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		break;
+	}
+
+bc12_work_func_out:
+	mutex_unlock(&priv->attach_lock);
+
+	if (rpt_psy)
+		power_supply_changed(priv->psy);
+}
+
+static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
+					 const char *irq_name, bool en)
+{
+	int irq_num;
+	struct platform_device *pdev = to_platform_device(priv->dev);
+
+	irq_num = platform_get_irq_byname(pdev, irq_name);
+	if (irq_num < 0)
+		return;
+
+	if (en)
+		enable_irq(irq_num);
+	else
+		disable_irq_nosync(irq_num);
+}
+
+static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int fl_strobe;
+
+	/* check if flash led in strobe mode */
+	ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get FL_STROBE_EN\n");
+		return ret;
+	}
+
+	if (fl_strobe) {
+		dev_err(priv->dev, "Flash led is still in strobe mode\n");
+		return ret;
+	}
+
+	/* cfo off */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable CFO_EN\n");
+		return ret;
+	}
+
+	/* cfo on */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 1);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to enable CFO_EN\n");
+
+	return ret;
+}
+
+static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan,
+				    int *val)
+{
+	int ret;
+
+	if (chan >= MT6370_ADC_CHAN_MAX)
+		return -EINVAL;
+
+	ret = iio_read_channel_processed(&priv->iio_adcs[chan], val);
+	if (ret)
+		dev_err(priv->dev, "Failed to read ADC\n");
+
+	return ret;
+}
+
+static void mt6370_chg_mivr_dwork_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						mivr_dwork.work);
+	int ret;
+	unsigned int mivr_stat, ibus;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get mivr state\n");
+		goto mivr_handler_out;
+	}
+
+	if (!mivr_stat)
+		goto mivr_handler_out;
+
+	ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get ibus\n");
+		goto mivr_handler_out;
+	}
+
+	if (ibus < MT6370_MIVR_IBUS_TH_100_mA) {
+		ret = mt6370_chg_toggle_cfo(priv);
+		if (ret)
+			dev_err(priv->dev, "Failed to toggle cfo\n");
+	}
+
+mivr_handler_out:
+	mt6370_chg_enable_irq(priv, "mivr", true);
+	pm_relax(priv->dev);
+}
+
+static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int pwr_rdy, otg_en;
+	union power_supply_propval val;
+
+	/* Check in OTG mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get OTG state\n");
+		return;
+	}
+
+	if (otg_en)
+		return;
+
+	ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &pwr_rdy);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get pwr_rdy state reg\n");
+		return;
+	}
+
+	val.intval = !pwr_rdy;
+
+	ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&val);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to start attach/detach flow\n");
+}
+
+static int mt6370_chg_get_online(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	mutex_lock(&priv->attach_lock);
+	val->intval = !!priv->attach;
+	mutex_unlock(&priv->attach_lock);
+
+	return 0;
+}
+
+static int mt6370_chg_get_status(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	int ret;
+	unsigned int chg_stat;
+	union power_supply_propval online;
+
+	ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&online);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get online status\n");
+		return ret;
+	}
+
+	if (!online.intval) {
+		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		return 0;
+	}
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_FAULT:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_DONE:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return ret;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		return ret;
+	}
+}
+
+static int mt6370_chg_get_charge_type(struct mt6370_priv *priv,
+				      union power_supply_propval *val)
+{
+	int type, ret;
+	unsigned int chg_stat, vbat_lvl;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		if (vbat_lvl)
+			type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		else
+			type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_DONE:
+	case MT6370_CHG_STAT_FAULT:
+	default:
+		type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		break;
+	}
+
+	val->intval = type;
+
+	return 0;
+}
+
+static int mt6370_chg_set_online(struct mt6370_priv *priv,
+				 const union power_supply_propval *val)
+{
+	bool pwr_rdy = !!val->intval;
+
+	mutex_lock(&priv->attach_lock);
+	if (pwr_rdy == !!priv->attach) {
+		dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy);
+		mutex_unlock(&priv->attach_lock);
+		return 0;
+	}
+
+	priv->attach = pwr_rdy;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return 0;
+}
+
+static int mt6370_chg_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_get_online(priv, val);
+	case POWER_SUPPLY_PROP_STATUS:
+		return mt6370_chg_get_status(priv, val);
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		return mt6370_chg_get_charge_type(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_ICHG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_ICHG]);
+		return 0;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_get(priv, F_VOREG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_VOREG]);
+		return 0;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_get(priv, F_IAICR, &val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_get(priv, F_VMIVR, &val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_IPREC, &val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_get(priv, F_IEOC, &val->intval);
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = priv->psy_usb_type;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_set_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   const union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_set_online(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_ICHG, val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_set(priv, F_VOREG, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_set(priv, F_IAICR, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_set(priv, F_VMIVR, val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_IPREC, val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_set(priv, F_IEOC, val->intval);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_property_is_writeable(struct power_supply *psy,
+					    enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static enum power_supply_property mt6370_chg_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_USB_TYPE,
+};
+
+static enum power_supply_usb_type mt6370_chg_usb_types[] = {
+	POWER_SUPPLY_USB_TYPE_UNKNOWN,
+	POWER_SUPPLY_USB_TYPE_SDP,
+	POWER_SUPPLY_USB_TYPE_CDP,
+	POWER_SUPPLY_USB_TYPE_DCP,
+};
+
+static const struct power_supply_desc mt6370_chg_psy_desc = {
+	.name = "mt6370-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = mt6370_chg_properties,
+	.num_properties = ARRAY_SIZE(mt6370_chg_properties),
+	.get_property = mt6370_chg_get_property,
+	.set_property = mt6370_chg_set_property,
+	.property_is_writeable = mt6370_chg_property_is_writeable,
+	.usb_types = mt6370_chg_usb_types,
+	.num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types),
+};
+
+static const struct regulator_ops mt6370_chg_otg_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const u32 mt6370_chg_otg_oc_ma[] = {
+	500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000,
+};
+
+static const struct regulator_desc mt6370_chg_otg_rdesc = {
+	.of_match = "usb-otg-vbus-regulator",
+	.of_parse_cb = mt6370_chg_otg_of_parse_cb,
+	.name = "mt6370-usb-otg-vbus",
+	.ops = &mt6370_chg_otg_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4425000,
+	.uV_step = 25000,
+	.n_voltages = 57,
+	.vsel_reg = MT6370_REG_CHG_CTRL5,
+	.vsel_mask = MT6370_VOBST_MASK,
+	.enable_reg = MT6370_REG_CHG_CTRL1,
+	.enable_mask = MT6370_OPA_MODE_MASK,
+	.curr_table = mt6370_chg_otg_oc_ma,
+	.n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma),
+	.csel_reg = MT6370_REG_CHG_CTRL10,
+	.csel_mask = MT6370_OTG_OC_MASK,
+};
+
+static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv)
+{
+	int i;
+	const struct mt6370_chg_field *fds = mt6370_chg_fields;
+
+	for (i = 0; i < F_MAX; i++) {
+		priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev,
+							       priv->regmap,
+							       fds[i].field);
+		if (IS_ERR(priv->rmap_fields[i]))
+			return dev_err_probe(priv->dev,
+					PTR_ERR(priv->rmap_fields[i]),
+					"Failed to allocate regmapfield[%s]\n",
+					fds[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_init_setting(struct mt6370_priv *priv)
+{
+	int ret;
+
+	/* Disable usb_chg_en */
+	ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable usb_chg_en\n");
+		return ret;
+	}
+
+	/* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */
+	ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set ICHG to 900mA");
+		return ret;
+	}
+
+	/* Change input current limit selection to using IAICR results */
+	ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set IINLMTSEL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field)	\
+{							\
+	.name = "mediatek,chg-" #_name,			\
+	.type = MT6370_PARSE_TYPE_##_type,		\
+	.fd = _field,					\
+}
+
+static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv)
+{
+	struct regulator_config rcfg = {
+		.dev = priv->dev,
+		.regmap = priv->regmap,
+		.driver_data = priv,
+	};
+
+	priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc,
+					     &rcfg);
+
+	return PTR_ERR_OR_ZERO(priv->rdev);
+}
+
+static int mt6370_chg_init_psy(struct mt6370_priv *priv)
+{
+	struct power_supply_config cfg = {
+		.drv_data = priv,
+		.of_node = dev_of_node(priv->dev),
+	};
+
+	priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc,
+					       &cfg);
+
+	return PTR_ERR_OR_ZERO(priv->psy);
+}
+
+static void mt6370_chg_destroy_attach_lock(void *data)
+{
+	struct mutex *attach_lock = data;
+
+	mutex_destroy(attach_lock);
+}
+
+static void mt6370_chg_destroy_wq(void *data)
+{
+	struct workqueue_struct *wq = data;
+
+	flush_workqueue(wq);
+	destroy_workqueue(wq);
+}
+
+static void mt6370_chg_cancel_mivr_dwork(void *data)
+{
+	struct delayed_work *mivr_dwork = data;
+
+	cancel_delayed_work_sync(mivr_dwork);
+}
+
+static irqreturn_t mt6370_attach_i_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+	unsigned int otg_en;
+	int ret;
+
+	/* Check in otg mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get otg state\n");
+		return IRQ_NONE;
+	}
+
+	if (otg_en)
+		return IRQ_HANDLED;
+
+	mutex_lock(&priv->attach_lock);
+	priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_mivr_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	pm_stay_awake(priv->dev);
+	mt6370_chg_enable_irq(priv, "mivr", false);
+	schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+#define MT6370_CHG_IRQ(_name)						\
+{									\
+	.name = #_name,							\
+	.handler = mt6370_##_name##_handler,				\
+}
+
+static int mt6370_chg_init_irq(struct mt6370_priv *priv)
+{
+	int i, ret;
+	const struct {
+		char *name;
+		irq_handler_t handler;
+	} mt6370_chg_irqs[] = {
+		MT6370_CHG_IRQ(attach_i),
+		MT6370_CHG_IRQ(uvp_d_evt),
+		MT6370_CHG_IRQ(mivr),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) {
+		ret = platform_get_irq_byname(to_platform_device(priv->dev),
+					      mt6370_chg_irqs[i].name);
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to get irq %s\n",
+					     mt6370_chg_irqs[i].name);
+
+		ret = devm_request_threaded_irq(priv->dev, ret, NULL,
+						mt6370_chg_irqs[i].handler,
+						IRQF_TRIGGER_FALLING,
+						dev_name(priv->dev), priv);
+
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to request irq %s\n",
+					     mt6370_chg_irqs[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_chg_init_rmap_fields(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init regmap fields\n");
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->iio_adcs = devm_iio_channel_get_all(priv->dev);
+	if (IS_ERR(priv->iio_adcs))
+		return dev_err_probe(dev, PTR_ERR(priv->iio_adcs),
+				     "Failed to get iio adc\n");
+
+	ret = mt6370_chg_init_otg_regulator(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init otg regulator\n");
+
+	ret = mt6370_chg_init_psy(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init psy\n");
+
+	mutex_init(&priv->attach_lock);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock,
+				       &priv->attach_lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init attach lock\n");
+
+	priv->attach = MT6370_ATTACH_STAT_DETACH;
+
+	priv->wq = create_singlethread_workqueue(dev_name(priv->dev));
+	if (IS_ERR(priv->wq))
+		return dev_err_probe(dev, PTR_ERR(priv->wq),
+				     "Failed to create workqueue\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init wq\n");
+
+	INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func);
+	INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_cancel_mivr_dwork,
+				       &priv->mivr_dwork);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init mivr dwork\n");
+
+	ret = mt6370_chg_init_setting(priv);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init mt6370 charger setting\n");
+
+	ret = mt6370_chg_init_irq(priv);
+	if (ret)
+		return ret;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_chg_of_match[] = {
+	{ .compatible = "mediatek,mt6370-charger", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_chg_of_match);
+
+static struct platform_driver mt6370_chg_driver = {
+	.probe = mt6370_chg_probe,
+	.driver = {
+		.name = "mt6370-charger",
+		.of_match_table = mt6370_chg_of_match,
+	},
+};
+module_platform_driver(mt6370_chg_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds MediaTek MT6370 Charger driver support. The charger module
of MT6370 supports High-Accuracy Voltage/Current Regulation,
Average Input Current Regulation, Battery Temperature Sensing,
Over-Temperature Protection, DPDM Detection for BC1.2.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---

v6
- Remove the varable (*psy_desc) of struct mt6370_priv
- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
  POWER_SUPPLY_TYPE_USB_DCP)
- Remove useless remove()
- Revise all units from mini- to micro-
- Revise get/set power_supply_prop (change to directly return get/set
  regmap_field)
- Revise probe() and use devm_add_action_or_reset() for handling of the
  workqueue/delayed_work/mutex
- Revise mt6370_chg_psy_desc
  - Add '.name = "mt6370-charger"'
  - Use 'static const'

---

uevent dump:
vim3l:/sys/class/power_supply/mt6370-charger # cat uevent
POWER_SUPPLY_NAME=mt6370-charger
POWER_SUPPLY_TYPE=USB
POWER_SUPPLY_ONLINE=0
POWER_SUPPLY_STATUS=Discharging
POWER_SUPPLY_CHARGE_TYPE=N/A
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT=900000
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT_MAX=5000000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE=4200000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE_MAX=4710000
POWER_SUPPLY_INPUT_CURRENT_LIMIT=500000
POWER_SUPPLY_INPUT_VOLTAGE_LIMIT=4400000
POWER_SUPPLY_PRECHARGE_CURRENT=150000
POWER_SUPPLY_CHARGE_TERM_CURRENT=250000
POWER_SUPPLY_USB_TYPE=[Unknown] SDP CDP DCP
---
 drivers/power/supply/Kconfig          |  14 +
 drivers/power/supply/Makefile         |   1 +
 drivers/power/supply/mt6370-charger.c | 973 ++++++++++++++++++++++++++++++++++
 3 files changed, 988 insertions(+)
 create mode 100644 drivers/power/supply/mt6370-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 1aa8323..591deb8 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -619,6 +619,20 @@ config CHARGER_MT6360
 	  Average Input Current Regulation, Battery Temperature Sensing,
 	  Over-Temperature Protection, DPDM Detection for BC1.2.
 
+config CHARGER_MT6370
+	tristate "MediaTek MT6370 Charger Driver"
+	depends on MFD_MT6370
+	depends on REGULATOR
+	select LINEAR_RANGES
+	help
+	  Say Y here to enable MT6370 Charger Part.
+	  The device supports High-Accuracy Voltage/Current Regulation,
+	  Average Input Current Regulation, Battery Temperature Sensing,
+	  Over-Temperature Protection, DPDM Detection for BC1.2.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-charger".
+
 config CHARGER_QCOM_SMBB
 	tristate "Qualcomm Switch-Mode Battery Charger and Boost"
 	depends on MFD_SPMI_PMIC || COMPILE_TEST
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7f02f36..8c95276 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_MP2629)	+= mp2629_charger.o
 obj-$(CONFIG_CHARGER_MT6360)	+= mt6360_charger.o
+obj-$(CONFIG_CHARGER_MT6370)	+= mt6370-charger.o
 obj-$(CONFIG_CHARGER_QCOM_SMBB)	+= qcom_smbb.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
 obj-$(CONFIG_CHARGER_BQ24190)	+= bq24190_charger.o
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
new file mode 100644
index 0000000..84f1436
--- /dev/null
+++ b/drivers/power/supply/mt6370-charger.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/workqueue.h>
+
+#define MT6370_REG_CHG_CTRL1		0x111
+#define MT6370_REG_CHG_CTRL2		0x112
+#define MT6370_REG_CHG_CTRL3		0x113
+#define MT6370_REG_CHG_CTRL4		0x114
+#define MT6370_REG_CHG_CTRL5		0x115
+#define MT6370_REG_CHG_CTRL6		0x116
+#define MT6370_REG_CHG_CTRL7		0x117
+#define MT6370_REG_CHG_CTRL8		0x118
+#define MT6370_REG_CHG_CTRL9		0x119
+#define MT6370_REG_CHG_CTRL10		0x11A
+#define MT6370_REG_DEVICE_TYPE		0x122
+#define MT6370_REG_USB_STATUS1		0x127
+#define MT6370_REG_CHG_STAT		0x14A
+#define MT6370_REG_FLED_EN		0x17E
+#define MT6370_REG_CHG_STAT1		0X1D0
+#define MT6370_REG_OVPCTRL_STAT		0x1D8
+
+#define MT6370_VOBST_MASK		GENMASK(7, 2)
+#define MT6370_OTG_PIN_EN_MASK		BIT(1)
+#define MT6370_OPA_MODE_MASK		BIT(0)
+#define MT6370_OTG_OC_MASK		GENMASK(2, 0)
+
+#define MT6370_MIVR_IBUS_TH_100_mA	100000
+#define MT6370_ADC_CHAN_IBUS		5
+#define MT6370_ADC_CHAN_MAX		9
+
+enum mt6370_chg_reg_field {
+	/* MT6370_REG_CHG_CTRL2 */
+	F_IINLMTSEL, F_CFO_EN, F_CHG_EN,
+	/* MT6370_REG_CHG_CTRL3 */
+	F_IAICR, F_AICR_EN, F_ILIM_EN,
+	/* MT6370_REG_CHG_CTRL4 */
+	F_VOREG,
+	/* MT6370_REG_CHG_CTRL6 */
+	F_VMIVR,
+	/* MT6370_REG_CHG_CTRL7 */
+	F_ICHG,
+	/* MT6370_REG_CHG_CTRL8 */
+	F_IPREC,
+	/* MT6370_REG_CHG_CTRL9 */
+	F_IEOC,
+	/* MT6370_REG_DEVICE_TYPE */
+	F_USBCHGEN,
+	/* MT6370_REG_USB_STATUS1 */
+	F_USB_STAT, F_CHGDET,
+	/* MT6370_REG_CHG_STAT */
+	F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL,
+	/* MT6370_REG_FLED_EN */
+	F_FL_STROBE,
+	/* MT6370_REG_CHG_STAT1 */
+	F_CHG_MIVR_STAT,
+	/* MT6370_REG_OVPCTRL_STAT */
+	F_UVP_D_STAT,
+	F_MAX
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct iio_channel *iio_adcs;
+	struct mutex attach_lock;
+	struct power_supply *psy;
+	struct regmap *regmap;
+	struct regmap_field *rmap_fields[F_MAX];
+	struct regulator_dev *rdev;
+	struct workqueue_struct *wq;
+	struct work_struct bc12_work;
+	struct delayed_work mivr_dwork;
+	int attach;
+	int psy_usb_type;
+	bool pwr_rdy;
+};
+
+enum mt6370_usb_status {
+	MT6370_USB_STAT_NO_VBUS = 0,
+	MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING,
+	MT6370_USB_STAT_SDP,
+	MT6370_USB_STAT_SDP_NSTD,
+	MT6370_USB_STAT_DCP,
+	MT6370_USB_STAT_CDP,
+	MT6370_USB_STAT_MAX
+};
+
+struct mt6370_chg_field {
+	const char *name;
+	const struct linear_range *range;
+	struct reg_field field;
+};
+
+enum {
+	MT6370_RANGE_F_IAICR = 0,
+	MT6370_RANGE_F_VOREG,
+	MT6370_RANGE_F_VMIVR,
+	MT6370_RANGE_F_ICHG,
+	MT6370_RANGE_F_IPREC,
+	MT6370_RANGE_F_IEOC,
+	MT6370_RANGE_F_MAX
+};
+
+#define MT6370_CHG_LINEAR_RANGE(_rfd, _min, _min_sel, _max_sel, _step)	\
+[_rfd] = {								\
+	.min = _min,							\
+	.min_sel = _min_sel,						\
+	.max_sel = _max_sel,						\
+	.step = _step,							\
+}
+
+static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = {
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IAICR, 100000, 0x0, 0x3F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VOREG, 3900000, 0x0, 0x51, 10000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VMIVR, 3900000, 0x0, 0x5F, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_ICHG, 900000, 0x08, 0x31, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IPREC, 100000, 0x0, 0x0F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IEOC, 100000, 0x0, 0x0F, 50000),
+};
+
+#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb)				\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = NULL,							\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb)			\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = &mt6370_chg_ranges[MT6370_RANGE_##_fd],		\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = {
+	MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3),
+	MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1),
+	MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7),
+	MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1),
+	MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7),
+	MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3),
+	MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7),
+	MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7),
+	MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6),
+	MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3),
+	MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7),
+	MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3),
+	MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5),
+	MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2),
+	MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6),
+	MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4),
+};
+
+static inline int mt6370_chg_field_get(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int *val)
+{
+	int ret;
+	unsigned int reg_val;
+
+	ret = regmap_field_read(priv->rmap_fields[fd], &reg_val);
+	if (ret < 0)
+		return ret;
+
+	if (mt6370_chg_fields[fd].range)
+		return linear_range_get_value(mt6370_chg_fields[fd].range,
+					      reg_val, val);
+
+	*val = reg_val;
+	return 0;
+}
+
+static inline int mt6370_chg_field_set(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int val)
+{
+	int ret;
+	bool f;
+	const struct linear_range *r;
+
+	if (mt6370_chg_fields[fd].range) {
+		r = mt6370_chg_fields[fd].range;
+
+		if (fd == F_VMIVR) {
+			ret = linear_range_get_selector_high(r, val, &val, &f);
+			if (!ret)
+				val = r->max_sel;
+		} else {
+			linear_range_get_selector_within(r, val, &val);
+		}
+	}
+
+	return regmap_field_write(priv->rmap_fields[fd], val);
+}
+
+enum {
+	MT6370_CHG_STAT_READY = 0,
+	MT6370_CHG_STAT_CHARGE_IN_PROGRESS,
+	MT6370_CHG_STAT_DONE,
+	MT6370_CHG_STAT_FAULT,
+	MT6370_CHG_STAT_MAX
+};
+
+enum {
+	MT6370_ATTACH_STAT_DETACH = 0,
+	MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE,
+	MT6370_ATTACH_STAT_ATTACH_BC12_DONE,
+	MT6370_ATTACH_STAT_ATTACH_MAX
+};
+
+static int mt6370_chg_otg_of_parse_cb(struct device_node *of,
+				      const struct regulator_desc *rdesc,
+				      struct regulator_config *rcfg)
+{
+	struct mt6370_priv *priv = rcfg->driver_data;
+
+	rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of),
+						 "enable", 0, GPIOD_OUT_LOW |
+						 GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+						 rdesc->name);
+	if (IS_ERR(rcfg->ena_gpiod)) {
+		rcfg->ena_gpiod = NULL;
+		return 0;
+	}
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1,
+				  MT6370_OTG_PIN_EN_MASK,
+				  MT6370_OTG_PIN_EN_MASK);
+}
+
+static void mt6370_chg_bc12_work_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						bc12_work);
+	int ret;
+	bool rpt_psy = false;
+	unsigned int attach, usb_stat;
+
+	mutex_lock(&priv->attach_lock);
+	attach = priv->attach;
+
+	switch (attach) {
+	case MT6370_ATTACH_STAT_DETACH:
+		usb_stat = 0;
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_DONE:
+		ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat);
+		if (ret < 0) {
+			dev_err(priv->dev, "Failed to get USB status\n");
+			goto bc12_work_func_out;
+		}
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE:
+		ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach);
+		if (ret < 0)
+			dev_err(priv->dev, "Failed to enable USB CHG EN\n");
+		goto bc12_work_func_out;
+	default:
+		dev_err(priv->dev, "Invalid attach state\n");
+		goto bc12_work_func_out;
+	}
+
+	rpt_psy = true;
+
+	switch (usb_stat) {
+	case MT6370_USB_STAT_SDP:
+	case MT6370_USB_STAT_SDP_NSTD:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
+		break;
+	case MT6370_USB_STAT_DCP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+		break;
+	case MT6370_USB_STAT_CDP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
+		break;
+	case MT6370_USB_STAT_NO_VBUS:
+	case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING:
+	default:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		break;
+	}
+
+bc12_work_func_out:
+	mutex_unlock(&priv->attach_lock);
+
+	if (rpt_psy)
+		power_supply_changed(priv->psy);
+}
+
+static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
+					 const char *irq_name, bool en)
+{
+	int irq_num;
+	struct platform_device *pdev = to_platform_device(priv->dev);
+
+	irq_num = platform_get_irq_byname(pdev, irq_name);
+	if (irq_num < 0)
+		return;
+
+	if (en)
+		enable_irq(irq_num);
+	else
+		disable_irq_nosync(irq_num);
+}
+
+static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int fl_strobe;
+
+	/* check if flash led in strobe mode */
+	ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get FL_STROBE_EN\n");
+		return ret;
+	}
+
+	if (fl_strobe) {
+		dev_err(priv->dev, "Flash led is still in strobe mode\n");
+		return ret;
+	}
+
+	/* cfo off */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable CFO_EN\n");
+		return ret;
+	}
+
+	/* cfo on */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 1);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to enable CFO_EN\n");
+
+	return ret;
+}
+
+static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan,
+				    int *val)
+{
+	int ret;
+
+	if (chan >= MT6370_ADC_CHAN_MAX)
+		return -EINVAL;
+
+	ret = iio_read_channel_processed(&priv->iio_adcs[chan], val);
+	if (ret)
+		dev_err(priv->dev, "Failed to read ADC\n");
+
+	return ret;
+}
+
+static void mt6370_chg_mivr_dwork_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						mivr_dwork.work);
+	int ret;
+	unsigned int mivr_stat, ibus;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get mivr state\n");
+		goto mivr_handler_out;
+	}
+
+	if (!mivr_stat)
+		goto mivr_handler_out;
+
+	ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get ibus\n");
+		goto mivr_handler_out;
+	}
+
+	if (ibus < MT6370_MIVR_IBUS_TH_100_mA) {
+		ret = mt6370_chg_toggle_cfo(priv);
+		if (ret)
+			dev_err(priv->dev, "Failed to toggle cfo\n");
+	}
+
+mivr_handler_out:
+	mt6370_chg_enable_irq(priv, "mivr", true);
+	pm_relax(priv->dev);
+}
+
+static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int pwr_rdy, otg_en;
+	union power_supply_propval val;
+
+	/* Check in OTG mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get OTG state\n");
+		return;
+	}
+
+	if (otg_en)
+		return;
+
+	ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &pwr_rdy);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get pwr_rdy state reg\n");
+		return;
+	}
+
+	val.intval = !pwr_rdy;
+
+	ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&val);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to start attach/detach flow\n");
+}
+
+static int mt6370_chg_get_online(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	mutex_lock(&priv->attach_lock);
+	val->intval = !!priv->attach;
+	mutex_unlock(&priv->attach_lock);
+
+	return 0;
+}
+
+static int mt6370_chg_get_status(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	int ret;
+	unsigned int chg_stat;
+	union power_supply_propval online;
+
+	ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&online);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get online status\n");
+		return ret;
+	}
+
+	if (!online.intval) {
+		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		return 0;
+	}
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_FAULT:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_DONE:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return ret;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		return ret;
+	}
+}
+
+static int mt6370_chg_get_charge_type(struct mt6370_priv *priv,
+				      union power_supply_propval *val)
+{
+	int type, ret;
+	unsigned int chg_stat, vbat_lvl;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		if (vbat_lvl)
+			type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		else
+			type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_DONE:
+	case MT6370_CHG_STAT_FAULT:
+	default:
+		type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		break;
+	}
+
+	val->intval = type;
+
+	return 0;
+}
+
+static int mt6370_chg_set_online(struct mt6370_priv *priv,
+				 const union power_supply_propval *val)
+{
+	bool pwr_rdy = !!val->intval;
+
+	mutex_lock(&priv->attach_lock);
+	if (pwr_rdy == !!priv->attach) {
+		dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy);
+		mutex_unlock(&priv->attach_lock);
+		return 0;
+	}
+
+	priv->attach = pwr_rdy;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return 0;
+}
+
+static int mt6370_chg_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_get_online(priv, val);
+	case POWER_SUPPLY_PROP_STATUS:
+		return mt6370_chg_get_status(priv, val);
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		return mt6370_chg_get_charge_type(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_ICHG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_ICHG]);
+		return 0;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_get(priv, F_VOREG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_VOREG]);
+		return 0;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_get(priv, F_IAICR, &val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_get(priv, F_VMIVR, &val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_IPREC, &val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_get(priv, F_IEOC, &val->intval);
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = priv->psy_usb_type;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_set_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   const union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_set_online(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_ICHG, val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_set(priv, F_VOREG, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_set(priv, F_IAICR, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_set(priv, F_VMIVR, val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_IPREC, val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_set(priv, F_IEOC, val->intval);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_property_is_writeable(struct power_supply *psy,
+					    enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static enum power_supply_property mt6370_chg_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_USB_TYPE,
+};
+
+static enum power_supply_usb_type mt6370_chg_usb_types[] = {
+	POWER_SUPPLY_USB_TYPE_UNKNOWN,
+	POWER_SUPPLY_USB_TYPE_SDP,
+	POWER_SUPPLY_USB_TYPE_CDP,
+	POWER_SUPPLY_USB_TYPE_DCP,
+};
+
+static const struct power_supply_desc mt6370_chg_psy_desc = {
+	.name = "mt6370-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = mt6370_chg_properties,
+	.num_properties = ARRAY_SIZE(mt6370_chg_properties),
+	.get_property = mt6370_chg_get_property,
+	.set_property = mt6370_chg_set_property,
+	.property_is_writeable = mt6370_chg_property_is_writeable,
+	.usb_types = mt6370_chg_usb_types,
+	.num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types),
+};
+
+static const struct regulator_ops mt6370_chg_otg_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const u32 mt6370_chg_otg_oc_ma[] = {
+	500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000,
+};
+
+static const struct regulator_desc mt6370_chg_otg_rdesc = {
+	.of_match = "usb-otg-vbus-regulator",
+	.of_parse_cb = mt6370_chg_otg_of_parse_cb,
+	.name = "mt6370-usb-otg-vbus",
+	.ops = &mt6370_chg_otg_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4425000,
+	.uV_step = 25000,
+	.n_voltages = 57,
+	.vsel_reg = MT6370_REG_CHG_CTRL5,
+	.vsel_mask = MT6370_VOBST_MASK,
+	.enable_reg = MT6370_REG_CHG_CTRL1,
+	.enable_mask = MT6370_OPA_MODE_MASK,
+	.curr_table = mt6370_chg_otg_oc_ma,
+	.n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma),
+	.csel_reg = MT6370_REG_CHG_CTRL10,
+	.csel_mask = MT6370_OTG_OC_MASK,
+};
+
+static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv)
+{
+	int i;
+	const struct mt6370_chg_field *fds = mt6370_chg_fields;
+
+	for (i = 0; i < F_MAX; i++) {
+		priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev,
+							       priv->regmap,
+							       fds[i].field);
+		if (IS_ERR(priv->rmap_fields[i]))
+			return dev_err_probe(priv->dev,
+					PTR_ERR(priv->rmap_fields[i]),
+					"Failed to allocate regmapfield[%s]\n",
+					fds[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_init_setting(struct mt6370_priv *priv)
+{
+	int ret;
+
+	/* Disable usb_chg_en */
+	ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable usb_chg_en\n");
+		return ret;
+	}
+
+	/* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */
+	ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set ICHG to 900mA");
+		return ret;
+	}
+
+	/* Change input current limit selection to using IAICR results */
+	ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set IINLMTSEL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field)	\
+{							\
+	.name = "mediatek,chg-" #_name,			\
+	.type = MT6370_PARSE_TYPE_##_type,		\
+	.fd = _field,					\
+}
+
+static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv)
+{
+	struct regulator_config rcfg = {
+		.dev = priv->dev,
+		.regmap = priv->regmap,
+		.driver_data = priv,
+	};
+
+	priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc,
+					     &rcfg);
+
+	return PTR_ERR_OR_ZERO(priv->rdev);
+}
+
+static int mt6370_chg_init_psy(struct mt6370_priv *priv)
+{
+	struct power_supply_config cfg = {
+		.drv_data = priv,
+		.of_node = dev_of_node(priv->dev),
+	};
+
+	priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc,
+					       &cfg);
+
+	return PTR_ERR_OR_ZERO(priv->psy);
+}
+
+static void mt6370_chg_destroy_attach_lock(void *data)
+{
+	struct mutex *attach_lock = data;
+
+	mutex_destroy(attach_lock);
+}
+
+static void mt6370_chg_destroy_wq(void *data)
+{
+	struct workqueue_struct *wq = data;
+
+	flush_workqueue(wq);
+	destroy_workqueue(wq);
+}
+
+static void mt6370_chg_cancel_mivr_dwork(void *data)
+{
+	struct delayed_work *mivr_dwork = data;
+
+	cancel_delayed_work_sync(mivr_dwork);
+}
+
+static irqreturn_t mt6370_attach_i_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+	unsigned int otg_en;
+	int ret;
+
+	/* Check in otg mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get otg state\n");
+		return IRQ_NONE;
+	}
+
+	if (otg_en)
+		return IRQ_HANDLED;
+
+	mutex_lock(&priv->attach_lock);
+	priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_mivr_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	pm_stay_awake(priv->dev);
+	mt6370_chg_enable_irq(priv, "mivr", false);
+	schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+#define MT6370_CHG_IRQ(_name)						\
+{									\
+	.name = #_name,							\
+	.handler = mt6370_##_name##_handler,				\
+}
+
+static int mt6370_chg_init_irq(struct mt6370_priv *priv)
+{
+	int i, ret;
+	const struct {
+		char *name;
+		irq_handler_t handler;
+	} mt6370_chg_irqs[] = {
+		MT6370_CHG_IRQ(attach_i),
+		MT6370_CHG_IRQ(uvp_d_evt),
+		MT6370_CHG_IRQ(mivr),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) {
+		ret = platform_get_irq_byname(to_platform_device(priv->dev),
+					      mt6370_chg_irqs[i].name);
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to get irq %s\n",
+					     mt6370_chg_irqs[i].name);
+
+		ret = devm_request_threaded_irq(priv->dev, ret, NULL,
+						mt6370_chg_irqs[i].handler,
+						IRQF_TRIGGER_FALLING,
+						dev_name(priv->dev), priv);
+
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to request irq %s\n",
+					     mt6370_chg_irqs[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_chg_init_rmap_fields(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init regmap fields\n");
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->iio_adcs = devm_iio_channel_get_all(priv->dev);
+	if (IS_ERR(priv->iio_adcs))
+		return dev_err_probe(dev, PTR_ERR(priv->iio_adcs),
+				     "Failed to get iio adc\n");
+
+	ret = mt6370_chg_init_otg_regulator(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init otg regulator\n");
+
+	ret = mt6370_chg_init_psy(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init psy\n");
+
+	mutex_init(&priv->attach_lock);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock,
+				       &priv->attach_lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init attach lock\n");
+
+	priv->attach = MT6370_ATTACH_STAT_DETACH;
+
+	priv->wq = create_singlethread_workqueue(dev_name(priv->dev));
+	if (IS_ERR(priv->wq))
+		return dev_err_probe(dev, PTR_ERR(priv->wq),
+				     "Failed to create workqueue\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init wq\n");
+
+	INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func);
+	INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_cancel_mivr_dwork,
+				       &priv->mivr_dwork);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init mivr dwork\n");
+
+	ret = mt6370_chg_init_setting(priv);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init mt6370 charger setting\n");
+
+	ret = mt6370_chg_init_irq(priv);
+	if (ret)
+		return ret;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_chg_of_match[] = {
+	{ .compatible = "mediatek,mt6370-charger", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_chg_of_match);
+
+static struct platform_driver mt6370_chg_driver = {
+	.probe = mt6370_chg_probe,
+	.driver = {
+		.name = "mt6370-charger",
+		.of_match_table = mt6370_chg_of_match,
+	},
+};
+module_platform_driver(mt6370_chg_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds MediaTek MT6370 Charger driver support. The charger module
of MT6370 supports High-Accuracy Voltage/Current Regulation,
Average Input Current Regulation, Battery Temperature Sensing,
Over-Temperature Protection, DPDM Detection for BC1.2.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---

v6
- Remove the varable (*psy_desc) of struct mt6370_priv
- Remove the deprecated usb type (POWER_SUPPLY_TYPE_USB_CDP and
  POWER_SUPPLY_TYPE_USB_DCP)
- Remove useless remove()
- Revise all units from mini- to micro-
- Revise get/set power_supply_prop (change to directly return get/set
  regmap_field)
- Revise probe() and use devm_add_action_or_reset() for handling of the
  workqueue/delayed_work/mutex
- Revise mt6370_chg_psy_desc
  - Add '.name = "mt6370-charger"'
  - Use 'static const'

---

uevent dump:
vim3l:/sys/class/power_supply/mt6370-charger # cat uevent
POWER_SUPPLY_NAME=mt6370-charger
POWER_SUPPLY_TYPE=USB
POWER_SUPPLY_ONLINE=0
POWER_SUPPLY_STATUS=Discharging
POWER_SUPPLY_CHARGE_TYPE=N/A
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT=900000
POWER_SUPPLY_CONSTANT_CHARGE_CURRENT_MAX=5000000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE=4200000
POWER_SUPPLY_CONSTANT_CHARGE_VOLTAGE_MAX=4710000
POWER_SUPPLY_INPUT_CURRENT_LIMIT=500000
POWER_SUPPLY_INPUT_VOLTAGE_LIMIT=4400000
POWER_SUPPLY_PRECHARGE_CURRENT=150000
POWER_SUPPLY_CHARGE_TERM_CURRENT=250000
POWER_SUPPLY_USB_TYPE=[Unknown] SDP CDP DCP
---
 drivers/power/supply/Kconfig          |  14 +
 drivers/power/supply/Makefile         |   1 +
 drivers/power/supply/mt6370-charger.c | 973 ++++++++++++++++++++++++++++++++++
 3 files changed, 988 insertions(+)
 create mode 100644 drivers/power/supply/mt6370-charger.c

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 1aa8323..591deb8 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -619,6 +619,20 @@ config CHARGER_MT6360
 	  Average Input Current Regulation, Battery Temperature Sensing,
 	  Over-Temperature Protection, DPDM Detection for BC1.2.
 
+config CHARGER_MT6370
+	tristate "MediaTek MT6370 Charger Driver"
+	depends on MFD_MT6370
+	depends on REGULATOR
+	select LINEAR_RANGES
+	help
+	  Say Y here to enable MT6370 Charger Part.
+	  The device supports High-Accuracy Voltage/Current Regulation,
+	  Average Input Current Regulation, Battery Temperature Sensing,
+	  Over-Temperature Protection, DPDM Detection for BC1.2.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-charger".
+
 config CHARGER_QCOM_SMBB
 	tristate "Qualcomm Switch-Mode Battery Charger and Boost"
 	depends on MFD_SPMI_PMIC || COMPILE_TEST
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 7f02f36..8c95276 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_MP2629)	+= mp2629_charger.o
 obj-$(CONFIG_CHARGER_MT6360)	+= mt6360_charger.o
+obj-$(CONFIG_CHARGER_MT6370)	+= mt6370-charger.o
 obj-$(CONFIG_CHARGER_QCOM_SMBB)	+= qcom_smbb.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
 obj-$(CONFIG_CHARGER_BQ24190)	+= bq24190_charger.o
diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c
new file mode 100644
index 0000000..84f1436
--- /dev/null
+++ b/drivers/power/supply/mt6370-charger.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/linear_range.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/workqueue.h>
+
+#define MT6370_REG_CHG_CTRL1		0x111
+#define MT6370_REG_CHG_CTRL2		0x112
+#define MT6370_REG_CHG_CTRL3		0x113
+#define MT6370_REG_CHG_CTRL4		0x114
+#define MT6370_REG_CHG_CTRL5		0x115
+#define MT6370_REG_CHG_CTRL6		0x116
+#define MT6370_REG_CHG_CTRL7		0x117
+#define MT6370_REG_CHG_CTRL8		0x118
+#define MT6370_REG_CHG_CTRL9		0x119
+#define MT6370_REG_CHG_CTRL10		0x11A
+#define MT6370_REG_DEVICE_TYPE		0x122
+#define MT6370_REG_USB_STATUS1		0x127
+#define MT6370_REG_CHG_STAT		0x14A
+#define MT6370_REG_FLED_EN		0x17E
+#define MT6370_REG_CHG_STAT1		0X1D0
+#define MT6370_REG_OVPCTRL_STAT		0x1D8
+
+#define MT6370_VOBST_MASK		GENMASK(7, 2)
+#define MT6370_OTG_PIN_EN_MASK		BIT(1)
+#define MT6370_OPA_MODE_MASK		BIT(0)
+#define MT6370_OTG_OC_MASK		GENMASK(2, 0)
+
+#define MT6370_MIVR_IBUS_TH_100_mA	100000
+#define MT6370_ADC_CHAN_IBUS		5
+#define MT6370_ADC_CHAN_MAX		9
+
+enum mt6370_chg_reg_field {
+	/* MT6370_REG_CHG_CTRL2 */
+	F_IINLMTSEL, F_CFO_EN, F_CHG_EN,
+	/* MT6370_REG_CHG_CTRL3 */
+	F_IAICR, F_AICR_EN, F_ILIM_EN,
+	/* MT6370_REG_CHG_CTRL4 */
+	F_VOREG,
+	/* MT6370_REG_CHG_CTRL6 */
+	F_VMIVR,
+	/* MT6370_REG_CHG_CTRL7 */
+	F_ICHG,
+	/* MT6370_REG_CHG_CTRL8 */
+	F_IPREC,
+	/* MT6370_REG_CHG_CTRL9 */
+	F_IEOC,
+	/* MT6370_REG_DEVICE_TYPE */
+	F_USBCHGEN,
+	/* MT6370_REG_USB_STATUS1 */
+	F_USB_STAT, F_CHGDET,
+	/* MT6370_REG_CHG_STAT */
+	F_CHG_STAT, F_BOOST_STAT, F_VBAT_LVL,
+	/* MT6370_REG_FLED_EN */
+	F_FL_STROBE,
+	/* MT6370_REG_CHG_STAT1 */
+	F_CHG_MIVR_STAT,
+	/* MT6370_REG_OVPCTRL_STAT */
+	F_UVP_D_STAT,
+	F_MAX
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct iio_channel *iio_adcs;
+	struct mutex attach_lock;
+	struct power_supply *psy;
+	struct regmap *regmap;
+	struct regmap_field *rmap_fields[F_MAX];
+	struct regulator_dev *rdev;
+	struct workqueue_struct *wq;
+	struct work_struct bc12_work;
+	struct delayed_work mivr_dwork;
+	int attach;
+	int psy_usb_type;
+	bool pwr_rdy;
+};
+
+enum mt6370_usb_status {
+	MT6370_USB_STAT_NO_VBUS = 0,
+	MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING,
+	MT6370_USB_STAT_SDP,
+	MT6370_USB_STAT_SDP_NSTD,
+	MT6370_USB_STAT_DCP,
+	MT6370_USB_STAT_CDP,
+	MT6370_USB_STAT_MAX
+};
+
+struct mt6370_chg_field {
+	const char *name;
+	const struct linear_range *range;
+	struct reg_field field;
+};
+
+enum {
+	MT6370_RANGE_F_IAICR = 0,
+	MT6370_RANGE_F_VOREG,
+	MT6370_RANGE_F_VMIVR,
+	MT6370_RANGE_F_ICHG,
+	MT6370_RANGE_F_IPREC,
+	MT6370_RANGE_F_IEOC,
+	MT6370_RANGE_F_MAX
+};
+
+#define MT6370_CHG_LINEAR_RANGE(_rfd, _min, _min_sel, _max_sel, _step)	\
+[_rfd] = {								\
+	.min = _min,							\
+	.min_sel = _min_sel,						\
+	.max_sel = _max_sel,						\
+	.step = _step,							\
+}
+
+static const struct linear_range mt6370_chg_ranges[MT6370_RANGE_F_MAX] = {
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IAICR, 100000, 0x0, 0x3F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VOREG, 3900000, 0x0, 0x51, 10000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_VMIVR, 3900000, 0x0, 0x5F, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_ICHG, 900000, 0x08, 0x31, 100000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IPREC, 100000, 0x0, 0x0F, 50000),
+	MT6370_CHG_LINEAR_RANGE(MT6370_RANGE_F_IEOC, 100000, 0x0, 0x0F, 50000),
+};
+
+#define MT6370_CHG_FIELD(_fd, _reg, _lsb, _msb)				\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = NULL,							\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+#define MT6370_CHG_FIELD_RANGE(_fd, _reg, _lsb, _msb)			\
+[_fd] = {								\
+	.name = #_fd,							\
+	.range = &mt6370_chg_ranges[MT6370_RANGE_##_fd],		\
+	.field = REG_FIELD(_reg, _lsb, _msb),				\
+}
+
+static const struct mt6370_chg_field mt6370_chg_fields[F_MAX] = {
+	MT6370_CHG_FIELD(F_IINLMTSEL, MT6370_REG_CHG_CTRL2, 2, 3),
+	MT6370_CHG_FIELD(F_CFO_EN, MT6370_REG_CHG_CTRL2, 1, 1),
+	MT6370_CHG_FIELD(F_CHG_EN, MT6370_REG_CHG_CTRL2, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_IAICR, MT6370_REG_CHG_CTRL3, 2, 7),
+	MT6370_CHG_FIELD(F_AICR_EN, MT6370_REG_CHG_CTRL3, 1, 1),
+	MT6370_CHG_FIELD(F_ILIM_EN, MT6370_REG_CHG_CTRL3, 0, 0),
+	MT6370_CHG_FIELD_RANGE(F_VOREG, MT6370_REG_CHG_CTRL4, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_VMIVR, MT6370_REG_CHG_CTRL6, 1, 7),
+	MT6370_CHG_FIELD_RANGE(F_ICHG, MT6370_REG_CHG_CTRL7, 2, 7),
+	MT6370_CHG_FIELD_RANGE(F_IPREC, MT6370_REG_CHG_CTRL8, 0, 3),
+	MT6370_CHG_FIELD_RANGE(F_IEOC, MT6370_REG_CHG_CTRL9, 4, 7),
+	MT6370_CHG_FIELD(F_USBCHGEN, MT6370_REG_DEVICE_TYPE, 7, 7),
+	MT6370_CHG_FIELD(F_USB_STAT, MT6370_REG_USB_STATUS1, 4, 6),
+	MT6370_CHG_FIELD(F_CHGDET, MT6370_REG_USB_STATUS1, 3, 3),
+	MT6370_CHG_FIELD(F_CHG_STAT, MT6370_REG_CHG_STAT, 6, 7),
+	MT6370_CHG_FIELD(F_BOOST_STAT, MT6370_REG_CHG_STAT, 3, 3),
+	MT6370_CHG_FIELD(F_VBAT_LVL, MT6370_REG_CHG_STAT, 5, 5),
+	MT6370_CHG_FIELD(F_FL_STROBE, MT6370_REG_FLED_EN, 2, 2),
+	MT6370_CHG_FIELD(F_CHG_MIVR_STAT, MT6370_REG_CHG_STAT1, 6, 6),
+	MT6370_CHG_FIELD(F_UVP_D_STAT, MT6370_REG_OVPCTRL_STAT, 4, 4),
+};
+
+static inline int mt6370_chg_field_get(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int *val)
+{
+	int ret;
+	unsigned int reg_val;
+
+	ret = regmap_field_read(priv->rmap_fields[fd], &reg_val);
+	if (ret < 0)
+		return ret;
+
+	if (mt6370_chg_fields[fd].range)
+		return linear_range_get_value(mt6370_chg_fields[fd].range,
+					      reg_val, val);
+
+	*val = reg_val;
+	return 0;
+}
+
+static inline int mt6370_chg_field_set(struct mt6370_priv *priv,
+				       enum mt6370_chg_reg_field fd,
+				       unsigned int val)
+{
+	int ret;
+	bool f;
+	const struct linear_range *r;
+
+	if (mt6370_chg_fields[fd].range) {
+		r = mt6370_chg_fields[fd].range;
+
+		if (fd == F_VMIVR) {
+			ret = linear_range_get_selector_high(r, val, &val, &f);
+			if (!ret)
+				val = r->max_sel;
+		} else {
+			linear_range_get_selector_within(r, val, &val);
+		}
+	}
+
+	return regmap_field_write(priv->rmap_fields[fd], val);
+}
+
+enum {
+	MT6370_CHG_STAT_READY = 0,
+	MT6370_CHG_STAT_CHARGE_IN_PROGRESS,
+	MT6370_CHG_STAT_DONE,
+	MT6370_CHG_STAT_FAULT,
+	MT6370_CHG_STAT_MAX
+};
+
+enum {
+	MT6370_ATTACH_STAT_DETACH = 0,
+	MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE,
+	MT6370_ATTACH_STAT_ATTACH_BC12_DONE,
+	MT6370_ATTACH_STAT_ATTACH_MAX
+};
+
+static int mt6370_chg_otg_of_parse_cb(struct device_node *of,
+				      const struct regulator_desc *rdesc,
+				      struct regulator_config *rcfg)
+{
+	struct mt6370_priv *priv = rcfg->driver_data;
+
+	rcfg->ena_gpiod = fwnode_gpiod_get_index(of_fwnode_handle(of),
+						 "enable", 0, GPIOD_OUT_LOW |
+						 GPIOD_FLAGS_BIT_NONEXCLUSIVE,
+						 rdesc->name);
+	if (IS_ERR(rcfg->ena_gpiod)) {
+		rcfg->ena_gpiod = NULL;
+		return 0;
+	}
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_CHG_CTRL1,
+				  MT6370_OTG_PIN_EN_MASK,
+				  MT6370_OTG_PIN_EN_MASK);
+}
+
+static void mt6370_chg_bc12_work_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						bc12_work);
+	int ret;
+	bool rpt_psy = false;
+	unsigned int attach, usb_stat;
+
+	mutex_lock(&priv->attach_lock);
+	attach = priv->attach;
+
+	switch (attach) {
+	case MT6370_ATTACH_STAT_DETACH:
+		usb_stat = 0;
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_DONE:
+		ret = mt6370_chg_field_get(priv, F_USB_STAT, &usb_stat);
+		if (ret < 0) {
+			dev_err(priv->dev, "Failed to get USB status\n");
+			goto bc12_work_func_out;
+		}
+		break;
+	case MT6370_ATTACH_STAT_ATTACH_BC12_NOT_DONE:
+		ret = mt6370_chg_field_set(priv, F_USBCHGEN, attach);
+		if (ret < 0)
+			dev_err(priv->dev, "Failed to enable USB CHG EN\n");
+		goto bc12_work_func_out;
+	default:
+		dev_err(priv->dev, "Invalid attach state\n");
+		goto bc12_work_func_out;
+	}
+
+	rpt_psy = true;
+
+	switch (usb_stat) {
+	case MT6370_USB_STAT_SDP:
+	case MT6370_USB_STAT_SDP_NSTD:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP;
+		break;
+	case MT6370_USB_STAT_DCP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP;
+		break;
+	case MT6370_USB_STAT_CDP:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP;
+		break;
+	case MT6370_USB_STAT_NO_VBUS:
+	case MT6370_USB_STAT_VBUS_FLOW_IS_UNDER_GOING:
+	default:
+		priv->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
+		break;
+	}
+
+bc12_work_func_out:
+	mutex_unlock(&priv->attach_lock);
+
+	if (rpt_psy)
+		power_supply_changed(priv->psy);
+}
+
+static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
+					 const char *irq_name, bool en)
+{
+	int irq_num;
+	struct platform_device *pdev = to_platform_device(priv->dev);
+
+	irq_num = platform_get_irq_byname(pdev, irq_name);
+	if (irq_num < 0)
+		return;
+
+	if (en)
+		enable_irq(irq_num);
+	else
+		disable_irq_nosync(irq_num);
+}
+
+static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int fl_strobe;
+
+	/* check if flash led in strobe mode */
+	ret = mt6370_chg_field_get(priv, F_FL_STROBE, &fl_strobe);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get FL_STROBE_EN\n");
+		return ret;
+	}
+
+	if (fl_strobe) {
+		dev_err(priv->dev, "Flash led is still in strobe mode\n");
+		return ret;
+	}
+
+	/* cfo off */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable CFO_EN\n");
+		return ret;
+	}
+
+	/* cfo on */
+	ret = mt6370_chg_field_set(priv, F_CFO_EN, 1);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to enable CFO_EN\n");
+
+	return ret;
+}
+
+static int mt6370_chg_read_adc_chan(struct mt6370_priv *priv, unsigned int chan,
+				    int *val)
+{
+	int ret;
+
+	if (chan >= MT6370_ADC_CHAN_MAX)
+		return -EINVAL;
+
+	ret = iio_read_channel_processed(&priv->iio_adcs[chan], val);
+	if (ret)
+		dev_err(priv->dev, "Failed to read ADC\n");
+
+	return ret;
+}
+
+static void mt6370_chg_mivr_dwork_func(struct work_struct *work)
+{
+	struct mt6370_priv *priv = container_of(work, struct mt6370_priv,
+						mivr_dwork.work);
+	int ret;
+	unsigned int mivr_stat, ibus;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_MIVR_STAT, &mivr_stat);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get mivr state\n");
+		goto mivr_handler_out;
+	}
+
+	if (!mivr_stat)
+		goto mivr_handler_out;
+
+	ret = mt6370_chg_read_adc_chan(priv, MT6370_ADC_CHAN_IBUS, &ibus);
+	if (ret) {
+		dev_err(priv->dev, "Failed to get ibus\n");
+		goto mivr_handler_out;
+	}
+
+	if (ibus < MT6370_MIVR_IBUS_TH_100_mA) {
+		ret = mt6370_chg_toggle_cfo(priv);
+		if (ret)
+			dev_err(priv->dev, "Failed to toggle cfo\n");
+	}
+
+mivr_handler_out:
+	mt6370_chg_enable_irq(priv, "mivr", true);
+	pm_relax(priv->dev);
+}
+
+static void mt6370_chg_pwr_rdy_check(struct mt6370_priv *priv)
+{
+	int ret;
+	unsigned int pwr_rdy, otg_en;
+	union power_supply_propval val;
+
+	/* Check in OTG mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get OTG state\n");
+		return;
+	}
+
+	if (otg_en)
+		return;
+
+	ret = mt6370_chg_field_get(priv, F_UVP_D_STAT, &pwr_rdy);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get pwr_rdy state reg\n");
+		return;
+	}
+
+	val.intval = !pwr_rdy;
+
+	ret = power_supply_set_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&val);
+	if (ret < 0)
+		dev_err(priv->dev, "Failed to start attach/detach flow\n");
+}
+
+static int mt6370_chg_get_online(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	mutex_lock(&priv->attach_lock);
+	val->intval = !!priv->attach;
+	mutex_unlock(&priv->attach_lock);
+
+	return 0;
+}
+
+static int mt6370_chg_get_status(struct mt6370_priv *priv,
+				 union power_supply_propval *val)
+{
+	int ret;
+	unsigned int chg_stat;
+	union power_supply_propval online;
+
+	ret = power_supply_get_property(priv->psy, POWER_SUPPLY_PROP_ONLINE,
+					&online);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get online status\n");
+		return ret;
+	}
+
+	if (!online.intval) {
+		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		return 0;
+	}
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_FAULT:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		return ret;
+	case MT6370_CHG_STAT_DONE:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		return ret;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		return ret;
+	}
+}
+
+static int mt6370_chg_get_charge_type(struct mt6370_priv *priv,
+				      union power_supply_propval *val)
+{
+	int type, ret;
+	unsigned int chg_stat, vbat_lvl;
+
+	ret = mt6370_chg_field_get(priv, F_CHG_STAT, &chg_stat);
+	if (ret < 0)
+		return ret;
+
+	ret = mt6370_chg_field_get(priv, F_VBAT_LVL, &vbat_lvl);
+	if (ret < 0)
+		return ret;
+
+	switch (chg_stat) {
+	case MT6370_CHG_STAT_CHARGE_IN_PROGRESS:
+		if (vbat_lvl)
+			type = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		else
+			type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	case MT6370_CHG_STAT_READY:
+	case MT6370_CHG_STAT_DONE:
+	case MT6370_CHG_STAT_FAULT:
+	default:
+		type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		break;
+	}
+
+	val->intval = type;
+
+	return 0;
+}
+
+static int mt6370_chg_set_online(struct mt6370_priv *priv,
+				 const union power_supply_propval *val)
+{
+	bool pwr_rdy = !!val->intval;
+
+	mutex_lock(&priv->attach_lock);
+	if (pwr_rdy == !!priv->attach) {
+		dev_err(priv->dev, "pwr_rdy is same(%d)\n", pwr_rdy);
+		mutex_unlock(&priv->attach_lock);
+		return 0;
+	}
+
+	priv->attach = pwr_rdy;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return 0;
+}
+
+static int mt6370_chg_get_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_get_online(priv, val);
+	case POWER_SUPPLY_PROP_STATUS:
+		return mt6370_chg_get_status(priv, val);
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		return mt6370_chg_get_charge_type(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_ICHG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_ICHG]);
+		return 0;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_get(priv, F_VOREG, &val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		val->intval = linear_range_get_max_value(&mt6370_chg_ranges[MT6370_RANGE_F_VOREG]);
+		return 0;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_get(priv, F_IAICR, &val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_get(priv, F_VMIVR, &val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_get(priv, F_IPREC, &val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_get(priv, F_IEOC, &val->intval);
+	case POWER_SUPPLY_PROP_USB_TYPE:
+		val->intval = priv->psy_usb_type;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_set_property(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   const union power_supply_propval *val)
+{
+	struct mt6370_priv *priv = power_supply_get_drvdata(psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		return mt6370_chg_set_online(priv, val);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_ICHG, val->intval);
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		return mt6370_chg_field_set(priv, F_VOREG, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		return mt6370_chg_field_set(priv, F_IAICR, val->intval);
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+		return mt6370_chg_field_set(priv, F_VMIVR, val->intval);
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+		return mt6370_chg_field_set(priv, F_IPREC, val->intval);
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return mt6370_chg_field_set(priv, F_IEOC, val->intval);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int mt6370_chg_property_is_writeable(struct power_supply *psy,
+					    enum power_supply_property psp)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
+	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static enum power_supply_property mt6370_chg_properties[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
+	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_USB_TYPE,
+};
+
+static enum power_supply_usb_type mt6370_chg_usb_types[] = {
+	POWER_SUPPLY_USB_TYPE_UNKNOWN,
+	POWER_SUPPLY_USB_TYPE_SDP,
+	POWER_SUPPLY_USB_TYPE_CDP,
+	POWER_SUPPLY_USB_TYPE_DCP,
+};
+
+static const struct power_supply_desc mt6370_chg_psy_desc = {
+	.name = "mt6370-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = mt6370_chg_properties,
+	.num_properties = ARRAY_SIZE(mt6370_chg_properties),
+	.get_property = mt6370_chg_get_property,
+	.set_property = mt6370_chg_set_property,
+	.property_is_writeable = mt6370_chg_property_is_writeable,
+	.usb_types = mt6370_chg_usb_types,
+	.num_usb_types = ARRAY_SIZE(mt6370_chg_usb_types),
+};
+
+static const struct regulator_ops mt6370_chg_otg_ops = {
+	.list_voltage = regulator_list_voltage_linear,
+	.enable = regulator_enable_regmap,
+	.disable = regulator_disable_regmap,
+	.is_enabled = regulator_is_enabled_regmap,
+	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel = regulator_get_voltage_sel_regmap,
+	.set_current_limit = regulator_set_current_limit_regmap,
+	.get_current_limit = regulator_get_current_limit_regmap,
+};
+
+static const u32 mt6370_chg_otg_oc_ma[] = {
+	500000, 700000, 1100000, 1300000, 1800000, 2100000, 2400000,
+};
+
+static const struct regulator_desc mt6370_chg_otg_rdesc = {
+	.of_match = "usb-otg-vbus-regulator",
+	.of_parse_cb = mt6370_chg_otg_of_parse_cb,
+	.name = "mt6370-usb-otg-vbus",
+	.ops = &mt6370_chg_otg_ops,
+	.owner = THIS_MODULE,
+	.type = REGULATOR_VOLTAGE,
+	.min_uV = 4425000,
+	.uV_step = 25000,
+	.n_voltages = 57,
+	.vsel_reg = MT6370_REG_CHG_CTRL5,
+	.vsel_mask = MT6370_VOBST_MASK,
+	.enable_reg = MT6370_REG_CHG_CTRL1,
+	.enable_mask = MT6370_OPA_MODE_MASK,
+	.curr_table = mt6370_chg_otg_oc_ma,
+	.n_current_limits = ARRAY_SIZE(mt6370_chg_otg_oc_ma),
+	.csel_reg = MT6370_REG_CHG_CTRL10,
+	.csel_mask = MT6370_OTG_OC_MASK,
+};
+
+static int mt6370_chg_init_rmap_fields(struct mt6370_priv *priv)
+{
+	int i;
+	const struct mt6370_chg_field *fds = mt6370_chg_fields;
+
+	for (i = 0; i < F_MAX; i++) {
+		priv->rmap_fields[i] = devm_regmap_field_alloc(priv->dev,
+							       priv->regmap,
+							       fds[i].field);
+		if (IS_ERR(priv->rmap_fields[i]))
+			return dev_err_probe(priv->dev,
+					PTR_ERR(priv->rmap_fields[i]),
+					"Failed to allocate regmapfield[%s]\n",
+					fds[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_init_setting(struct mt6370_priv *priv)
+{
+	int ret;
+
+	/* Disable usb_chg_en */
+	ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to disable usb_chg_en\n");
+		return ret;
+	}
+
+	/* ICHG/IEOC Workaround, ICHG can not be set less than 900mA */
+	ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set ICHG to 900mA");
+		return ret;
+	}
+
+	/* Change input current limit selection to using IAICR results */
+	ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to set IINLMTSEL\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+#define MT6370_CHG_DT_PROP_DECL(_name, _type, _field)	\
+{							\
+	.name = "mediatek,chg-" #_name,			\
+	.type = MT6370_PARSE_TYPE_##_type,		\
+	.fd = _field,					\
+}
+
+static int mt6370_chg_init_otg_regulator(struct mt6370_priv *priv)
+{
+	struct regulator_config rcfg = {
+		.dev = priv->dev,
+		.regmap = priv->regmap,
+		.driver_data = priv,
+	};
+
+	priv->rdev = devm_regulator_register(priv->dev, &mt6370_chg_otg_rdesc,
+					     &rcfg);
+
+	return PTR_ERR_OR_ZERO(priv->rdev);
+}
+
+static int mt6370_chg_init_psy(struct mt6370_priv *priv)
+{
+	struct power_supply_config cfg = {
+		.drv_data = priv,
+		.of_node = dev_of_node(priv->dev),
+	};
+
+	priv->psy = devm_power_supply_register(priv->dev, &mt6370_chg_psy_desc,
+					       &cfg);
+
+	return PTR_ERR_OR_ZERO(priv->psy);
+}
+
+static void mt6370_chg_destroy_attach_lock(void *data)
+{
+	struct mutex *attach_lock = data;
+
+	mutex_destroy(attach_lock);
+}
+
+static void mt6370_chg_destroy_wq(void *data)
+{
+	struct workqueue_struct *wq = data;
+
+	flush_workqueue(wq);
+	destroy_workqueue(wq);
+}
+
+static void mt6370_chg_cancel_mivr_dwork(void *data)
+{
+	struct delayed_work *mivr_dwork = data;
+
+	cancel_delayed_work_sync(mivr_dwork);
+}
+
+static irqreturn_t mt6370_attach_i_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+	unsigned int otg_en;
+	int ret;
+
+	/* Check in otg mode or not */
+	ret = mt6370_chg_field_get(priv, F_BOOST_STAT, &otg_en);
+	if (ret < 0) {
+		dev_err(priv->dev, "Failed to get otg state\n");
+		return IRQ_NONE;
+	}
+
+	if (otg_en)
+		return IRQ_HANDLED;
+
+	mutex_lock(&priv->attach_lock);
+	priv->attach = MT6370_ATTACH_STAT_ATTACH_BC12_DONE;
+	mutex_unlock(&priv->attach_lock);
+
+	if (!queue_work(priv->wq, &priv->bc12_work))
+		dev_err(priv->dev, "bc12 work has already queued\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_uvp_d_evt_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mt6370_mivr_handler(int irq, void *data)
+{
+	struct mt6370_priv *priv = data;
+
+	pm_stay_awake(priv->dev);
+	mt6370_chg_enable_irq(priv, "mivr", false);
+	schedule_delayed_work(&priv->mivr_dwork, msecs_to_jiffies(200));
+
+	return IRQ_HANDLED;
+}
+
+#define MT6370_CHG_IRQ(_name)						\
+{									\
+	.name = #_name,							\
+	.handler = mt6370_##_name##_handler,				\
+}
+
+static int mt6370_chg_init_irq(struct mt6370_priv *priv)
+{
+	int i, ret;
+	const struct {
+		char *name;
+		irq_handler_t handler;
+	} mt6370_chg_irqs[] = {
+		MT6370_CHG_IRQ(attach_i),
+		MT6370_CHG_IRQ(uvp_d_evt),
+		MT6370_CHG_IRQ(mivr),
+	};
+
+	for (i = 0; i < ARRAY_SIZE(mt6370_chg_irqs); i++) {
+		ret = platform_get_irq_byname(to_platform_device(priv->dev),
+					      mt6370_chg_irqs[i].name);
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to get irq %s\n",
+					     mt6370_chg_irqs[i].name);
+
+		ret = devm_request_threaded_irq(priv->dev, ret, NULL,
+						mt6370_chg_irqs[i].handler,
+						IRQF_TRIGGER_FALLING,
+						dev_name(priv->dev), priv);
+
+		if (ret < 0)
+			return dev_err_probe(priv->dev, ret,
+					     "Failed to request irq %s\n",
+					     mt6370_chg_irqs[i].name);
+	}
+
+	return 0;
+}
+
+static int mt6370_chg_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = &pdev->dev;
+
+	priv->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_chg_init_rmap_fields(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init regmap fields\n");
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->iio_adcs = devm_iio_channel_get_all(priv->dev);
+	if (IS_ERR(priv->iio_adcs))
+		return dev_err_probe(dev, PTR_ERR(priv->iio_adcs),
+				     "Failed to get iio adc\n");
+
+	ret = mt6370_chg_init_otg_regulator(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init otg regulator\n");
+
+	ret = mt6370_chg_init_psy(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init psy\n");
+
+	mutex_init(&priv->attach_lock);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_attach_lock,
+				       &priv->attach_lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init attach lock\n");
+
+	priv->attach = MT6370_ATTACH_STAT_DETACH;
+
+	priv->wq = create_singlethread_workqueue(dev_name(priv->dev));
+	if (IS_ERR(priv->wq))
+		return dev_err_probe(dev, PTR_ERR(priv->wq),
+				     "Failed to create workqueue\n");
+
+	ret = devm_add_action_or_reset(dev, mt6370_chg_destroy_wq, priv->wq);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init wq\n");
+
+	INIT_WORK(&priv->bc12_work, mt6370_chg_bc12_work_func);
+	INIT_DELAYED_WORK(&priv->mivr_dwork, mt6370_chg_mivr_dwork_func);
+	ret = devm_add_action_or_reset(dev, mt6370_chg_cancel_mivr_dwork,
+				       &priv->mivr_dwork);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to init mivr dwork\n");
+
+	ret = mt6370_chg_init_setting(priv);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init mt6370 charger setting\n");
+
+	ret = mt6370_chg_init_irq(priv);
+	if (ret)
+		return ret;
+
+	mt6370_chg_pwr_rdy_check(priv);
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_chg_of_match[] = {
+	{ .compatible = "mediatek,mt6370-charger", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_chg_of_match);
+
+static struct platform_driver mt6370_chg_driver = {
+	.probe = mt6370_chg_probe,
+	.driver = {
+		.name = "mt6370-charger",
+		.of_match_table = mt6370_chg_of_match,
+	},
+};
+module_platform_driver(mt6370_chg_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Charger Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

In MediaTek MT6370, there are four channel current-sink RGB LEDs that
support hardware pattern for constant current, PWM, and breath mode.
Isink4 channel can also be used as a CHG_VIN power good indicator.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---

v6
- Remove the 'ko' from mt6370 led Kconfig description.
- Add both authors for Alice and ChiYuan.
- Use pdata to distinguish the code from mt6370/71 to mt6372.
- Instead of 'state' define, use the 'state' enum.
- Fix the typo for 'MT6372_PMW_DUTY'.
- For pwm_duty define, replace with bit macro - 1.
- Refine all the labels from 'out' to 'out_unlock'.
- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
- Revise for the array initialization from {0} to {}.
- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
- Refine the 'comma' usage in struct/enum.
---
 drivers/leds/rgb/Kconfig           |   13 +
 drivers/leds/rgb/Makefile          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
 3 files changed, 1018 insertions(+)
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c

diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig
index 204cf47..d6ad875 100644
--- a/drivers/leds/rgb/Kconfig
+++ b/drivers/leds/rgb/Kconfig
@@ -26,4 +26,17 @@ config LEDS_QCOM_LPG
 
 	  If compiled as a module, the module will be named leds-qcom-lpg.
 
+config LEDS_MT6370_RGB
+	tristate "LED Support for MediaTek MT6370 PMIC"
+	depends on MFD_MT6370
+	select LINEAR_RANGE
+	help
+	  Say Y here to enable support for MT6370_RGB LED device.
+	  In MT6370, there are four channel current-sink LED drivers that
+	  support hardware pattern for constant current, PWM, and breath mode.
+	  Isink4 channel can also be used as a CHG_VIN power good indicator.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-rgb".
+
 endif # LEDS_CLASS_MULTICOLOR
diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile
index 0675bc0..8c01daf 100644
--- a/drivers/leds/rgb/Makefile
+++ b/drivers/leds/rgb/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_LEDS_PWM_MULTICOLOR)	+= leds-pwm-multicolor.o
 obj-$(CONFIG_LEDS_QCOM_LPG)		+= leds-qcom-lpg.o
+obj-$(CONFIG_LEDS_MT6370_RGB)		+= leds-mt6370-rgb.o
diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c
new file mode 100644
index 0000000..bf52989
--- /dev/null
+++ b/drivers/leds/rgb/leds-mt6370-rgb.c
@@ -0,0 +1,1004 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com>
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/linear_range.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/util_macros.h>
+
+enum {
+	MT6370_LED_ISNK1 = 0,
+	MT6370_LED_ISNK2,
+	MT6370_LED_ISNK3,
+	MT6370_LED_ISNK4,
+	MT6370_MAX_LEDS
+};
+
+enum mt6370_led_mode {
+	MT6370_LED_PWM_MODE = 0,
+	MT6370_LED_BREATH_MODE,
+	MT6370_LED_REG_MODE,
+	MT6370_LED_MAX_MODE
+};
+
+enum mt6370_led_field {
+	F_RGB_EN = 0,
+	F_CHGIND_EN,
+	F_LED1_CURR,
+	F_LED2_CURR,
+	F_LED3_CURR,
+	F_LED4_CURR,
+	F_LED1_MODE,
+	F_LED2_MODE,
+	F_LED3_MODE,
+	F_LED4_MODE,
+	F_LED1_DUTY,
+	F_LED2_DUTY,
+	F_LED3_DUTY,
+	F_LED4_DUTY,
+	F_LED1_FREQ,
+	F_LED2_FREQ,
+	F_LED3_FREQ,
+	F_LED4_FREQ,
+	F_MAX_FIELDS
+};
+
+enum mt6370_led_ranges {
+	R_LED123_CURR = 0,
+	R_LED4_CURR,
+	R_LED_TRFON,
+	R_LED_TOFF,
+	R_MAX_RANGES
+};
+
+enum mt6370_pattern {
+	P_LED_TR1 = 0,
+	P_LED_TR2,
+	P_LED_TF1,
+	P_LED_TF2,
+	P_LED_TON,
+	P_LED_TOFF,
+	P_MAX_PATTERNS
+};
+
+enum mt6370_state {
+	STATE_OFF = 0,
+	STATE_KEEP,
+	STATE_ON,
+	STATE_MAX
+};
+
+#define MT6370_REG_DEV_INFO			0x100
+#define MT6370_REG_RGB1_DIM			0x182
+#define MT6370_REG_RGB2_DIM			0x183
+#define MT6370_REG_RGB3_DIM			0x184
+#define MT6370_REG_RGB_EN			0x185
+#define MT6370_REG_RGB1_ISNK			0x186
+#define MT6370_REG_RGB2_ISNK			0x187
+#define MT6370_REG_RGB3_ISNK			0x188
+#define MT6370_REG_RGB1_TR			0x189
+#define MT6370_REG_RGB_CHRIND_DIM		0x192
+#define MT6370_REG_RGB_CHRIND_CTRL		0x193
+#define MT6370_REG_RGB_CHRIND_TR		0x194
+
+#define MT6372_REG_RGB_EN			0x182
+#define MT6372_REG_RGB1_ISNK			0x183
+#define MT6372_REG_RGB2_ISNK			0x184
+#define MT6372_REG_RGB3_ISNK			0x185
+#define MT6372_REG_RGB4_ISNK			0x186
+#define MT6372_REG_RGB1_DIM			0x187
+#define MT6372_REG_RGB2_DIM			0x188
+#define MT6372_REG_RGB3_DIM			0x189
+#define MT6372_REG_RGB4_DIM			0x18A
+#define MT6372_REG_RGB12_FREQ			0x18B
+#define MT6372_REG_RGB34_FREQ			0x18C
+#define MT6372_REG_RGB1_TR			0x18D
+
+#define MT6370_VENID_MASK			GENMASK(7, 4)
+#define MT6370_CHEN_BIT(id)			BIT(MT6370_LED_ISNK4 - id)
+#define MT6370_VIRTUAL_MULTICOLOR		5
+#define MC_CHANNEL_NUM				3
+#define MT6370_PWM_DUTY				(BIT(5) - 1)
+#define MT6372_PWM_DUTY				(BIT(8) - 1)
+
+struct mt6370_led {
+	union {
+		struct led_classdev isink;
+		struct led_classdev_mc mc;
+	};
+	struct mt6370_priv *priv;
+	u32 default_state;
+	u32 index;
+};
+
+struct mt6370_pdata {
+	const unsigned int *tfreq;
+	unsigned int tfreq_len;
+	u8 pwm_duty;
+	u16 reg_rgb1_tr;
+	s16 reg_rgb_chrind_tr;
+};
+
+struct mt6370_priv {
+	/* Per LED access lock */
+	struct mutex lock;
+	struct device *dev;
+	struct regmap *regmap;
+	struct regmap_field *fields[F_MAX_FIELDS];
+	const struct reg_field *reg_fields;
+	const struct linear_range *ranges;
+	struct reg_cfg *reg_cfgs;
+	const struct mt6370_pdata *pdata;
+	unsigned int leds_count;
+	unsigned int leds_active;
+	struct mt6370_led leds[];
+};
+
+static const struct reg_field common_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6370_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7),
+	[F_LED1_CURR]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2),
+	[F_LED2_CURR]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2),
+	[F_LED3_CURR]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2),
+	[F_LED4_CURR]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1),
+	[F_LED1_MODE]	= REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6),
+	[F_LED2_MODE]	= REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6),
+	[F_LED3_MODE]	= REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6),
+	[F_LED4_MODE]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6),
+	[F_LED1_DUTY]	= REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4),
+	[F_LED2_DUTY]	= REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4),
+	[F_LED3_DUTY]	= REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4),
+	[F_LED4_DUTY]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4),
+	[F_LED1_FREQ]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5),
+	[F_LED2_FREQ]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5),
+	[F_LED3_FREQ]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5),
+	[F_LED4_FREQ]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4),
+};
+
+static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 3, 3),
+	[F_LED1_CURR]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3),
+	[F_LED2_CURR]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3),
+	[F_LED3_CURR]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3),
+	[F_LED4_CURR]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3),
+	[F_LED1_MODE]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7),
+	[F_LED2_MODE]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7),
+	[F_LED3_MODE]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7),
+	[F_LED4_MODE]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7),
+	[F_LED1_DUTY]	= REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7),
+	[F_LED2_DUTY]	= REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7),
+	[F_LED3_DUTY]	= REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7),
+	[F_LED4_DUTY]	= REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7),
+	[F_LED1_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7),
+	[F_LED2_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4),
+	[F_LED3_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7),
+	[F_LED4_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4),
+};
+
+/* Current unit: microamp, time unit: millisecond */
+static const struct linear_range common_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 4000, 1, 6, 4000 },
+	[R_LED4_CURR]	= { 2000, 1, 3, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 200 },
+	[R_LED_TOFF]	= { 250, 0, 15, 400 },
+};
+
+static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED4_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 250 },
+	[R_LED_TOFF]	= { 250, 0, 15, 500 },
+};
+
+static const unsigned int common_tfreqs[] = {
+	10000, 5000, 2000, 1000, 500, 200, 5, 1,
+};
+
+static const unsigned int mt6372_tfreqs[] = {
+	8000, 4000, 2000, 1000, 500, 250, 8, 4,
+};
+
+static const struct mt6370_pdata common_pdata = {
+	.tfreq = common_tfreqs,
+	.tfreq_len = ARRAY_SIZE(common_tfreqs),
+	.pwm_duty = MT6370_PWM_DUTY,
+	.reg_rgb1_tr = MT6370_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = MT6370_REG_RGB_CHRIND_TR,
+};
+
+static const struct mt6370_pdata mt6372_pdata = {
+	.tfreq = mt6372_tfreqs,
+	.tfreq_len = ARRAY_SIZE(mt6372_tfreqs),
+	.pwm_duty = MT6372_PWM_DUTY,
+	.reg_rgb1_tr = MT6372_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = -1,
+};
+
+static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no)
+{
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		return F_LED1_CURR;
+	case MT6370_LED_ISNK2:
+		return F_LED2_CURR;
+	case MT6370_LED_ISNK3:
+		return F_LED3_CURR;
+	default:
+		return F_LED4_CURR;
+	}
+}
+
+static int mt6370_set_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_write(priv->fields[sel_field], level);
+}
+
+static int mt6370_get_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int *level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_read(priv->fields[sel_field], level);
+}
+
+static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int divisor, ratio;
+
+	divisor = pdata->pwm_duty;
+	ratio = ton * divisor / (ton + toff);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_DUTY;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_DUTY;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_DUTY;
+		break;
+	default:
+		sel_field = F_LED4_DUTY;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], ratio);
+}
+
+static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int tfreq_len = pdata->tfreq_len;
+	unsigned int tsum, sel;
+
+	tsum = ton + toff;
+
+	if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1])
+		return -EOPNOTSUPP;
+
+	sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_FREQ;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_FREQ;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_FREQ;
+		break;
+	default:
+		sel_field = F_LED4_FREQ;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], sel);
+}
+
+static void mt6370_get_breath_reg_base(struct mt6370_priv *priv,
+				       unsigned int led_no, unsigned int *base)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+
+	if (pdata->reg_rgb_chrind_tr < 0) {
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		return;
+	}
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+	case MT6370_LED_ISNK2:
+	case MT6370_LED_ISNK3:
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		break;
+	default:
+		*base = pdata->reg_rgb_chrind_tr;
+		break;
+	}
+}
+
+static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
+				     struct led_pattern *pattern, u32 len,
+				     u8 *pattern_val, u32 val_len)
+{
+	enum mt6370_led_ranges sel_range;
+	struct led_pattern *curr;
+	unsigned int sel;
+	u8 val[P_MAX_PATTERNS / 2] = {};
+	int i;
+
+	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
+		return -EINVAL;
+
+	/*
+	 * Pattern list
+	 * tr1:	byte 0, b'[7: 4]
+	 * tr2:	byte 0, b'[3: 0]
+	 * tf1:	byte 1, b'[7: 4]
+	 * tf2:	byte 1, b'[3: 0]
+	 * ton:	byte 2, b'[7: 4]
+	 * toff: byte 2, b'[3: 0]
+	 */
+	for (i = 0; i < P_MAX_PATTERNS; i++) {
+		curr = pattern + i;
+
+		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
+
+		linear_range_get_selector_within(priv->ranges + sel_range,
+						 curr->delta_t, &sel);
+
+		val[i / 2] |= sel << (4 * ((i + 1) % 2));
+	}
+
+	memcpy(pattern_val, val, 3);
+
+	return 0;
+}
+
+static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no,
+			       enum mt6370_led_mode mode)
+{
+	enum mt6370_led_field sel_field;
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_MODE;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_MODE;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_MODE;
+		break;
+	default:
+		sel_field = F_LED4_MODE;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], mode);
+}
+
+static int mt6370_mc_brightness_set(struct led_classdev *lcdev,
+				    enum led_brightness level)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	led_mc_calc_color_components(mccdev, level);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		u32 brightness;
+
+		subled = mccdev->subled_info + i;
+		brightness = min(subled->brightness, lcdev->max_brightness);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		if (level == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+
+			ret = mt6370_set_led_mode(priv, subled->channel,
+						  MT6370_LED_REG_MODE);
+			if (ret)
+				goto out_unlock;
+
+			continue;
+		}
+
+		if (brightness == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+			continue;
+		}
+
+		enable |= MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_brightness(priv, subled->channel,
+						brightness);
+		if (ret)
+			goto out_unlock;
+	}
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_blink_set(struct led_classdev *lcdev,
+			       unsigned long *delay_on,
+			       unsigned long *delay_off)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_duty(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_freq(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_PWM_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_pattern_set(struct led_classdev *lcdev,
+			struct led_pattern *pattern, u32 len, int repeat)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int reg_base, enable, disable;
+	u8 params[P_MAX_PATTERNS / 2];
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		mt6370_get_breath_reg_base(priv, subled->channel, &reg_base);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = regmap_raw_write(priv->regmap, reg_base, params,
+				       sizeof(params));
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_BREATH_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing be the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	int i, ret = 0;
+
+	mutex_lock(&led->priv->lock);
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_brightness_set(struct led_classdev *lcdev,
+				      enum led_brightness level)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	if (level == LED_OFF) {
+		enable &= ~MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_mode(priv, led->index,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	} else {
+		enable |= MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_brightness(priv, led->index, level);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	}
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_blink_set(struct led_classdev *lcdev,
+				 unsigned long *delay_on,
+				 unsigned long *delay_off)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_pattern_set(struct led_classdev *lcdev,
+				   struct led_pattern *pattern, u32 len,
+				   int repeat)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int reg_base;
+	u8 params[P_MAX_PATTERNS / 2];
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	mt6370_get_breath_reg_base(priv, led->index, &reg_base);
+
+	ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&led->priv->lock);
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_init_led_properties(struct mt6370_led *led,
+				      struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	struct device *dev = priv->dev;
+	struct led_classdev *lcdev;
+	struct fwnode_handle *child;
+	enum mt6370_led_ranges sel_range;
+	u32 max_uA, max_level;
+	const char * const states[] = { "off", "keep", "on" };
+	const char *stat_str;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		struct mc_subled *sub_led;
+		u32 num_color = 0;
+
+		sub_led = devm_kcalloc(dev, MC_CHANNEL_NUM, sizeof(*sub_led),
+				       GFP_KERNEL);
+		if (!sub_led)
+			return -ENOMEM;
+
+		fwnode_for_each_child_node(init_data->fwnode, child) {
+			u32 reg, color;
+
+			ret = fwnode_property_read_u32(child, "reg", &reg);
+			if (ret || reg > MT6370_LED_ISNK3 ||
+			    priv->leds_active & BIT(reg))
+				return -EINVAL;
+
+			ret = fwnode_property_read_u32(child, "color", &color);
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "led %d, no color specified\n",
+						     led->index);
+
+			priv->leds_active |= BIT(reg);
+			sub_led[num_color].color_index = color;
+			sub_led[num_color].channel = reg;
+			sub_led[num_color].intensity = 0;
+			num_color++;
+		}
+
+		if (num_color < 2)
+			return dev_err_probe(dev, -EINVAL,
+					     "Multicolor must include 2 or more led channel\n");
+
+		led->mc.num_colors = num_color;
+		led->mc.subled_info = sub_led;
+
+		lcdev = &led->mc.led_cdev;
+		lcdev->brightness_set_blocking = mt6370_mc_brightness_set;
+		lcdev->blink_set = mt6370_mc_blink_set;
+		lcdev->pattern_set = mt6370_mc_pattern_set;
+		lcdev->pattern_clear = mt6370_mc_pattern_clear;
+	} else {
+		lcdev = &led->isink;
+		lcdev->brightness_set_blocking = mt6370_isnk_brightness_set;
+		lcdev->blink_set = mt6370_isnk_blink_set;
+		lcdev->pattern_set = mt6370_isnk_pattern_set;
+		lcdev->pattern_clear = mt6370_isnk_pattern_clear;
+	}
+
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
+				       &max_uA);
+	if (ret) {
+		dev_warn(dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		max_uA = 0;
+	}
+
+	if (led->index == MT6370_LED_ISNK4)
+		sel_range = R_LED4_CURR;
+	else
+		sel_range = R_LED123_CURR;
+
+	linear_range_get_selector_within(priv->ranges + sel_range, max_uA,
+					 &max_level);
+
+	lcdev->max_brightness = max_level;
+
+	fwnode_property_read_string(init_data->fwnode, "linux,default-trigger",
+				    &lcdev->default_trigger);
+
+	if (!fwnode_property_read_string(init_data->fwnode, "default-state",
+					 &stat_str)) {
+		ret = match_string(states, ARRAY_SIZE(states), stat_str);
+		if (ret < 0)
+			ret = STATE_OFF;
+
+		led->default_state = ret;
+	}
+
+	return 0;
+}
+
+static int mt6370_isnk_init_default_state(struct mt6370_led *led)
+{
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable, level;
+	int ret;
+
+	ret = mt6370_get_led_brightness(priv, led->index, &level);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_CHEN_BIT(led->index)))
+		level = LED_OFF;
+
+	switch (led->default_state) {
+	case STATE_ON:
+		led->isink.brightness = led->isink.max_brightness;
+		break;
+	case STATE_KEEP:
+		led->isink.brightness = min(level, led->isink.max_brightness);
+		break;
+	default:
+		led->isink.brightness = LED_OFF;
+		break;
+	}
+
+	return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+			       struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		ret = mt6370_mc_brightness_set(&led->mc.led_cdev, LED_OFF);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't set multicolor brightness\n");
+
+		ret = devm_led_classdev_multicolor_register_ext(parent,
+								&led->mc,
+								init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register multicolor\n");
+	} else {
+		if (led->index == MT6370_LED_ISNK4) {
+			ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1);
+			if (ret)
+				return dev_err_probe(parent, ret,
+						     "Failed to set CHRIND to SW\n");
+		}
+
+		ret = mt6370_isnk_init_default_state(led);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Failed to init %d isnk state\n",
+					     led->index);
+
+		ret = devm_led_classdev_register_ext(parent, &led->isink,
+						     init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register isink %d\n",
+					     led->index);
+	}
+
+	return 0;
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	unsigned int devinfo, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, devinfo);
+	if (vid == 0x9 || vid == 0xb) {
+		priv->reg_fields = mt6372_reg_fields;
+		priv->ranges = mt6372_led_ranges;
+		priv->pdata = &mt6372_pdata;
+	} else {
+		/* Common for MT6370/71 */
+		priv->reg_fields = common_reg_fields;
+		priv->ranges = common_led_ranges;
+		priv->pdata = &common_pdata;
+	}
+
+	return 0;
+}
+
+static int mt6370_leds_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+				     "No child node or node count over max led number %zu\n",
+				      count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields,
+					   priv->reg_fields, F_MAX_FIELDS);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate regmap field\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i++;
+		struct led_init_data init_data = { .fwnode = child };
+		u32 reg, color;
+
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse reg property\n");
+
+		if (reg >= MT6370_MAX_LEDS)
+			return dev_err_probe(dev, -EINVAL, "Error reg property number\n");
+
+		ret = fwnode_property_read_u32(child, "color", &color);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse color property\n");
+
+		if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI)
+			reg = MT6370_VIRTUAL_MULTICOLOR;
+
+		if (priv->leds_active & BIT(reg))
+			return dev_err_probe(dev, -EINVAL, "Duplicate reg property\n");
+
+		priv->leds_active |= BIT(reg);
+
+		led->index = reg;
+		led->priv = priv;
+
+		ret = mt6370_init_led_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(&pdev->dev, led, &init_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_rgbled_device_table[] = {
+	{ .compatible = "mediatek,mt6370-indicator" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table);
+
+static struct platform_driver mt6370_rgbled_driver = {
+	.driver = {
+		.name = "mt6370-indicator",
+		.of_match_table = mt6370_rgbled_device_table,
+	},
+	.probe = mt6370_leds_probe,
+};
+module_platform_driver(mt6370_rgbled_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 RGB Led Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

In MediaTek MT6370, there are four channel current-sink RGB LEDs that
support hardware pattern for constant current, PWM, and breath mode.
Isink4 channel can also be used as a CHG_VIN power good indicator.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---

v6
- Remove the 'ko' from mt6370 led Kconfig description.
- Add both authors for Alice and ChiYuan.
- Use pdata to distinguish the code from mt6370/71 to mt6372.
- Instead of 'state' define, use the 'state' enum.
- Fix the typo for 'MT6372_PMW_DUTY'.
- For pwm_duty define, replace with bit macro - 1.
- Refine all the labels from 'out' to 'out_unlock'.
- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
- Revise for the array initialization from {0} to {}.
- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
- Refine the 'comma' usage in struct/enum.
---
 drivers/leds/rgb/Kconfig           |   13 +
 drivers/leds/rgb/Makefile          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
 3 files changed, 1018 insertions(+)
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c

diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig
index 204cf47..d6ad875 100644
--- a/drivers/leds/rgb/Kconfig
+++ b/drivers/leds/rgb/Kconfig
@@ -26,4 +26,17 @@ config LEDS_QCOM_LPG
 
 	  If compiled as a module, the module will be named leds-qcom-lpg.
 
+config LEDS_MT6370_RGB
+	tristate "LED Support for MediaTek MT6370 PMIC"
+	depends on MFD_MT6370
+	select LINEAR_RANGE
+	help
+	  Say Y here to enable support for MT6370_RGB LED device.
+	  In MT6370, there are four channel current-sink LED drivers that
+	  support hardware pattern for constant current, PWM, and breath mode.
+	  Isink4 channel can also be used as a CHG_VIN power good indicator.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-rgb".
+
 endif # LEDS_CLASS_MULTICOLOR
diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile
index 0675bc0..8c01daf 100644
--- a/drivers/leds/rgb/Makefile
+++ b/drivers/leds/rgb/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_LEDS_PWM_MULTICOLOR)	+= leds-pwm-multicolor.o
 obj-$(CONFIG_LEDS_QCOM_LPG)		+= leds-qcom-lpg.o
+obj-$(CONFIG_LEDS_MT6370_RGB)		+= leds-mt6370-rgb.o
diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c
new file mode 100644
index 0000000..bf52989
--- /dev/null
+++ b/drivers/leds/rgb/leds-mt6370-rgb.c
@@ -0,0 +1,1004 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com>
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/linear_range.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/util_macros.h>
+
+enum {
+	MT6370_LED_ISNK1 = 0,
+	MT6370_LED_ISNK2,
+	MT6370_LED_ISNK3,
+	MT6370_LED_ISNK4,
+	MT6370_MAX_LEDS
+};
+
+enum mt6370_led_mode {
+	MT6370_LED_PWM_MODE = 0,
+	MT6370_LED_BREATH_MODE,
+	MT6370_LED_REG_MODE,
+	MT6370_LED_MAX_MODE
+};
+
+enum mt6370_led_field {
+	F_RGB_EN = 0,
+	F_CHGIND_EN,
+	F_LED1_CURR,
+	F_LED2_CURR,
+	F_LED3_CURR,
+	F_LED4_CURR,
+	F_LED1_MODE,
+	F_LED2_MODE,
+	F_LED3_MODE,
+	F_LED4_MODE,
+	F_LED1_DUTY,
+	F_LED2_DUTY,
+	F_LED3_DUTY,
+	F_LED4_DUTY,
+	F_LED1_FREQ,
+	F_LED2_FREQ,
+	F_LED3_FREQ,
+	F_LED4_FREQ,
+	F_MAX_FIELDS
+};
+
+enum mt6370_led_ranges {
+	R_LED123_CURR = 0,
+	R_LED4_CURR,
+	R_LED_TRFON,
+	R_LED_TOFF,
+	R_MAX_RANGES
+};
+
+enum mt6370_pattern {
+	P_LED_TR1 = 0,
+	P_LED_TR2,
+	P_LED_TF1,
+	P_LED_TF2,
+	P_LED_TON,
+	P_LED_TOFF,
+	P_MAX_PATTERNS
+};
+
+enum mt6370_state {
+	STATE_OFF = 0,
+	STATE_KEEP,
+	STATE_ON,
+	STATE_MAX
+};
+
+#define MT6370_REG_DEV_INFO			0x100
+#define MT6370_REG_RGB1_DIM			0x182
+#define MT6370_REG_RGB2_DIM			0x183
+#define MT6370_REG_RGB3_DIM			0x184
+#define MT6370_REG_RGB_EN			0x185
+#define MT6370_REG_RGB1_ISNK			0x186
+#define MT6370_REG_RGB2_ISNK			0x187
+#define MT6370_REG_RGB3_ISNK			0x188
+#define MT6370_REG_RGB1_TR			0x189
+#define MT6370_REG_RGB_CHRIND_DIM		0x192
+#define MT6370_REG_RGB_CHRIND_CTRL		0x193
+#define MT6370_REG_RGB_CHRIND_TR		0x194
+
+#define MT6372_REG_RGB_EN			0x182
+#define MT6372_REG_RGB1_ISNK			0x183
+#define MT6372_REG_RGB2_ISNK			0x184
+#define MT6372_REG_RGB3_ISNK			0x185
+#define MT6372_REG_RGB4_ISNK			0x186
+#define MT6372_REG_RGB1_DIM			0x187
+#define MT6372_REG_RGB2_DIM			0x188
+#define MT6372_REG_RGB3_DIM			0x189
+#define MT6372_REG_RGB4_DIM			0x18A
+#define MT6372_REG_RGB12_FREQ			0x18B
+#define MT6372_REG_RGB34_FREQ			0x18C
+#define MT6372_REG_RGB1_TR			0x18D
+
+#define MT6370_VENID_MASK			GENMASK(7, 4)
+#define MT6370_CHEN_BIT(id)			BIT(MT6370_LED_ISNK4 - id)
+#define MT6370_VIRTUAL_MULTICOLOR		5
+#define MC_CHANNEL_NUM				3
+#define MT6370_PWM_DUTY				(BIT(5) - 1)
+#define MT6372_PWM_DUTY				(BIT(8) - 1)
+
+struct mt6370_led {
+	union {
+		struct led_classdev isink;
+		struct led_classdev_mc mc;
+	};
+	struct mt6370_priv *priv;
+	u32 default_state;
+	u32 index;
+};
+
+struct mt6370_pdata {
+	const unsigned int *tfreq;
+	unsigned int tfreq_len;
+	u8 pwm_duty;
+	u16 reg_rgb1_tr;
+	s16 reg_rgb_chrind_tr;
+};
+
+struct mt6370_priv {
+	/* Per LED access lock */
+	struct mutex lock;
+	struct device *dev;
+	struct regmap *regmap;
+	struct regmap_field *fields[F_MAX_FIELDS];
+	const struct reg_field *reg_fields;
+	const struct linear_range *ranges;
+	struct reg_cfg *reg_cfgs;
+	const struct mt6370_pdata *pdata;
+	unsigned int leds_count;
+	unsigned int leds_active;
+	struct mt6370_led leds[];
+};
+
+static const struct reg_field common_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6370_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7),
+	[F_LED1_CURR]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2),
+	[F_LED2_CURR]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2),
+	[F_LED3_CURR]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2),
+	[F_LED4_CURR]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1),
+	[F_LED1_MODE]	= REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6),
+	[F_LED2_MODE]	= REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6),
+	[F_LED3_MODE]	= REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6),
+	[F_LED4_MODE]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6),
+	[F_LED1_DUTY]	= REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4),
+	[F_LED2_DUTY]	= REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4),
+	[F_LED3_DUTY]	= REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4),
+	[F_LED4_DUTY]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4),
+	[F_LED1_FREQ]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5),
+	[F_LED2_FREQ]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5),
+	[F_LED3_FREQ]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5),
+	[F_LED4_FREQ]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4),
+};
+
+static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 3, 3),
+	[F_LED1_CURR]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3),
+	[F_LED2_CURR]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3),
+	[F_LED3_CURR]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3),
+	[F_LED4_CURR]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3),
+	[F_LED1_MODE]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7),
+	[F_LED2_MODE]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7),
+	[F_LED3_MODE]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7),
+	[F_LED4_MODE]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7),
+	[F_LED1_DUTY]	= REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7),
+	[F_LED2_DUTY]	= REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7),
+	[F_LED3_DUTY]	= REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7),
+	[F_LED4_DUTY]	= REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7),
+	[F_LED1_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7),
+	[F_LED2_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4),
+	[F_LED3_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7),
+	[F_LED4_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4),
+};
+
+/* Current unit: microamp, time unit: millisecond */
+static const struct linear_range common_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 4000, 1, 6, 4000 },
+	[R_LED4_CURR]	= { 2000, 1, 3, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 200 },
+	[R_LED_TOFF]	= { 250, 0, 15, 400 },
+};
+
+static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED4_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 250 },
+	[R_LED_TOFF]	= { 250, 0, 15, 500 },
+};
+
+static const unsigned int common_tfreqs[] = {
+	10000, 5000, 2000, 1000, 500, 200, 5, 1,
+};
+
+static const unsigned int mt6372_tfreqs[] = {
+	8000, 4000, 2000, 1000, 500, 250, 8, 4,
+};
+
+static const struct mt6370_pdata common_pdata = {
+	.tfreq = common_tfreqs,
+	.tfreq_len = ARRAY_SIZE(common_tfreqs),
+	.pwm_duty = MT6370_PWM_DUTY,
+	.reg_rgb1_tr = MT6370_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = MT6370_REG_RGB_CHRIND_TR,
+};
+
+static const struct mt6370_pdata mt6372_pdata = {
+	.tfreq = mt6372_tfreqs,
+	.tfreq_len = ARRAY_SIZE(mt6372_tfreqs),
+	.pwm_duty = MT6372_PWM_DUTY,
+	.reg_rgb1_tr = MT6372_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = -1,
+};
+
+static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no)
+{
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		return F_LED1_CURR;
+	case MT6370_LED_ISNK2:
+		return F_LED2_CURR;
+	case MT6370_LED_ISNK3:
+		return F_LED3_CURR;
+	default:
+		return F_LED4_CURR;
+	}
+}
+
+static int mt6370_set_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_write(priv->fields[sel_field], level);
+}
+
+static int mt6370_get_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int *level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_read(priv->fields[sel_field], level);
+}
+
+static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int divisor, ratio;
+
+	divisor = pdata->pwm_duty;
+	ratio = ton * divisor / (ton + toff);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_DUTY;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_DUTY;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_DUTY;
+		break;
+	default:
+		sel_field = F_LED4_DUTY;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], ratio);
+}
+
+static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int tfreq_len = pdata->tfreq_len;
+	unsigned int tsum, sel;
+
+	tsum = ton + toff;
+
+	if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1])
+		return -EOPNOTSUPP;
+
+	sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_FREQ;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_FREQ;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_FREQ;
+		break;
+	default:
+		sel_field = F_LED4_FREQ;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], sel);
+}
+
+static void mt6370_get_breath_reg_base(struct mt6370_priv *priv,
+				       unsigned int led_no, unsigned int *base)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+
+	if (pdata->reg_rgb_chrind_tr < 0) {
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		return;
+	}
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+	case MT6370_LED_ISNK2:
+	case MT6370_LED_ISNK3:
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		break;
+	default:
+		*base = pdata->reg_rgb_chrind_tr;
+		break;
+	}
+}
+
+static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
+				     struct led_pattern *pattern, u32 len,
+				     u8 *pattern_val, u32 val_len)
+{
+	enum mt6370_led_ranges sel_range;
+	struct led_pattern *curr;
+	unsigned int sel;
+	u8 val[P_MAX_PATTERNS / 2] = {};
+	int i;
+
+	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
+		return -EINVAL;
+
+	/*
+	 * Pattern list
+	 * tr1:	byte 0, b'[7: 4]
+	 * tr2:	byte 0, b'[3: 0]
+	 * tf1:	byte 1, b'[7: 4]
+	 * tf2:	byte 1, b'[3: 0]
+	 * ton:	byte 2, b'[7: 4]
+	 * toff: byte 2, b'[3: 0]
+	 */
+	for (i = 0; i < P_MAX_PATTERNS; i++) {
+		curr = pattern + i;
+
+		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
+
+		linear_range_get_selector_within(priv->ranges + sel_range,
+						 curr->delta_t, &sel);
+
+		val[i / 2] |= sel << (4 * ((i + 1) % 2));
+	}
+
+	memcpy(pattern_val, val, 3);
+
+	return 0;
+}
+
+static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no,
+			       enum mt6370_led_mode mode)
+{
+	enum mt6370_led_field sel_field;
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_MODE;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_MODE;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_MODE;
+		break;
+	default:
+		sel_field = F_LED4_MODE;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], mode);
+}
+
+static int mt6370_mc_brightness_set(struct led_classdev *lcdev,
+				    enum led_brightness level)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	led_mc_calc_color_components(mccdev, level);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		u32 brightness;
+
+		subled = mccdev->subled_info + i;
+		brightness = min(subled->brightness, lcdev->max_brightness);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		if (level == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+
+			ret = mt6370_set_led_mode(priv, subled->channel,
+						  MT6370_LED_REG_MODE);
+			if (ret)
+				goto out_unlock;
+
+			continue;
+		}
+
+		if (brightness == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+			continue;
+		}
+
+		enable |= MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_brightness(priv, subled->channel,
+						brightness);
+		if (ret)
+			goto out_unlock;
+	}
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_blink_set(struct led_classdev *lcdev,
+			       unsigned long *delay_on,
+			       unsigned long *delay_off)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_duty(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_freq(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_PWM_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_pattern_set(struct led_classdev *lcdev,
+			struct led_pattern *pattern, u32 len, int repeat)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int reg_base, enable, disable;
+	u8 params[P_MAX_PATTERNS / 2];
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		mt6370_get_breath_reg_base(priv, subled->channel, &reg_base);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = regmap_raw_write(priv->regmap, reg_base, params,
+				       sizeof(params));
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_BREATH_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing be the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	int i, ret = 0;
+
+	mutex_lock(&led->priv->lock);
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_brightness_set(struct led_classdev *lcdev,
+				      enum led_brightness level)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	if (level == LED_OFF) {
+		enable &= ~MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_mode(priv, led->index,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	} else {
+		enable |= MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_brightness(priv, led->index, level);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	}
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_blink_set(struct led_classdev *lcdev,
+				 unsigned long *delay_on,
+				 unsigned long *delay_off)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_pattern_set(struct led_classdev *lcdev,
+				   struct led_pattern *pattern, u32 len,
+				   int repeat)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int reg_base;
+	u8 params[P_MAX_PATTERNS / 2];
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	mt6370_get_breath_reg_base(priv, led->index, &reg_base);
+
+	ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&led->priv->lock);
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_init_led_properties(struct mt6370_led *led,
+				      struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	struct device *dev = priv->dev;
+	struct led_classdev *lcdev;
+	struct fwnode_handle *child;
+	enum mt6370_led_ranges sel_range;
+	u32 max_uA, max_level;
+	const char * const states[] = { "off", "keep", "on" };
+	const char *stat_str;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		struct mc_subled *sub_led;
+		u32 num_color = 0;
+
+		sub_led = devm_kcalloc(dev, MC_CHANNEL_NUM, sizeof(*sub_led),
+				       GFP_KERNEL);
+		if (!sub_led)
+			return -ENOMEM;
+
+		fwnode_for_each_child_node(init_data->fwnode, child) {
+			u32 reg, color;
+
+			ret = fwnode_property_read_u32(child, "reg", &reg);
+			if (ret || reg > MT6370_LED_ISNK3 ||
+			    priv->leds_active & BIT(reg))
+				return -EINVAL;
+
+			ret = fwnode_property_read_u32(child, "color", &color);
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "led %d, no color specified\n",
+						     led->index);
+
+			priv->leds_active |= BIT(reg);
+			sub_led[num_color].color_index = color;
+			sub_led[num_color].channel = reg;
+			sub_led[num_color].intensity = 0;
+			num_color++;
+		}
+
+		if (num_color < 2)
+			return dev_err_probe(dev, -EINVAL,
+					     "Multicolor must include 2 or more led channel\n");
+
+		led->mc.num_colors = num_color;
+		led->mc.subled_info = sub_led;
+
+		lcdev = &led->mc.led_cdev;
+		lcdev->brightness_set_blocking = mt6370_mc_brightness_set;
+		lcdev->blink_set = mt6370_mc_blink_set;
+		lcdev->pattern_set = mt6370_mc_pattern_set;
+		lcdev->pattern_clear = mt6370_mc_pattern_clear;
+	} else {
+		lcdev = &led->isink;
+		lcdev->brightness_set_blocking = mt6370_isnk_brightness_set;
+		lcdev->blink_set = mt6370_isnk_blink_set;
+		lcdev->pattern_set = mt6370_isnk_pattern_set;
+		lcdev->pattern_clear = mt6370_isnk_pattern_clear;
+	}
+
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
+				       &max_uA);
+	if (ret) {
+		dev_warn(dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		max_uA = 0;
+	}
+
+	if (led->index == MT6370_LED_ISNK4)
+		sel_range = R_LED4_CURR;
+	else
+		sel_range = R_LED123_CURR;
+
+	linear_range_get_selector_within(priv->ranges + sel_range, max_uA,
+					 &max_level);
+
+	lcdev->max_brightness = max_level;
+
+	fwnode_property_read_string(init_data->fwnode, "linux,default-trigger",
+				    &lcdev->default_trigger);
+
+	if (!fwnode_property_read_string(init_data->fwnode, "default-state",
+					 &stat_str)) {
+		ret = match_string(states, ARRAY_SIZE(states), stat_str);
+		if (ret < 0)
+			ret = STATE_OFF;
+
+		led->default_state = ret;
+	}
+
+	return 0;
+}
+
+static int mt6370_isnk_init_default_state(struct mt6370_led *led)
+{
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable, level;
+	int ret;
+
+	ret = mt6370_get_led_brightness(priv, led->index, &level);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_CHEN_BIT(led->index)))
+		level = LED_OFF;
+
+	switch (led->default_state) {
+	case STATE_ON:
+		led->isink.brightness = led->isink.max_brightness;
+		break;
+	case STATE_KEEP:
+		led->isink.brightness = min(level, led->isink.max_brightness);
+		break;
+	default:
+		led->isink.brightness = LED_OFF;
+		break;
+	}
+
+	return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+			       struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		ret = mt6370_mc_brightness_set(&led->mc.led_cdev, LED_OFF);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't set multicolor brightness\n");
+
+		ret = devm_led_classdev_multicolor_register_ext(parent,
+								&led->mc,
+								init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register multicolor\n");
+	} else {
+		if (led->index == MT6370_LED_ISNK4) {
+			ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1);
+			if (ret)
+				return dev_err_probe(parent, ret,
+						     "Failed to set CHRIND to SW\n");
+		}
+
+		ret = mt6370_isnk_init_default_state(led);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Failed to init %d isnk state\n",
+					     led->index);
+
+		ret = devm_led_classdev_register_ext(parent, &led->isink,
+						     init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register isink %d\n",
+					     led->index);
+	}
+
+	return 0;
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	unsigned int devinfo, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, devinfo);
+	if (vid == 0x9 || vid == 0xb) {
+		priv->reg_fields = mt6372_reg_fields;
+		priv->ranges = mt6372_led_ranges;
+		priv->pdata = &mt6372_pdata;
+	} else {
+		/* Common for MT6370/71 */
+		priv->reg_fields = common_reg_fields;
+		priv->ranges = common_led_ranges;
+		priv->pdata = &common_pdata;
+	}
+
+	return 0;
+}
+
+static int mt6370_leds_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+				     "No child node or node count over max led number %zu\n",
+				      count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields,
+					   priv->reg_fields, F_MAX_FIELDS);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate regmap field\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i++;
+		struct led_init_data init_data = { .fwnode = child };
+		u32 reg, color;
+
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse reg property\n");
+
+		if (reg >= MT6370_MAX_LEDS)
+			return dev_err_probe(dev, -EINVAL, "Error reg property number\n");
+
+		ret = fwnode_property_read_u32(child, "color", &color);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse color property\n");
+
+		if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI)
+			reg = MT6370_VIRTUAL_MULTICOLOR;
+
+		if (priv->leds_active & BIT(reg))
+			return dev_err_probe(dev, -EINVAL, "Duplicate reg property\n");
+
+		priv->leds_active |= BIT(reg);
+
+		led->index = reg;
+		led->priv = priv;
+
+		ret = mt6370_init_led_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(&pdev->dev, led, &init_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_rgbled_device_table[] = {
+	{ .compatible = "mediatek,mt6370-indicator" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table);
+
+static struct platform_driver mt6370_rgbled_driver = {
+	.driver = {
+		.name = "mt6370-indicator",
+		.of_match_table = mt6370_rgbled_device_table,
+	},
+	.probe = mt6370_leds_probe,
+};
+module_platform_driver(mt6370_rgbled_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 RGB Led Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiYuan Huang <cy_huang@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual
Flash LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

In MediaTek MT6370, there are four channel current-sink RGB LEDs that
support hardware pattern for constant current, PWM, and breath mode.
Isink4 channel can also be used as a CHG_VIN power good indicator.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---

v6
- Remove the 'ko' from mt6370 led Kconfig description.
- Add both authors for Alice and ChiYuan.
- Use pdata to distinguish the code from mt6370/71 to mt6372.
- Instead of 'state' define, use the 'state' enum.
- Fix the typo for 'MT6372_PMW_DUTY'.
- For pwm_duty define, replace with bit macro - 1.
- Refine all the labels from 'out' to 'out_unlock'.
- Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
- Revise for the array initialization from {0} to {}.
- Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
- Refine the 'comma' usage in struct/enum.
---
 drivers/leds/rgb/Kconfig           |   13 +
 drivers/leds/rgb/Makefile          |    1 +
 drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
 3 files changed, 1018 insertions(+)
 create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c

diff --git a/drivers/leds/rgb/Kconfig b/drivers/leds/rgb/Kconfig
index 204cf47..d6ad875 100644
--- a/drivers/leds/rgb/Kconfig
+++ b/drivers/leds/rgb/Kconfig
@@ -26,4 +26,17 @@ config LEDS_QCOM_LPG
 
 	  If compiled as a module, the module will be named leds-qcom-lpg.
 
+config LEDS_MT6370_RGB
+	tristate "LED Support for MediaTek MT6370 PMIC"
+	depends on MFD_MT6370
+	select LINEAR_RANGE
+	help
+	  Say Y here to enable support for MT6370_RGB LED device.
+	  In MT6370, there are four channel current-sink LED drivers that
+	  support hardware pattern for constant current, PWM, and breath mode.
+	  Isink4 channel can also be used as a CHG_VIN power good indicator.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-rgb".
+
 endif # LEDS_CLASS_MULTICOLOR
diff --git a/drivers/leds/rgb/Makefile b/drivers/leds/rgb/Makefile
index 0675bc0..8c01daf 100644
--- a/drivers/leds/rgb/Makefile
+++ b/drivers/leds/rgb/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_LEDS_PWM_MULTICOLOR)	+= leds-pwm-multicolor.o
 obj-$(CONFIG_LEDS_QCOM_LPG)		+= leds-qcom-lpg.o
+obj-$(CONFIG_LEDS_MT6370_RGB)		+= leds-mt6370-rgb.o
diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c
new file mode 100644
index 0000000..bf52989
--- /dev/null
+++ b/drivers/leds/rgb/leds-mt6370-rgb.c
@@ -0,0 +1,1004 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com>
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
+#include <linux/linear_range.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/util_macros.h>
+
+enum {
+	MT6370_LED_ISNK1 = 0,
+	MT6370_LED_ISNK2,
+	MT6370_LED_ISNK3,
+	MT6370_LED_ISNK4,
+	MT6370_MAX_LEDS
+};
+
+enum mt6370_led_mode {
+	MT6370_LED_PWM_MODE = 0,
+	MT6370_LED_BREATH_MODE,
+	MT6370_LED_REG_MODE,
+	MT6370_LED_MAX_MODE
+};
+
+enum mt6370_led_field {
+	F_RGB_EN = 0,
+	F_CHGIND_EN,
+	F_LED1_CURR,
+	F_LED2_CURR,
+	F_LED3_CURR,
+	F_LED4_CURR,
+	F_LED1_MODE,
+	F_LED2_MODE,
+	F_LED3_MODE,
+	F_LED4_MODE,
+	F_LED1_DUTY,
+	F_LED2_DUTY,
+	F_LED3_DUTY,
+	F_LED4_DUTY,
+	F_LED1_FREQ,
+	F_LED2_FREQ,
+	F_LED3_FREQ,
+	F_LED4_FREQ,
+	F_MAX_FIELDS
+};
+
+enum mt6370_led_ranges {
+	R_LED123_CURR = 0,
+	R_LED4_CURR,
+	R_LED_TRFON,
+	R_LED_TOFF,
+	R_MAX_RANGES
+};
+
+enum mt6370_pattern {
+	P_LED_TR1 = 0,
+	P_LED_TR2,
+	P_LED_TF1,
+	P_LED_TF2,
+	P_LED_TON,
+	P_LED_TOFF,
+	P_MAX_PATTERNS
+};
+
+enum mt6370_state {
+	STATE_OFF = 0,
+	STATE_KEEP,
+	STATE_ON,
+	STATE_MAX
+};
+
+#define MT6370_REG_DEV_INFO			0x100
+#define MT6370_REG_RGB1_DIM			0x182
+#define MT6370_REG_RGB2_DIM			0x183
+#define MT6370_REG_RGB3_DIM			0x184
+#define MT6370_REG_RGB_EN			0x185
+#define MT6370_REG_RGB1_ISNK			0x186
+#define MT6370_REG_RGB2_ISNK			0x187
+#define MT6370_REG_RGB3_ISNK			0x188
+#define MT6370_REG_RGB1_TR			0x189
+#define MT6370_REG_RGB_CHRIND_DIM		0x192
+#define MT6370_REG_RGB_CHRIND_CTRL		0x193
+#define MT6370_REG_RGB_CHRIND_TR		0x194
+
+#define MT6372_REG_RGB_EN			0x182
+#define MT6372_REG_RGB1_ISNK			0x183
+#define MT6372_REG_RGB2_ISNK			0x184
+#define MT6372_REG_RGB3_ISNK			0x185
+#define MT6372_REG_RGB4_ISNK			0x186
+#define MT6372_REG_RGB1_DIM			0x187
+#define MT6372_REG_RGB2_DIM			0x188
+#define MT6372_REG_RGB3_DIM			0x189
+#define MT6372_REG_RGB4_DIM			0x18A
+#define MT6372_REG_RGB12_FREQ			0x18B
+#define MT6372_REG_RGB34_FREQ			0x18C
+#define MT6372_REG_RGB1_TR			0x18D
+
+#define MT6370_VENID_MASK			GENMASK(7, 4)
+#define MT6370_CHEN_BIT(id)			BIT(MT6370_LED_ISNK4 - id)
+#define MT6370_VIRTUAL_MULTICOLOR		5
+#define MC_CHANNEL_NUM				3
+#define MT6370_PWM_DUTY				(BIT(5) - 1)
+#define MT6372_PWM_DUTY				(BIT(8) - 1)
+
+struct mt6370_led {
+	union {
+		struct led_classdev isink;
+		struct led_classdev_mc mc;
+	};
+	struct mt6370_priv *priv;
+	u32 default_state;
+	u32 index;
+};
+
+struct mt6370_pdata {
+	const unsigned int *tfreq;
+	unsigned int tfreq_len;
+	u8 pwm_duty;
+	u16 reg_rgb1_tr;
+	s16 reg_rgb_chrind_tr;
+};
+
+struct mt6370_priv {
+	/* Per LED access lock */
+	struct mutex lock;
+	struct device *dev;
+	struct regmap *regmap;
+	struct regmap_field *fields[F_MAX_FIELDS];
+	const struct reg_field *reg_fields;
+	const struct linear_range *ranges;
+	struct reg_cfg *reg_cfgs;
+	const struct mt6370_pdata *pdata;
+	unsigned int leds_count;
+	unsigned int leds_active;
+	struct mt6370_led leds[];
+};
+
+static const struct reg_field common_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6370_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 7, 7),
+	[F_LED1_CURR]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 0, 2),
+	[F_LED2_CURR]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 0, 2),
+	[F_LED3_CURR]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 0, 2),
+	[F_LED4_CURR]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 0, 1),
+	[F_LED1_MODE]	= REG_FIELD(MT6370_REG_RGB1_DIM, 5, 6),
+	[F_LED2_MODE]	= REG_FIELD(MT6370_REG_RGB2_DIM, 5, 6),
+	[F_LED3_MODE]	= REG_FIELD(MT6370_REG_RGB3_DIM, 5, 6),
+	[F_LED4_MODE]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 5, 6),
+	[F_LED1_DUTY]	= REG_FIELD(MT6370_REG_RGB1_DIM, 0, 4),
+	[F_LED2_DUTY]	= REG_FIELD(MT6370_REG_RGB2_DIM, 0, 4),
+	[F_LED3_DUTY]	= REG_FIELD(MT6370_REG_RGB3_DIM, 0, 4),
+	[F_LED4_DUTY]	= REG_FIELD(MT6370_REG_RGB_CHRIND_DIM, 0, 4),
+	[F_LED1_FREQ]	= REG_FIELD(MT6370_REG_RGB1_ISNK, 3, 5),
+	[F_LED2_FREQ]	= REG_FIELD(MT6370_REG_RGB2_ISNK, 3, 5),
+	[F_LED3_FREQ]	= REG_FIELD(MT6370_REG_RGB3_ISNK, 3, 5),
+	[F_LED4_FREQ]	= REG_FIELD(MT6370_REG_RGB_CHRIND_CTRL, 2, 4),
+};
+
+static const struct reg_field mt6372_reg_fields[F_MAX_FIELDS] = {
+	[F_RGB_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 4, 7),
+	[F_CHGIND_EN]	= REG_FIELD(MT6372_REG_RGB_EN, 3, 3),
+	[F_LED1_CURR]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 0, 3),
+	[F_LED2_CURR]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 0, 3),
+	[F_LED3_CURR]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 0, 3),
+	[F_LED4_CURR]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 0, 3),
+	[F_LED1_MODE]	= REG_FIELD(MT6372_REG_RGB1_ISNK, 6, 7),
+	[F_LED2_MODE]	= REG_FIELD(MT6372_REG_RGB2_ISNK, 6, 7),
+	[F_LED3_MODE]	= REG_FIELD(MT6372_REG_RGB3_ISNK, 6, 7),
+	[F_LED4_MODE]	= REG_FIELD(MT6372_REG_RGB4_ISNK, 6, 7),
+	[F_LED1_DUTY]	= REG_FIELD(MT6372_REG_RGB1_DIM, 0, 7),
+	[F_LED2_DUTY]	= REG_FIELD(MT6372_REG_RGB2_DIM, 0, 7),
+	[F_LED3_DUTY]	= REG_FIELD(MT6372_REG_RGB3_DIM, 0, 7),
+	[F_LED4_DUTY]	= REG_FIELD(MT6372_REG_RGB4_DIM, 0, 7),
+	[F_LED1_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 5, 7),
+	[F_LED2_FREQ]	= REG_FIELD(MT6372_REG_RGB12_FREQ, 2, 4),
+	[F_LED3_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 5, 7),
+	[F_LED4_FREQ]	= REG_FIELD(MT6372_REG_RGB34_FREQ, 2, 4),
+};
+
+/* Current unit: microamp, time unit: millisecond */
+static const struct linear_range common_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 4000, 1, 6, 4000 },
+	[R_LED4_CURR]	= { 2000, 1, 3, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 200 },
+	[R_LED_TOFF]	= { 250, 0, 15, 400 },
+};
+
+static const struct linear_range mt6372_led_ranges[R_MAX_RANGES] = {
+	[R_LED123_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED4_CURR]	= { 2000, 1, 14, 2000 },
+	[R_LED_TRFON]	= { 125, 0, 15, 250 },
+	[R_LED_TOFF]	= { 250, 0, 15, 500 },
+};
+
+static const unsigned int common_tfreqs[] = {
+	10000, 5000, 2000, 1000, 500, 200, 5, 1,
+};
+
+static const unsigned int mt6372_tfreqs[] = {
+	8000, 4000, 2000, 1000, 500, 250, 8, 4,
+};
+
+static const struct mt6370_pdata common_pdata = {
+	.tfreq = common_tfreqs,
+	.tfreq_len = ARRAY_SIZE(common_tfreqs),
+	.pwm_duty = MT6370_PWM_DUTY,
+	.reg_rgb1_tr = MT6370_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = MT6370_REG_RGB_CHRIND_TR,
+};
+
+static const struct mt6370_pdata mt6372_pdata = {
+	.tfreq = mt6372_tfreqs,
+	.tfreq_len = ARRAY_SIZE(mt6372_tfreqs),
+	.pwm_duty = MT6372_PWM_DUTY,
+	.reg_rgb1_tr = MT6372_REG_RGB1_TR,
+	.reg_rgb_chrind_tr = -1,
+};
+
+static enum mt6370_led_field mt6370_get_led_current_field(unsigned int led_no)
+{
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		return F_LED1_CURR;
+	case MT6370_LED_ISNK2:
+		return F_LED2_CURR;
+	case MT6370_LED_ISNK3:
+		return F_LED3_CURR;
+	default:
+		return F_LED4_CURR;
+	}
+}
+
+static int mt6370_set_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_write(priv->fields[sel_field], level);
+}
+
+static int mt6370_get_led_brightness(struct mt6370_priv *priv,
+				     unsigned int led_no, unsigned int *level)
+{
+	enum mt6370_led_field sel_field;
+
+	sel_field = mt6370_get_led_current_field(led_no);
+
+	return regmap_field_read(priv->fields[sel_field], level);
+}
+
+static int mt6370_set_led_duty(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int divisor, ratio;
+
+	divisor = pdata->pwm_duty;
+	ratio = ton * divisor / (ton + toff);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_DUTY;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_DUTY;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_DUTY;
+		break;
+	default:
+		sel_field = F_LED4_DUTY;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], ratio);
+}
+
+static int mt6370_set_led_freq(struct mt6370_priv *priv, unsigned int led_no,
+			       unsigned int ton, unsigned int toff)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+	enum mt6370_led_field sel_field;
+	unsigned int tfreq_len = pdata->tfreq_len;
+	unsigned int tsum, sel;
+
+	tsum = ton + toff;
+
+	if (tsum > pdata->tfreq[0] || tsum < pdata->tfreq[tfreq_len - 1])
+		return -EOPNOTSUPP;
+
+	sel = find_closest_descending(tsum, pdata->tfreq, tfreq_len);
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_FREQ;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_FREQ;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_FREQ;
+		break;
+	default:
+		sel_field = F_LED4_FREQ;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], sel);
+}
+
+static void mt6370_get_breath_reg_base(struct mt6370_priv *priv,
+				       unsigned int led_no, unsigned int *base)
+{
+	const struct mt6370_pdata *pdata = priv->pdata;
+
+	if (pdata->reg_rgb_chrind_tr < 0) {
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		return;
+	}
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+	case MT6370_LED_ISNK2:
+	case MT6370_LED_ISNK3:
+		*base = pdata->reg_rgb1_tr + led_no * 3;
+		break;
+	default:
+		*base = pdata->reg_rgb_chrind_tr;
+		break;
+	}
+}
+
+static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
+				     struct led_pattern *pattern, u32 len,
+				     u8 *pattern_val, u32 val_len)
+{
+	enum mt6370_led_ranges sel_range;
+	struct led_pattern *curr;
+	unsigned int sel;
+	u8 val[P_MAX_PATTERNS / 2] = {};
+	int i;
+
+	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
+		return -EINVAL;
+
+	/*
+	 * Pattern list
+	 * tr1:	byte 0, b'[7: 4]
+	 * tr2:	byte 0, b'[3: 0]
+	 * tf1:	byte 1, b'[7: 4]
+	 * tf2:	byte 1, b'[3: 0]
+	 * ton:	byte 2, b'[7: 4]
+	 * toff: byte 2, b'[3: 0]
+	 */
+	for (i = 0; i < P_MAX_PATTERNS; i++) {
+		curr = pattern + i;
+
+		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
+
+		linear_range_get_selector_within(priv->ranges + sel_range,
+						 curr->delta_t, &sel);
+
+		val[i / 2] |= sel << (4 * ((i + 1) % 2));
+	}
+
+	memcpy(pattern_val, val, 3);
+
+	return 0;
+}
+
+static int mt6370_set_led_mode(struct mt6370_priv *priv, unsigned int led_no,
+			       enum mt6370_led_mode mode)
+{
+	enum mt6370_led_field sel_field;
+
+	switch (led_no) {
+	case MT6370_LED_ISNK1:
+		sel_field = F_LED1_MODE;
+		break;
+	case MT6370_LED_ISNK2:
+		sel_field = F_LED2_MODE;
+		break;
+	case MT6370_LED_ISNK3:
+		sel_field = F_LED3_MODE;
+		break;
+	default:
+		sel_field = F_LED4_MODE;
+		break;
+	}
+
+	return regmap_field_write(priv->fields[sel_field], mode);
+}
+
+static int mt6370_mc_brightness_set(struct led_classdev *lcdev,
+				    enum led_brightness level)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	led_mc_calc_color_components(mccdev, level);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		u32 brightness;
+
+		subled = mccdev->subled_info + i;
+		brightness = min(subled->brightness, lcdev->max_brightness);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		if (level == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+
+			ret = mt6370_set_led_mode(priv, subled->channel,
+						  MT6370_LED_REG_MODE);
+			if (ret)
+				goto out_unlock;
+
+			continue;
+		}
+
+		if (brightness == LED_OFF) {
+			enable &= ~MT6370_CHEN_BIT(subled->channel);
+			continue;
+		}
+
+		enable |= MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_brightness(priv, subled->channel,
+						brightness);
+		if (ret)
+			goto out_unlock;
+	}
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_blink_set(struct led_classdev *lcdev,
+			       unsigned long *delay_on,
+			       unsigned long *delay_off)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int enable, disable;
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = mt6370_set_led_duty(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_freq(priv, subled->channel, *delay_on,
+					  *delay_off);
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_PWM_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_mc_pattern_set(struct led_classdev *lcdev,
+			struct led_pattern *pattern, u32 len, int repeat)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	unsigned int reg_base, enable, disable;
+	u8 params[P_MAX_PATTERNS / 2];
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	disable = enable;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		mt6370_get_breath_reg_base(priv, subled->channel, &reg_base);
+		disable &= ~MT6370_CHEN_BIT(subled->channel);
+
+		ret = regmap_raw_write(priv->regmap, reg_base, params,
+				       sizeof(params));
+		if (ret)
+			goto out_unlock;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_BREATH_MODE);
+		if (ret)
+			goto out_unlock;
+	}
+
+	/* Toggle to make pattern timing be the same */
+	ret = regmap_field_write(priv->fields[F_RGB_EN], disable);
+	if (ret)
+		goto out_unlock;
+
+	ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
+	struct mt6370_priv *priv = led->priv;
+	struct mc_subled *subled;
+	int i, ret = 0;
+
+	mutex_lock(&led->priv->lock);
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		subled = mccdev->subled_info + i;
+
+		ret = mt6370_set_led_mode(priv, subled->channel,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_brightness_set(struct led_classdev *lcdev,
+				      enum led_brightness level)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		goto out_unlock;
+
+	if (level == LED_OFF) {
+		enable &= ~MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_mode(priv, led->index,
+					  MT6370_LED_REG_MODE);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	} else {
+		enable |= MT6370_CHEN_BIT(led->index);
+
+		ret = mt6370_set_led_brightness(priv, led->index, level);
+		if (ret)
+			goto out_unlock;
+
+		ret = regmap_field_write(priv->fields[F_RGB_EN], enable);
+	}
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_blink_set(struct led_classdev *lcdev,
+				 unsigned long *delay_on,
+				 unsigned long *delay_off)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	if (!*delay_on && !*delay_off)
+		*delay_on = *delay_off = 500;
+
+	ret = mt6370_set_led_duty(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_freq(priv, led->index, *delay_on, *delay_off);
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_PWM_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_isnk_pattern_set(struct led_classdev *lcdev,
+				   struct led_pattern *pattern, u32 len,
+				   int repeat)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	unsigned int reg_base;
+	u8 params[P_MAX_PATTERNS / 2];
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = mt6370_gen_breath_pattern(priv, pattern, len, params,
+					sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	mt6370_get_breath_reg_base(priv, led->index, &reg_base);
+
+	ret = regmap_raw_write(priv->regmap, reg_base, params, sizeof(params));
+	if (ret)
+		goto out_unlock;
+
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_BREATH_MODE);
+
+out_unlock:
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static inline int mt6370_isnk_pattern_clear(struct led_classdev *lcdev)
+{
+	struct mt6370_led *led = container_of(lcdev, struct mt6370_led, isink);
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&led->priv->lock);
+	ret = mt6370_set_led_mode(priv, led->index, MT6370_LED_REG_MODE);
+	mutex_unlock(&led->priv->lock);
+
+	return ret;
+}
+
+static int mt6370_init_led_properties(struct mt6370_led *led,
+				      struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	struct device *dev = priv->dev;
+	struct led_classdev *lcdev;
+	struct fwnode_handle *child;
+	enum mt6370_led_ranges sel_range;
+	u32 max_uA, max_level;
+	const char * const states[] = { "off", "keep", "on" };
+	const char *stat_str;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		struct mc_subled *sub_led;
+		u32 num_color = 0;
+
+		sub_led = devm_kcalloc(dev, MC_CHANNEL_NUM, sizeof(*sub_led),
+				       GFP_KERNEL);
+		if (!sub_led)
+			return -ENOMEM;
+
+		fwnode_for_each_child_node(init_data->fwnode, child) {
+			u32 reg, color;
+
+			ret = fwnode_property_read_u32(child, "reg", &reg);
+			if (ret || reg > MT6370_LED_ISNK3 ||
+			    priv->leds_active & BIT(reg))
+				return -EINVAL;
+
+			ret = fwnode_property_read_u32(child, "color", &color);
+			if (ret)
+				return dev_err_probe(dev, ret,
+						     "led %d, no color specified\n",
+						     led->index);
+
+			priv->leds_active |= BIT(reg);
+			sub_led[num_color].color_index = color;
+			sub_led[num_color].channel = reg;
+			sub_led[num_color].intensity = 0;
+			num_color++;
+		}
+
+		if (num_color < 2)
+			return dev_err_probe(dev, -EINVAL,
+					     "Multicolor must include 2 or more led channel\n");
+
+		led->mc.num_colors = num_color;
+		led->mc.subled_info = sub_led;
+
+		lcdev = &led->mc.led_cdev;
+		lcdev->brightness_set_blocking = mt6370_mc_brightness_set;
+		lcdev->blink_set = mt6370_mc_blink_set;
+		lcdev->pattern_set = mt6370_mc_pattern_set;
+		lcdev->pattern_clear = mt6370_mc_pattern_clear;
+	} else {
+		lcdev = &led->isink;
+		lcdev->brightness_set_blocking = mt6370_isnk_brightness_set;
+		lcdev->blink_set = mt6370_isnk_blink_set;
+		lcdev->pattern_set = mt6370_isnk_pattern_set;
+		lcdev->pattern_clear = mt6370_isnk_pattern_clear;
+	}
+
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
+				       &max_uA);
+	if (ret) {
+		dev_warn(dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		max_uA = 0;
+	}
+
+	if (led->index == MT6370_LED_ISNK4)
+		sel_range = R_LED4_CURR;
+	else
+		sel_range = R_LED123_CURR;
+
+	linear_range_get_selector_within(priv->ranges + sel_range, max_uA,
+					 &max_level);
+
+	lcdev->max_brightness = max_level;
+
+	fwnode_property_read_string(init_data->fwnode, "linux,default-trigger",
+				    &lcdev->default_trigger);
+
+	if (!fwnode_property_read_string(init_data->fwnode, "default-state",
+					 &stat_str)) {
+		ret = match_string(states, ARRAY_SIZE(states), stat_str);
+		if (ret < 0)
+			ret = STATE_OFF;
+
+		led->default_state = ret;
+	}
+
+	return 0;
+}
+
+static int mt6370_isnk_init_default_state(struct mt6370_led *led)
+{
+	struct mt6370_priv *priv = led->priv;
+	unsigned int enable, level;
+	int ret;
+
+	ret = mt6370_get_led_brightness(priv, led->index, &level);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_CHEN_BIT(led->index)))
+		level = LED_OFF;
+
+	switch (led->default_state) {
+	case STATE_ON:
+		led->isink.brightness = led->isink.max_brightness;
+		break;
+	case STATE_KEEP:
+		led->isink.brightness = min(level, led->isink.max_brightness);
+		break;
+	default:
+		led->isink.brightness = LED_OFF;
+		break;
+	}
+
+	return mt6370_isnk_brightness_set(&led->isink, led->isink.brightness);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+			       struct led_init_data *init_data)
+{
+	struct mt6370_priv *priv = led->priv;
+	int ret;
+
+	if (led->index == MT6370_VIRTUAL_MULTICOLOR) {
+		ret = mt6370_mc_brightness_set(&led->mc.led_cdev, LED_OFF);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't set multicolor brightness\n");
+
+		ret = devm_led_classdev_multicolor_register_ext(parent,
+								&led->mc,
+								init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register multicolor\n");
+	} else {
+		if (led->index == MT6370_LED_ISNK4) {
+			ret = regmap_field_write(priv->fields[F_CHGIND_EN], 1);
+			if (ret)
+				return dev_err_probe(parent, ret,
+						     "Failed to set CHRIND to SW\n");
+		}
+
+		ret = mt6370_isnk_init_default_state(led);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Failed to init %d isnk state\n",
+					     led->index);
+
+		ret = devm_led_classdev_register_ext(parent, &led->isink,
+						     init_data);
+		if (ret)
+			return dev_err_probe(parent, ret,
+					     "Couldn't register isink %d\n",
+					     led->index);
+	}
+
+	return 0;
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	unsigned int devinfo, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &devinfo);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, devinfo);
+	if (vid == 0x9 || vid == 0xb) {
+		priv->reg_fields = mt6372_reg_fields;
+		priv->ranges = mt6372_led_ranges;
+		priv->pdata = &mt6372_pdata;
+	} else {
+		/* Common for MT6370/71 */
+		priv->reg_fields = common_reg_fields;
+		priv->ranges = common_led_ranges;
+		priv->pdata = &common_pdata;
+	}
+
+	return 0;
+}
+
+static int mt6370_leds_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+				     "No child node or node count over max led number %zu\n",
+				      count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	ret = devm_regmap_field_bulk_alloc(dev, priv->regmap, priv->fields,
+					   priv->reg_fields, F_MAX_FIELDS);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to allocate regmap field\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i++;
+		struct led_init_data init_data = { .fwnode = child };
+		u32 reg, color;
+
+		ret = fwnode_property_read_u32(child, "reg", &reg);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse reg property\n");
+
+		if (reg >= MT6370_MAX_LEDS)
+			return dev_err_probe(dev, -EINVAL, "Error reg property number\n");
+
+		ret = fwnode_property_read_u32(child, "color", &color);
+		if (ret)
+			return dev_err_probe(dev, ret, "Failed to parse color property\n");
+
+		if (color == LED_COLOR_ID_RGB || color == LED_COLOR_ID_MULTI)
+			reg = MT6370_VIRTUAL_MULTICOLOR;
+
+		if (priv->leds_active & BIT(reg))
+			return dev_err_probe(dev, -EINVAL, "Duplicate reg property\n");
+
+		priv->leds_active |= BIT(reg);
+
+		led->index = reg;
+		led->priv = priv;
+
+		ret = mt6370_init_led_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(&pdev->dev, led, &init_data);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_rgbled_device_table[] = {
+	{ .compatible = "mediatek,mt6370-indicator" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_rgbled_device_table);
+
+static struct platform_driver mt6370_rgbled_driver = {
+	.driver = {
+		.name = "mt6370-indicator",
+		.of_match_table = mt6370_rgbled_device_table,
+	},
+	.probe = mt6370_leds_probe,
+};
+module_platform_driver(mt6370_rgbled_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 RGB Led Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: Alice Chen <alice_chen@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
Add the support of MT6370 FLASH LED.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
---

v6
- Use 'GENMASK' instead of 'BIT'.
- Use dev_err_probe to decrease LOC.
- Use 'dev' variable to make probe function more clean.
- Refine the return of _mt6370_flash_brightness_set function.
- Refine the descriptions.
- Use mt6370_clamp() instead of clamp_align().
- Use device resource managed API for v4l2 flash_release.
---
 drivers/leds/flash/Kconfig             |  12 +
 drivers/leds/flash/Makefile            |   1 +
 drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
 3 files changed, 646 insertions(+)
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c

diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index d3eb689..d5761ed 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -90,4 +90,16 @@ config LEDS_SGM3140
 	  This option enables support for the SGM3140 500mA Buck/Boost Charge
 	  Pump LED Driver.
 
+config LEDS_MT6370_FLASHLIGHT
+	tristate "Flash LED Support for MediaTek MT6370 PMIC"
+	depends on LEDS_CLASS
+	depends on MFD_MT6370
+	help
+	  Support 2 channels and torch/strobe mode.
+	  Say Y here to enable support for
+	  MT6370_FLASH_LED device.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-flash".
+
 endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
index 0acbddc..4c4c171 100644
--- a/drivers/leds/flash/Makefile
+++ b/drivers/leds/flash/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
 obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
 obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
 obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
+obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
new file mode 100644
index 0000000..fe439ee
--- /dev/null
+++ b/drivers/leds/flash/leds-mt6370-flash.c
@@ -0,0 +1,633 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <media/v4l2-flash-led-class.h>
+
+enum {
+	MT6370_LED_FLASH1,
+	MT6370_LED_FLASH2,
+	MT6370_MAX_LEDS
+};
+
+/* Virtual definition for multicolor */
+
+#define MT6370_REG_FLEDEN		0x17E
+#define MT6370_REG_STRBTO		0x173
+#define MT6370_REG_CHGSTAT2		0x1D1
+#define MT6370_REG_FLEDSTAT1		0x1D9
+#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)
+#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
+#define MT6370_ITORCH_MASK		GENMASK(4, 0)
+#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
+#define MT6370_STRBTO_MASK		GENMASK(6, 0)
+#define MT6370_TORCHEN_MASK		BIT(3)
+#define MT6370_STROBEN_MASK		BIT(2)
+#define MT6370_FLCSEN_MASK(_id)		BIT(MT6370_LED_FLASH2 - _id)
+#define MT6370_FLCSEN_MASK_ALL		GENMASK(1, 0)
+#define MT6370_FLEDCHGVINOVP_MASK	BIT(3)
+#define MT6370_FLED1STRBTO_MASK		BIT(11)
+#define MT6370_FLED2STRBTO_MASK		BIT(10)
+#define MT6370_FLED1STRB_MASK		BIT(9)
+#define MT6370_FLED2STRB_MASK		BIT(8)
+#define MT6370_FLED1SHORT_MASK		BIT(7)
+#define MT6370_FLED2SHORT_MASK		BIT(6)
+#define MT6370_FLEDLVF_MASK		BIT(3)
+
+#define MT6370_LED_JOINT		2
+#define MT6370_RANGE_FLED_REG		4
+#define MT6370_ITORCH_MIN_UA		25000
+#define MT6370_ITORCH_STEP_UA		12500
+#define MT6370_ITORCH_MAX_UA		400000
+#define MT6370_ITORCH_DOUBLE_MAX_UA	800000
+#define MT6370_ISTRB_MIN_UA		50000
+#define MT6370_ISTRB_STEP_UA		12500
+#define MT6370_ISTRB_MAX_UA		1500000
+#define MT6370_ISTRB_DOUBLE_MAX_UA	3000000
+#define MT6370_STRBTO_MIN_US		64000
+#define MT6370_STRBTO_STEP_US		32000
+#define MT6370_STRBTO_MAX_US		2432000
+
+#define STATE_OFF			0
+#define STATE_KEEP			1
+#define STATE_ON			2
+
+#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member)
+
+struct mt6370_led {
+	struct led_classdev_flash flash;
+	struct v4l2_flash *v4l2_flash;
+	struct mt6370_priv *priv;
+	u32 led_no;
+	u32 default_state;
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	unsigned int fled_strobe_used;
+	unsigned int fled_torch_used;
+	unsigned int leds_active;
+	unsigned int leds_count;
+	struct mt6370_led leds[];
+};
+
+static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
+				       enum led_brightness level)
+{
+	struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
+	struct mt6370_priv *priv = led->priv;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
+	u32 val = level ? led_enable_mask : 0;
+	u32 prev = priv->fled_torch_used, curr;
+	int ret, i;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid strobe is currently used.
+	 */
+	if (priv->fled_strobe_used) {
+		dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
+			 priv->fled_strobe_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (level)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_TORCHEN_MASK;
+
+	if (level) {
+		level -= 1;
+		if (led->led_no == MT6370_LED_JOINT) {
+			int flevel[MT6370_MAX_LEDS];
+
+			flevel[0] = level / 2;
+			flevel[1] = level - flevel[0];
+			for (i = 0; i < MT6370_MAX_LEDS; i++) {
+				ret = regmap_update_bits(priv->regmap,
+						MT6370_REG_FLEDITOR(i),
+						MT6370_ITORCH_MASK, flevel[i]);
+				if (ret)
+					goto unlock;
+			}
+		} else {
+			ret = regmap_update_bits(priv->regmap,
+					MT6370_REG_FLEDITOR(led->led_no),
+					MT6370_ITORCH_MASK, level);
+			if (ret)
+				goto unlock;
+		}
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
+				 enable_mask, val);
+	if (ret)
+		goto unlock;
+
+	priv->fled_torch_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+				       u32 brightness)
+{
+	/*
+	 * Due to the current spike when turning on flash,
+	 * let brightness be kept by the framework.
+	 * This empty function is used to
+	 * prevent led_classdev_flash register ops check failure.
+	 */
+	return 0;
+}
+
+static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+					u32 brightness)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 val = (brightness - s->min) / s->step;
+	int ret, i;
+
+	if (led->led_no == MT6370_LED_JOINT) {
+		int flevel[MT6370_MAX_LEDS];
+
+		flevel[0] = val / 2;
+		flevel[1] = val - flevel[0];
+		for (i = 0; i < MT6370_MAX_LEDS; i++) {
+			ret = regmap_update_bits(priv->regmap,
+						 MT6370_REG_FLEDISTRB(i),
+						 MT6370_ISTROBE_MASK, flevel[i]);
+			if (ret)
+				return ret;
+		}
+	} else {
+		return regmap_update_bits(priv->regmap,
+					  MT6370_REG_FLEDISTRB(led->led_no),
+					  MT6370_ISTROBE_MASK, val);
+	}
+
+	return 0;
+}
+
+static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_classdev *lcdev = &fl_cdev->led_cdev;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask;
+	u32 val = state ? led_enable_mask : 0;
+	u32 prev = priv->fled_strobe_used, curr;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid torch is currently used
+	 */
+	if (priv->fled_torch_used) {
+		dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n",
+				      priv->fled_torch_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (state)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_STROBEN_MASK;
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask,
+				 val);
+	if (ret) {
+		dev_err(lcdev->dev, "[%d] control current source %d fail\n",
+				     led->led_no, state);
+		goto unlock;
+	}
+
+	/*
+	 * If the flash needs to be on,
+	 * config the flash current ramping up to the setting value.
+	 * Else, always recover back to the minimum one.
+	 */
+	ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min);
+	if (ret)
+		goto unlock;
+
+	/*
+	 * For the flash to turn on/off, need to wait HW ramping up/down time
+	 * 5ms/500us to prevent the unexpected problem.
+	 */
+	if (!prev && curr)
+		usleep_range(5000, 6000);
+	else if (prev && !curr)
+		udelay(500);
+
+	priv->fled_strobe_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+
+	mutex_lock(&priv->lock);
+	*state = !!(priv->fled_strobe_used & BIT(led->led_no));
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->timeout;
+	u32 val = (timeout - s->min) / s->step;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO,
+				 MT6370_STRBTO_MASK, val);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	u16 fled_stat;
+	unsigned int chg_stat, strobe_timeout_mask, fled_short_mask;
+	u32 rfault = 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat);
+	if (ret)
+		goto unlock;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat,
+			      sizeof(fled_stat));
+	if (ret)
+		goto unlock;
+
+	switch (led->led_no) {
+	case MT6370_LED_FLASH1:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK;
+		break;
+
+	case MT6370_LED_FLASH2:
+		strobe_timeout_mask = MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED2SHORT_MASK;
+		break;
+
+	case MT6370_LED_JOINT:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK |
+				      MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK |
+				  MT6370_FLED2SHORT_MASK;
+	}
+
+	if (chg_stat & MT6370_FLEDCHGVINOVP_MASK)
+		rfault |= LED_FAULT_INPUT_VOLTAGE;
+
+	if (fled_stat & strobe_timeout_mask)
+		rfault |= LED_FAULT_TIMEOUT;
+
+	if (fled_stat & fled_short_mask)
+		rfault |= LED_FAULT_SHORT_CIRCUIT;
+
+	if (fled_stat & MT6370_FLEDLVF_MASK)
+		rfault |= LED_FAULT_UNDER_VOLTAGE;
+
+	*fault = rfault;
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct led_flash_ops mt6370_flash_ops = {
+	.flash_brightness_set = mt6370_flash_brightness_set,
+	.strobe_set = mt6370_strobe_set,
+	.strobe_get = mt6370_strobe_get,
+	.timeout_set = mt6370_timeout_set,
+	.fault_get = mt6370_fault_get,
+};
+
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
+					    bool enable)
+{
+	struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
+	struct mt6370_led *led = to_mt6370_led(flash, flash);
+	struct mt6370_priv *priv = led->priv;
+	u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL :
+		   MT6370_FLCSEN_MASK(led->led_no);
+	u32 val = enable ? mask : 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val);
+	if (ret)
+		goto unlock;
+
+	if (enable)
+		priv->fled_strobe_used |= BIT(led->led_no);
+	else
+		priv->fled_strobe_used &= ~BIT(led->led_no);
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+	.external_strobe_set = mt6370_flash_external_strobe_set,
+};
+
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+	struct led_classdev *lcdev;
+	struct led_flash_setting *s = &config->intensity;
+
+	lcdev = &led->flash.led_cdev;
+
+	s->min = MT6370_ITORCH_MIN_UA;
+	s->step = MT6370_ITORCH_STEP_UA;
+	s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step;
+
+	config->has_external_strobe = 1;
+	strscpy(config->dev_name, lcdev->dev->kobj.name,
+		sizeof(config->dev_name));
+
+	config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT |
+			       LED_FAULT_INPUT_VOLTAGE |
+			       LED_FAULT_UNDER_VOLTAGE;
+}
+#else
+static const struct v4l2_flash_ops v4l2_flash_ops;
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+}
+#endif
+
+static void mt6370_v4l2_flash_release(void *v4l2_flash)
+{
+	v4l2_flash_release(v4l2_flash);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+				struct led_init_data *init_data)
+{
+	struct v4l2_flash_config v4l2_config = {0};
+	int ret;
+
+	ret = devm_led_classdev_flash_register_ext(parent, &led->flash,
+						   init_data);
+	if (ret)
+		return dev_err_probe(parent, ret,
+				     "Couldn't register flash %d\n", led->led_no);
+
+	mt6370_init_v4l2_flash_config(led, &v4l2_config);
+	led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode,
+					  &led->flash, &v4l2_flash_ops,
+					  &v4l2_config);
+	if (IS_ERR(led->v4l2_flash))
+		return dev_err_probe(parent, PTR_ERR(led->v4l2_flash),
+				     "Failed to register %d v4l2 sd\n", led->led_no);
+
+	return devm_add_action_or_reset(parent, mt6370_v4l2_flash_release,
+					led->v4l2_flash);
+}
+
+static u32 mt6370_clamp(u32 val, u32 min, u32 max, u32 step)
+{
+	u32 retval;
+
+	retval = clamp_val(val, min, max);
+	if (step > 1)
+		retval = rounddown(retval - min, step) + min;
+
+	return retval;
+}
+
+static int mt6370_init_flash_properties(struct mt6370_led *led,
+					struct led_init_data *init_data)
+{
+	struct led_classdev_flash *flash = &led->flash;
+	struct led_classdev *lcdev = &flash->led_cdev;
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s;
+	u32 sources[MT6370_MAX_LEDS];
+	u32 max_uA, val;
+	int i, ret, num;
+
+	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
+	if (num < 1 || num > MT6370_MAX_LEDS)
+		return dev_err_probe(priv->dev, -EINVAL,
+				     "Not specified or wrong number of led-sources\n");
+
+	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num; i++) {
+		if (sources[i] >= MT6370_MAX_LEDS)
+			return -EINVAL;
+		if (priv->leds_active & BIT(sources[i]))
+			return -EINVAL;
+		priv->leds_active |= BIT(sources[i]);
+
+	}
+	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
+		       sources[0];
+
+	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		val = MT6370_ITORCH_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
+				  MT6370_ITORCH_STEP_UA);
+	}
+
+	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
+				MT6370_ITORCH_STEP_UA + 1;
+	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
+	lcdev->flags |= LED_DEV_CAP_FLASH;
+
+	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+		   "Not specified flash-max-microamp, config to the minimum\n");
+		val = MT6370_ISTRB_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
+				  MT6370_ISTRB_STEP_UA);
+	}
+
+	s = &flash->brightness;
+	s->min = MT6370_ISTRB_MIN_UA;
+	s->step = MT6370_ISTRB_STEP_UA;
+	s->val = s->max = val;
+
+	/*
+	 * Always configure as min level when off to
+	 * prevent flash current spike
+	 */
+	ret = _mt6370_flash_brightness_set(flash, s->min);
+	if (ret)
+		return ret;
+
+	ret = fwnode_property_read_u32(init_data->fwnode,
+				       "flash-max-timeout-us", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified flash-max-timeout-us, config to the minimum\n");
+		val = MT6370_STRBTO_MIN_US;
+	} else {
+		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
+				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
+	}
+
+	s = &flash->timeout;
+	s->min = MT6370_STRBTO_MIN_US;
+	s->step = MT6370_STRBTO_STEP_US;
+	s->val = s->max = val;
+
+	flash->ops = &mt6370_flash_ops;
+
+	return 0;
+}
+
+static int mt6370_init_common_properties(struct mt6370_led *led,
+					 struct led_init_data *init_data)
+{
+	const char * const states[] = { "off", "keep", "on" };
+	const char *str = states[STATE_OFF];
+	int ret;
+
+	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
+	ret = match_string(states, ARRAY_SIZE(states), str);
+	if (ret >= 0)
+		led->default_state = ret;
+
+	return 0;
+}
+
+static int mt6370_led_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+		       "No child node or node count over max led number %zu\n", count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i;
+		struct led_init_data init_data = { .fwnode = child, };
+
+		led->priv = priv;
+		ret = mt6370_init_common_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_init_flash_properties(led, &init_data);
+
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(dev, led, &init_data);
+		if (ret)
+			return ret;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_led_of_id[] = {
+	{ .compatible = "mediatek,mt6370-flashlight" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_led_of_id);
+
+static struct platform_driver mt6370_led_driver = {
+	.driver = {
+		.name = "mt6370-flashlight",
+		.of_match_table = mt6370_led_of_id,
+	},
+	.probe = mt6370_led_probe,
+};
+module_platform_driver(mt6370_led_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_DESCRIPTION("MT6370 FLASH LED Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: Alice Chen <alice_chen@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
Add the support of MT6370 FLASH LED.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
---

v6
- Use 'GENMASK' instead of 'BIT'.
- Use dev_err_probe to decrease LOC.
- Use 'dev' variable to make probe function more clean.
- Refine the return of _mt6370_flash_brightness_set function.
- Refine the descriptions.
- Use mt6370_clamp() instead of clamp_align().
- Use device resource managed API for v4l2 flash_release.
---
 drivers/leds/flash/Kconfig             |  12 +
 drivers/leds/flash/Makefile            |   1 +
 drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
 3 files changed, 646 insertions(+)
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c

diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index d3eb689..d5761ed 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -90,4 +90,16 @@ config LEDS_SGM3140
 	  This option enables support for the SGM3140 500mA Buck/Boost Charge
 	  Pump LED Driver.
 
+config LEDS_MT6370_FLASHLIGHT
+	tristate "Flash LED Support for MediaTek MT6370 PMIC"
+	depends on LEDS_CLASS
+	depends on MFD_MT6370
+	help
+	  Support 2 channels and torch/strobe mode.
+	  Say Y here to enable support for
+	  MT6370_FLASH_LED device.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-flash".
+
 endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
index 0acbddc..4c4c171 100644
--- a/drivers/leds/flash/Makefile
+++ b/drivers/leds/flash/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
 obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
 obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
 obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
+obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
new file mode 100644
index 0000000..fe439ee
--- /dev/null
+++ b/drivers/leds/flash/leds-mt6370-flash.c
@@ -0,0 +1,633 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <media/v4l2-flash-led-class.h>
+
+enum {
+	MT6370_LED_FLASH1,
+	MT6370_LED_FLASH2,
+	MT6370_MAX_LEDS
+};
+
+/* Virtual definition for multicolor */
+
+#define MT6370_REG_FLEDEN		0x17E
+#define MT6370_REG_STRBTO		0x173
+#define MT6370_REG_CHGSTAT2		0x1D1
+#define MT6370_REG_FLEDSTAT1		0x1D9
+#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)
+#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
+#define MT6370_ITORCH_MASK		GENMASK(4, 0)
+#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
+#define MT6370_STRBTO_MASK		GENMASK(6, 0)
+#define MT6370_TORCHEN_MASK		BIT(3)
+#define MT6370_STROBEN_MASK		BIT(2)
+#define MT6370_FLCSEN_MASK(_id)		BIT(MT6370_LED_FLASH2 - _id)
+#define MT6370_FLCSEN_MASK_ALL		GENMASK(1, 0)
+#define MT6370_FLEDCHGVINOVP_MASK	BIT(3)
+#define MT6370_FLED1STRBTO_MASK		BIT(11)
+#define MT6370_FLED2STRBTO_MASK		BIT(10)
+#define MT6370_FLED1STRB_MASK		BIT(9)
+#define MT6370_FLED2STRB_MASK		BIT(8)
+#define MT6370_FLED1SHORT_MASK		BIT(7)
+#define MT6370_FLED2SHORT_MASK		BIT(6)
+#define MT6370_FLEDLVF_MASK		BIT(3)
+
+#define MT6370_LED_JOINT		2
+#define MT6370_RANGE_FLED_REG		4
+#define MT6370_ITORCH_MIN_UA		25000
+#define MT6370_ITORCH_STEP_UA		12500
+#define MT6370_ITORCH_MAX_UA		400000
+#define MT6370_ITORCH_DOUBLE_MAX_UA	800000
+#define MT6370_ISTRB_MIN_UA		50000
+#define MT6370_ISTRB_STEP_UA		12500
+#define MT6370_ISTRB_MAX_UA		1500000
+#define MT6370_ISTRB_DOUBLE_MAX_UA	3000000
+#define MT6370_STRBTO_MIN_US		64000
+#define MT6370_STRBTO_STEP_US		32000
+#define MT6370_STRBTO_MAX_US		2432000
+
+#define STATE_OFF			0
+#define STATE_KEEP			1
+#define STATE_ON			2
+
+#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member)
+
+struct mt6370_led {
+	struct led_classdev_flash flash;
+	struct v4l2_flash *v4l2_flash;
+	struct mt6370_priv *priv;
+	u32 led_no;
+	u32 default_state;
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	unsigned int fled_strobe_used;
+	unsigned int fled_torch_used;
+	unsigned int leds_active;
+	unsigned int leds_count;
+	struct mt6370_led leds[];
+};
+
+static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
+				       enum led_brightness level)
+{
+	struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
+	struct mt6370_priv *priv = led->priv;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
+	u32 val = level ? led_enable_mask : 0;
+	u32 prev = priv->fled_torch_used, curr;
+	int ret, i;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid strobe is currently used.
+	 */
+	if (priv->fled_strobe_used) {
+		dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
+			 priv->fled_strobe_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (level)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_TORCHEN_MASK;
+
+	if (level) {
+		level -= 1;
+		if (led->led_no == MT6370_LED_JOINT) {
+			int flevel[MT6370_MAX_LEDS];
+
+			flevel[0] = level / 2;
+			flevel[1] = level - flevel[0];
+			for (i = 0; i < MT6370_MAX_LEDS; i++) {
+				ret = regmap_update_bits(priv->regmap,
+						MT6370_REG_FLEDITOR(i),
+						MT6370_ITORCH_MASK, flevel[i]);
+				if (ret)
+					goto unlock;
+			}
+		} else {
+			ret = regmap_update_bits(priv->regmap,
+					MT6370_REG_FLEDITOR(led->led_no),
+					MT6370_ITORCH_MASK, level);
+			if (ret)
+				goto unlock;
+		}
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
+				 enable_mask, val);
+	if (ret)
+		goto unlock;
+
+	priv->fled_torch_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+				       u32 brightness)
+{
+	/*
+	 * Due to the current spike when turning on flash,
+	 * let brightness be kept by the framework.
+	 * This empty function is used to
+	 * prevent led_classdev_flash register ops check failure.
+	 */
+	return 0;
+}
+
+static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+					u32 brightness)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 val = (brightness - s->min) / s->step;
+	int ret, i;
+
+	if (led->led_no == MT6370_LED_JOINT) {
+		int flevel[MT6370_MAX_LEDS];
+
+		flevel[0] = val / 2;
+		flevel[1] = val - flevel[0];
+		for (i = 0; i < MT6370_MAX_LEDS; i++) {
+			ret = regmap_update_bits(priv->regmap,
+						 MT6370_REG_FLEDISTRB(i),
+						 MT6370_ISTROBE_MASK, flevel[i]);
+			if (ret)
+				return ret;
+		}
+	} else {
+		return regmap_update_bits(priv->regmap,
+					  MT6370_REG_FLEDISTRB(led->led_no),
+					  MT6370_ISTROBE_MASK, val);
+	}
+
+	return 0;
+}
+
+static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_classdev *lcdev = &fl_cdev->led_cdev;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask;
+	u32 val = state ? led_enable_mask : 0;
+	u32 prev = priv->fled_strobe_used, curr;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid torch is currently used
+	 */
+	if (priv->fled_torch_used) {
+		dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n",
+				      priv->fled_torch_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (state)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_STROBEN_MASK;
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask,
+				 val);
+	if (ret) {
+		dev_err(lcdev->dev, "[%d] control current source %d fail\n",
+				     led->led_no, state);
+		goto unlock;
+	}
+
+	/*
+	 * If the flash needs to be on,
+	 * config the flash current ramping up to the setting value.
+	 * Else, always recover back to the minimum one.
+	 */
+	ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min);
+	if (ret)
+		goto unlock;
+
+	/*
+	 * For the flash to turn on/off, need to wait HW ramping up/down time
+	 * 5ms/500us to prevent the unexpected problem.
+	 */
+	if (!prev && curr)
+		usleep_range(5000, 6000);
+	else if (prev && !curr)
+		udelay(500);
+
+	priv->fled_strobe_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+
+	mutex_lock(&priv->lock);
+	*state = !!(priv->fled_strobe_used & BIT(led->led_no));
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->timeout;
+	u32 val = (timeout - s->min) / s->step;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO,
+				 MT6370_STRBTO_MASK, val);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	u16 fled_stat;
+	unsigned int chg_stat, strobe_timeout_mask, fled_short_mask;
+	u32 rfault = 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat);
+	if (ret)
+		goto unlock;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat,
+			      sizeof(fled_stat));
+	if (ret)
+		goto unlock;
+
+	switch (led->led_no) {
+	case MT6370_LED_FLASH1:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK;
+		break;
+
+	case MT6370_LED_FLASH2:
+		strobe_timeout_mask = MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED2SHORT_MASK;
+		break;
+
+	case MT6370_LED_JOINT:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK |
+				      MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK |
+				  MT6370_FLED2SHORT_MASK;
+	}
+
+	if (chg_stat & MT6370_FLEDCHGVINOVP_MASK)
+		rfault |= LED_FAULT_INPUT_VOLTAGE;
+
+	if (fled_stat & strobe_timeout_mask)
+		rfault |= LED_FAULT_TIMEOUT;
+
+	if (fled_stat & fled_short_mask)
+		rfault |= LED_FAULT_SHORT_CIRCUIT;
+
+	if (fled_stat & MT6370_FLEDLVF_MASK)
+		rfault |= LED_FAULT_UNDER_VOLTAGE;
+
+	*fault = rfault;
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct led_flash_ops mt6370_flash_ops = {
+	.flash_brightness_set = mt6370_flash_brightness_set,
+	.strobe_set = mt6370_strobe_set,
+	.strobe_get = mt6370_strobe_get,
+	.timeout_set = mt6370_timeout_set,
+	.fault_get = mt6370_fault_get,
+};
+
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
+					    bool enable)
+{
+	struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
+	struct mt6370_led *led = to_mt6370_led(flash, flash);
+	struct mt6370_priv *priv = led->priv;
+	u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL :
+		   MT6370_FLCSEN_MASK(led->led_no);
+	u32 val = enable ? mask : 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val);
+	if (ret)
+		goto unlock;
+
+	if (enable)
+		priv->fled_strobe_used |= BIT(led->led_no);
+	else
+		priv->fled_strobe_used &= ~BIT(led->led_no);
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+	.external_strobe_set = mt6370_flash_external_strobe_set,
+};
+
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+	struct led_classdev *lcdev;
+	struct led_flash_setting *s = &config->intensity;
+
+	lcdev = &led->flash.led_cdev;
+
+	s->min = MT6370_ITORCH_MIN_UA;
+	s->step = MT6370_ITORCH_STEP_UA;
+	s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step;
+
+	config->has_external_strobe = 1;
+	strscpy(config->dev_name, lcdev->dev->kobj.name,
+		sizeof(config->dev_name));
+
+	config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT |
+			       LED_FAULT_INPUT_VOLTAGE |
+			       LED_FAULT_UNDER_VOLTAGE;
+}
+#else
+static const struct v4l2_flash_ops v4l2_flash_ops;
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+}
+#endif
+
+static void mt6370_v4l2_flash_release(void *v4l2_flash)
+{
+	v4l2_flash_release(v4l2_flash);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+				struct led_init_data *init_data)
+{
+	struct v4l2_flash_config v4l2_config = {0};
+	int ret;
+
+	ret = devm_led_classdev_flash_register_ext(parent, &led->flash,
+						   init_data);
+	if (ret)
+		return dev_err_probe(parent, ret,
+				     "Couldn't register flash %d\n", led->led_no);
+
+	mt6370_init_v4l2_flash_config(led, &v4l2_config);
+	led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode,
+					  &led->flash, &v4l2_flash_ops,
+					  &v4l2_config);
+	if (IS_ERR(led->v4l2_flash))
+		return dev_err_probe(parent, PTR_ERR(led->v4l2_flash),
+				     "Failed to register %d v4l2 sd\n", led->led_no);
+
+	return devm_add_action_or_reset(parent, mt6370_v4l2_flash_release,
+					led->v4l2_flash);
+}
+
+static u32 mt6370_clamp(u32 val, u32 min, u32 max, u32 step)
+{
+	u32 retval;
+
+	retval = clamp_val(val, min, max);
+	if (step > 1)
+		retval = rounddown(retval - min, step) + min;
+
+	return retval;
+}
+
+static int mt6370_init_flash_properties(struct mt6370_led *led,
+					struct led_init_data *init_data)
+{
+	struct led_classdev_flash *flash = &led->flash;
+	struct led_classdev *lcdev = &flash->led_cdev;
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s;
+	u32 sources[MT6370_MAX_LEDS];
+	u32 max_uA, val;
+	int i, ret, num;
+
+	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
+	if (num < 1 || num > MT6370_MAX_LEDS)
+		return dev_err_probe(priv->dev, -EINVAL,
+				     "Not specified or wrong number of led-sources\n");
+
+	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num; i++) {
+		if (sources[i] >= MT6370_MAX_LEDS)
+			return -EINVAL;
+		if (priv->leds_active & BIT(sources[i]))
+			return -EINVAL;
+		priv->leds_active |= BIT(sources[i]);
+
+	}
+	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
+		       sources[0];
+
+	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		val = MT6370_ITORCH_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
+				  MT6370_ITORCH_STEP_UA);
+	}
+
+	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
+				MT6370_ITORCH_STEP_UA + 1;
+	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
+	lcdev->flags |= LED_DEV_CAP_FLASH;
+
+	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+		   "Not specified flash-max-microamp, config to the minimum\n");
+		val = MT6370_ISTRB_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
+				  MT6370_ISTRB_STEP_UA);
+	}
+
+	s = &flash->brightness;
+	s->min = MT6370_ISTRB_MIN_UA;
+	s->step = MT6370_ISTRB_STEP_UA;
+	s->val = s->max = val;
+
+	/*
+	 * Always configure as min level when off to
+	 * prevent flash current spike
+	 */
+	ret = _mt6370_flash_brightness_set(flash, s->min);
+	if (ret)
+		return ret;
+
+	ret = fwnode_property_read_u32(init_data->fwnode,
+				       "flash-max-timeout-us", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified flash-max-timeout-us, config to the minimum\n");
+		val = MT6370_STRBTO_MIN_US;
+	} else {
+		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
+				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
+	}
+
+	s = &flash->timeout;
+	s->min = MT6370_STRBTO_MIN_US;
+	s->step = MT6370_STRBTO_STEP_US;
+	s->val = s->max = val;
+
+	flash->ops = &mt6370_flash_ops;
+
+	return 0;
+}
+
+static int mt6370_init_common_properties(struct mt6370_led *led,
+					 struct led_init_data *init_data)
+{
+	const char * const states[] = { "off", "keep", "on" };
+	const char *str = states[STATE_OFF];
+	int ret;
+
+	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
+	ret = match_string(states, ARRAY_SIZE(states), str);
+	if (ret >= 0)
+		led->default_state = ret;
+
+	return 0;
+}
+
+static int mt6370_led_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+		       "No child node or node count over max led number %zu\n", count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i;
+		struct led_init_data init_data = { .fwnode = child, };
+
+		led->priv = priv;
+		ret = mt6370_init_common_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_init_flash_properties(led, &init_data);
+
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(dev, led, &init_data);
+		if (ret)
+			return ret;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_led_of_id[] = {
+	{ .compatible = "mediatek,mt6370-flashlight" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_led_of_id);
+
+static struct platform_driver mt6370_led_driver = {
+	.driver = {
+		.name = "mt6370-flashlight",
+		.of_match_table = mt6370_led_of_id,
+	},
+	.probe = mt6370_led_probe,
+};
+module_platform_driver(mt6370_led_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_DESCRIPTION("MT6370 FLASH LED Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: Alice Chen <alice_chen@richtek.com>

The MediaTek MT6370 is a highly-integrated smart power management IC,
which includes a single cell Li-Ion/Li-Polymer switching battery
charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
LED current sources, a RGB LED driver, a backlight WLED driver,
a display bias driver and a general LDO for portable devices.

The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
Add the support of MT6370 FLASH LED.

Signed-off-by: Alice Chen <alice_chen@richtek.com>
---

v6
- Use 'GENMASK' instead of 'BIT'.
- Use dev_err_probe to decrease LOC.
- Use 'dev' variable to make probe function more clean.
- Refine the return of _mt6370_flash_brightness_set function.
- Refine the descriptions.
- Use mt6370_clamp() instead of clamp_align().
- Use device resource managed API for v4l2 flash_release.
---
 drivers/leds/flash/Kconfig             |  12 +
 drivers/leds/flash/Makefile            |   1 +
 drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
 3 files changed, 646 insertions(+)
 create mode 100644 drivers/leds/flash/leds-mt6370-flash.c

diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index d3eb689..d5761ed 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -90,4 +90,16 @@ config LEDS_SGM3140
 	  This option enables support for the SGM3140 500mA Buck/Boost Charge
 	  Pump LED Driver.
 
+config LEDS_MT6370_FLASHLIGHT
+	tristate "Flash LED Support for MediaTek MT6370 PMIC"
+	depends on LEDS_CLASS
+	depends on MFD_MT6370
+	help
+	  Support 2 channels and torch/strobe mode.
+	  Say Y here to enable support for
+	  MT6370_FLASH_LED device.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "leds-mt6370-flash".
+
 endif # LEDS_CLASS_FLASH
diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
index 0acbddc..4c4c171 100644
--- a/drivers/leds/flash/Makefile
+++ b/drivers/leds/flash/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
 obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
 obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
 obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
+obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
new file mode 100644
index 0000000..fe439ee
--- /dev/null
+++ b/drivers/leds/flash/leds-mt6370-flash.c
@@ -0,0 +1,633 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: Alice Chen <alice_chen@richtek.com
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/led-class-flash.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#include <media/v4l2-flash-led-class.h>
+
+enum {
+	MT6370_LED_FLASH1,
+	MT6370_LED_FLASH2,
+	MT6370_MAX_LEDS
+};
+
+/* Virtual definition for multicolor */
+
+#define MT6370_REG_FLEDEN		0x17E
+#define MT6370_REG_STRBTO		0x173
+#define MT6370_REG_CHGSTAT2		0x1D1
+#define MT6370_REG_FLEDSTAT1		0x1D9
+#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)
+#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
+#define MT6370_ITORCH_MASK		GENMASK(4, 0)
+#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
+#define MT6370_STRBTO_MASK		GENMASK(6, 0)
+#define MT6370_TORCHEN_MASK		BIT(3)
+#define MT6370_STROBEN_MASK		BIT(2)
+#define MT6370_FLCSEN_MASK(_id)		BIT(MT6370_LED_FLASH2 - _id)
+#define MT6370_FLCSEN_MASK_ALL		GENMASK(1, 0)
+#define MT6370_FLEDCHGVINOVP_MASK	BIT(3)
+#define MT6370_FLED1STRBTO_MASK		BIT(11)
+#define MT6370_FLED2STRBTO_MASK		BIT(10)
+#define MT6370_FLED1STRB_MASK		BIT(9)
+#define MT6370_FLED2STRB_MASK		BIT(8)
+#define MT6370_FLED1SHORT_MASK		BIT(7)
+#define MT6370_FLED2SHORT_MASK		BIT(6)
+#define MT6370_FLEDLVF_MASK		BIT(3)
+
+#define MT6370_LED_JOINT		2
+#define MT6370_RANGE_FLED_REG		4
+#define MT6370_ITORCH_MIN_UA		25000
+#define MT6370_ITORCH_STEP_UA		12500
+#define MT6370_ITORCH_MAX_UA		400000
+#define MT6370_ITORCH_DOUBLE_MAX_UA	800000
+#define MT6370_ISTRB_MIN_UA		50000
+#define MT6370_ISTRB_STEP_UA		12500
+#define MT6370_ISTRB_MAX_UA		1500000
+#define MT6370_ISTRB_DOUBLE_MAX_UA	3000000
+#define MT6370_STRBTO_MIN_US		64000
+#define MT6370_STRBTO_STEP_US		32000
+#define MT6370_STRBTO_MAX_US		2432000
+
+#define STATE_OFF			0
+#define STATE_KEEP			1
+#define STATE_ON			2
+
+#define to_mt6370_led(ptr, member) container_of(ptr, struct mt6370_led, member)
+
+struct mt6370_led {
+	struct led_classdev_flash flash;
+	struct v4l2_flash *v4l2_flash;
+	struct mt6370_priv *priv;
+	u32 led_no;
+	u32 default_state;
+};
+
+struct mt6370_priv {
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex lock;
+	unsigned int fled_strobe_used;
+	unsigned int fled_torch_used;
+	unsigned int leds_active;
+	unsigned int leds_count;
+	struct mt6370_led leds[];
+};
+
+static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
+				       enum led_brightness level)
+{
+	struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
+	struct mt6370_priv *priv = led->priv;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
+	u32 val = level ? led_enable_mask : 0;
+	u32 prev = priv->fled_torch_used, curr;
+	int ret, i;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid strobe is currently used.
+	 */
+	if (priv->fled_strobe_used) {
+		dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
+			 priv->fled_strobe_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (level)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_TORCHEN_MASK;
+
+	if (level) {
+		level -= 1;
+		if (led->led_no == MT6370_LED_JOINT) {
+			int flevel[MT6370_MAX_LEDS];
+
+			flevel[0] = level / 2;
+			flevel[1] = level - flevel[0];
+			for (i = 0; i < MT6370_MAX_LEDS; i++) {
+				ret = regmap_update_bits(priv->regmap,
+						MT6370_REG_FLEDITOR(i),
+						MT6370_ITORCH_MASK, flevel[i]);
+				if (ret)
+					goto unlock;
+			}
+		} else {
+			ret = regmap_update_bits(priv->regmap,
+					MT6370_REG_FLEDITOR(led->led_no),
+					MT6370_ITORCH_MASK, level);
+			if (ret)
+				goto unlock;
+		}
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
+				 enable_mask, val);
+	if (ret)
+		goto unlock;
+
+	priv->fled_torch_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+				       u32 brightness)
+{
+	/*
+	 * Due to the current spike when turning on flash,
+	 * let brightness be kept by the framework.
+	 * This empty function is used to
+	 * prevent led_classdev_flash register ops check failure.
+	 */
+	return 0;
+}
+
+static int _mt6370_flash_brightness_set(struct led_classdev_flash *fl_cdev,
+					u32 brightness)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 val = (brightness - s->min) / s->step;
+	int ret, i;
+
+	if (led->led_no == MT6370_LED_JOINT) {
+		int flevel[MT6370_MAX_LEDS];
+
+		flevel[0] = val / 2;
+		flevel[1] = val - flevel[0];
+		for (i = 0; i < MT6370_MAX_LEDS; i++) {
+			ret = regmap_update_bits(priv->regmap,
+						 MT6370_REG_FLEDISTRB(i),
+						 MT6370_ISTROBE_MASK, flevel[i]);
+			if (ret)
+				return ret;
+		}
+	} else {
+		return regmap_update_bits(priv->regmap,
+					  MT6370_REG_FLEDISTRB(led->led_no),
+					  MT6370_ISTROBE_MASK, val);
+	}
+
+	return 0;
+}
+
+static int mt6370_strobe_set(struct led_classdev_flash *fl_cdev, bool state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_classdev *lcdev = &fl_cdev->led_cdev;
+	struct led_flash_setting *s = &fl_cdev->brightness;
+	u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
+			      MT6370_FLCSEN_MASK_ALL :
+			      MT6370_FLCSEN_MASK(led->led_no);
+	u32 enable_mask = MT6370_STROBEN_MASK | led_enable_mask;
+	u32 val = state ? led_enable_mask : 0;
+	u32 prev = priv->fled_strobe_used, curr;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	/*
+	 * Only one set of flash control logic,
+	 * use the flag to avoid torch is currently used
+	 */
+	if (priv->fled_torch_used) {
+		dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n",
+				      priv->fled_torch_used);
+		ret = -EBUSY;
+		goto unlock;
+	}
+
+	if (state)
+		curr = prev | BIT(led->led_no);
+	else
+		curr = prev & ~BIT(led->led_no);
+
+	if (curr)
+		val |= MT6370_STROBEN_MASK;
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, enable_mask,
+				 val);
+	if (ret) {
+		dev_err(lcdev->dev, "[%d] control current source %d fail\n",
+				     led->led_no, state);
+		goto unlock;
+	}
+
+	/*
+	 * If the flash needs to be on,
+	 * config the flash current ramping up to the setting value.
+	 * Else, always recover back to the minimum one.
+	 */
+	ret = _mt6370_flash_brightness_set(fl_cdev, state ? s->val : s->min);
+	if (ret)
+		goto unlock;
+
+	/*
+	 * For the flash to turn on/off, need to wait HW ramping up/down time
+	 * 5ms/500us to prevent the unexpected problem.
+	 */
+	if (!prev && curr)
+		usleep_range(5000, 6000);
+	else if (prev && !curr)
+		udelay(500);
+
+	priv->fled_strobe_used = curr;
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6370_strobe_get(struct led_classdev_flash *fl_cdev, bool *state)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+
+	mutex_lock(&priv->lock);
+	*state = !!(priv->fled_strobe_used & BIT(led->led_no));
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int mt6370_timeout_set(struct led_classdev_flash *fl_cdev, u32 timeout)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s = &fl_cdev->timeout;
+	u32 val = (timeout - s->min) / s->step;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_STRBTO,
+				 MT6370_STRBTO_MASK, val);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
+static int mt6370_fault_get(struct led_classdev_flash *fl_cdev, u32 *fault)
+{
+	struct mt6370_led *led = to_mt6370_led(fl_cdev, flash);
+	struct mt6370_priv *priv = led->priv;
+	u16 fled_stat;
+	unsigned int chg_stat, strobe_timeout_mask, fled_short_mask;
+	u32 rfault = 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_read(priv->regmap, MT6370_REG_CHGSTAT2, &chg_stat);
+	if (ret)
+		goto unlock;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_FLEDSTAT1, &fled_stat,
+			      sizeof(fled_stat));
+	if (ret)
+		goto unlock;
+
+	switch (led->led_no) {
+	case MT6370_LED_FLASH1:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK;
+		break;
+
+	case MT6370_LED_FLASH2:
+		strobe_timeout_mask = MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED2SHORT_MASK;
+		break;
+
+	case MT6370_LED_JOINT:
+		strobe_timeout_mask = MT6370_FLED1STRBTO_MASK |
+				      MT6370_FLED2STRBTO_MASK;
+		fled_short_mask = MT6370_FLED1SHORT_MASK |
+				  MT6370_FLED2SHORT_MASK;
+	}
+
+	if (chg_stat & MT6370_FLEDCHGVINOVP_MASK)
+		rfault |= LED_FAULT_INPUT_VOLTAGE;
+
+	if (fled_stat & strobe_timeout_mask)
+		rfault |= LED_FAULT_TIMEOUT;
+
+	if (fled_stat & fled_short_mask)
+		rfault |= LED_FAULT_SHORT_CIRCUIT;
+
+	if (fled_stat & MT6370_FLEDLVF_MASK)
+		rfault |= LED_FAULT_UNDER_VOLTAGE;
+
+	*fault = rfault;
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct led_flash_ops mt6370_flash_ops = {
+	.flash_brightness_set = mt6370_flash_brightness_set,
+	.strobe_set = mt6370_strobe_set,
+	.strobe_get = mt6370_strobe_get,
+	.timeout_set = mt6370_timeout_set,
+	.fault_get = mt6370_fault_get,
+};
+
+#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)
+static int mt6370_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,
+					    bool enable)
+{
+	struct led_classdev_flash *flash = v4l2_flash->fled_cdev;
+	struct mt6370_led *led = to_mt6370_led(flash, flash);
+	struct mt6370_priv *priv = led->priv;
+	u32 mask = (led->led_no == MT6370_LED_JOINT) ? MT6370_FLCSEN_MASK_ALL :
+		   MT6370_FLCSEN_MASK(led->led_no);
+	u32 val = enable ? mask : 0;
+	int ret;
+
+	mutex_lock(&priv->lock);
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN, mask, val);
+	if (ret)
+		goto unlock;
+
+	if (enable)
+		priv->fled_strobe_used |= BIT(led->led_no);
+	else
+		priv->fled_strobe_used &= ~BIT(led->led_no);
+
+unlock:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static const struct v4l2_flash_ops v4l2_flash_ops = {
+	.external_strobe_set = mt6370_flash_external_strobe_set,
+};
+
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+	struct led_classdev *lcdev;
+	struct led_flash_setting *s = &config->intensity;
+
+	lcdev = &led->flash.led_cdev;
+
+	s->min = MT6370_ITORCH_MIN_UA;
+	s->step = MT6370_ITORCH_STEP_UA;
+	s->val = s->max = s->min + (lcdev->max_brightness - 1) * s->step;
+
+	config->has_external_strobe = 1;
+	strscpy(config->dev_name, lcdev->dev->kobj.name,
+		sizeof(config->dev_name));
+
+	config->flash_faults = LED_FAULT_SHORT_CIRCUIT | LED_FAULT_TIMEOUT |
+			       LED_FAULT_INPUT_VOLTAGE |
+			       LED_FAULT_UNDER_VOLTAGE;
+}
+#else
+static const struct v4l2_flash_ops v4l2_flash_ops;
+static void mt6370_init_v4l2_flash_config(struct mt6370_led *led,
+					  struct v4l2_flash_config *config)
+{
+}
+#endif
+
+static void mt6370_v4l2_flash_release(void *v4l2_flash)
+{
+	v4l2_flash_release(v4l2_flash);
+}
+
+static int mt6370_led_register(struct device *parent, struct mt6370_led *led,
+				struct led_init_data *init_data)
+{
+	struct v4l2_flash_config v4l2_config = {0};
+	int ret;
+
+	ret = devm_led_classdev_flash_register_ext(parent, &led->flash,
+						   init_data);
+	if (ret)
+		return dev_err_probe(parent, ret,
+				     "Couldn't register flash %d\n", led->led_no);
+
+	mt6370_init_v4l2_flash_config(led, &v4l2_config);
+	led->v4l2_flash = v4l2_flash_init(parent, init_data->fwnode,
+					  &led->flash, &v4l2_flash_ops,
+					  &v4l2_config);
+	if (IS_ERR(led->v4l2_flash))
+		return dev_err_probe(parent, PTR_ERR(led->v4l2_flash),
+				     "Failed to register %d v4l2 sd\n", led->led_no);
+
+	return devm_add_action_or_reset(parent, mt6370_v4l2_flash_release,
+					led->v4l2_flash);
+}
+
+static u32 mt6370_clamp(u32 val, u32 min, u32 max, u32 step)
+{
+	u32 retval;
+
+	retval = clamp_val(val, min, max);
+	if (step > 1)
+		retval = rounddown(retval - min, step) + min;
+
+	return retval;
+}
+
+static int mt6370_init_flash_properties(struct mt6370_led *led,
+					struct led_init_data *init_data)
+{
+	struct led_classdev_flash *flash = &led->flash;
+	struct led_classdev *lcdev = &flash->led_cdev;
+	struct mt6370_priv *priv = led->priv;
+	struct led_flash_setting *s;
+	u32 sources[MT6370_MAX_LEDS];
+	u32 max_uA, val;
+	int i, ret, num;
+
+	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
+	if (num < 1 || num > MT6370_MAX_LEDS)
+		return dev_err_probe(priv->dev, -EINVAL,
+				     "Not specified or wrong number of led-sources\n");
+
+	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num; i++) {
+		if (sources[i] >= MT6370_MAX_LEDS)
+			return -EINVAL;
+		if (priv->leds_active & BIT(sources[i]))
+			return -EINVAL;
+		priv->leds_active |= BIT(sources[i]);
+
+	}
+	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
+		       sources[0];
+
+	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified led-max-microamp, config to the minimum\n");
+		val = MT6370_ITORCH_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
+				  MT6370_ITORCH_STEP_UA);
+	}
+
+	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
+				MT6370_ITORCH_STEP_UA + 1;
+	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
+	lcdev->flags |= LED_DEV_CAP_FLASH;
+
+	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
+	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+		   "Not specified flash-max-microamp, config to the minimum\n");
+		val = MT6370_ISTRB_MIN_UA;
+	} else {
+		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
+				  MT6370_ISTRB_STEP_UA);
+	}
+
+	s = &flash->brightness;
+	s->min = MT6370_ISTRB_MIN_UA;
+	s->step = MT6370_ISTRB_STEP_UA;
+	s->val = s->max = val;
+
+	/*
+	 * Always configure as min level when off to
+	 * prevent flash current spike
+	 */
+	ret = _mt6370_flash_brightness_set(flash, s->min);
+	if (ret)
+		return ret;
+
+	ret = fwnode_property_read_u32(init_data->fwnode,
+				       "flash-max-timeout-us", &val);
+	if (ret) {
+		dev_warn(priv->dev,
+			 "Not specified flash-max-timeout-us, config to the minimum\n");
+		val = MT6370_STRBTO_MIN_US;
+	} else {
+		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
+				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
+	}
+
+	s = &flash->timeout;
+	s->min = MT6370_STRBTO_MIN_US;
+	s->step = MT6370_STRBTO_STEP_US;
+	s->val = s->max = val;
+
+	flash->ops = &mt6370_flash_ops;
+
+	return 0;
+}
+
+static int mt6370_init_common_properties(struct mt6370_led *led,
+					 struct led_init_data *init_data)
+{
+	const char * const states[] = { "off", "keep", "on" };
+	const char *str = states[STATE_OFF];
+	int ret;
+
+	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
+	ret = match_string(states, ARRAY_SIZE(states), str);
+	if (ret >= 0)
+		led->default_state = ret;
+
+	return 0;
+}
+
+static int mt6370_led_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	struct fwnode_handle *child;
+	size_t count;
+	int i = 0, ret;
+
+	count = device_get_child_node_count(dev);
+	if (!count || count > MT6370_MAX_LEDS)
+		return dev_err_probe(dev, -EINVAL,
+		       "No child node or node count over max led number %zu\n", count);
+
+	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->leds_count = count;
+	priv->dev = dev;
+	mutex_init(&priv->lock);
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
+
+	device_for_each_child_node(dev, child) {
+		struct mt6370_led *led = priv->leds + i;
+		struct led_init_data init_data = { .fwnode = child, };
+
+		led->priv = priv;
+		ret = mt6370_init_common_properties(led, &init_data);
+		if (ret)
+			return ret;
+
+		ret = mt6370_init_flash_properties(led, &init_data);
+
+		if (ret)
+			return ret;
+
+		ret = mt6370_led_register(dev, led, &init_data);
+		if (ret)
+			return ret;
+
+		i++;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id mt6370_led_of_id[] = {
+	{ .compatible = "mediatek,mt6370-flashlight" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_led_of_id);
+
+static struct platform_driver mt6370_led_driver = {
+	.driver = {
+		.name = "mt6370-flashlight",
+		.of_match_table = mt6370_led_of_id,
+	},
+	.probe = mt6370_led_probe,
+};
+module_platform_driver(mt6370_led_driver);
+
+MODULE_AUTHOR("Alice Chen <alice_chen@richtek.com>");
+MODULE_DESCRIPTION("MT6370 FLASH LED Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:23 ` ChiaEn Wu
  (?)
@ 2022-07-22 10:24   ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds support for MediaTek MT6370 Backlight driver. It's commonly used
to drive the display WLED. There are 4 channels inside, and each channel
supports up to 30mA of current capability with 2048 current steps in
exponential or linear mapping curves.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---
 drivers/video/backlight/Kconfig            |  12 +
 drivers/video/backlight/Makefile           |   1 +
 drivers/video/backlight/mt6370-backlight.c | 339 +++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
 create mode 100644 drivers/video/backlight/mt6370-backlight.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a003e02..846dbe7 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
 	  If you have a LCD backlight connected to the WLED output of MAX8925
 	  WLED output, say Y here to enable this driver.
 
+config BACKLIGHT_MT6370
+	tristate "MediaTek MT6370 Backlight Driver"
+	depends on MFD_MT6370
+	help
+	  This enables support for Mediatek MT6370 Backlight driver.
+	  It's commonly used to drive the display WLED. There are 4 channels
+	  inside, and each channel supports up to 30mA of current capability
+	  with 2048 current steps in exponential or linear mapping curves.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-backlight".
+
 config BACKLIGHT_APPLE
 	tristate "Apple Backlight Driver"
 	depends on X86 && ACPI
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index cae2c83..e815f3f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_MT6370)		+= mt6370-backlight.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
 obj-$(CONFIG_BACKLIGHT_PANDORA)		+= pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
new file mode 100644
index 0000000..ba00a8f
--- /dev/null
+++ b/drivers/video/backlight/mt6370-backlight.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MT6370_REG_DEV_INFO		0x100
+#define MT6370_REG_BL_EN		0x1A0
+#define MT6370_REG_BL_BSTCTRL		0x1A1
+#define MT6370_REG_BL_PWM		0x1A2
+#define MT6370_REG_BL_DIM2		0x1A4
+
+#define MT6370_VENID_MASK		GENMASK(7, 4)
+#define MT6370_BL_EXT_EN_MASK		BIT(7)
+#define MT6370_BL_EN_MASK		BIT(6)
+#define MT6370_BL_CONFIG_MASK		BIT(0)
+#define MT6370_BL_CH_MASK		GENMASK(5, 2)
+#define MT6370_BL_DIM2_MASK		GENMASK(2, 0)
+#define MT6370_BL_DUMMY_6372_MASK	GENMASK(2, 0)
+#define MT6370_BL_DIM2_6372_SHIFT	3
+#define MT6370_BL_PWM_EN_MASK		BIT(7)
+#define MT6370_BL_PWM_HYS_EN_MASK	BIT(2)
+#define MT6370_BL_PWM_HYS_SEL_MASK	GENMASK(1, 0)
+#define MT6370_BL_OVP_EN_MASK		BIT(7)
+#define MT6370_BL_OVP_SEL_MASK		GENMASK(6, 5)
+#define MT6370_BL_OC_EN_MASK		BIT(3)
+#define MT6370_BL_OC_SEL_MASK		GENMASK(2, 1)
+
+#define MT6370_BL_PWM_HYS_TH_MIN_STEP	1
+#define MT6370_BL_PWM_HYS_TH_MAX_STEP	64
+#define MT6370_BL_OVP_MIN_UV		17000000
+#define MT6370_BL_OVP_MAX_UV		29000000
+#define MT6370_BL_OVP_STEP_UV		4000000
+#define MT6370_BL_OCP_MIN_UA		900000
+#define MT6370_BL_OCP_MAX_UA		1800000
+#define MT6370_BL_OCP_STEP_UA		300000
+#define MT6370_BL_MAX_BRIGHTNESS	2048
+#define MT6370_BL_MAX_CH		15
+
+enum {
+	MT6370_VID_COMMON = 0,
+	MT6370_VID_6372,
+};
+
+struct mt6370_priv {
+	int vid_type;
+	struct backlight_device *bl;
+	struct device *dev;
+	struct gpio_desc *enable_gpio;
+	struct regmap *regmap;
+};
+
+static int mt6370_bl_update_status(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	int brightness = backlight_get_brightness(bl_dev);
+	unsigned int enable_val;
+	u8 brightness_val[2];
+	int ret;
+
+	if (brightness) {
+		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
+		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
+
+		/*
+		 * To make MT6372 using 14 bits to control the brightness
+		 * backward compatible with 11 bits brightness control
+		 * (like MT6370 and MT6371 do), we left shift the value
+		 * and pad with 1 to remaining bits. Hence, the MT6372's
+		 * backlight brightness will be almost the same as MT6370's
+		 * and MT6371's.
+		 */
+		if (priv->vid_type == MT6370_VID_6372) {
+			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
+			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
+		}
+
+		ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2,
+				       brightness_val, sizeof(brightness_val));
+		if (ret)
+			return ret;
+	}
+
+	gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);
+
+	enable_val = brightness ? MT6370_BL_EN_MASK : 0;
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN,
+				  MT6370_BL_EN_MASK, enable_val);
+}
+
+static int mt6370_bl_get_brightness(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	unsigned int enable;
+	u8 brightness_val[2];
+	int brightness, ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_BL_EN, &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_BL_EN_MASK))
+		return 0;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_BL_DIM2,
+			      brightness_val, sizeof(brightness_val));
+	if (ret)
+		return ret;
+
+	if (priv->vid_type == MT6370_VID_6372)
+		brightness_val[0] >>= MT6370_BL_DIM2_6372_SHIFT;
+
+	brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);
+	brightness += brightness_val[0] & MT6370_BL_DIM2_MASK;
+
+	return brightness + 1;
+}
+
+static const struct backlight_ops mt6370_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = mt6370_bl_update_status,
+	.get_brightness = mt6370_bl_get_brightness,
+};
+
+static int mt6370_init_backlight_properties(struct mt6370_priv *priv,
+					    struct backlight_properties *props)
+{
+	struct device *dev = priv->dev;
+	u8 prop_val;
+	u32 brightness, ovp_uV, ocp_uA;
+	unsigned int mask, val;
+	int ret;
+
+	/* Vendor optional properties */
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-enable"))
+		val |= MT6370_BL_PWM_EN_MASK;
+
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-hys-enable"))
+		val |= MT6370_BL_PWM_HYS_EN_MASK;
+
+	ret = device_property_read_u8(dev,
+				      "mediatek,bled-pwm-hys-input-th-steps",
+				      &prop_val);
+	if (!ret) {
+		prop_val = clamp_val(prop_val,
+				     MT6370_BL_PWM_HYS_TH_MIN_STEP,
+				     MT6370_BL_PWM_HYS_TH_MAX_STEP);
+		prop_val = prop_val <= 1 ? 0 :
+			   prop_val <= 4 ? 1 :
+			   prop_val <= 16 ? 2 : 3;
+		val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_PWM,
+				 val, val);
+	if (ret)
+		return ret;
+
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-ovp-shutdown"))
+		val |= MT6370_BL_OVP_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ovp-microvolt",
+				       &ovp_uV);
+	if (!ret) {
+		ovp_uV = clamp_val(ovp_uV, MT6370_BL_OVP_MIN_UV,
+				   MT6370_BL_OVP_MAX_UV);
+		ovp_uV = DIV_ROUND_UP(ovp_uV - MT6370_BL_OVP_MIN_UV,
+				      MT6370_BL_OVP_STEP_UV);
+		val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);
+	}
+
+	if (device_property_read_bool(dev, "mediatek,bled-ocp-shutdown"))
+		val |= MT6370_BL_OC_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ocp-microamp",
+				       &ocp_uA);
+	if (!ret) {
+		ocp_uA = clamp_val(ocp_uA, MT6370_BL_OCP_MIN_UA,
+				   MT6370_BL_OCP_MAX_UA);
+		ocp_uA = DIV_ROUND_UP(ocp_uA - MT6370_BL_OCP_MIN_UA,
+				      MT6370_BL_OCP_STEP_UA);
+		val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_BSTCTRL,
+				 val, val);
+	if (ret)
+		return ret;
+
+	/* Common properties */
+	ret = device_property_read_u32(dev, "max-brightness", &brightness);
+	if (ret)
+		brightness = MT6370_BL_MAX_BRIGHTNESS;
+
+	props->max_brightness = min_t(u32, brightness, MT6370_BL_MAX_BRIGHTNESS);
+
+	ret = device_property_read_u32(dev, "default-brightness", &brightness);
+	if (ret)
+		brightness = props->max_brightness;
+
+	props->brightness = min_t(u32, brightness, props->max_brightness);
+
+	ret = device_property_read_u8(dev, "mediatek,bled-channel-use",
+				      &prop_val);
+	if (ret) {
+		dev_err(dev, "mediatek,bled-channel-use DT property missing\n");
+		return ret;
+	}
+
+	if (!prop_val || prop_val > MT6370_BL_MAX_CH) {
+		dev_err(dev,
+			"No channel specified or over than upper bound (%d)\n",
+			prop_val);
+		return -EINVAL;
+	}
+
+	mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK;
+	val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);
+
+	if (priv->enable_gpio)
+		val |= MT6370_BL_EXT_EN_MASK;
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	/*
+	 * MT6372 uses 14 bits to control the brightness but MT6370 and MT6371
+	 * use 11 bits. They are different so we have to use this function to
+	 * check the vendor ID and use different methods to calculate the
+	 * brightness.
+	 */
+	unsigned int dev_info, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, dev_info);
+	if (vid == 0x9 || vid == 0xb)
+		priv->vid_type = MT6370_VID_6372;
+	else
+		priv->vid_type = MT6370_VID_COMMON;
+
+	return 0;
+}
+
+static int mt6370_bl_probe(struct platform_device *pdev)
+{
+	struct backlight_properties props = {
+		.type = BACKLIGHT_RAW,
+		.scale = BACKLIGHT_SCALE_LINEAR,
+	};
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->enable_gpio))
+		dev_err(dev, "Failed to get 'enable' gpio\n");
+
+	ret = mt6370_init_backlight_properties(priv, &props);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init backlight properties\n");
+
+	priv->bl = devm_backlight_device_register(dev, pdev->name, dev, priv,
+						  &mt6370_bl_ops, &props);
+	if (IS_ERR(priv->bl))
+		return dev_err_probe(dev, PTR_ERR(priv->bl),
+				     "Failed to register backlight\n");
+
+	backlight_update_status(priv->bl);
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static int mt6370_bl_remove(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv = platform_get_drvdata(pdev);
+	struct backlight_device *bl_dev = priv->bl;
+
+	bl_dev->props.brightness = 0;
+	backlight_update_status(priv->bl);
+
+	return 0;
+}
+
+static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = {
+	{ .compatible = "mediatek,mt6370-backlight", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_bl_of_match);
+
+static struct platform_driver mt6370_bl_driver = {
+	.driver = {
+		.name = "mt6370-backlight",
+		.of_match_table = mt6370_bl_of_match,
+	},
+	.probe = mt6370_bl_probe,
+	.remove = mt6370_bl_remove,
+};
+module_platform_driver(mt6370_bl_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Backlight Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds support for MediaTek MT6370 Backlight driver. It's commonly used
to drive the display WLED. There are 4 channels inside, and each channel
supports up to 30mA of current capability with 2048 current steps in
exponential or linear mapping curves.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---
 drivers/video/backlight/Kconfig            |  12 +
 drivers/video/backlight/Makefile           |   1 +
 drivers/video/backlight/mt6370-backlight.c | 339 +++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
 create mode 100644 drivers/video/backlight/mt6370-backlight.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a003e02..846dbe7 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
 	  If you have a LCD backlight connected to the WLED output of MAX8925
 	  WLED output, say Y here to enable this driver.
 
+config BACKLIGHT_MT6370
+	tristate "MediaTek MT6370 Backlight Driver"
+	depends on MFD_MT6370
+	help
+	  This enables support for Mediatek MT6370 Backlight driver.
+	  It's commonly used to drive the display WLED. There are 4 channels
+	  inside, and each channel supports up to 30mA of current capability
+	  with 2048 current steps in exponential or linear mapping curves.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-backlight".
+
 config BACKLIGHT_APPLE
 	tristate "Apple Backlight Driver"
 	depends on X86 && ACPI
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index cae2c83..e815f3f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_MT6370)		+= mt6370-backlight.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
 obj-$(CONFIG_BACKLIGHT_PANDORA)		+= pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
new file mode 100644
index 0000000..ba00a8f
--- /dev/null
+++ b/drivers/video/backlight/mt6370-backlight.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MT6370_REG_DEV_INFO		0x100
+#define MT6370_REG_BL_EN		0x1A0
+#define MT6370_REG_BL_BSTCTRL		0x1A1
+#define MT6370_REG_BL_PWM		0x1A2
+#define MT6370_REG_BL_DIM2		0x1A4
+
+#define MT6370_VENID_MASK		GENMASK(7, 4)
+#define MT6370_BL_EXT_EN_MASK		BIT(7)
+#define MT6370_BL_EN_MASK		BIT(6)
+#define MT6370_BL_CONFIG_MASK		BIT(0)
+#define MT6370_BL_CH_MASK		GENMASK(5, 2)
+#define MT6370_BL_DIM2_MASK		GENMASK(2, 0)
+#define MT6370_BL_DUMMY_6372_MASK	GENMASK(2, 0)
+#define MT6370_BL_DIM2_6372_SHIFT	3
+#define MT6370_BL_PWM_EN_MASK		BIT(7)
+#define MT6370_BL_PWM_HYS_EN_MASK	BIT(2)
+#define MT6370_BL_PWM_HYS_SEL_MASK	GENMASK(1, 0)
+#define MT6370_BL_OVP_EN_MASK		BIT(7)
+#define MT6370_BL_OVP_SEL_MASK		GENMASK(6, 5)
+#define MT6370_BL_OC_EN_MASK		BIT(3)
+#define MT6370_BL_OC_SEL_MASK		GENMASK(2, 1)
+
+#define MT6370_BL_PWM_HYS_TH_MIN_STEP	1
+#define MT6370_BL_PWM_HYS_TH_MAX_STEP	64
+#define MT6370_BL_OVP_MIN_UV		17000000
+#define MT6370_BL_OVP_MAX_UV		29000000
+#define MT6370_BL_OVP_STEP_UV		4000000
+#define MT6370_BL_OCP_MIN_UA		900000
+#define MT6370_BL_OCP_MAX_UA		1800000
+#define MT6370_BL_OCP_STEP_UA		300000
+#define MT6370_BL_MAX_BRIGHTNESS	2048
+#define MT6370_BL_MAX_CH		15
+
+enum {
+	MT6370_VID_COMMON = 0,
+	MT6370_VID_6372,
+};
+
+struct mt6370_priv {
+	int vid_type;
+	struct backlight_device *bl;
+	struct device *dev;
+	struct gpio_desc *enable_gpio;
+	struct regmap *regmap;
+};
+
+static int mt6370_bl_update_status(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	int brightness = backlight_get_brightness(bl_dev);
+	unsigned int enable_val;
+	u8 brightness_val[2];
+	int ret;
+
+	if (brightness) {
+		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
+		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
+
+		/*
+		 * To make MT6372 using 14 bits to control the brightness
+		 * backward compatible with 11 bits brightness control
+		 * (like MT6370 and MT6371 do), we left shift the value
+		 * and pad with 1 to remaining bits. Hence, the MT6372's
+		 * backlight brightness will be almost the same as MT6370's
+		 * and MT6371's.
+		 */
+		if (priv->vid_type == MT6370_VID_6372) {
+			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
+			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
+		}
+
+		ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2,
+				       brightness_val, sizeof(brightness_val));
+		if (ret)
+			return ret;
+	}
+
+	gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);
+
+	enable_val = brightness ? MT6370_BL_EN_MASK : 0;
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN,
+				  MT6370_BL_EN_MASK, enable_val);
+}
+
+static int mt6370_bl_get_brightness(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	unsigned int enable;
+	u8 brightness_val[2];
+	int brightness, ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_BL_EN, &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_BL_EN_MASK))
+		return 0;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_BL_DIM2,
+			      brightness_val, sizeof(brightness_val));
+	if (ret)
+		return ret;
+
+	if (priv->vid_type == MT6370_VID_6372)
+		brightness_val[0] >>= MT6370_BL_DIM2_6372_SHIFT;
+
+	brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);
+	brightness += brightness_val[0] & MT6370_BL_DIM2_MASK;
+
+	return brightness + 1;
+}
+
+static const struct backlight_ops mt6370_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = mt6370_bl_update_status,
+	.get_brightness = mt6370_bl_get_brightness,
+};
+
+static int mt6370_init_backlight_properties(struct mt6370_priv *priv,
+					    struct backlight_properties *props)
+{
+	struct device *dev = priv->dev;
+	u8 prop_val;
+	u32 brightness, ovp_uV, ocp_uA;
+	unsigned int mask, val;
+	int ret;
+
+	/* Vendor optional properties */
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-enable"))
+		val |= MT6370_BL_PWM_EN_MASK;
+
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-hys-enable"))
+		val |= MT6370_BL_PWM_HYS_EN_MASK;
+
+	ret = device_property_read_u8(dev,
+				      "mediatek,bled-pwm-hys-input-th-steps",
+				      &prop_val);
+	if (!ret) {
+		prop_val = clamp_val(prop_val,
+				     MT6370_BL_PWM_HYS_TH_MIN_STEP,
+				     MT6370_BL_PWM_HYS_TH_MAX_STEP);
+		prop_val = prop_val <= 1 ? 0 :
+			   prop_val <= 4 ? 1 :
+			   prop_val <= 16 ? 2 : 3;
+		val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_PWM,
+				 val, val);
+	if (ret)
+		return ret;
+
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-ovp-shutdown"))
+		val |= MT6370_BL_OVP_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ovp-microvolt",
+				       &ovp_uV);
+	if (!ret) {
+		ovp_uV = clamp_val(ovp_uV, MT6370_BL_OVP_MIN_UV,
+				   MT6370_BL_OVP_MAX_UV);
+		ovp_uV = DIV_ROUND_UP(ovp_uV - MT6370_BL_OVP_MIN_UV,
+				      MT6370_BL_OVP_STEP_UV);
+		val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);
+	}
+
+	if (device_property_read_bool(dev, "mediatek,bled-ocp-shutdown"))
+		val |= MT6370_BL_OC_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ocp-microamp",
+				       &ocp_uA);
+	if (!ret) {
+		ocp_uA = clamp_val(ocp_uA, MT6370_BL_OCP_MIN_UA,
+				   MT6370_BL_OCP_MAX_UA);
+		ocp_uA = DIV_ROUND_UP(ocp_uA - MT6370_BL_OCP_MIN_UA,
+				      MT6370_BL_OCP_STEP_UA);
+		val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_BSTCTRL,
+				 val, val);
+	if (ret)
+		return ret;
+
+	/* Common properties */
+	ret = device_property_read_u32(dev, "max-brightness", &brightness);
+	if (ret)
+		brightness = MT6370_BL_MAX_BRIGHTNESS;
+
+	props->max_brightness = min_t(u32, brightness, MT6370_BL_MAX_BRIGHTNESS);
+
+	ret = device_property_read_u32(dev, "default-brightness", &brightness);
+	if (ret)
+		brightness = props->max_brightness;
+
+	props->brightness = min_t(u32, brightness, props->max_brightness);
+
+	ret = device_property_read_u8(dev, "mediatek,bled-channel-use",
+				      &prop_val);
+	if (ret) {
+		dev_err(dev, "mediatek,bled-channel-use DT property missing\n");
+		return ret;
+	}
+
+	if (!prop_val || prop_val > MT6370_BL_MAX_CH) {
+		dev_err(dev,
+			"No channel specified or over than upper bound (%d)\n",
+			prop_val);
+		return -EINVAL;
+	}
+
+	mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK;
+	val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);
+
+	if (priv->enable_gpio)
+		val |= MT6370_BL_EXT_EN_MASK;
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	/*
+	 * MT6372 uses 14 bits to control the brightness but MT6370 and MT6371
+	 * use 11 bits. They are different so we have to use this function to
+	 * check the vendor ID and use different methods to calculate the
+	 * brightness.
+	 */
+	unsigned int dev_info, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, dev_info);
+	if (vid == 0x9 || vid == 0xb)
+		priv->vid_type = MT6370_VID_6372;
+	else
+		priv->vid_type = MT6370_VID_COMMON;
+
+	return 0;
+}
+
+static int mt6370_bl_probe(struct platform_device *pdev)
+{
+	struct backlight_properties props = {
+		.type = BACKLIGHT_RAW,
+		.scale = BACKLIGHT_SCALE_LINEAR,
+	};
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->enable_gpio))
+		dev_err(dev, "Failed to get 'enable' gpio\n");
+
+	ret = mt6370_init_backlight_properties(priv, &props);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init backlight properties\n");
+
+	priv->bl = devm_backlight_device_register(dev, pdev->name, dev, priv,
+						  &mt6370_bl_ops, &props);
+	if (IS_ERR(priv->bl))
+		return dev_err_probe(dev, PTR_ERR(priv->bl),
+				     "Failed to register backlight\n");
+
+	backlight_update_status(priv->bl);
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static int mt6370_bl_remove(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv = platform_get_drvdata(pdev);
+	struct backlight_device *bl_dev = priv->bl;
+
+	bl_dev->props.brightness = 0;
+	backlight_update_status(priv->bl);
+
+	return 0;
+}
+
+static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = {
+	{ .compatible = "mediatek,mt6370-backlight", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_bl_of_match);
+
+static struct platform_driver mt6370_bl_driver = {
+	.driver = {
+		.name = "mt6370-backlight",
+		.of_match_table = mt6370_bl_of_match,
+	},
+	.probe = mt6370_bl_probe,
+	.remove = mt6370_bl_remove,
+};
+module_platform_driver(mt6370_bl_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Backlight Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 154+ messages in thread

* [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-22 10:24   ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-22 10:24 UTC (permalink / raw)
  To: lee.jones, daniel.thompson, jingoohan1, pavel, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

From: ChiaEn Wu <chiaen_wu@richtek.com>

MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
driver, display bias voltage supply, one general purpose LDO, and the
USB Type-C & PD controller complies with the latest USB Type-C and PD
standards.

This adds support for MediaTek MT6370 Backlight driver. It's commonly used
to drive the display WLED. There are 4 channels inside, and each channel
supports up to 30mA of current capability with 2048 current steps in
exponential or linear mapping curves.

Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
---
 drivers/video/backlight/Kconfig            |  12 +
 drivers/video/backlight/Makefile           |   1 +
 drivers/video/backlight/mt6370-backlight.c | 339 +++++++++++++++++++++++++++++
 3 files changed, 352 insertions(+)
 create mode 100644 drivers/video/backlight/mt6370-backlight.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index a003e02..846dbe7 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
 	  If you have a LCD backlight connected to the WLED output of MAX8925
 	  WLED output, say Y here to enable this driver.
 
+config BACKLIGHT_MT6370
+	tristate "MediaTek MT6370 Backlight Driver"
+	depends on MFD_MT6370
+	help
+	  This enables support for Mediatek MT6370 Backlight driver.
+	  It's commonly used to drive the display WLED. There are 4 channels
+	  inside, and each channel supports up to 30mA of current capability
+	  with 2048 current steps in exponential or linear mapping curves.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called "mt6370-backlight".
+
 config BACKLIGHT_APPLE
 	tristate "Apple Backlight Driver"
 	depends on X86 && ACPI
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index cae2c83..e815f3f 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
 obj-$(CONFIG_BACKLIGHT_MAX8925)		+= max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_MT6370)		+= mt6370-backlight.o
 obj-$(CONFIG_BACKLIGHT_OMAP1)		+= omap1_bl.o
 obj-$(CONFIG_BACKLIGHT_PANDORA)		+= pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)	+= pcf50633-backlight.o
diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
new file mode 100644
index 0000000..ba00a8f
--- /dev/null
+++ b/drivers/video/backlight/mt6370-backlight.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ *
+ * Author: ChiaEn Wu <chiaen_wu@richtek.com>
+ */
+
+#include <linux/backlight.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MT6370_REG_DEV_INFO		0x100
+#define MT6370_REG_BL_EN		0x1A0
+#define MT6370_REG_BL_BSTCTRL		0x1A1
+#define MT6370_REG_BL_PWM		0x1A2
+#define MT6370_REG_BL_DIM2		0x1A4
+
+#define MT6370_VENID_MASK		GENMASK(7, 4)
+#define MT6370_BL_EXT_EN_MASK		BIT(7)
+#define MT6370_BL_EN_MASK		BIT(6)
+#define MT6370_BL_CONFIG_MASK		BIT(0)
+#define MT6370_BL_CH_MASK		GENMASK(5, 2)
+#define MT6370_BL_DIM2_MASK		GENMASK(2, 0)
+#define MT6370_BL_DUMMY_6372_MASK	GENMASK(2, 0)
+#define MT6370_BL_DIM2_6372_SHIFT	3
+#define MT6370_BL_PWM_EN_MASK		BIT(7)
+#define MT6370_BL_PWM_HYS_EN_MASK	BIT(2)
+#define MT6370_BL_PWM_HYS_SEL_MASK	GENMASK(1, 0)
+#define MT6370_BL_OVP_EN_MASK		BIT(7)
+#define MT6370_BL_OVP_SEL_MASK		GENMASK(6, 5)
+#define MT6370_BL_OC_EN_MASK		BIT(3)
+#define MT6370_BL_OC_SEL_MASK		GENMASK(2, 1)
+
+#define MT6370_BL_PWM_HYS_TH_MIN_STEP	1
+#define MT6370_BL_PWM_HYS_TH_MAX_STEP	64
+#define MT6370_BL_OVP_MIN_UV		17000000
+#define MT6370_BL_OVP_MAX_UV		29000000
+#define MT6370_BL_OVP_STEP_UV		4000000
+#define MT6370_BL_OCP_MIN_UA		900000
+#define MT6370_BL_OCP_MAX_UA		1800000
+#define MT6370_BL_OCP_STEP_UA		300000
+#define MT6370_BL_MAX_BRIGHTNESS	2048
+#define MT6370_BL_MAX_CH		15
+
+enum {
+	MT6370_VID_COMMON = 0,
+	MT6370_VID_6372,
+};
+
+struct mt6370_priv {
+	int vid_type;
+	struct backlight_device *bl;
+	struct device *dev;
+	struct gpio_desc *enable_gpio;
+	struct regmap *regmap;
+};
+
+static int mt6370_bl_update_status(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	int brightness = backlight_get_brightness(bl_dev);
+	unsigned int enable_val;
+	u8 brightness_val[2];
+	int ret;
+
+	if (brightness) {
+		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
+		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
+
+		/*
+		 * To make MT6372 using 14 bits to control the brightness
+		 * backward compatible with 11 bits brightness control
+		 * (like MT6370 and MT6371 do), we left shift the value
+		 * and pad with 1 to remaining bits. Hence, the MT6372's
+		 * backlight brightness will be almost the same as MT6370's
+		 * and MT6371's.
+		 */
+		if (priv->vid_type == MT6370_VID_6372) {
+			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
+			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
+		}
+
+		ret = regmap_raw_write(priv->regmap, MT6370_REG_BL_DIM2,
+				       brightness_val, sizeof(brightness_val));
+		if (ret)
+			return ret;
+	}
+
+	gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);
+
+	enable_val = brightness ? MT6370_BL_EN_MASK : 0;
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN,
+				  MT6370_BL_EN_MASK, enable_val);
+}
+
+static int mt6370_bl_get_brightness(struct backlight_device *bl_dev)
+{
+	struct mt6370_priv *priv = bl_get_data(bl_dev);
+	unsigned int enable;
+	u8 brightness_val[2];
+	int brightness, ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_BL_EN, &enable);
+	if (ret)
+		return ret;
+
+	if (!(enable & MT6370_BL_EN_MASK))
+		return 0;
+
+	ret = regmap_raw_read(priv->regmap, MT6370_REG_BL_DIM2,
+			      brightness_val, sizeof(brightness_val));
+	if (ret)
+		return ret;
+
+	if (priv->vid_type == MT6370_VID_6372)
+		brightness_val[0] >>= MT6370_BL_DIM2_6372_SHIFT;
+
+	brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);
+	brightness += brightness_val[0] & MT6370_BL_DIM2_MASK;
+
+	return brightness + 1;
+}
+
+static const struct backlight_ops mt6370_bl_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = mt6370_bl_update_status,
+	.get_brightness = mt6370_bl_get_brightness,
+};
+
+static int mt6370_init_backlight_properties(struct mt6370_priv *priv,
+					    struct backlight_properties *props)
+{
+	struct device *dev = priv->dev;
+	u8 prop_val;
+	u32 brightness, ovp_uV, ocp_uA;
+	unsigned int mask, val;
+	int ret;
+
+	/* Vendor optional properties */
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-enable"))
+		val |= MT6370_BL_PWM_EN_MASK;
+
+	if (device_property_read_bool(dev, "mediatek,bled-pwm-hys-enable"))
+		val |= MT6370_BL_PWM_HYS_EN_MASK;
+
+	ret = device_property_read_u8(dev,
+				      "mediatek,bled-pwm-hys-input-th-steps",
+				      &prop_val);
+	if (!ret) {
+		prop_val = clamp_val(prop_val,
+				     MT6370_BL_PWM_HYS_TH_MIN_STEP,
+				     MT6370_BL_PWM_HYS_TH_MAX_STEP);
+		prop_val = prop_val <= 1 ? 0 :
+			   prop_val <= 4 ? 1 :
+			   prop_val <= 16 ? 2 : 3;
+		val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_PWM,
+				 val, val);
+	if (ret)
+		return ret;
+
+	val = 0;
+	if (device_property_read_bool(dev, "mediatek,bled-ovp-shutdown"))
+		val |= MT6370_BL_OVP_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ovp-microvolt",
+				       &ovp_uV);
+	if (!ret) {
+		ovp_uV = clamp_val(ovp_uV, MT6370_BL_OVP_MIN_UV,
+				   MT6370_BL_OVP_MAX_UV);
+		ovp_uV = DIV_ROUND_UP(ovp_uV - MT6370_BL_OVP_MIN_UV,
+				      MT6370_BL_OVP_STEP_UV);
+		val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);
+	}
+
+	if (device_property_read_bool(dev, "mediatek,bled-ocp-shutdown"))
+		val |= MT6370_BL_OC_EN_MASK;
+
+	ret = device_property_read_u32(dev, "mediatek,bled-ocp-microamp",
+				       &ocp_uA);
+	if (!ret) {
+		ocp_uA = clamp_val(ocp_uA, MT6370_BL_OCP_MIN_UA,
+				   MT6370_BL_OCP_MAX_UA);
+		ocp_uA = DIV_ROUND_UP(ocp_uA - MT6370_BL_OCP_MIN_UA,
+				      MT6370_BL_OCP_STEP_UA);
+		val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);
+	}
+
+	ret = regmap_update_bits(priv->regmap, MT6370_REG_BL_BSTCTRL,
+				 val, val);
+	if (ret)
+		return ret;
+
+	/* Common properties */
+	ret = device_property_read_u32(dev, "max-brightness", &brightness);
+	if (ret)
+		brightness = MT6370_BL_MAX_BRIGHTNESS;
+
+	props->max_brightness = min_t(u32, brightness, MT6370_BL_MAX_BRIGHTNESS);
+
+	ret = device_property_read_u32(dev, "default-brightness", &brightness);
+	if (ret)
+		brightness = props->max_brightness;
+
+	props->brightness = min_t(u32, brightness, props->max_brightness);
+
+	ret = device_property_read_u8(dev, "mediatek,bled-channel-use",
+				      &prop_val);
+	if (ret) {
+		dev_err(dev, "mediatek,bled-channel-use DT property missing\n");
+		return ret;
+	}
+
+	if (!prop_val || prop_val > MT6370_BL_MAX_CH) {
+		dev_err(dev,
+			"No channel specified or over than upper bound (%d)\n",
+			prop_val);
+		return -EINVAL;
+	}
+
+	mask = MT6370_BL_EXT_EN_MASK | MT6370_BL_CH_MASK;
+	val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);
+
+	if (priv->enable_gpio)
+		val |= MT6370_BL_EXT_EN_MASK;
+
+	return regmap_update_bits(priv->regmap, MT6370_REG_BL_EN, mask, val);
+}
+
+static int mt6370_check_vendor_info(struct mt6370_priv *priv)
+{
+	/*
+	 * MT6372 uses 14 bits to control the brightness but MT6370 and MT6371
+	 * use 11 bits. They are different so we have to use this function to
+	 * check the vendor ID and use different methods to calculate the
+	 * brightness.
+	 */
+	unsigned int dev_info, vid;
+	int ret;
+
+	ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info);
+	if (ret)
+		return ret;
+
+	vid = FIELD_GET(MT6370_VENID_MASK, dev_info);
+	if (vid == 0x9 || vid == 0xb)
+		priv->vid_type = MT6370_VID_6372;
+	else
+		priv->vid_type = MT6370_VID_COMMON;
+
+	return 0;
+}
+
+static int mt6370_bl_probe(struct platform_device *pdev)
+{
+	struct backlight_properties props = {
+		.type = BACKLIGHT_RAW,
+		.scale = BACKLIGHT_SCALE_LINEAR,
+	};
+	struct device *dev = &pdev->dev;
+	struct mt6370_priv *priv;
+	int ret;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->dev = dev;
+
+	priv->regmap = dev_get_regmap(dev->parent, NULL);
+	if (!priv->regmap)
+		return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
+
+	ret = mt6370_check_vendor_info(priv);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to check vendor info\n");
+
+	priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+						    GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->enable_gpio))
+		dev_err(dev, "Failed to get 'enable' gpio\n");
+
+	ret = mt6370_init_backlight_properties(priv, &props);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to init backlight properties\n");
+
+	priv->bl = devm_backlight_device_register(dev, pdev->name, dev, priv,
+						  &mt6370_bl_ops, &props);
+	if (IS_ERR(priv->bl))
+		return dev_err_probe(dev, PTR_ERR(priv->bl),
+				     "Failed to register backlight\n");
+
+	backlight_update_status(priv->bl);
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+}
+
+static int mt6370_bl_remove(struct platform_device *pdev)
+{
+	struct mt6370_priv *priv = platform_get_drvdata(pdev);
+	struct backlight_device *bl_dev = priv->bl;
+
+	bl_dev->props.brightness = 0;
+	backlight_update_status(priv->bl);
+
+	return 0;
+}
+
+static const struct of_device_id __maybe_unused mt6370_bl_of_match[] = {
+	{ .compatible = "mediatek,mt6370-backlight", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, mt6370_bl_of_match);
+
+static struct platform_driver mt6370_bl_driver = {
+	.driver = {
+		.name = "mt6370-backlight",
+		.of_match_table = mt6370_bl_of_match,
+	},
+	.probe = mt6370_bl_probe,
+	.remove = mt6370_bl_remove,
+};
+module_platform_driver(mt6370_bl_driver);
+
+MODULE_AUTHOR("ChiaEn Wu <chiaen_wu@richtek.com>");
+MODULE_DESCRIPTION("MediaTek MT6370 Backlight Driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-22 10:48     ` AngeloGioacchino Del Regno
  -1 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:48 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> ---
> 
> v6
> - Use 'GENMASK' instead of 'BIT'.
> - Use dev_err_probe to decrease LOC.
> - Use 'dev' variable to make probe function more clean.
> - Refine the return of _mt6370_flash_brightness_set function.
> - Refine the descriptions.
> - Use mt6370_clamp() instead of clamp_align().
> - Use device resource managed API for v4l2 flash_release.
> ---
>   drivers/leds/flash/Kconfig             |  12 +
>   drivers/leds/flash/Makefile            |   1 +
>   drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
>   3 files changed, 646 insertions(+)
>   create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
> 
> diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
> index d3eb689..d5761ed 100644
> --- a/drivers/leds/flash/Kconfig
> +++ b/drivers/leds/flash/Kconfig
> @@ -90,4 +90,16 @@ config LEDS_SGM3140
>   	  This option enables support for the SGM3140 500mA Buck/Boost Charge
>   	  Pump LED Driver.
>   
> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS
> +	depends on MFD_MT6370
> +	help
> +	  Support 2 channels and torch/strobe mode.
> +	  Say Y here to enable support for
> +	  MT6370_FLASH_LED device.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "leds-mt6370-flash".
> +
>   endif # LEDS_CLASS_FLASH
> diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
> index 0acbddc..4c4c171 100644
> --- a/drivers/leds/flash/Makefile
> +++ b/drivers/leds/flash/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
>   obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
>   obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
>   obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
> +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
> diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
> new file mode 100644
> index 0000000..fe439ee
> --- /dev/null
> +++ b/drivers/leds/flash/leds-mt6370-flash.c
> @@ -0,0 +1,633 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/led-class-flash.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#include <media/v4l2-flash-led-class.h>
> +
> +enum {
> +	MT6370_LED_FLASH1,
> +	MT6370_LED_FLASH2,
> +	MT6370_MAX_LEDS
> +};
> +
> +/* Virtual definition for multicolor */
> +
> +#define MT6370_REG_FLEDEN		0x17E
> +#define MT6370_REG_STRBTO		0x173
> +#define MT6370_REG_CHGSTAT2		0x1D1
> +#define MT6370_REG_FLEDSTAT1		0x1D9
> +#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)

Please fix the indentation.

> +#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
> +#define MT6370_ITORCH_MASK		GENMASK(4, 0)
> +#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
> +#define MT6370_STRBTO_MASK		GENMASK(6, 0)
> +#define MT6370_TORCHEN_MASK		BIT(3)

..snip..

> +
> +static int mt6370_init_flash_properties(struct mt6370_led *led,
> +					struct led_init_data *init_data)
> +{
> +	struct led_classdev_flash *flash = &led->flash;
> +	struct led_classdev *lcdev = &flash->led_cdev;
> +	struct mt6370_priv *priv = led->priv;
> +	struct led_flash_setting *s;
> +	u32 sources[MT6370_MAX_LEDS];
> +	u32 max_uA, val;
> +	int i, ret, num;
> +
> +	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
> +	if (num < 1 || num > MT6370_MAX_LEDS)
> +		return dev_err_probe(priv->dev, -EINVAL,
> +				     "Not specified or wrong number of led-sources\n");
> +
> +	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < num; i++) {
> +		if (sources[i] >= MT6370_MAX_LEDS)
> +			return -EINVAL;
> +		if (priv->leds_active & BIT(sources[i]))
> +			return -EINVAL;
> +		priv->leds_active |= BIT(sources[i]);
> +
> +	}
> +	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
> +		       sources[0];
> +
> +	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified led-max-microamp, config to the minimum\n");

This should be a dev_info() instead.

> +		val = MT6370_ITORCH_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
> +				  MT6370_ITORCH_STEP_UA);
> +	}
> +
> +	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
> +				MT6370_ITORCH_STEP_UA + 1;
> +	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
> +	lcdev->flags |= LED_DEV_CAP_FLASH;
> +
> +	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +		   "Not specified flash-max-microamp, config to the minimum\n");

same here

> +		val = MT6370_ISTRB_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
> +				  MT6370_ISTRB_STEP_UA);
> +	}
> +
> +	s = &flash->brightness;
> +	s->min = MT6370_ISTRB_MIN_UA;
> +	s->step = MT6370_ISTRB_STEP_UA;
> +	s->val = s->max = val;
> +
> +	/*
> +	 * Always configure as min level when off to
> +	 * prevent flash current spike
> +	 */
> +	ret = _mt6370_flash_brightness_set(flash, s->min);
> +	if (ret)
> +		return ret;
> +
> +	ret = fwnode_property_read_u32(init_data->fwnode,
> +				       "flash-max-timeout-us", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified flash-max-timeout-us, config to the minimum\n");

and same here

> +		val = MT6370_STRBTO_MIN_US;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
> +				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
> +	}
> +
> +	s = &flash->timeout;
> +	s->min = MT6370_STRBTO_MIN_US;
> +	s->step = MT6370_STRBTO_STEP_US;
> +	s->val = s->max = val;
> +
> +	flash->ops = &mt6370_flash_ops;
> +
> +	return 0;
> +}
> +
> +static int mt6370_init_common_properties(struct mt6370_led *led,
> +					 struct led_init_data *init_data)
> +{
> +	const char * const states[] = { "off", "keep", "on" };
> +	const char *str = states[STATE_OFF];
> +	int ret;
> +
> +	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
> +	ret = match_string(states, ARRAY_SIZE(states), str);
> +	if (ret >= 0)
> +		led->default_state = ret;
> +
> +	return 0;
> +}
> +
> +static int mt6370_led_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mt6370_priv *priv;
> +	struct fwnode_handle *child;
> +	size_t count;
> +	int i = 0, ret;
> +
> +	count = device_get_child_node_count(dev);
> +	if (!count || count > MT6370_MAX_LEDS)
> +		return dev_err_probe(dev, -EINVAL,
> +		       "No child node or node count over max led number %zu\n", count);
> +
> +	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->leds_count = count;
> +	priv->dev = dev;
> +	mutex_init(&priv->lock);
> +
> +	priv->regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
> +
> +	device_for_each_child_node(dev, child) {
> +		struct mt6370_led *led = priv->leds + i;
> +		struct led_init_data init_data = { .fwnode = child, };
> +
> +		led->priv = priv;
> +		ret = mt6370_init_common_properties(led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_init_flash_properties(led, &init_data);
> +

Unnecessary blank line here.

> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_led_register(dev, led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_led_of_id[] = {
> +	{ .compatible = "mediatek,mt6370-flashlight" },

As common practice, write that the last element is a sentinel.

	{ /* sentinel */ },


Everything else looks good.

Regards,
Angelo


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-22 10:48     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:48 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> ---
> 
> v6
> - Use 'GENMASK' instead of 'BIT'.
> - Use dev_err_probe to decrease LOC.
> - Use 'dev' variable to make probe function more clean.
> - Refine the return of _mt6370_flash_brightness_set function.
> - Refine the descriptions.
> - Use mt6370_clamp() instead of clamp_align().
> - Use device resource managed API for v4l2 flash_release.
> ---
>   drivers/leds/flash/Kconfig             |  12 +
>   drivers/leds/flash/Makefile            |   1 +
>   drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
>   3 files changed, 646 insertions(+)
>   create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
> 
> diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
> index d3eb689..d5761ed 100644
> --- a/drivers/leds/flash/Kconfig
> +++ b/drivers/leds/flash/Kconfig
> @@ -90,4 +90,16 @@ config LEDS_SGM3140
>   	  This option enables support for the SGM3140 500mA Buck/Boost Charge
>   	  Pump LED Driver.
>   
> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS
> +	depends on MFD_MT6370
> +	help
> +	  Support 2 channels and torch/strobe mode.
> +	  Say Y here to enable support for
> +	  MT6370_FLASH_LED device.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "leds-mt6370-flash".
> +
>   endif # LEDS_CLASS_FLASH
> diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
> index 0acbddc..4c4c171 100644
> --- a/drivers/leds/flash/Makefile
> +++ b/drivers/leds/flash/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
>   obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
>   obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
>   obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
> +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
> diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
> new file mode 100644
> index 0000000..fe439ee
> --- /dev/null
> +++ b/drivers/leds/flash/leds-mt6370-flash.c
> @@ -0,0 +1,633 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/led-class-flash.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#include <media/v4l2-flash-led-class.h>
> +
> +enum {
> +	MT6370_LED_FLASH1,
> +	MT6370_LED_FLASH2,
> +	MT6370_MAX_LEDS
> +};
> +
> +/* Virtual definition for multicolor */
> +
> +#define MT6370_REG_FLEDEN		0x17E
> +#define MT6370_REG_STRBTO		0x173
> +#define MT6370_REG_CHGSTAT2		0x1D1
> +#define MT6370_REG_FLEDSTAT1		0x1D9
> +#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)

Please fix the indentation.

> +#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
> +#define MT6370_ITORCH_MASK		GENMASK(4, 0)
> +#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
> +#define MT6370_STRBTO_MASK		GENMASK(6, 0)
> +#define MT6370_TORCHEN_MASK		BIT(3)

..snip..

> +
> +static int mt6370_init_flash_properties(struct mt6370_led *led,
> +					struct led_init_data *init_data)
> +{
> +	struct led_classdev_flash *flash = &led->flash;
> +	struct led_classdev *lcdev = &flash->led_cdev;
> +	struct mt6370_priv *priv = led->priv;
> +	struct led_flash_setting *s;
> +	u32 sources[MT6370_MAX_LEDS];
> +	u32 max_uA, val;
> +	int i, ret, num;
> +
> +	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
> +	if (num < 1 || num > MT6370_MAX_LEDS)
> +		return dev_err_probe(priv->dev, -EINVAL,
> +				     "Not specified or wrong number of led-sources\n");
> +
> +	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < num; i++) {
> +		if (sources[i] >= MT6370_MAX_LEDS)
> +			return -EINVAL;
> +		if (priv->leds_active & BIT(sources[i]))
> +			return -EINVAL;
> +		priv->leds_active |= BIT(sources[i]);
> +
> +	}
> +	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
> +		       sources[0];
> +
> +	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified led-max-microamp, config to the minimum\n");

This should be a dev_info() instead.

> +		val = MT6370_ITORCH_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
> +				  MT6370_ITORCH_STEP_UA);
> +	}
> +
> +	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
> +				MT6370_ITORCH_STEP_UA + 1;
> +	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
> +	lcdev->flags |= LED_DEV_CAP_FLASH;
> +
> +	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +		   "Not specified flash-max-microamp, config to the minimum\n");

same here

> +		val = MT6370_ISTRB_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
> +				  MT6370_ISTRB_STEP_UA);
> +	}
> +
> +	s = &flash->brightness;
> +	s->min = MT6370_ISTRB_MIN_UA;
> +	s->step = MT6370_ISTRB_STEP_UA;
> +	s->val = s->max = val;
> +
> +	/*
> +	 * Always configure as min level when off to
> +	 * prevent flash current spike
> +	 */
> +	ret = _mt6370_flash_brightness_set(flash, s->min);
> +	if (ret)
> +		return ret;
> +
> +	ret = fwnode_property_read_u32(init_data->fwnode,
> +				       "flash-max-timeout-us", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified flash-max-timeout-us, config to the minimum\n");

and same here

> +		val = MT6370_STRBTO_MIN_US;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
> +				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
> +	}
> +
> +	s = &flash->timeout;
> +	s->min = MT6370_STRBTO_MIN_US;
> +	s->step = MT6370_STRBTO_STEP_US;
> +	s->val = s->max = val;
> +
> +	flash->ops = &mt6370_flash_ops;
> +
> +	return 0;
> +}
> +
> +static int mt6370_init_common_properties(struct mt6370_led *led,
> +					 struct led_init_data *init_data)
> +{
> +	const char * const states[] = { "off", "keep", "on" };
> +	const char *str = states[STATE_OFF];
> +	int ret;
> +
> +	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
> +	ret = match_string(states, ARRAY_SIZE(states), str);
> +	if (ret >= 0)
> +		led->default_state = ret;
> +
> +	return 0;
> +}
> +
> +static int mt6370_led_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mt6370_priv *priv;
> +	struct fwnode_handle *child;
> +	size_t count;
> +	int i = 0, ret;
> +
> +	count = device_get_child_node_count(dev);
> +	if (!count || count > MT6370_MAX_LEDS)
> +		return dev_err_probe(dev, -EINVAL,
> +		       "No child node or node count over max led number %zu\n", count);
> +
> +	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->leds_count = count;
> +	priv->dev = dev;
> +	mutex_init(&priv->lock);
> +
> +	priv->regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
> +
> +	device_for_each_child_node(dev, child) {
> +		struct mt6370_led *led = priv->leds + i;
> +		struct led_init_data init_data = { .fwnode = child, };
> +
> +		led->priv = priv;
> +		ret = mt6370_init_common_properties(led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_init_flash_properties(led, &init_data);
> +

Unnecessary blank line here.

> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_led_register(dev, led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_led_of_id[] = {
> +	{ .compatible = "mediatek,mt6370-flashlight" },

As common practice, write that the last element is a sentinel.

	{ /* sentinel */ },


Everything else looks good.

Regards,
Angelo


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-22 10:48     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:48 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> ---
> 
> v6
> - Use 'GENMASK' instead of 'BIT'.
> - Use dev_err_probe to decrease LOC.
> - Use 'dev' variable to make probe function more clean.
> - Refine the return of _mt6370_flash_brightness_set function.
> - Refine the descriptions.
> - Use mt6370_clamp() instead of clamp_align().
> - Use device resource managed API for v4l2 flash_release.
> ---
>   drivers/leds/flash/Kconfig             |  12 +
>   drivers/leds/flash/Makefile            |   1 +
>   drivers/leds/flash/leds-mt6370-flash.c | 633 +++++++++++++++++++++++++++++++++
>   3 files changed, 646 insertions(+)
>   create mode 100644 drivers/leds/flash/leds-mt6370-flash.c
> 
> diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
> index d3eb689..d5761ed 100644
> --- a/drivers/leds/flash/Kconfig
> +++ b/drivers/leds/flash/Kconfig
> @@ -90,4 +90,16 @@ config LEDS_SGM3140
>   	  This option enables support for the SGM3140 500mA Buck/Boost Charge
>   	  Pump LED Driver.
>   
> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS
> +	depends on MFD_MT6370
> +	help
> +	  Support 2 channels and torch/strobe mode.
> +	  Say Y here to enable support for
> +	  MT6370_FLASH_LED device.
> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "leds-mt6370-flash".
> +
>   endif # LEDS_CLASS_FLASH
> diff --git a/drivers/leds/flash/Makefile b/drivers/leds/flash/Makefile
> index 0acbddc..4c4c171 100644
> --- a/drivers/leds/flash/Makefile
> +++ b/drivers/leds/flash/Makefile
> @@ -9,3 +9,4 @@ obj-$(CONFIG_LEDS_MAX77693)	+= leds-max77693.o
>   obj-$(CONFIG_LEDS_RT4505)	+= leds-rt4505.o
>   obj-$(CONFIG_LEDS_RT8515)	+= leds-rt8515.o
>   obj-$(CONFIG_LEDS_SGM3140)	+= leds-sgm3140.o
> +obj-$(CONFIG_LEDS_MT6370_FLASHLIGHT)	+= leds-mt6370-flash.o
> diff --git a/drivers/leds/flash/leds-mt6370-flash.c b/drivers/leds/flash/leds-mt6370-flash.c
> new file mode 100644
> index 0000000..fe439ee
> --- /dev/null
> +++ b/drivers/leds/flash/leds-mt6370-flash.c
> @@ -0,0 +1,633 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/led-class-flash.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#include <media/v4l2-flash-led-class.h>
> +
> +enum {
> +	MT6370_LED_FLASH1,
> +	MT6370_LED_FLASH2,
> +	MT6370_MAX_LEDS
> +};
> +
> +/* Virtual definition for multicolor */
> +
> +#define MT6370_REG_FLEDEN		0x17E
> +#define MT6370_REG_STRBTO		0x173
> +#define MT6370_REG_CHGSTAT2		0x1D1
> +#define MT6370_REG_FLEDSTAT1		0x1D9
> +#define	MT6370_REG_FLEDISTRB(_id)	(0x174 + 4 * _id)

Please fix the indentation.

> +#define MT6370_REG_FLEDITOR(_id)	(0x175 + 4 * _id)
> +#define MT6370_ITORCH_MASK		GENMASK(4, 0)
> +#define MT6370_ISTROBE_MASK		GENMASK(6, 0)
> +#define MT6370_STRBTO_MASK		GENMASK(6, 0)
> +#define MT6370_TORCHEN_MASK		BIT(3)

..snip..

> +
> +static int mt6370_init_flash_properties(struct mt6370_led *led,
> +					struct led_init_data *init_data)
> +{
> +	struct led_classdev_flash *flash = &led->flash;
> +	struct led_classdev *lcdev = &flash->led_cdev;
> +	struct mt6370_priv *priv = led->priv;
> +	struct led_flash_setting *s;
> +	u32 sources[MT6370_MAX_LEDS];
> +	u32 max_uA, val;
> +	int i, ret, num;
> +
> +	num = fwnode_property_count_u32(init_data->fwnode, "led-sources");
> +	if (num < 1 || num > MT6370_MAX_LEDS)
> +		return dev_err_probe(priv->dev, -EINVAL,
> +				     "Not specified or wrong number of led-sources\n");
> +
> +	ret = fwnode_property_read_u32_array(init_data->fwnode, "led-sources", sources, num);
> +	if (ret)
> +		return ret;
> +
> +	for (i = 0; i < num; i++) {
> +		if (sources[i] >= MT6370_MAX_LEDS)
> +			return -EINVAL;
> +		if (priv->leds_active & BIT(sources[i]))
> +			return -EINVAL;
> +		priv->leds_active |= BIT(sources[i]);
> +
> +	}
> +	led->led_no = (num == MT6370_MAX_LEDS) ? MT6370_LED_JOINT :
> +		       sources[0];
> +
> +	max_uA = (num == 2) ? MT6370_ITORCH_DOUBLE_MAX_UA : MT6370_ITORCH_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified led-max-microamp, config to the minimum\n");

This should be a dev_info() instead.

> +		val = MT6370_ITORCH_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ITORCH_MIN_UA, max_uA,
> +				  MT6370_ITORCH_STEP_UA);
> +	}
> +
> +	lcdev->max_brightness = (val - MT6370_ITORCH_MIN_UA) /
> +				MT6370_ITORCH_STEP_UA + 1;
> +	lcdev->brightness_set_blocking = mt6370_torch_brightness_set;
> +	lcdev->flags |= LED_DEV_CAP_FLASH;
> +
> +	max_uA = (num == 2) ? MT6370_ISTRB_DOUBLE_MAX_UA : MT6370_ISTRB_MAX_UA;
> +	ret = fwnode_property_read_u32(init_data->fwnode, "flash-max-microamp", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +		   "Not specified flash-max-microamp, config to the minimum\n");

same here

> +		val = MT6370_ISTRB_MIN_UA;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_ISTRB_MIN_UA, max_uA,
> +				  MT6370_ISTRB_STEP_UA);
> +	}
> +
> +	s = &flash->brightness;
> +	s->min = MT6370_ISTRB_MIN_UA;
> +	s->step = MT6370_ISTRB_STEP_UA;
> +	s->val = s->max = val;
> +
> +	/*
> +	 * Always configure as min level when off to
> +	 * prevent flash current spike
> +	 */
> +	ret = _mt6370_flash_brightness_set(flash, s->min);
> +	if (ret)
> +		return ret;
> +
> +	ret = fwnode_property_read_u32(init_data->fwnode,
> +				       "flash-max-timeout-us", &val);
> +	if (ret) {
> +		dev_warn(priv->dev,
> +			 "Not specified flash-max-timeout-us, config to the minimum\n");

and same here

> +		val = MT6370_STRBTO_MIN_US;
> +	} else {
> +		val = mt6370_clamp(val, MT6370_STRBTO_MIN_US,
> +				   MT6370_STRBTO_MAX_US, MT6370_STRBTO_STEP_US);
> +	}
> +
> +	s = &flash->timeout;
> +	s->min = MT6370_STRBTO_MIN_US;
> +	s->step = MT6370_STRBTO_STEP_US;
> +	s->val = s->max = val;
> +
> +	flash->ops = &mt6370_flash_ops;
> +
> +	return 0;
> +}
> +
> +static int mt6370_init_common_properties(struct mt6370_led *led,
> +					 struct led_init_data *init_data)
> +{
> +	const char * const states[] = { "off", "keep", "on" };
> +	const char *str = states[STATE_OFF];
> +	int ret;
> +
> +	fwnode_property_read_string(init_data->fwnode, "default-state", &str);
> +	ret = match_string(states, ARRAY_SIZE(states), str);
> +	if (ret >= 0)
> +		led->default_state = ret;
> +
> +	return 0;
> +}
> +
> +static int mt6370_led_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct mt6370_priv *priv;
> +	struct fwnode_handle *child;
> +	size_t count;
> +	int i = 0, ret;
> +
> +	count = device_get_child_node_count(dev);
> +	if (!count || count > MT6370_MAX_LEDS)
> +		return dev_err_probe(dev, -EINVAL,
> +		       "No child node or node count over max led number %zu\n", count);
> +
> +	priv = devm_kzalloc(dev, struct_size(priv, leds, count), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->leds_count = count;
> +	priv->dev = dev;
> +	mutex_init(&priv->lock);
> +
> +	priv->regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to get parent regmap\n");
> +
> +	device_for_each_child_node(dev, child) {
> +		struct mt6370_led *led = priv->leds + i;
> +		struct led_init_data init_data = { .fwnode = child, };
> +
> +		led->priv = priv;
> +		ret = mt6370_init_common_properties(led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_init_flash_properties(led, &init_data);
> +

Unnecessary blank line here.

> +		if (ret)
> +			return ret;
> +
> +		ret = mt6370_led_register(dev, led, &init_data);
> +		if (ret)
> +			return ret;
> +
> +		i++;
> +	}
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_led_of_id[] = {
> +	{ .compatible = "mediatek,mt6370-flashlight" },

As common practice, write that the last element is a sentinel.

	{ /* sentinel */ },


Everything else looks good.

Regards,
Angelo


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-22 10:52     ` AngeloGioacchino Del Regno
  -1 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:52 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

> ---
> 
> v6
> - Remove the 'ko' from mt6370 led Kconfig description.
> - Add both authors for Alice and ChiYuan.
> - Use pdata to distinguish the code from mt6370/71 to mt6372.
> - Instead of 'state' define, use the 'state' enum.
> - Fix the typo for 'MT6372_PMW_DUTY'.
> - For pwm_duty define, replace with bit macro - 1.
> - Refine all the labels from 'out' to 'out_unlock'.
> - Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
> - Revise for the array initialization from {0} to {}.
> - Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
> - Refine the 'comma' usage in struct/enum.
> ---
>   drivers/leds/rgb/Kconfig           |   13 +
>   drivers/leds/rgb/Makefile          |    1 +
>   drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 1018 insertions(+)
>   create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
> 

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-22 10:52     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:52 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

> ---
> 
> v6
> - Remove the 'ko' from mt6370 led Kconfig description.
> - Add both authors for Alice and ChiYuan.
> - Use pdata to distinguish the code from mt6370/71 to mt6372.
> - Instead of 'state' define, use the 'state' enum.
> - Fix the typo for 'MT6372_PMW_DUTY'.
> - For pwm_duty define, replace with bit macro - 1.
> - Refine all the labels from 'out' to 'out_unlock'.
> - Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
> - Revise for the array initialization from {0} to {}.
> - Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
> - Refine the 'comma' usage in struct/enum.
> ---
>   drivers/leds/rgb/Kconfig           |   13 +
>   drivers/leds/rgb/Makefile          |    1 +
>   drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 1018 insertions(+)
>   create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
> 

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-22 10:52     ` AngeloGioacchino Del Regno
  0 siblings, 0 replies; 154+ messages in thread
From: AngeloGioacchino Del Regno @ 2022-07-22 10:52 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, linux, heikki.krogerus,
	deller, andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

Il 22/07/22 12:24, ChiaEn Wu ha scritto:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

> ---
> 
> v6
> - Remove the 'ko' from mt6370 led Kconfig description.
> - Add both authors for Alice and ChiYuan.
> - Use pdata to distinguish the code from mt6370/71 to mt6372.
> - Instead of 'state' define, use the 'state' enum.
> - Fix the typo for 'MT6372_PMW_DUTY'.
> - For pwm_duty define, replace with bit macro - 1.
> - Refine all the labels from 'out' to 'out_unlock'.
> - Use struct 'dev' variable and 'dev_err_probe' to optimize the LOC.
> - Revise for the array initialization from {0} to {}.
> - Move into rgb folder and rename file name to 'leds-mt6370-rgb'.
> - Refine the 'comma' usage in struct/enum.
> ---
>   drivers/leds/rgb/Kconfig           |   13 +
>   drivers/leds/rgb/Makefile          |    1 +
>   drivers/leds/rgb/leds-mt6370-rgb.c | 1004 ++++++++++++++++++++++++++++++++++++
>   3 files changed, 1018 insertions(+)
>   create mode 100644 drivers/leds/rgb/leds-mt6370-rgb.c
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-22 14:19     ` Guenter Roeck
  -1 siblings, 0 replies; 154+ messages in thread
From: Guenter Roeck @ 2022-07-22 14:19 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

On 7/22/22 03:24, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
> 
> v6
> - Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>   drivers/usb/typec/tcpm/Kconfig        |  11 ++
>   drivers/usb/typec/tcpm/Makefile       |   1 +
>   drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
>   3 files changed, 220 insertions(+)
>   create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>   	  USB Type-C. It works with Type-C Port Controller Manager
>   	  to provide USB PD and USB Type-C functionalities.
>   
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>   config TYPEC_TCPCI_MAXIM
>   	tristate "Maxim TCPCI based Type-C chip driver"
>   	help
> diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>   obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>   obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>   obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>   obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
> +				bool source, bool sink)
> +{
> +	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n", vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci port\n");
> +
> +	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev), priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-22 14:19     ` Guenter Roeck
  0 siblings, 0 replies; 154+ messages in thread
From: Guenter Roeck @ 2022-07-22 14:19 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds,
	AngeloGioacchino Del Regno

On 7/22/22 03:24, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
> 
> v6
> - Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>   drivers/usb/typec/tcpm/Kconfig        |  11 ++
>   drivers/usb/typec/tcpm/Makefile       |   1 +
>   drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
>   3 files changed, 220 insertions(+)
>   create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>   	  USB Type-C. It works with Type-C Port Controller Manager
>   	  to provide USB PD and USB Type-C functionalities.
>   
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>   config TYPEC_TCPCI_MAXIM
>   	tristate "Maxim TCPCI based Type-C chip driver"
>   	help
> diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>   obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>   obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>   obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>   obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
> +				bool source, bool sink)
> +{
> +	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n", vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci port\n");
> +
> +	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev), priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-22 14:19     ` Guenter Roeck
  0 siblings, 0 replies; 154+ messages in thread
From: Guenter Roeck @ 2022-07-22 14:19 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun,
	gregkh, jic23, lars, lgirdwood, broonie, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

On 7/22/22 03:24, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
> 
> v6
> - Convert tcpci as device resource managed with 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>   drivers/usb/typec/tcpm/Kconfig        |  11 ++
>   drivers/usb/typec/tcpm/Makefile       |   1 +
>   drivers/usb/typec/tcpm/tcpci_mt6370.c | 208 ++++++++++++++++++++++++++++++++++
>   3 files changed, 220 insertions(+)
>   create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>   	  USB Type-C. It works with Type-C Port Controller Manager
>   	  to provide USB PD and USB Type-C functionalities.
>   
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>   config TYPEC_TCPCI_MAXIM
>   	tristate "Maxim TCPCI based Type-C chip driver"
>   	help
> diff --git a/drivers/usb/typec/tcpm/Makefile b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>   obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>   obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>   obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>   obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL, 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct tcpci_data *data,
> +				bool source, bool sink)
> +{
> +	struct mt6370_priv *priv = container_of(data, struct mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid, sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n", vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci port\n");
> +
> +	ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL, mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev), priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface Driver");
> +MODULE_LICENSE("GPL v2");


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  7:06     ` Chunfeng Yun
  -1 siblings, 0 replies; 154+ messages in thread
From: Chunfeng Yun @ 2022-07-25  7:06 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <
> angelogioacchino.delregno@collabora.com>
> ---
> 
> v6
> - Convert tcpci as device resource managed with
> 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>  drivers/usb/typec/tcpm/Kconfig        |  11 ++
>  drivers/usb/typec/tcpm/Makefile       |   1 +
>  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 220 insertions(+)
>  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig
> b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>  	  USB Type-C. It works with Type-C Port Controller Manager
>  	  to provide USB PD and USB Type-C functionalities.
>  
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>  config TYPEC_TCPCI_MAXIM
>  	tristate "Maxim TCPCI based Type-C chip driver"
>  	help
> diff --git a/drivers/usb/typec/tcpm/Makefile
> b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>  obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>  obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>  obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				bool source, bool sink)
@sink is not used in this function?

> +{
> +	struct mt6370_priv *priv = container_of(data, struct
> mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n",
> vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init
> regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci
> port\n");
> +
> +	ret = devm_add_action_or_reset(dev,
> mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL,
> mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev),
> priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate
> irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> Driver");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  7:06     ` Chunfeng Yun
  0 siblings, 0 replies; 154+ messages in thread
From: Chunfeng Yun @ 2022-07-25  7:06 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: devicetree, linux-fbdev, szunichen, alice_chen, linux-pm,
	linux-iio, linux-usb, linux-kernel, dri-devel, cy_huang,
	chiaen_wu, linux-mediatek, linux-arm-kernel, linux-leds,
	AngeloGioacchino Del Regno

On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <
> angelogioacchino.delregno@collabora.com>
> ---
> 
> v6
> - Convert tcpci as device resource managed with
> 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>  drivers/usb/typec/tcpm/Kconfig        |  11 ++
>  drivers/usb/typec/tcpm/Makefile       |   1 +
>  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 220 insertions(+)
>  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig
> b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>  	  USB Type-C. It works with Type-C Port Controller Manager
>  	  to provide USB PD and USB Type-C functionalities.
>  
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>  config TYPEC_TCPCI_MAXIM
>  	tristate "Maxim TCPCI based Type-C chip driver"
>  	help
> diff --git a/drivers/usb/typec/tcpm/Makefile
> b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>  obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>  obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>  obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				bool source, bool sink)
@sink is not used in this function?

> +{
> +	struct mt6370_priv *priv = container_of(data, struct
> mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n",
> vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init
> regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci
> port\n");
> +
> +	ret = devm_add_action_or_reset(dev,
> mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL,
> mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev),
> priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate
> irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> Driver");
> +MODULE_LICENSE("GPL v2");


^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  7:06     ` Chunfeng Yun
  0 siblings, 0 replies; 154+ messages in thread
From: Chunfeng Yun @ 2022-07-25  7:06 UTC (permalink / raw)
  To: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, pavel,
	robh+dt, krzysztof.kozlowski+dt, matthias.bgg, sre, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko
  Cc: chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen,
	AngeloGioacchino Del Regno

On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.
> 
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: AngeloGioacchino Del Regno <
> angelogioacchino.delregno@collabora.com>
> ---
> 
> v6
> - Convert tcpci as device resource managed with
> 'devm_add_action_or_reset' API.
> - Refine remvoe callback.
> - Refine the commit text from 'This commit add' to 'Add'.
> ---
>  drivers/usb/typec/tcpm/Kconfig        |  11 ++
>  drivers/usb/typec/tcpm/Makefile       |   1 +
>  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> ++++++++++++++++++++++++++++++++++
>  3 files changed, 220 insertions(+)
>  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> 
> diff --git a/drivers/usb/typec/tcpm/Kconfig
> b/drivers/usb/typec/tcpm/Kconfig
> index 073fd2e..e6b88ca 100644
> --- a/drivers/usb/typec/tcpm/Kconfig
> +++ b/drivers/usb/typec/tcpm/Kconfig
> @@ -35,6 +35,17 @@ config TYPEC_MT6360
>  	  USB Type-C. It works with Type-C Port Controller Manager
>  	  to provide USB PD and USB Type-C functionalities.
>  
> +config TYPEC_TCPCI_MT6370
> +	tristate "MediaTek MT6370 Type-C driver"
> +	depends on MFD_MT6370
> +	help
> +	  MediaTek MT6370 is a multi-functional IC that includes
> +	  USB Type-C. It works with Type-C Port Controller Manager
> +	  to provide USB PD and USB Type-C functionalities.
> +
> +	  This driver can also be built as a module. The module
> +	  will be called "tcpci_mt6370".
> +
>  config TYPEC_TCPCI_MAXIM
>  	tristate "Maxim TCPCI based Type-C chip driver"
>  	help
> diff --git a/drivers/usb/typec/tcpm/Makefile
> b/drivers/usb/typec/tcpm/Makefile
> index 7d499f3..906d9dc 100644
> --- a/drivers/usb/typec/tcpm/Makefile
> +++ b/drivers/usb/typec/tcpm/Makefile
> @@ -6,4 +6,5 @@ typec_wcove-y				:= wcove.o
>  obj-$(CONFIG_TYPEC_TCPCI)		+= tcpci.o
>  obj-$(CONFIG_TYPEC_RT1711H)		+= tcpci_rt1711h.o
>  obj-$(CONFIG_TYPEC_MT6360)		+= tcpci_mt6360.o
> +obj-$(CONFIG_TYPEC_TCPCI_MT6370)	+= tcpci_mt6370.o
>  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)		+= tcpci_maxim.o
> diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> new file mode 100644
> index 0000000..4f53319
> --- /dev/null
> +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> @@ -0,0 +1,208 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: ChiYuan Huang <cy_huang@richtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_wakeup.h>
> +#include <linux/pm_wakeirq.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/usb/tcpm.h>
> +#include "tcpci.h"
> +
> +#define MT6370_REG_SYSCTRL8	0x9B
> +
> +#define MT6370_AUTOIDLE_MASK	BIT(3)
> +
> +#define MT6370_VENDOR_ID	0x29CF
> +#define MT6370_TCPC_DID_A	0x2170
> +
> +struct mt6370_priv {
> +	struct device *dev;
> +	struct regulator *vbus;
> +	struct tcpci *tcpci;
> +	struct tcpci_data tcpci_data;
> +};
> +
> +static const struct reg_sequence mt6370_reg_init[] = {
> +	REG_SEQ(0xA0, 0x1, 1000),
> +	REG_SEQ(0x81, 0x38, 0),
> +	REG_SEQ(0x82, 0x82, 0),
> +	REG_SEQ(0xBA, 0xFC, 0),
> +	REG_SEQ(0xBB, 0x50, 0),
> +	REG_SEQ(0x9E, 0x8F, 0),
> +	REG_SEQ(0xA1, 0x5, 0),
> +	REG_SEQ(0xA2, 0x4, 0),
> +	REG_SEQ(0xA3, 0x4A, 0),
> +	REG_SEQ(0xA4, 0x01, 0),
> +	REG_SEQ(0x95, 0x01, 0),
> +	REG_SEQ(0x80, 0x71, 0),
> +	REG_SEQ(0x9B, 0x3A, 1000),
> +};
> +
> +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> *data)
> +{
> +	u16 did;
> +	int ret;
> +
> +	ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> +				    ARRAY_SIZE(mt6370_reg_init));
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (did == MT6370_TCPC_DID_A)
> +		return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> 0x80);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				 bool enable)
> +{
> +	return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +				  MT6370_AUTOIDLE_MASK,
> +				  !enable ? MT6370_AUTOIDLE_MASK : 0);
> +}
> +
> +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> tcpci_data *data,
> +				bool source, bool sink)
@sink is not used in this function?

> +{
> +	struct mt6370_priv *priv = container_of(data, struct
> mt6370_priv,
> +						tcpci_data);
> +	int ret;
> +
> +	ret = regulator_is_enabled(priv->vbus);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (ret && !source)
> +		return regulator_disable(priv->vbus);
> +
> +	if (!ret && source)
> +		return regulator_enable(priv->vbus);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> +{
> +	struct mt6370_priv *priv = dev_id;
> +
> +	return tcpci_irq(priv->tcpci);
> +}
> +
> +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> +{
> +	struct regmap *regmap = priv->tcpci_data.regmap;
> +	u16 vid;
> +	int ret;
> +
> +	ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> sizeof(u16));
> +	if (ret)
> +		return ret;
> +
> +	if (vid != MT6370_VENDOR_ID)
> +		return dev_err_probe(priv->dev, -ENODEV,
> +				     "Vendor ID not correct 0x%02x\n",
> vid);
> +
> +	return 0;
> +}
> +
> +static void mt6370_unregister_tcpci_port(void *tcpci)
> +{
> +	tcpci_unregister_port(tcpci);
> +}
> +
> +static int mt6370_tcpc_probe(struct platform_device *pdev)
> +{
> +	struct mt6370_priv *priv;
> +	struct device *dev = &pdev->dev;
> +	int irq, ret;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> +	if (!priv->tcpci_data.regmap)
> +		return dev_err_probe(dev, -ENODEV, "Failed to init
> regmap\n");
> +
> +	ret = mt6370_check_vendor_info(priv);
> +	if (ret)
> +		return ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return dev_err_probe(dev, irq, "Failed to get irq\n");
> +
> +	/* Assign TCPCI feature and ops */
> +	priv->tcpci_data.auto_discharge_disconnect = 1;
> +	priv->tcpci_data.init = mt6370_tcpc_init;
> +	priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> +
> +	priv->vbus = devm_regulator_get_optional(dev, "vbus");
> +	if (!IS_ERR(priv->vbus))
> +		priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> +
> +	priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> +	if (IS_ERR(priv->tcpci))
> +		return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> +				     "Failed to register tcpci
> port\n");
> +
> +	ret = devm_add_action_or_reset(dev,
> mt6370_unregister_tcpci_port,
> +				       priv->tcpci);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_threaded_irq(dev, irq, NULL,
> mt6370_irq_handler,
> +					IRQF_ONESHOT, dev_name(dev),
> priv);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "Failed to allocate
> irq\n");
> +
> +	device_init_wakeup(dev, true);
> +	dev_pm_set_wake_irq(dev, irq);
> +
> +	return 0;
> +}
> +
> +static int mt6370_tcpc_remove(struct platform_device *pdev)
> +{
> +	dev_pm_clear_wake_irq(&pdev->dev);
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> +	{ .compatible = "mediatek,mt6370-tcpc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> +
> +static struct platform_driver mt6370_tcpc_driver = {
> +	.driver = {
> +		.name = "mt6370-tcpc",
> +		.of_match_table = mt6370_tcpc_devid_table,
> +	},
> +	.probe = mt6370_tcpc_probe,
> +	.remove = mt6370_tcpc_remove,
> +};
> +module_platform_driver(mt6370_tcpc_driver);
> +
> +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> Driver");
> +MODULE_LICENSE("GPL v2");
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  2022-07-25  7:06     ` Chunfeng Yun
  (?)
@ 2022-07-25  7:17       ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  7:17 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Mon, Jul 25, 2022 at 3:06 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual
> > Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > Add support for the Type-C & Power Delivery controller in
> > MediaTek MT6370 IC.
> >
> > Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> > Reviewed-by: AngeloGioacchino Del Regno <
> > angelogioacchino.delregno@collabora.com>
> > ---
> >
> > v6
> > - Convert tcpci as device resource managed with
> > 'devm_add_action_or_reset' API.
> > - Refine remvoe callback.
> > - Refine the commit text from 'This commit add' to 'Add'.
> > ---
> >  drivers/usb/typec/tcpm/Kconfig        |  11 ++
> >  drivers/usb/typec/tcpm/Makefile       |   1 +
> >  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 220 insertions(+)
> >  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> >
> > diff --git a/drivers/usb/typec/tcpm/Kconfig
> > b/drivers/usb/typec/tcpm/Kconfig
> > index 073fd2e..e6b88ca 100644
> > --- a/drivers/usb/typec/tcpm/Kconfig
> > +++ b/drivers/usb/typec/tcpm/Kconfig
> > @@ -35,6 +35,17 @@ config TYPEC_MT6360
> >         USB Type-C. It works with Type-C Port Controller Manager
> >         to provide USB PD and USB Type-C functionalities.
> >
> > +config TYPEC_TCPCI_MT6370
> > +     tristate "MediaTek MT6370 Type-C driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       MediaTek MT6370 is a multi-functional IC that includes
> > +       USB Type-C. It works with Type-C Port Controller Manager
> > +       to provide USB PD and USB Type-C functionalities.
> > +
> > +       This driver can also be built as a module. The module
> > +       will be called "tcpci_mt6370".
> > +
> >  config TYPEC_TCPCI_MAXIM
> >       tristate "Maxim TCPCI based Type-C chip driver"
> >       help
> > diff --git a/drivers/usb/typec/tcpm/Makefile
> > b/drivers/usb/typec/tcpm/Makefile
> > index 7d499f3..906d9dc 100644
> > --- a/drivers/usb/typec/tcpm/Makefile
> > +++ b/drivers/usb/typec/tcpm/Makefile
> > @@ -6,4 +6,5 @@ typec_wcove-y                         := wcove.o
> >  obj-$(CONFIG_TYPEC_TCPCI)            += tcpci.o
> >  obj-$(CONFIG_TYPEC_RT1711H)          += tcpci_rt1711h.o
> >  obj-$(CONFIG_TYPEC_MT6360)           += tcpci_mt6360.o
> > +obj-$(CONFIG_TYPEC_TCPCI_MT6370)     += tcpci_mt6370.o
> >  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)              += tcpci_maxim.o
> > diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > new file mode 100644
> > index 0000000..4f53319
> > --- /dev/null
> > +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > @@ -0,0 +1,208 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
> > + */
> > +
> > +#include <linux/bits.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_wakeup.h>
> > +#include <linux/pm_wakeirq.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/usb/tcpm.h>
> > +#include "tcpci.h"
> > +
> > +#define MT6370_REG_SYSCTRL8  0x9B
> > +
> > +#define MT6370_AUTOIDLE_MASK BIT(3)
> > +
> > +#define MT6370_VENDOR_ID     0x29CF
> > +#define MT6370_TCPC_DID_A    0x2170
> > +
> > +struct mt6370_priv {
> > +     struct device *dev;
> > +     struct regulator *vbus;
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data tcpci_data;
> > +};
> > +
> > +static const struct reg_sequence mt6370_reg_init[] = {
> > +     REG_SEQ(0xA0, 0x1, 1000),
> > +     REG_SEQ(0x81, 0x38, 0),
> > +     REG_SEQ(0x82, 0x82, 0),
> > +     REG_SEQ(0xBA, 0xFC, 0),
> > +     REG_SEQ(0xBB, 0x50, 0),
> > +     REG_SEQ(0x9E, 0x8F, 0),
> > +     REG_SEQ(0xA1, 0x5, 0),
> > +     REG_SEQ(0xA2, 0x4, 0),
> > +     REG_SEQ(0xA3, 0x4A, 0),
> > +     REG_SEQ(0xA4, 0x01, 0),
> > +     REG_SEQ(0x95, 0x01, 0),
> > +     REG_SEQ(0x80, 0x71, 0),
> > +     REG_SEQ(0x9B, 0x3A, 1000),
> > +};
> > +
> > +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> > *data)
> > +{
> > +     u16 did;
> > +     int ret;
> > +
> > +     ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> > +                                 ARRAY_SIZE(mt6370_reg_init));
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (did == MT6370_TCPC_DID_A)
> > +             return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> > 0x80);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                              bool enable)
> > +{
> > +     return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> > +                               MT6370_AUTOIDLE_MASK,
> > +                               !enable ? MT6370_AUTOIDLE_MASK : 0);
> > +}
> > +
> > +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                             bool source, bool sink)
> @sink is not used in this function?

Hi Chunfeng,
The default HW binding is using the mt6370 switching charger.
Due to the switching charger design, 'src usb boost' and 'sink battery
charger', only one can be used at the same time.
Thanks.

>
> > +{
> > +     struct mt6370_priv *priv = container_of(data, struct
> > mt6370_priv,
> > +                                             tcpci_data);
> > +     int ret;
> > +
> > +     ret = regulator_is_enabled(priv->vbus);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     if (ret && !source)
> > +             return regulator_disable(priv->vbus);
> > +
> > +     if (!ret && source)
> > +             return regulator_enable(priv->vbus);
> > +
> > +     return 0;
> > +}
> > +
> > +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> > +{
> > +     struct mt6370_priv *priv = dev_id;
> > +
> > +     return tcpci_irq(priv->tcpci);
> > +}
> > +
> > +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> > +{
> > +     struct regmap *regmap = priv->tcpci_data.regmap;
> > +     u16 vid;
> > +     int ret;
> > +
> > +     ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (vid != MT6370_VENDOR_ID)
> > +             return dev_err_probe(priv->dev, -ENODEV,
> > +                                  "Vendor ID not correct 0x%02x\n",
> > vid);
> > +
> > +     return 0;
> > +}
> > +
> > +static void mt6370_unregister_tcpci_port(void *tcpci)
> > +{
> > +     tcpci_unregister_port(tcpci);
> > +}
> > +
> > +static int mt6370_tcpc_probe(struct platform_device *pdev)
> > +{
> > +     struct mt6370_priv *priv;
> > +     struct device *dev = &pdev->dev;
> > +     int irq, ret;
> > +
> > +     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     priv->dev = dev;
> > +
> > +     priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> > +     if (!priv->tcpci_data.regmap)
> > +             return dev_err_probe(dev, -ENODEV, "Failed to init
> > regmap\n");
> > +
> > +     ret = mt6370_check_vendor_info(priv);
> > +     if (ret)
> > +             return ret;
> > +
> > +     irq = platform_get_irq(pdev, 0);
> > +     if (irq < 0)
> > +             return dev_err_probe(dev, irq, "Failed to get irq\n");
> > +
> > +     /* Assign TCPCI feature and ops */
> > +     priv->tcpci_data.auto_discharge_disconnect = 1;
> > +     priv->tcpci_data.init = mt6370_tcpc_init;
> > +     priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> > +
> > +     priv->vbus = devm_regulator_get_optional(dev, "vbus");
> > +     if (!IS_ERR(priv->vbus))
> > +             priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> > +
> > +     priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> > +     if (IS_ERR(priv->tcpci))
> > +             return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> > +                                  "Failed to register tcpci
> > port\n");
> > +
> > +     ret = devm_add_action_or_reset(dev,
> > mt6370_unregister_tcpci_port,
> > +                                    priv->tcpci);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = devm_request_threaded_irq(dev, irq, NULL,
> > mt6370_irq_handler,
> > +                                     IRQF_ONESHOT, dev_name(dev),
> > priv);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "Failed to allocate
> > irq\n");
> > +
> > +     device_init_wakeup(dev, true);
> > +     dev_pm_set_wake_irq(dev, irq);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_remove(struct platform_device *pdev)
> > +{
> > +     dev_pm_clear_wake_irq(&pdev->dev);
> > +     device_init_wakeup(&pdev->dev, false);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> > +     { .compatible = "mediatek,mt6370-tcpc" },
> > +     {}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> > +
> > +static struct platform_driver mt6370_tcpc_driver = {
> > +     .driver = {
> > +             .name = "mt6370-tcpc",
> > +             .of_match_table = mt6370_tcpc_devid_table,
> > +     },
> > +     .probe = mt6370_tcpc_probe,
> > +     .remove = mt6370_tcpc_remove,
> > +};
> > +module_platform_driver(mt6370_tcpc_driver);
> > +
> > +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> > +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> > Driver");
> > +MODULE_LICENSE("GPL v2");
>


-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  7:17       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  7:17 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Andy Shevchenko, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List,
	AngeloGioacchino Del Regno, Jingoo Han, USB, Sebastian Reichel,
	Linux Kernel Mailing List, ChiaEn Wu, Greg Kroah-Hartman,
	Jonathan Cameron

On Mon, Jul 25, 2022 at 3:06 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual
> > Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > Add support for the Type-C & Power Delivery controller in
> > MediaTek MT6370 IC.
> >
> > Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> > Reviewed-by: AngeloGioacchino Del Regno <
> > angelogioacchino.delregno@collabora.com>
> > ---
> >
> > v6
> > - Convert tcpci as device resource managed with
> > 'devm_add_action_or_reset' API.
> > - Refine remvoe callback.
> > - Refine the commit text from 'This commit add' to 'Add'.
> > ---
> >  drivers/usb/typec/tcpm/Kconfig        |  11 ++
> >  drivers/usb/typec/tcpm/Makefile       |   1 +
> >  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 220 insertions(+)
> >  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> >
> > diff --git a/drivers/usb/typec/tcpm/Kconfig
> > b/drivers/usb/typec/tcpm/Kconfig
> > index 073fd2e..e6b88ca 100644
> > --- a/drivers/usb/typec/tcpm/Kconfig
> > +++ b/drivers/usb/typec/tcpm/Kconfig
> > @@ -35,6 +35,17 @@ config TYPEC_MT6360
> >         USB Type-C. It works with Type-C Port Controller Manager
> >         to provide USB PD and USB Type-C functionalities.
> >
> > +config TYPEC_TCPCI_MT6370
> > +     tristate "MediaTek MT6370 Type-C driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       MediaTek MT6370 is a multi-functional IC that includes
> > +       USB Type-C. It works with Type-C Port Controller Manager
> > +       to provide USB PD and USB Type-C functionalities.
> > +
> > +       This driver can also be built as a module. The module
> > +       will be called "tcpci_mt6370".
> > +
> >  config TYPEC_TCPCI_MAXIM
> >       tristate "Maxim TCPCI based Type-C chip driver"
> >       help
> > diff --git a/drivers/usb/typec/tcpm/Makefile
> > b/drivers/usb/typec/tcpm/Makefile
> > index 7d499f3..906d9dc 100644
> > --- a/drivers/usb/typec/tcpm/Makefile
> > +++ b/drivers/usb/typec/tcpm/Makefile
> > @@ -6,4 +6,5 @@ typec_wcove-y                         := wcove.o
> >  obj-$(CONFIG_TYPEC_TCPCI)            += tcpci.o
> >  obj-$(CONFIG_TYPEC_RT1711H)          += tcpci_rt1711h.o
> >  obj-$(CONFIG_TYPEC_MT6360)           += tcpci_mt6360.o
> > +obj-$(CONFIG_TYPEC_TCPCI_MT6370)     += tcpci_mt6370.o
> >  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)              += tcpci_maxim.o
> > diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > new file mode 100644
> > index 0000000..4f53319
> > --- /dev/null
> > +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > @@ -0,0 +1,208 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
> > + */
> > +
> > +#include <linux/bits.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_wakeup.h>
> > +#include <linux/pm_wakeirq.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/usb/tcpm.h>
> > +#include "tcpci.h"
> > +
> > +#define MT6370_REG_SYSCTRL8  0x9B
> > +
> > +#define MT6370_AUTOIDLE_MASK BIT(3)
> > +
> > +#define MT6370_VENDOR_ID     0x29CF
> > +#define MT6370_TCPC_DID_A    0x2170
> > +
> > +struct mt6370_priv {
> > +     struct device *dev;
> > +     struct regulator *vbus;
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data tcpci_data;
> > +};
> > +
> > +static const struct reg_sequence mt6370_reg_init[] = {
> > +     REG_SEQ(0xA0, 0x1, 1000),
> > +     REG_SEQ(0x81, 0x38, 0),
> > +     REG_SEQ(0x82, 0x82, 0),
> > +     REG_SEQ(0xBA, 0xFC, 0),
> > +     REG_SEQ(0xBB, 0x50, 0),
> > +     REG_SEQ(0x9E, 0x8F, 0),
> > +     REG_SEQ(0xA1, 0x5, 0),
> > +     REG_SEQ(0xA2, 0x4, 0),
> > +     REG_SEQ(0xA3, 0x4A, 0),
> > +     REG_SEQ(0xA4, 0x01, 0),
> > +     REG_SEQ(0x95, 0x01, 0),
> > +     REG_SEQ(0x80, 0x71, 0),
> > +     REG_SEQ(0x9B, 0x3A, 1000),
> > +};
> > +
> > +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> > *data)
> > +{
> > +     u16 did;
> > +     int ret;
> > +
> > +     ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> > +                                 ARRAY_SIZE(mt6370_reg_init));
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (did == MT6370_TCPC_DID_A)
> > +             return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> > 0x80);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                              bool enable)
> > +{
> > +     return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> > +                               MT6370_AUTOIDLE_MASK,
> > +                               !enable ? MT6370_AUTOIDLE_MASK : 0);
> > +}
> > +
> > +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                             bool source, bool sink)
> @sink is not used in this function?

Hi Chunfeng,
The default HW binding is using the mt6370 switching charger.
Due to the switching charger design, 'src usb boost' and 'sink battery
charger', only one can be used at the same time.
Thanks.

>
> > +{
> > +     struct mt6370_priv *priv = container_of(data, struct
> > mt6370_priv,
> > +                                             tcpci_data);
> > +     int ret;
> > +
> > +     ret = regulator_is_enabled(priv->vbus);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     if (ret && !source)
> > +             return regulator_disable(priv->vbus);
> > +
> > +     if (!ret && source)
> > +             return regulator_enable(priv->vbus);
> > +
> > +     return 0;
> > +}
> > +
> > +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> > +{
> > +     struct mt6370_priv *priv = dev_id;
> > +
> > +     return tcpci_irq(priv->tcpci);
> > +}
> > +
> > +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> > +{
> > +     struct regmap *regmap = priv->tcpci_data.regmap;
> > +     u16 vid;
> > +     int ret;
> > +
> > +     ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (vid != MT6370_VENDOR_ID)
> > +             return dev_err_probe(priv->dev, -ENODEV,
> > +                                  "Vendor ID not correct 0x%02x\n",
> > vid);
> > +
> > +     return 0;
> > +}
> > +
> > +static void mt6370_unregister_tcpci_port(void *tcpci)
> > +{
> > +     tcpci_unregister_port(tcpci);
> > +}
> > +
> > +static int mt6370_tcpc_probe(struct platform_device *pdev)
> > +{
> > +     struct mt6370_priv *priv;
> > +     struct device *dev = &pdev->dev;
> > +     int irq, ret;
> > +
> > +     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     priv->dev = dev;
> > +
> > +     priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> > +     if (!priv->tcpci_data.regmap)
> > +             return dev_err_probe(dev, -ENODEV, "Failed to init
> > regmap\n");
> > +
> > +     ret = mt6370_check_vendor_info(priv);
> > +     if (ret)
> > +             return ret;
> > +
> > +     irq = platform_get_irq(pdev, 0);
> > +     if (irq < 0)
> > +             return dev_err_probe(dev, irq, "Failed to get irq\n");
> > +
> > +     /* Assign TCPCI feature and ops */
> > +     priv->tcpci_data.auto_discharge_disconnect = 1;
> > +     priv->tcpci_data.init = mt6370_tcpc_init;
> > +     priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> > +
> > +     priv->vbus = devm_regulator_get_optional(dev, "vbus");
> > +     if (!IS_ERR(priv->vbus))
> > +             priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> > +
> > +     priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> > +     if (IS_ERR(priv->tcpci))
> > +             return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> > +                                  "Failed to register tcpci
> > port\n");
> > +
> > +     ret = devm_add_action_or_reset(dev,
> > mt6370_unregister_tcpci_port,
> > +                                    priv->tcpci);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = devm_request_threaded_irq(dev, irq, NULL,
> > mt6370_irq_handler,
> > +                                     IRQF_ONESHOT, dev_name(dev),
> > priv);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "Failed to allocate
> > irq\n");
> > +
> > +     device_init_wakeup(dev, true);
> > +     dev_pm_set_wake_irq(dev, irq);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_remove(struct platform_device *pdev)
> > +{
> > +     dev_pm_clear_wake_irq(&pdev->dev);
> > +     device_init_wakeup(&pdev->dev, false);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> > +     { .compatible = "mediatek,mt6370-tcpc" },
> > +     {}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> > +
> > +static struct platform_driver mt6370_tcpc_driver = {
> > +     .driver = {
> > +             .name = "mt6370-tcpc",
> > +             .of_match_table = mt6370_tcpc_devid_table,
> > +     },
> > +     .probe = mt6370_tcpc_probe,
> > +     .remove = mt6370_tcpc_remove,
> > +};
> > +module_platform_driver(mt6370_tcpc_driver);
> > +
> > +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> > +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> > Driver");
> > +MODULE_LICENSE("GPL v2");
>


-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  7:17       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  7:17 UTC (permalink / raw)
  To: Chunfeng Yun
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Mon, Jul 25, 2022 at 3:06 PM Chunfeng Yun <chunfeng.yun@mediatek.com> wrote:
>
> On Fri, 2022-07-22 at 18:24 +0800, ChiaEn Wu wrote:
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual
> > Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > Add support for the Type-C & Power Delivery controller in
> > MediaTek MT6370 IC.
> >
> > Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> > Reviewed-by: AngeloGioacchino Del Regno <
> > angelogioacchino.delregno@collabora.com>
> > ---
> >
> > v6
> > - Convert tcpci as device resource managed with
> > 'devm_add_action_or_reset' API.
> > - Refine remvoe callback.
> > - Refine the commit text from 'This commit add' to 'Add'.
> > ---
> >  drivers/usb/typec/tcpm/Kconfig        |  11 ++
> >  drivers/usb/typec/tcpm/Makefile       |   1 +
> >  drivers/usb/typec/tcpm/tcpci_mt6370.c | 208
> > ++++++++++++++++++++++++++++++++++
> >  3 files changed, 220 insertions(+)
> >  create mode 100644 drivers/usb/typec/tcpm/tcpci_mt6370.c
> >
> > diff --git a/drivers/usb/typec/tcpm/Kconfig
> > b/drivers/usb/typec/tcpm/Kconfig
> > index 073fd2e..e6b88ca 100644
> > --- a/drivers/usb/typec/tcpm/Kconfig
> > +++ b/drivers/usb/typec/tcpm/Kconfig
> > @@ -35,6 +35,17 @@ config TYPEC_MT6360
> >         USB Type-C. It works with Type-C Port Controller Manager
> >         to provide USB PD and USB Type-C functionalities.
> >
> > +config TYPEC_TCPCI_MT6370
> > +     tristate "MediaTek MT6370 Type-C driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       MediaTek MT6370 is a multi-functional IC that includes
> > +       USB Type-C. It works with Type-C Port Controller Manager
> > +       to provide USB PD and USB Type-C functionalities.
> > +
> > +       This driver can also be built as a module. The module
> > +       will be called "tcpci_mt6370".
> > +
> >  config TYPEC_TCPCI_MAXIM
> >       tristate "Maxim TCPCI based Type-C chip driver"
> >       help
> > diff --git a/drivers/usb/typec/tcpm/Makefile
> > b/drivers/usb/typec/tcpm/Makefile
> > index 7d499f3..906d9dc 100644
> > --- a/drivers/usb/typec/tcpm/Makefile
> > +++ b/drivers/usb/typec/tcpm/Makefile
> > @@ -6,4 +6,5 @@ typec_wcove-y                         := wcove.o
> >  obj-$(CONFIG_TYPEC_TCPCI)            += tcpci.o
> >  obj-$(CONFIG_TYPEC_RT1711H)          += tcpci_rt1711h.o
> >  obj-$(CONFIG_TYPEC_MT6360)           += tcpci_mt6360.o
> > +obj-$(CONFIG_TYPEC_TCPCI_MT6370)     += tcpci_mt6370.o
> >  obj-$(CONFIG_TYPEC_TCPCI_MAXIM)              += tcpci_maxim.o
> > diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > new file mode 100644
> > index 0000000..4f53319
> > --- /dev/null
> > +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c
> > @@ -0,0 +1,208 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
> > + */
> > +
> > +#include <linux/bits.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm_wakeup.h>
> > +#include <linux/pm_wakeirq.h>
> > +#include <linux/regmap.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/usb/tcpm.h>
> > +#include "tcpci.h"
> > +
> > +#define MT6370_REG_SYSCTRL8  0x9B
> > +
> > +#define MT6370_AUTOIDLE_MASK BIT(3)
> > +
> > +#define MT6370_VENDOR_ID     0x29CF
> > +#define MT6370_TCPC_DID_A    0x2170
> > +
> > +struct mt6370_priv {
> > +     struct device *dev;
> > +     struct regulator *vbus;
> > +     struct tcpci *tcpci;
> > +     struct tcpci_data tcpci_data;
> > +};
> > +
> > +static const struct reg_sequence mt6370_reg_init[] = {
> > +     REG_SEQ(0xA0, 0x1, 1000),
> > +     REG_SEQ(0x81, 0x38, 0),
> > +     REG_SEQ(0x82, 0x82, 0),
> > +     REG_SEQ(0xBA, 0xFC, 0),
> > +     REG_SEQ(0xBB, 0x50, 0),
> > +     REG_SEQ(0x9E, 0x8F, 0),
> > +     REG_SEQ(0xA1, 0x5, 0),
> > +     REG_SEQ(0xA2, 0x4, 0),
> > +     REG_SEQ(0xA3, 0x4A, 0),
> > +     REG_SEQ(0xA4, 0x01, 0),
> > +     REG_SEQ(0x95, 0x01, 0),
> > +     REG_SEQ(0x80, 0x71, 0),
> > +     REG_SEQ(0x9B, 0x3A, 1000),
> > +};
> > +
> > +static int mt6370_tcpc_init(struct tcpci *tcpci, struct tcpci_data
> > *data)
> > +{
> > +     u16 did;
> > +     int ret;
> > +
> > +     ret = regmap_register_patch(data->regmap, mt6370_reg_init,
> > +                                 ARRAY_SIZE(mt6370_reg_init));
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = regmap_raw_read(data->regmap, TCPC_BCD_DEV, &did,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (did == MT6370_TCPC_DID_A)
> > +             return regmap_write(data->regmap, TCPC_FAULT_CTRL,
> > 0x80);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                              bool enable)
> > +{
> > +     return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> > +                               MT6370_AUTOIDLE_MASK,
> > +                               !enable ? MT6370_AUTOIDLE_MASK : 0);
> > +}
> > +
> > +static int mt6370_tcpc_set_vbus(struct tcpci *tcpci, struct
> > tcpci_data *data,
> > +                             bool source, bool sink)
> @sink is not used in this function?

Hi Chunfeng,
The default HW binding is using the mt6370 switching charger.
Due to the switching charger design, 'src usb boost' and 'sink battery
charger', only one can be used at the same time.
Thanks.

>
> > +{
> > +     struct mt6370_priv *priv = container_of(data, struct
> > mt6370_priv,
> > +                                             tcpci_data);
> > +     int ret;
> > +
> > +     ret = regulator_is_enabled(priv->vbus);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     if (ret && !source)
> > +             return regulator_disable(priv->vbus);
> > +
> > +     if (!ret && source)
> > +             return regulator_enable(priv->vbus);
> > +
> > +     return 0;
> > +}
> > +
> > +static irqreturn_t mt6370_irq_handler(int irq, void *dev_id)
> > +{
> > +     struct mt6370_priv *priv = dev_id;
> > +
> > +     return tcpci_irq(priv->tcpci);
> > +}
> > +
> > +static int mt6370_check_vendor_info(struct mt6370_priv *priv)
> > +{
> > +     struct regmap *regmap = priv->tcpci_data.regmap;
> > +     u16 vid;
> > +     int ret;
> > +
> > +     ret = regmap_raw_read(regmap, TCPC_VENDOR_ID, &vid,
> > sizeof(u16));
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (vid != MT6370_VENDOR_ID)
> > +             return dev_err_probe(priv->dev, -ENODEV,
> > +                                  "Vendor ID not correct 0x%02x\n",
> > vid);
> > +
> > +     return 0;
> > +}
> > +
> > +static void mt6370_unregister_tcpci_port(void *tcpci)
> > +{
> > +     tcpci_unregister_port(tcpci);
> > +}
> > +
> > +static int mt6370_tcpc_probe(struct platform_device *pdev)
> > +{
> > +     struct mt6370_priv *priv;
> > +     struct device *dev = &pdev->dev;
> > +     int irq, ret;
> > +
> > +     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +     if (!priv)
> > +             return -ENOMEM;
> > +
> > +     priv->dev = dev;
> > +
> > +     priv->tcpci_data.regmap = dev_get_regmap(dev->parent, NULL);
> > +     if (!priv->tcpci_data.regmap)
> > +             return dev_err_probe(dev, -ENODEV, "Failed to init
> > regmap\n");
> > +
> > +     ret = mt6370_check_vendor_info(priv);
> > +     if (ret)
> > +             return ret;
> > +
> > +     irq = platform_get_irq(pdev, 0);
> > +     if (irq < 0)
> > +             return dev_err_probe(dev, irq, "Failed to get irq\n");
> > +
> > +     /* Assign TCPCI feature and ops */
> > +     priv->tcpci_data.auto_discharge_disconnect = 1;
> > +     priv->tcpci_data.init = mt6370_tcpc_init;
> > +     priv->tcpci_data.set_vconn = mt6370_tcpc_set_vconn;
> > +
> > +     priv->vbus = devm_regulator_get_optional(dev, "vbus");
> > +     if (!IS_ERR(priv->vbus))
> > +             priv->tcpci_data.set_vbus = mt6370_tcpc_set_vbus;
> > +
> > +     priv->tcpci = tcpci_register_port(dev, &priv->tcpci_data);
> > +     if (IS_ERR(priv->tcpci))
> > +             return dev_err_probe(dev, PTR_ERR(priv->tcpci),
> > +                                  "Failed to register tcpci
> > port\n");
> > +
> > +     ret = devm_add_action_or_reset(dev,
> > mt6370_unregister_tcpci_port,
> > +                                    priv->tcpci);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = devm_request_threaded_irq(dev, irq, NULL,
> > mt6370_irq_handler,
> > +                                     IRQF_ONESHOT, dev_name(dev),
> > priv);
> > +     if (ret)
> > +             return dev_err_probe(dev, ret, "Failed to allocate
> > irq\n");
> > +
> > +     device_init_wakeup(dev, true);
> > +     dev_pm_set_wake_irq(dev, irq);
> > +
> > +     return 0;
> > +}
> > +
> > +static int mt6370_tcpc_remove(struct platform_device *pdev)
> > +{
> > +     dev_pm_clear_wake_irq(&pdev->dev);
> > +     device_init_wakeup(&pdev->dev, false);
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct of_device_id mt6370_tcpc_devid_table[] = {
> > +     { .compatible = "mediatek,mt6370-tcpc" },
> > +     {}
> > +};
> > +MODULE_DEVICE_TABLE(of, mt6370_tcpc_devid_table);
> > +
> > +static struct platform_driver mt6370_tcpc_driver = {
> > +     .driver = {
> > +             .name = "mt6370-tcpc",
> > +             .of_match_table = mt6370_tcpc_devid_table,
> > +     },
> > +     .probe = mt6370_tcpc_probe,
> > +     .remove = mt6370_tcpc_remove,
> > +};
> > +module_platform_driver(mt6370_tcpc_driver);
> > +
> > +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
> > +MODULE_DESCRIPTION("MT6370 USB Type-C Port Controller Interface
> > Driver");
> > +MODULE_LICENSE("GPL v2");
>


-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  7:59     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  7:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
> SubPMIC consisting of a single cell battery charger with ADC monitoring,
> RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
> voltage supply, one general purpose LDO, and the USB Type-C & PD controller
> complies with the latest USB Type-C and PD standards.

...

> +#define MT6370_REG_DEV_INFO    0x100
> +#define MT6370_REG_CHG_IRQ1    0x1C0
> +#define MT6370_REG_CHG_MASK1   0x1E0
> +
> +#define MT6370_VENID_MASK      GENMASK(7, 4)
> +
> +#define MT6370_NUM_IRQREGS     16
> +#define MT6370_USBC_I2CADDR    0x4E

> +#define MT6370_REG_ADDRLEN     2
> +#define MT6370_REG_MAXADDR     0x1FF

These two more logically to have near to other _REG_* definitions above.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  7:59     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  7:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
> SubPMIC consisting of a single cell battery charger with ADC monitoring,
> RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
> voltage supply, one general purpose LDO, and the USB Type-C & PD controller
> complies with the latest USB Type-C and PD standards.

...

> +#define MT6370_REG_DEV_INFO    0x100
> +#define MT6370_REG_CHG_IRQ1    0x1C0
> +#define MT6370_REG_CHG_MASK1   0x1E0
> +
> +#define MT6370_VENID_MASK      GENMASK(7, 4)
> +
> +#define MT6370_NUM_IRQREGS     16
> +#define MT6370_USBC_I2CADDR    0x4E

> +#define MT6370_REG_ADDRLEN     2
> +#define MT6370_REG_MAXADDR     0x1FF

These two more logically to have near to other _REG_* definitions above.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  7:59     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  7:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> This adds support for the MediaTek MT6370 SubPMIC. MediaTek MT6370 is a
> SubPMIC consisting of a single cell battery charger with ADC monitoring,
> RGB LEDs, dual channel flashlight, WLED backlight driver, display bias
> voltage supply, one general purpose LDO, and the USB Type-C & PD controller
> complies with the latest USB Type-C and PD standards.

...

> +#define MT6370_REG_DEV_INFO    0x100
> +#define MT6370_REG_CHG_IRQ1    0x1C0
> +#define MT6370_REG_CHG_MASK1   0x1E0
> +
> +#define MT6370_VENID_MASK      GENMASK(7, 4)
> +
> +#define MT6370_NUM_IRQREGS     16
> +#define MT6370_USBC_I2CADDR    0x4E

> +#define MT6370_REG_ADDRLEN     2
> +#define MT6370_REG_MAXADDR     0x1FF

These two more logically to have near to other _REG_* definitions above.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:03     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.

...

> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +                                bool enable)
> +{
> +       return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +                                 MT6370_AUTOIDLE_MASK,
> +                                 !enable ? MT6370_AUTOIDLE_MASK : 0);

Why not positive conditional?

  enable ? 0 : mask

> +}

...

> +       ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +                                      priv->tcpci);

I believe nothing bad will happen if you put it on one line.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  8:03     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List,
	AngeloGioacchino Del Regno, Jingoo Han, USB, Sebastian Reichel,
	Linux Kernel Mailing List, ChiaEn Wu, Greg Kroah-Hartman,
	Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.

...

> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +                                bool enable)
> +{
> +       return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +                                 MT6370_AUTOIDLE_MASK,
> +                                 !enable ? MT6370_AUTOIDLE_MASK : 0);

Why not positive conditional?

  enable ? 0 : mask

> +}

...

> +       ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +                                      priv->tcpci);

I believe nothing bad will happen if you put it on one line.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver
@ 2022-07-25  8:03     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> Add support for the Type-C & Power Delivery controller in
> MediaTek MT6370 IC.

...

> +static int mt6370_tcpc_set_vconn(struct tcpci *tcpci, struct tcpci_data *data,
> +                                bool enable)
> +{
> +       return regmap_update_bits(data->regmap, MT6370_REG_SYSCTRL8,
> +                                 MT6370_AUTOIDLE_MASK,
> +                                 !enable ? MT6370_AUTOIDLE_MASK : 0);

Why not positive conditional?

  enable ? 0 : mask

> +}

...

> +       ret = devm_add_action_or_reset(dev, mt6370_unregister_tcpci_port,
> +                                      priv->tcpci);

I believe nothing bad will happen if you put it on one line.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:10     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:10 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> Add a support the MT6370 ADC driver for system monitoring, including

support for the

> charger current, voltage, and temperature.

...

> +#define MT6370_AICR_400_mA             0x6
> +#define MT6370_ICHG_500_mA             0x4
> +#define MT6370_ICHG_900_mA             0x8

^^^^ (Note this and read below)

...

> +               reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
> +               if (reg_val < MT6370_AICR_400_mA)
> +                       *val1 = 3350;
> +               else
> +                       *val1 = 5000;

Here...

...

> +               if (reg_val < MT6370_ICHG_500_mA)
> +                       *val1 = 2375;
> +               else if (reg_val >= MT6370_ICHG_500_mA &&
> +                        reg_val < MT6370_ICHG_900_mA)
> +                       *val1 = 2680;
> +               else
> +                       *val1 = 5000;

...and especially here it is so counterintuitive to have an if-else
chain because the values are not ordered by semantic meaning.

What if the new standard/hardware decides to use 0x7 for 100mA (hypothetically)?

So, please use switch cases or other robust methods.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:10     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:10 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List,
	AngeloGioacchino Del Regno, Jingoo Han, USB, Sebastian Reichel,
	Linux Kernel Mailing List, ChiaEn Wu, Greg Kroah-Hartman,
	Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> Add a support the MT6370 ADC driver for system monitoring, including

support for the

> charger current, voltage, and temperature.

...

> +#define MT6370_AICR_400_mA             0x6
> +#define MT6370_ICHG_500_mA             0x4
> +#define MT6370_ICHG_900_mA             0x8

^^^^ (Note this and read below)

...

> +               reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
> +               if (reg_val < MT6370_AICR_400_mA)
> +                       *val1 = 3350;
> +               else
> +                       *val1 = 5000;

Here...

...

> +               if (reg_val < MT6370_ICHG_500_mA)
> +                       *val1 = 2375;
> +               else if (reg_val >= MT6370_ICHG_500_mA &&
> +                        reg_val < MT6370_ICHG_900_mA)
> +                       *val1 = 2680;
> +               else
> +                       *val1 = 5000;

...and especially here it is so counterintuitive to have an if-else
chain because the values are not ordered by semantic meaning.

What if the new standard/hardware decides to use 0x7 for 100mA (hypothetically)?

So, please use switch cases or other robust methods.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:10     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:10 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen,
	AngeloGioacchino Del Regno

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> Add a support the MT6370 ADC driver for system monitoring, including

support for the

> charger current, voltage, and temperature.

...

> +#define MT6370_AICR_400_mA             0x6
> +#define MT6370_ICHG_500_mA             0x4
> +#define MT6370_ICHG_900_mA             0x8

^^^^ (Note this and read below)

...

> +               reg_val = FIELD_GET(MT6370_AICR_ICHG_MASK, reg_val);
> +               if (reg_val < MT6370_AICR_400_mA)
> +                       *val1 = 3350;
> +               else
> +                       *val1 = 5000;

Here...

...

> +               if (reg_val < MT6370_ICHG_500_mA)
> +                       *val1 = 2375;
> +               else if (reg_val >= MT6370_ICHG_500_mA &&
> +                        reg_val < MT6370_ICHG_900_mA)
> +                       *val1 = 2680;
> +               else
> +                       *val1 = 5000;

...and especially here it is so counterintuitive to have an if-else
chain because the values are not ordered by semantic meaning.

What if the new standard/hardware decides to use 0x7 for 100mA (hypothetically)?

So, please use switch cases or other robust methods.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:25     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:25 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds MediaTek MT6370 Charger driver support. The charger module
> of MT6370 supports High-Accuracy Voltage/Current Regulation,
> Average Input Current Regulation, Battery Temperature Sensing,
> Over-Temperature Protection, DPDM Detection for BC1.2.

...

> +static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
> +                                        const char *irq_name, bool en)
> +{
> +       int irq_num;
> +       struct platform_device *pdev = to_platform_device(priv->dev);
> +
> +       irq_num = platform_get_irq_byname(pdev, irq_name);

Every time the IRQ is not found you will get an error message printed here.
1) Is IRQ optional?
2) If not, can't you do validation only once?

> +       if (irq_num < 0)
> +               return;
> +
> +       if (en)
> +               enable_irq(irq_num);
> +       else
> +               disable_irq_nosync(irq_num);
> +}


...

> +       ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
> +       if (ret < 0) {

Do all these ' < 0' parts make sense?
(Not only these cases, but in many in the entire driver)

...

> +       /* Check in otg mode or not */

OTG

...

> +               ret = devm_request_threaded_irq(priv->dev, ret, NULL,
> +                                               mt6370_chg_irqs[i].handler,
> +                                               IRQF_TRIGGER_FALLING,
> +                                               dev_name(priv->dev), priv);

> +

Redundant blank line.

> +               if (ret < 0)
> +                       return dev_err_probe(priv->dev, ret,
> +                                            "Failed to request irq %s\n",
> +                                            mt6370_chg_irqs[i].name);
> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
@ 2022-07-25  8:25     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:25 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds MediaTek MT6370 Charger driver support. The charger module
> of MT6370 supports High-Accuracy Voltage/Current Regulation,
> Average Input Current Regulation, Battery Temperature Sensing,
> Over-Temperature Protection, DPDM Detection for BC1.2.

...

> +static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
> +                                        const char *irq_name, bool en)
> +{
> +       int irq_num;
> +       struct platform_device *pdev = to_platform_device(priv->dev);
> +
> +       irq_num = platform_get_irq_byname(pdev, irq_name);

Every time the IRQ is not found you will get an error message printed here.
1) Is IRQ optional?
2) If not, can't you do validation only once?

> +       if (irq_num < 0)
> +               return;
> +
> +       if (en)
> +               enable_irq(irq_num);
> +       else
> +               disable_irq_nosync(irq_num);
> +}


...

> +       ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
> +       if (ret < 0) {

Do all these ' < 0' parts make sense?
(Not only these cases, but in many in the entire driver)

...

> +       /* Check in otg mode or not */

OTG

...

> +               ret = devm_request_threaded_irq(priv->dev, ret, NULL,
> +                                               mt6370_chg_irqs[i].handler,
> +                                               IRQF_TRIGGER_FALLING,
> +                                               dev_name(priv->dev), priv);

> +

Redundant blank line.

> +               if (ret < 0)
> +                       return dev_err_probe(priv->dev, ret,
> +                                            "Failed to request irq %s\n",
> +                                            mt6370_chg_irqs[i].name);
> +       }

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver
@ 2022-07-25  8:25     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:25 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds MediaTek MT6370 Charger driver support. The charger module
> of MT6370 supports High-Accuracy Voltage/Current Regulation,
> Average Input Current Regulation, Battery Temperature Sensing,
> Over-Temperature Protection, DPDM Detection for BC1.2.

...

> +static inline void mt6370_chg_enable_irq(struct mt6370_priv *priv,
> +                                        const char *irq_name, bool en)
> +{
> +       int irq_num;
> +       struct platform_device *pdev = to_platform_device(priv->dev);
> +
> +       irq_num = platform_get_irq_byname(pdev, irq_name);

Every time the IRQ is not found you will get an error message printed here.
1) Is IRQ optional?
2) If not, can't you do validation only once?

> +       if (irq_num < 0)
> +               return;
> +
> +       if (en)
> +               enable_irq(irq_num);
> +       else
> +               disable_irq_nosync(irq_num);
> +}


...

> +       ret = mt6370_chg_field_set(priv, F_USBCHGEN, 0);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_ICHG, 900000);
> +       if (ret < 0) {

> +       ret = mt6370_chg_field_set(priv, F_IINLMTSEL, 3);
> +       if (ret < 0) {

Do all these ' < 0' parts make sense?
(Not only these cases, but in many in the entire driver)

...

> +       /* Check in otg mode or not */

OTG

...

> +               ret = devm_request_threaded_irq(priv->dev, ret, NULL,
> +                                               mt6370_chg_irqs[i].handler,
> +                                               IRQF_TRIGGER_FALLING,
> +                                               dev_name(priv->dev), priv);

> +

Redundant blank line.

> +               if (ret < 0)
> +                       return dev_err_probe(priv->dev, ret,
> +                                            "Failed to request irq %s\n",
> +                                            mt6370_chg_irqs[i].name);
> +       }

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-25  7:59     ` Andy Shevchenko
  (?)
@ 2022-07-25  8:29       ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  8:29 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>

...

>
> > +#define MT6370_REG_DEV_INFO    0x100
> > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > +#define MT6370_REG_CHG_MASK1   0x1E0
> > +
> > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > +
> > +#define MT6370_NUM_IRQREGS     16
> > +#define MT6370_USBC_I2CADDR    0x4E
>
> > +#define MT6370_REG_ADDRLEN     2
> > +#define MT6370_REG_MAXADDR     0x1FF
>
> These two more logically to have near to other _REG_* definitions above.

Hi Andy,
Thanks for your review.
Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
'#define MT6370_REG_MAXADDR' after the line '#define
MT6370_REG_CHG_MASK1'?
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_USBC_I2CADDR    0x4E
#define MT6370_REG_MAXADDR     0x1FF

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_REG_ADDRLEN     2
-------------------------------------------------------------------
Like this?

>
> --
> With Best Regards,
> Andy Shevchenko

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:29       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  8:29 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>

...

>
> > +#define MT6370_REG_DEV_INFO    0x100
> > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > +#define MT6370_REG_CHG_MASK1   0x1E0
> > +
> > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > +
> > +#define MT6370_NUM_IRQREGS     16
> > +#define MT6370_USBC_I2CADDR    0x4E
>
> > +#define MT6370_REG_ADDRLEN     2
> > +#define MT6370_REG_MAXADDR     0x1FF
>
> These two more logically to have near to other _REG_* definitions above.

Hi Andy,
Thanks for your review.
Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
'#define MT6370_REG_MAXADDR' after the line '#define
MT6370_REG_CHG_MASK1'?
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_USBC_I2CADDR    0x4E
#define MT6370_REG_MAXADDR     0x1FF

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_REG_ADDRLEN     2
-------------------------------------------------------------------
Like this?

>
> --
> With Best Regards,
> Andy Shevchenko

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:29       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  8:29 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>

...

>
> > +#define MT6370_REG_DEV_INFO    0x100
> > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > +#define MT6370_REG_CHG_MASK1   0x1E0
> > +
> > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > +
> > +#define MT6370_NUM_IRQREGS     16
> > +#define MT6370_USBC_I2CADDR    0x4E
>
> > +#define MT6370_REG_ADDRLEN     2
> > +#define MT6370_REG_MAXADDR     0x1FF
>
> These two more logically to have near to other _REG_* definitions above.

Hi Andy,
Thanks for your review.
Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
'#define MT6370_REG_MAXADDR' after the line '#define
MT6370_REG_CHG_MASK1'?
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_USBC_I2CADDR    0x4E
#define MT6370_REG_MAXADDR     0x1FF

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_REG_ADDRLEN     2
-------------------------------------------------------------------
Like this?

>
> --
> With Best Regards,
> Andy Shevchenko

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:40     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:40 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>

^^^^ (Note this and read below)

>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.

> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

In conjunction with above what SoB of Alice means?

You really need to take your time and (re-)read
https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

...

> + * Author: Alice Chen <alice_chen@richtek.com>
> + * Author: ChiYuan Huang <cy_huang@richtek.com>

Would
 * Authors:
 *    Name_of_Author 1
 *    Name_of_Author 2

work for you?

...

> +struct mt6370_led {
> +       union {
> +               struct led_classdev isink;
> +               struct led_classdev_mc mc;
> +       };

Where is the field that makes union work?

> +       struct mt6370_priv *priv;
> +       u32 default_state;
> +       u32 index;
> +};

...

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +                                    struct led_pattern *pattern, u32 len,
> +                                    u8 *pattern_val, u32 val_len)
> +{
> +       enum mt6370_led_ranges sel_range;
> +       struct led_pattern *curr;
> +       unsigned int sel;
> +       u8 val[P_MAX_PATTERNS / 2] = {};
> +       int i;
> +
> +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +               return -EINVAL;
> +
> +       /*
> +        * Pattern list
> +        * tr1: byte 0, b'[7: 4]
> +        * tr2: byte 0, b'[3: 0]
> +        * tf1: byte 1, b'[7: 4]
> +        * tf2: byte 1, b'[3: 0]
> +        * ton: byte 2, b'[7: 4]
> +        * toff: byte 2, b'[3: 0]
> +        */
> +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> +               curr = pattern + i;
> +
> +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +               linear_range_get_selector_within(priv->ranges + sel_range,
> +                                                curr->delta_t, &sel);
> +
> +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +       }
> +
> +       memcpy(pattern_val, val, 3);

Isn't it something like put_unaligned_be24()/put_unaligned_le24()?


> +       return 0;
> +}

...

> +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
> +{
> +       struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
> +       struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
> +       struct mt6370_priv *priv = led->priv;
> +       struct mc_subled *subled;

> +       int i, ret = 0;

Redundant assignment.

> +       mutex_lock(&led->priv->lock);
> +
> +       for (i = 0; i < mccdev->num_colors; i++) {
> +               subled = mccdev->subled_info + i;
> +
> +               ret = mt6370_set_led_mode(priv, subled->channel,
> +                                         MT6370_LED_REG_MODE);
> +               if (ret)
> +                       break;
> +       }
> +
> +       mutex_unlock(&led->priv->lock);
> +
> +       return ret;
> +}

...

> +       if (!fwnode_property_read_string(init_data->fwnode, "default-state",
> +                                        &stat_str)) {

ret = fwnode_...(...);
if (!ret)

> +               ret = match_string(states, ARRAY_SIZE(states), stat_str);
> +               if (ret < 0)
> +                       ret = STATE_OFF;
> +
> +               led->default_state = ret;
> +       }

...

> +       int i = 0, ret;

unsigned int i = 0;
int ret;

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-25  8:40     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:40 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>

^^^^ (Note this and read below)

>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.

> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

In conjunction with above what SoB of Alice means?

You really need to take your time and (re-)read
https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

...

> + * Author: Alice Chen <alice_chen@richtek.com>
> + * Author: ChiYuan Huang <cy_huang@richtek.com>

Would
 * Authors:
 *    Name_of_Author 1
 *    Name_of_Author 2

work for you?

...

> +struct mt6370_led {
> +       union {
> +               struct led_classdev isink;
> +               struct led_classdev_mc mc;
> +       };

Where is the field that makes union work?

> +       struct mt6370_priv *priv;
> +       u32 default_state;
> +       u32 index;
> +};

...

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +                                    struct led_pattern *pattern, u32 len,
> +                                    u8 *pattern_val, u32 val_len)
> +{
> +       enum mt6370_led_ranges sel_range;
> +       struct led_pattern *curr;
> +       unsigned int sel;
> +       u8 val[P_MAX_PATTERNS / 2] = {};
> +       int i;
> +
> +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +               return -EINVAL;
> +
> +       /*
> +        * Pattern list
> +        * tr1: byte 0, b'[7: 4]
> +        * tr2: byte 0, b'[3: 0]
> +        * tf1: byte 1, b'[7: 4]
> +        * tf2: byte 1, b'[3: 0]
> +        * ton: byte 2, b'[7: 4]
> +        * toff: byte 2, b'[3: 0]
> +        */
> +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> +               curr = pattern + i;
> +
> +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +               linear_range_get_selector_within(priv->ranges + sel_range,
> +                                                curr->delta_t, &sel);
> +
> +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +       }
> +
> +       memcpy(pattern_val, val, 3);

Isn't it something like put_unaligned_be24()/put_unaligned_le24()?


> +       return 0;
> +}

...

> +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
> +{
> +       struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
> +       struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
> +       struct mt6370_priv *priv = led->priv;
> +       struct mc_subled *subled;

> +       int i, ret = 0;

Redundant assignment.

> +       mutex_lock(&led->priv->lock);
> +
> +       for (i = 0; i < mccdev->num_colors; i++) {
> +               subled = mccdev->subled_info + i;
> +
> +               ret = mt6370_set_led_mode(priv, subled->channel,
> +                                         MT6370_LED_REG_MODE);
> +               if (ret)
> +                       break;
> +       }
> +
> +       mutex_unlock(&led->priv->lock);
> +
> +       return ret;
> +}

...

> +       if (!fwnode_property_read_string(init_data->fwnode, "default-state",
> +                                        &stat_str)) {

ret = fwnode_...(...);
if (!ret)

> +               ret = match_string(states, ARRAY_SIZE(states), stat_str);
> +               if (ret < 0)
> +                       ret = STATE_OFF;
> +
> +               led->default_state = ret;
> +       }

...

> +       int i = 0, ret;

unsigned int i = 0;
int ret;

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-25  8:40     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:40 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiYuan Huang <cy_huang@richtek.com>

^^^^ (Note this and read below)

>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.

> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>

In conjunction with above what SoB of Alice means?

You really need to take your time and (re-)read
https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

...

> + * Author: Alice Chen <alice_chen@richtek.com>
> + * Author: ChiYuan Huang <cy_huang@richtek.com>

Would
 * Authors:
 *    Name_of_Author 1
 *    Name_of_Author 2

work for you?

...

> +struct mt6370_led {
> +       union {
> +               struct led_classdev isink;
> +               struct led_classdev_mc mc;
> +       };

Where is the field that makes union work?

> +       struct mt6370_priv *priv;
> +       u32 default_state;
> +       u32 index;
> +};

...

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +                                    struct led_pattern *pattern, u32 len,
> +                                    u8 *pattern_val, u32 val_len)
> +{
> +       enum mt6370_led_ranges sel_range;
> +       struct led_pattern *curr;
> +       unsigned int sel;
> +       u8 val[P_MAX_PATTERNS / 2] = {};
> +       int i;
> +
> +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +               return -EINVAL;
> +
> +       /*
> +        * Pattern list
> +        * tr1: byte 0, b'[7: 4]
> +        * tr2: byte 0, b'[3: 0]
> +        * tf1: byte 1, b'[7: 4]
> +        * tf2: byte 1, b'[3: 0]
> +        * ton: byte 2, b'[7: 4]
> +        * toff: byte 2, b'[3: 0]
> +        */
> +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> +               curr = pattern + i;
> +
> +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +               linear_range_get_selector_within(priv->ranges + sel_range,
> +                                                curr->delta_t, &sel);
> +
> +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +       }
> +
> +       memcpy(pattern_val, val, 3);

Isn't it something like put_unaligned_be24()/put_unaligned_le24()?


> +       return 0;
> +}

...

> +static inline int mt6370_mc_pattern_clear(struct led_classdev *lcdev)
> +{
> +       struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
> +       struct mt6370_led *led = container_of(mccdev, struct mt6370_led, mc);
> +       struct mt6370_priv *priv = led->priv;
> +       struct mc_subled *subled;

> +       int i, ret = 0;

Redundant assignment.

> +       mutex_lock(&led->priv->lock);
> +
> +       for (i = 0; i < mccdev->num_colors; i++) {
> +               subled = mccdev->subled_info + i;
> +
> +               ret = mt6370_set_led_mode(priv, subled->channel,
> +                                         MT6370_LED_REG_MODE);
> +               if (ret)
> +                       break;
> +       }
> +
> +       mutex_unlock(&led->priv->lock);
> +
> +       return ret;
> +}

...

> +       if (!fwnode_property_read_string(init_data->fwnode, "default-state",
> +                                        &stat_str)) {

ret = fwnode_...(...);
if (!ret)

> +               ret = match_string(states, ARRAY_SIZE(states), stat_str);
> +               if (ret < 0)
> +                       ret = STATE_OFF;
> +
> +               led->default_state = ret;
> +       }

...

> +       int i = 0, ret;

unsigned int i = 0;
int ret;

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-25  8:29       ` ChiaEn Wu
  (?)
@ 2022-07-25  8:43         ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:43 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 10:30 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +#define MT6370_REG_DEV_INFO    0x100
> > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > +
> > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > +
> > > +#define MT6370_NUM_IRQREGS     16
> > > +#define MT6370_USBC_I2CADDR    0x4E
> >
> > > +#define MT6370_REG_ADDRLEN     2
> > > +#define MT6370_REG_MAXADDR     0x1FF
> >
> > These two more logically to have near to other _REG_* definitions above.
>
> Hi Andy,
> Thanks for your review.
> Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
> '#define MT6370_REG_MAXADDR' after the line '#define
> MT6370_REG_CHG_MASK1'?
> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_USBC_I2CADDR    0x4E
> #define MT6370_REG_MAXADDR     0x1FF
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_REG_ADDRLEN     2
> -------------------------------------------------------------------
> Like this?

You lost me. Namespace has a meaning, i.e. grouping items of a kind.
In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
_not_ of the _REG_ kind as per above, why do they have this namespace
in the first place?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:43         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:43 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 10:30 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +#define MT6370_REG_DEV_INFO    0x100
> > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > +
> > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > +
> > > +#define MT6370_NUM_IRQREGS     16
> > > +#define MT6370_USBC_I2CADDR    0x4E
> >
> > > +#define MT6370_REG_ADDRLEN     2
> > > +#define MT6370_REG_MAXADDR     0x1FF
> >
> > These two more logically to have near to other _REG_* definitions above.
>
> Hi Andy,
> Thanks for your review.
> Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
> '#define MT6370_REG_MAXADDR' after the line '#define
> MT6370_REG_CHG_MASK1'?
> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_USBC_I2CADDR    0x4E
> #define MT6370_REG_MAXADDR     0x1FF
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_REG_ADDRLEN     2
> -------------------------------------------------------------------
> Like this?

You lost me. Namespace has a meaning, i.e. grouping items of a kind.
In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
_not_ of the _REG_ kind as per above, why do they have this namespace
in the first place?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  8:43         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:43 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 10:30 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:00 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +#define MT6370_REG_DEV_INFO    0x100
> > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > +
> > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > +
> > > +#define MT6370_NUM_IRQREGS     16
> > > +#define MT6370_USBC_I2CADDR    0x4E
> >
> > > +#define MT6370_REG_ADDRLEN     2
> > > +#define MT6370_REG_MAXADDR     0x1FF
> >
> > These two more logically to have near to other _REG_* definitions above.
>
> Hi Andy,
> Thanks for your review.
> Do you mean that we should move '#define MT6370_USBC_I2CADDR' and
> '#define MT6370_REG_MAXADDR' after the line '#define
> MT6370_REG_CHG_MASK1'?
> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_USBC_I2CADDR    0x4E
> #define MT6370_REG_MAXADDR     0x1FF
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_REG_ADDRLEN     2
> -------------------------------------------------------------------
> Like this?

You lost me. Namespace has a meaning, i.e. grouping items of a kind.
In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
_not_ of the _REG_ kind as per above, why do they have this namespace
in the first place?

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:51     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:51 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: Alice Chen <alice_chen@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
>
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

This SoB chain is wrong. Prioritize and read Submitting Patches!

...

> +static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
> +                                      enum led_brightness level)
> +{
> +       struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
> +       struct mt6370_priv *priv = led->priv;
> +       u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
> +                             MT6370_FLCSEN_MASK_ALL :
> +                             MT6370_FLCSEN_MASK(led->led_no);
> +       u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
> +       u32 val = level ? led_enable_mask : 0;

> +       u32 prev = priv->fled_torch_used, curr;

Here and in the other functions with similar variables it seems you
never use prev after assigning curr.
Just define a single variable and use it accordingly.

> +       int ret, i;
> +
> +       mutex_lock(&priv->lock);
> +
> +       /*
> +        * Only one set of flash control logic,
> +        * use the flag to avoid strobe is currently used.
> +        */
> +       if (priv->fled_strobe_used) {
> +               dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
> +                        priv->fled_strobe_used);
> +               ret = -EBUSY;
> +               goto unlock;
> +       }
> +
> +       if (level)
> +               curr = prev | BIT(led->led_no);
> +       else
> +               curr = prev & ~BIT(led->led_no);
> +
> +       if (curr)
> +               val |= MT6370_TORCHEN_MASK;
> +
> +       if (level) {
> +               level -= 1;
> +               if (led->led_no == MT6370_LED_JOINT) {
> +                       int flevel[MT6370_MAX_LEDS];
> +
> +                       flevel[0] = level / 2;
> +                       flevel[1] = level - flevel[0];
> +                       for (i = 0; i < MT6370_MAX_LEDS; i++) {
> +                               ret = regmap_update_bits(priv->regmap,
> +                                               MT6370_REG_FLEDITOR(i),
> +                                               MT6370_ITORCH_MASK, flevel[i]);
> +                               if (ret)
> +                                       goto unlock;
> +                       }
> +               } else {
> +                       ret = regmap_update_bits(priv->regmap,
> +                                       MT6370_REG_FLEDITOR(led->led_no),
> +                                       MT6370_ITORCH_MASK, level);
> +                       if (ret)
> +                               goto unlock;
> +               }
> +       }
> +
> +       ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
> +                                enable_mask, val);
> +       if (ret)
> +               goto unlock;
> +
> +       priv->fled_torch_used = curr;
> +
> +unlock:
> +       mutex_unlock(&priv->lock);
> +       return ret;
> +}

...

> +       struct v4l2_flash_config v4l2_config = {0};

0 is not needed.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-25  8:51     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:51 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: Alice Chen <alice_chen@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
>
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

This SoB chain is wrong. Prioritize and read Submitting Patches!

...

> +static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
> +                                      enum led_brightness level)
> +{
> +       struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
> +       struct mt6370_priv *priv = led->priv;
> +       u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
> +                             MT6370_FLCSEN_MASK_ALL :
> +                             MT6370_FLCSEN_MASK(led->led_no);
> +       u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
> +       u32 val = level ? led_enable_mask : 0;

> +       u32 prev = priv->fled_torch_used, curr;

Here and in the other functions with similar variables it seems you
never use prev after assigning curr.
Just define a single variable and use it accordingly.

> +       int ret, i;
> +
> +       mutex_lock(&priv->lock);
> +
> +       /*
> +        * Only one set of flash control logic,
> +        * use the flag to avoid strobe is currently used.
> +        */
> +       if (priv->fled_strobe_used) {
> +               dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
> +                        priv->fled_strobe_used);
> +               ret = -EBUSY;
> +               goto unlock;
> +       }
> +
> +       if (level)
> +               curr = prev | BIT(led->led_no);
> +       else
> +               curr = prev & ~BIT(led->led_no);
> +
> +       if (curr)
> +               val |= MT6370_TORCHEN_MASK;
> +
> +       if (level) {
> +               level -= 1;
> +               if (led->led_no == MT6370_LED_JOINT) {
> +                       int flevel[MT6370_MAX_LEDS];
> +
> +                       flevel[0] = level / 2;
> +                       flevel[1] = level - flevel[0];
> +                       for (i = 0; i < MT6370_MAX_LEDS; i++) {
> +                               ret = regmap_update_bits(priv->regmap,
> +                                               MT6370_REG_FLEDITOR(i),
> +                                               MT6370_ITORCH_MASK, flevel[i]);
> +                               if (ret)
> +                                       goto unlock;
> +                       }
> +               } else {
> +                       ret = regmap_update_bits(priv->regmap,
> +                                       MT6370_REG_FLEDITOR(led->led_no),
> +                                       MT6370_ITORCH_MASK, level);
> +                       if (ret)
> +                               goto unlock;
> +               }
> +       }
> +
> +       ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
> +                                enable_mask, val);
> +       if (ret)
> +               goto unlock;
> +
> +       priv->fled_torch_used = curr;
> +
> +unlock:
> +       mutex_unlock(&priv->lock);
> +       return ret;
> +}

...

> +       struct v4l2_flash_config v4l2_config = {0};

0 is not needed.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-25  8:51     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:51 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: Alice Chen <alice_chen@richtek.com>
>
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
>
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
>
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

This SoB chain is wrong. Prioritize and read Submitting Patches!

...

> +static int mt6370_torch_brightness_set(struct led_classdev *lcdev,
> +                                      enum led_brightness level)
> +{
> +       struct mt6370_led *led = to_mt6370_led(lcdev, flash.led_cdev);
> +       struct mt6370_priv *priv = led->priv;
> +       u32 led_enable_mask = (led->led_no == MT6370_LED_JOINT) ?
> +                             MT6370_FLCSEN_MASK_ALL :
> +                             MT6370_FLCSEN_MASK(led->led_no);
> +       u32 enable_mask = MT6370_TORCHEN_MASK | led_enable_mask;
> +       u32 val = level ? led_enable_mask : 0;

> +       u32 prev = priv->fled_torch_used, curr;

Here and in the other functions with similar variables it seems you
never use prev after assigning curr.
Just define a single variable and use it accordingly.

> +       int ret, i;
> +
> +       mutex_lock(&priv->lock);
> +
> +       /*
> +        * Only one set of flash control logic,
> +        * use the flag to avoid strobe is currently used.
> +        */
> +       if (priv->fled_strobe_used) {
> +               dev_warn(lcdev->dev, "Please disable strobe first [%d]\n",
> +                        priv->fled_strobe_used);
> +               ret = -EBUSY;
> +               goto unlock;
> +       }
> +
> +       if (level)
> +               curr = prev | BIT(led->led_no);
> +       else
> +               curr = prev & ~BIT(led->led_no);
> +
> +       if (curr)
> +               val |= MT6370_TORCHEN_MASK;
> +
> +       if (level) {
> +               level -= 1;
> +               if (led->led_no == MT6370_LED_JOINT) {
> +                       int flevel[MT6370_MAX_LEDS];
> +
> +                       flevel[0] = level / 2;
> +                       flevel[1] = level - flevel[0];
> +                       for (i = 0; i < MT6370_MAX_LEDS; i++) {
> +                               ret = regmap_update_bits(priv->regmap,
> +                                               MT6370_REG_FLEDITOR(i),
> +                                               MT6370_ITORCH_MASK, flevel[i]);
> +                               if (ret)
> +                                       goto unlock;
> +                       }
> +               } else {
> +                       ret = regmap_update_bits(priv->regmap,
> +                                       MT6370_REG_FLEDITOR(led->led_no),
> +                                       MT6370_ITORCH_MASK, level);
> +                       if (ret)
> +                               goto unlock;
> +               }
> +       }
> +
> +       ret = regmap_update_bits(priv->regmap, MT6370_REG_FLEDEN,
> +                                enable_mask, val);
> +       if (ret)
> +               goto unlock;
> +
> +       priv->fled_torch_used = curr;
> +
> +unlock:
> +       mutex_unlock(&priv->lock);
> +       return ret;
> +}

...

> +       struct v4l2_flash_config v4l2_config = {0};

0 is not needed.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  8:55     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:55 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:

Forgot to add a couple of things...

...

> +#define MT6370_ITORCH_MIN_UA           25000
> +#define MT6370_ITORCH_STEP_UA          12500
> +#define MT6370_ITORCH_MAX_UA           400000
> +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> +#define MT6370_ISTRB_MIN_UA            50000
> +#define MT6370_ISTRB_STEP_UA           12500
> +#define MT6370_ISTRB_MAX_UA            1500000
> +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000

Perhaps _uA would be better and consistent across your series
regarding current units.

...

> +       /*
> +        * For the flash to turn on/off, need to wait HW ramping up/down time

we need

> +        * 5ms/500us to prevent the unexpected problem.
> +        */
> +       if (!prev && curr)
> +               usleep_range(5000, 6000);
> +       else if (prev && !curr)
> +               udelay(500);

This still remains unanswered, why in the first place we allow
switching, and a busy loop in the other place?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-25  8:55     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:55 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:

Forgot to add a couple of things...

...

> +#define MT6370_ITORCH_MIN_UA           25000
> +#define MT6370_ITORCH_STEP_UA          12500
> +#define MT6370_ITORCH_MAX_UA           400000
> +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> +#define MT6370_ISTRB_MIN_UA            50000
> +#define MT6370_ISTRB_STEP_UA           12500
> +#define MT6370_ISTRB_MAX_UA            1500000
> +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000

Perhaps _uA would be better and consistent across your series
regarding current units.

...

> +       /*
> +        * For the flash to turn on/off, need to wait HW ramping up/down time

we need

> +        * 5ms/500us to prevent the unexpected problem.
> +        */
> +       if (!prev && curr)
> +               usleep_range(5000, 6000);
> +       else if (prev && !curr)
> +               udelay(500);

This still remains unanswered, why in the first place we allow
switching, and a busy loop in the other place?

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-25  8:55     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  8:55 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:

Forgot to add a couple of things...

...

> +#define MT6370_ITORCH_MIN_UA           25000
> +#define MT6370_ITORCH_STEP_UA          12500
> +#define MT6370_ITORCH_MAX_UA           400000
> +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> +#define MT6370_ISTRB_MIN_UA            50000
> +#define MT6370_ISTRB_STEP_UA           12500
> +#define MT6370_ISTRB_MAX_UA            1500000
> +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000

Perhaps _uA would be better and consistent across your series
regarding current units.

...

> +       /*
> +        * For the flash to turn on/off, need to wait HW ramping up/down time

we need

> +        * 5ms/500us to prevent the unexpected problem.
> +        */
> +       if (!prev && curr)
> +               usleep_range(5000, 6000);
> +       else if (prev && !curr)
> +               udelay(500);

This still remains unanswered, why in the first place we allow
switching, and a busy loop in the other place?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-25  8:43         ` Andy Shevchenko
  (?)
@ 2022-07-25  9:06           ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  9:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > +
> > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > +
> > > > +#define MT6370_NUM_IRQREGS     16
> > > > +#define MT6370_USBC_I2CADDR    0x4E
> > >
> > > > +#define MT6370_REG_ADDRLEN     2
> > > > +#define MT6370_REG_MAXADDR     0x1FF
> > >
> > > These two more logically to have near to other _REG_* definitions above.
> >

...

>
> You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> _not_ of the _REG_ kind as per above, why do they have this namespace
> in the first place?

oh... Sorry, I just got the wrong meaning
maybe it should be revised like this, right??
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_REG_MAXADDR     0x1FF // Move it to here

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_USBC_I2CADDR    0x4E

#define MT6370_MAX_ADDRLEN     2    // Rename
-------------------------------------------------------------------

Thanks!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:06           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  9:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > +
> > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > +
> > > > +#define MT6370_NUM_IRQREGS     16
> > > > +#define MT6370_USBC_I2CADDR    0x4E
> > >
> > > > +#define MT6370_REG_ADDRLEN     2
> > > > +#define MT6370_REG_MAXADDR     0x1FF
> > >
> > > These two more logically to have near to other _REG_* definitions above.
> >

...

>
> You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> _not_ of the _REG_ kind as per above, why do they have this namespace
> in the first place?

oh... Sorry, I just got the wrong meaning
maybe it should be revised like this, right??
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_REG_MAXADDR     0x1FF // Move it to here

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_USBC_I2CADDR    0x4E

#define MT6370_MAX_ADDRLEN     2    // Rename
-------------------------------------------------------------------

Thanks!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:06           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-25  9:06 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > +
> > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > +
> > > > +#define MT6370_NUM_IRQREGS     16
> > > > +#define MT6370_USBC_I2CADDR    0x4E
> > >
> > > > +#define MT6370_REG_ADDRLEN     2
> > > > +#define MT6370_REG_MAXADDR     0x1FF
> > >
> > > These two more logically to have near to other _REG_* definitions above.
> >

...

>
> You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> _not_ of the _REG_ kind as per above, why do they have this namespace
> in the first place?

oh... Sorry, I just got the wrong meaning
maybe it should be revised like this, right??
-------------------------------------------------------------------
#define MT6370_REG_DEV_INFO    0x100
#define MT6370_REG_CHG_IRQ1    0x1C0
#define MT6370_REG_CHG_MASK1   0x1E0
#define MT6370_REG_MAXADDR     0x1FF // Move it to here

#define MT6370_VENID_MASK      GENMASK(7, 4)

#define MT6370_NUM_IRQREGS     16
#define MT6370_USBC_I2CADDR    0x4E

#define MT6370_MAX_ADDRLEN     2    // Rename
-------------------------------------------------------------------

Thanks!

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25  9:07     ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:07 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds support for MediaTek MT6370 Backlight driver. It's commonly used

Read Submitting Patches, please!

(In this case, find "This patch" in the above mentioned document, read
and act accordingly)

> to drive the display WLED. There are 4 channels inside, and each channel
> supports up to 30mA of current capability with 2048 current steps in
> exponential or linear mapping curves.

...

> +               brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);


(see below)

...

> +               /*
> +                * To make MT6372 using 14 bits to control the brightness
> +                * backward compatible with 11 bits brightness control
> +                * (like MT6370 and MT6371 do), we left shift the value
> +                * and pad with 1 to remaining bits. Hence, the MT6372's

to the remaining

> +                * backlight brightness will be almost the same as MT6370's
> +                * and MT6371's.
> +                */
> +               if (priv->vid_type == MT6370_VID_6372) {
> +                       brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +                       brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +               }

Nice! Why not...

...

> +       gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);

!!brightness will do as well.

...

> +       brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);

> +               val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);

> +               val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);

> +               val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);

> +       val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);

...to use respective _SHIFTs in all these?

...

> +       priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
> +                                                   GPIOD_OUT_HIGH);
> +       if (IS_ERR(priv->enable_gpio))
> +               dev_err(dev, "Failed to get 'enable' gpio\n");

What does this mean? Shouldn't be

  return dev_err_probe()?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:07     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:07 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds support for MediaTek MT6370 Backlight driver. It's commonly used

Read Submitting Patches, please!

(In this case, find "This patch" in the above mentioned document, read
and act accordingly)

> to drive the display WLED. There are 4 channels inside, and each channel
> supports up to 30mA of current capability with 2048 current steps in
> exponential or linear mapping curves.

...

> +               brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);


(see below)

...

> +               /*
> +                * To make MT6372 using 14 bits to control the brightness
> +                * backward compatible with 11 bits brightness control
> +                * (like MT6370 and MT6371 do), we left shift the value
> +                * and pad with 1 to remaining bits. Hence, the MT6372's

to the remaining

> +                * backlight brightness will be almost the same as MT6370's
> +                * and MT6371's.
> +                */
> +               if (priv->vid_type == MT6370_VID_6372) {
> +                       brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +                       brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +               }

Nice! Why not...

...

> +       gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);

!!brightness will do as well.

...

> +       brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);

> +               val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);

> +               val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);

> +               val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);

> +       val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);

...to use respective _SHIFTs in all these?

...

> +       priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
> +                                                   GPIOD_OUT_HIGH);
> +       if (IS_ERR(priv->enable_gpio))
> +               dev_err(dev, "Failed to get 'enable' gpio\n");

What does this mean? Shouldn't be

  return dev_err_probe()?

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:07     ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:07 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> From: ChiaEn Wu <chiaen_wu@richtek.com>
>
> MediaTek MT6370 is a SubPMIC consisting of a single cell battery charger
> with ADC monitoring, RGB LEDs, dual channel flashlight, WLED backlight
> driver, display bias voltage supply, one general purpose LDO, and the
> USB Type-C & PD controller complies with the latest USB Type-C and PD
> standards.
>
> This adds support for MediaTek MT6370 Backlight driver. It's commonly used

Read Submitting Patches, please!

(In this case, find "This patch" in the above mentioned document, read
and act accordingly)

> to drive the display WLED. There are 4 channels inside, and each channel
> supports up to 30mA of current capability with 2048 current steps in
> exponential or linear mapping curves.

...

> +               brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);


(see below)

...

> +               /*
> +                * To make MT6372 using 14 bits to control the brightness
> +                * backward compatible with 11 bits brightness control
> +                * (like MT6370 and MT6371 do), we left shift the value
> +                * and pad with 1 to remaining bits. Hence, the MT6372's

to the remaining

> +                * backlight brightness will be almost the same as MT6370's
> +                * and MT6371's.
> +                */
> +               if (priv->vid_type == MT6370_VID_6372) {
> +                       brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +                       brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +               }

Nice! Why not...

...

> +       gpiod_set_value(priv->enable_gpio, brightness ? 1 : 0);

!!brightness will do as well.

...

> +       brightness = brightness_val[1] << fls(MT6370_BL_DIM2_MASK);

> +               val |= prop_val << (ffs(MT6370_BL_PWM_HYS_SEL_MASK) - 1);

> +               val |= ovp_uV << (ffs(MT6370_BL_OVP_SEL_MASK) - 1);

> +               val |= ocp_uA << (ffs(MT6370_BL_OC_SEL_MASK) - 1);

> +       val = prop_val << (ffs(MT6370_BL_CH_MASK) - 1);

...to use respective _SHIFTs in all these?

...

> +       priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
> +                                                   GPIOD_OUT_HIGH);
> +       if (IS_ERR(priv->enable_gpio))
> +               dev_err(dev, "Failed to get 'enable' gpio\n");

What does this mean? Shouldn't be

  return dev_err_probe()?

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
  2022-07-25  9:06           ` ChiaEn Wu
  (?)
@ 2022-07-25  9:09             ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:09 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 11:06 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > > +
> > > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > > +
> > > > > +#define MT6370_NUM_IRQREGS     16
> > > > > +#define MT6370_USBC_I2CADDR    0x4E
> > > >
> > > > > +#define MT6370_REG_ADDRLEN     2
> > > > > +#define MT6370_REG_MAXADDR     0x1FF
> > > >
> > > > These two more logically to have near to other _REG_* definitions above.

...

> > You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> > In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> > _not_ of the _REG_ kind as per above, why do they have this namespace
> > in the first place?

> oh... Sorry, I just got the wrong meaning
> maybe it should be revised like this, right??

I don't know. I am not an author of the code, I do not have access
(and don't want to) to the hardware datasheets, all up to you. From
the style perspective below looks good.

> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_REG_MAXADDR     0x1FF // Move it to here
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_USBC_I2CADDR    0x4E
>
> #define MT6370_MAX_ADDRLEN     2    // Rename



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:09             ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:09 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 11:06 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > > +
> > > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > > +
> > > > > +#define MT6370_NUM_IRQREGS     16
> > > > > +#define MT6370_USBC_I2CADDR    0x4E
> > > >
> > > > > +#define MT6370_REG_ADDRLEN     2
> > > > > +#define MT6370_REG_MAXADDR     0x1FF
> > > >
> > > > These two more logically to have near to other _REG_* definitions above.

...

> > You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> > In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> > _not_ of the _REG_ kind as per above, why do they have this namespace
> > in the first place?

> oh... Sorry, I just got the wrong meaning
> maybe it should be revised like this, right??

I don't know. I am not an author of the code, I do not have access
(and don't want to) to the hardware datasheets, all up to you. From
the style perspective below looks good.

> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_REG_MAXADDR     0x1FF // Move it to here
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_USBC_I2CADDR    0x4E
>
> #define MT6370_MAX_ADDRLEN     2    // Rename



-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support
@ 2022-07-25  9:09             ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-25  9:09 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 11:06 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:43 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > > > +#define MT6370_REG_DEV_INFO    0x100
> > > > > +#define MT6370_REG_CHG_IRQ1    0x1C0
> > > > > +#define MT6370_REG_CHG_MASK1   0x1E0
> > > > > +
> > > > > +#define MT6370_VENID_MASK      GENMASK(7, 4)
> > > > > +
> > > > > +#define MT6370_NUM_IRQREGS     16
> > > > > +#define MT6370_USBC_I2CADDR    0x4E
> > > >
> > > > > +#define MT6370_REG_ADDRLEN     2
> > > > > +#define MT6370_REG_MAXADDR     0x1FF
> > > >
> > > > These two more logically to have near to other _REG_* definitions above.

...

> > You lost me. Namespace has a meaning, i.e. grouping items of a kind.
> > In your proposal I don't see that. If REG_MAXADDR and REG_ADDRLEN are
> > _not_ of the _REG_ kind as per above, why do they have this namespace
> > in the first place?

> oh... Sorry, I just got the wrong meaning
> maybe it should be revised like this, right??

I don't know. I am not an author of the code, I do not have access
(and don't want to) to the hardware datasheets, all up to you. From
the style perspective below looks good.

> -------------------------------------------------------------------
> #define MT6370_REG_DEV_INFO    0x100
> #define MT6370_REG_CHG_IRQ1    0x1C0
> #define MT6370_REG_CHG_MASK1   0x1E0
> #define MT6370_REG_MAXADDR     0x1FF // Move it to here
>
> #define MT6370_VENID_MASK      GENMASK(7, 4)
>
> #define MT6370_NUM_IRQREGS     16
> #define MT6370_USBC_I2CADDR    0x4E
>
> #define MT6370_MAX_ADDRLEN     2    // Rename



-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-25 10:31     ` Daniel Thompson
  -1 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-25 10:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, jingoohan1, pavel, robh+dt, krzysztof.kozlowski+dt,
	matthias.bgg, sre, chunfeng.yun, gregkh, jic23, lars, lgirdwood,
	broonie, linux, heikki.krogerus, deller, andy.shevchenko,
	chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index a003e02..846dbe7 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
>  	  If you have a LCD backlight connected to the WLED output of MAX8925
>  	  WLED output, say Y here to enable this driver.
>
> +config BACKLIGHT_MT6370
> +	tristate "MediaTek MT6370 Backlight Driver"
> +	depends on MFD_MT6370
> +	help
> +	  This enables support for Mediatek MT6370 Backlight driver.
> +	  It's commonly used to drive the display WLED. There are 4 channels
> +	  inside, and each channel supports up to 30mA of current capability
> +	  with 2048 current steps in exponential or linear mapping curves.

Does the MT6372 support more steps than this? In other words does it use
a fourteen bit scale or does it use an 11-bit scale at a different
register location?


> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "mt6370-backlight".
> +
> [...]
> diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> new file mode 100644
> index 0000000..ba00a8f
> --- /dev/null
> +++ b/drivers/video/backlight/mt6370-backlight.c
> [...]
> +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> +{
> +	struct mt6370_priv *priv = bl_get_data(bl_dev);
> +	int brightness = backlight_get_brightness(bl_dev);
> +	unsigned int enable_val;
> +	u8 brightness_val[2];
> +	int ret;
> +
> +	if (brightness) {
> +		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> +		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> +
> +		/*
> +		 * To make MT6372 using 14 bits to control the brightness
> +		 * backward compatible with 11 bits brightness control
> +		 * (like MT6370 and MT6371 do), we left shift the value
> +		 * and pad with 1 to remaining bits. Hence, the MT6372's
> +		 * backlight brightness will be almost the same as MT6370's
> +		 * and MT6371's.
> +		 */
> +		if (priv->vid_type == MT6370_VID_6372) {
> +			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +		}

This somewhat depends on the answer to the first question above, but
what is the point of this shifting? If the range is 14-bit then the
driver should set max_brightness to 16384 and present the full range of
the MT6372 to the user.

Especially when using linear mappings (which are a totally pointless
scale to use for a backlight) the extra steps are useful for backlight
animation.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-25 10:31     ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-25 10:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: linux-fbdev, heikki.krogerus, krzysztof.kozlowski+dt, alice_chen,
	linux-iio, dri-devel, lgirdwood, cy_huang, pavel, lee.jones,
	linux-leds, deller, robh+dt, andy.shevchenko, chunfeng.yun,
	linux, devicetree, linux-pm, szunichen, broonie, linux-mediatek,
	matthias.bgg, linux-arm-kernel, jingoohan1, linux-usb, sre,
	linux-kernel, chiaen_wu, gregkh, jic23

On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index a003e02..846dbe7 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
>  	  If you have a LCD backlight connected to the WLED output of MAX8925
>  	  WLED output, say Y here to enable this driver.
>
> +config BACKLIGHT_MT6370
> +	tristate "MediaTek MT6370 Backlight Driver"
> +	depends on MFD_MT6370
> +	help
> +	  This enables support for Mediatek MT6370 Backlight driver.
> +	  It's commonly used to drive the display WLED. There are 4 channels
> +	  inside, and each channel supports up to 30mA of current capability
> +	  with 2048 current steps in exponential or linear mapping curves.

Does the MT6372 support more steps than this? In other words does it use
a fourteen bit scale or does it use an 11-bit scale at a different
register location?


> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "mt6370-backlight".
> +
> [...]
> diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> new file mode 100644
> index 0000000..ba00a8f
> --- /dev/null
> +++ b/drivers/video/backlight/mt6370-backlight.c
> [...]
> +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> +{
> +	struct mt6370_priv *priv = bl_get_data(bl_dev);
> +	int brightness = backlight_get_brightness(bl_dev);
> +	unsigned int enable_val;
> +	u8 brightness_val[2];
> +	int ret;
> +
> +	if (brightness) {
> +		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> +		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> +
> +		/*
> +		 * To make MT6372 using 14 bits to control the brightness
> +		 * backward compatible with 11 bits brightness control
> +		 * (like MT6370 and MT6371 do), we left shift the value
> +		 * and pad with 1 to remaining bits. Hence, the MT6372's
> +		 * backlight brightness will be almost the same as MT6370's
> +		 * and MT6371's.
> +		 */
> +		if (priv->vid_type == MT6370_VID_6372) {
> +			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +		}

This somewhat depends on the answer to the first question above, but
what is the point of this shifting? If the range is 14-bit then the
driver should set max_brightness to 16384 and present the full range of
the MT6372 to the user.

Especially when using linear mappings (which are a totally pointless
scale to use for a backlight) the extra steps are useful for backlight
animation.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-25 10:31     ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-25 10:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, jingoohan1, pavel, robh+dt, krzysztof.kozlowski+dt,
	matthias.bgg, sre, chunfeng.yun, gregkh, jic23, lars, lgirdwood,
	broonie, linux, heikki.krogerus, deller, andy.shevchenko,
	chiaen_wu, alice_chen, cy_huang, dri-devel, linux-leds,
	devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
	linux-pm, linux-usb, linux-iio, linux-fbdev, szunichen

On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index a003e02..846dbe7 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
>  	  If you have a LCD backlight connected to the WLED output of MAX8925
>  	  WLED output, say Y here to enable this driver.
>
> +config BACKLIGHT_MT6370
> +	tristate "MediaTek MT6370 Backlight Driver"
> +	depends on MFD_MT6370
> +	help
> +	  This enables support for Mediatek MT6370 Backlight driver.
> +	  It's commonly used to drive the display WLED. There are 4 channels
> +	  inside, and each channel supports up to 30mA of current capability
> +	  with 2048 current steps in exponential or linear mapping curves.

Does the MT6372 support more steps than this? In other words does it use
a fourteen bit scale or does it use an 11-bit scale at a different
register location?


> +
> +	  This driver can also be built as a module. If so, the module
> +	  will be called "mt6370-backlight".
> +
> [...]
> diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> new file mode 100644
> index 0000000..ba00a8f
> --- /dev/null
> +++ b/drivers/video/backlight/mt6370-backlight.c
> [...]
> +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> +{
> +	struct mt6370_priv *priv = bl_get_data(bl_dev);
> +	int brightness = backlight_get_brightness(bl_dev);
> +	unsigned int enable_val;
> +	u8 brightness_val[2];
> +	int ret;
> +
> +	if (brightness) {
> +		brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> +		brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> +
> +		/*
> +		 * To make MT6372 using 14 bits to control the brightness
> +		 * backward compatible with 11 bits brightness control
> +		 * (like MT6370 and MT6371 do), we left shift the value
> +		 * and pad with 1 to remaining bits. Hence, the MT6372's
> +		 * backlight brightness will be almost the same as MT6370's
> +		 * and MT6371's.
> +		 */
> +		if (priv->vid_type == MT6370_VID_6372) {
> +			brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> +			brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> +		}

This somewhat depends on the answer to the first question above, but
what is the point of this shifting? If the range is 14-bit then the
driver should set max_brightness to 16384 and present the full range of
the MT6372 to the user.

Especially when using linear mappings (which are a totally pointless
scale to use for a backlight) the extra steps are useful for backlight
animation.


Daniel.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-25 10:31     ` Daniel Thompson
  (?)
@ 2022-07-26  2:20       ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26  2:20 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
>
> On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > index a003e02..846dbe7 100644
> > --- a/drivers/video/backlight/Kconfig
> > +++ b/drivers/video/backlight/Kconfig
> > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> >         If you have a LCD backlight connected to the WLED output of MAX8925
> >         WLED output, say Y here to enable this driver.
> >
> > +config BACKLIGHT_MT6370
> > +     tristate "MediaTek MT6370 Backlight Driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       This enables support for Mediatek MT6370 Backlight driver.
> > +       It's commonly used to drive the display WLED. There are 4 channels
> > +       inside, and each channel supports up to 30mA of current capability
> > +       with 2048 current steps in exponential or linear mapping curves.
>
> Does the MT6372 support more steps than this? In other words does it use
> a fourteen bit scale or does it use an 11-bit scale at a different
> register location?

Hi Daniel,

Thanks for your reply.
Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
location. But the maximum current of each
channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
The main reason why MT6372 is designed this way is that one of the
customers asked for a more delicate
adjustment of the backlight brightness. But other customers actually
do not have such requirements.
Therefore, we designed it this way for maximum compatibility in software.

>
>
> > +
> > +       This driver can also be built as a module. If so, the module
> > +       will be called "mt6370-backlight".
> > +
> > [...]
> > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > new file mode 100644
> > index 0000000..ba00a8f
> > --- /dev/null
> > +++ b/drivers/video/backlight/mt6370-backlight.c
> > [...]
> > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > +{
> > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > +     int brightness = backlight_get_brightness(bl_dev);
> > +     unsigned int enable_val;
> > +     u8 brightness_val[2];
> > +     int ret;
> > +
> > +     if (brightness) {
> > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > +
> > +             /*
> > +              * To make MT6372 using 14 bits to control the brightness
> > +              * backward compatible with 11 bits brightness control
> > +              * (like MT6370 and MT6371 do), we left shift the value
> > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > +              * backlight brightness will be almost the same as MT6370's
> > +              * and MT6371's.
> > +              */
> > +             if (priv->vid_type == MT6370_VID_6372) {
> > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > +             }
>
> This somewhat depends on the answer to the first question above, but
> what is the point of this shifting? If the range is 14-bit then the
> driver should set max_brightness to 16384 and present the full range of
> the MT6372 to the user.

So should we make all 16384 steps of MT6372 available to users?
Does that mean the DTS needs to be modified as well?
Or, for the reasons, I have just explained (just one customer has this
requirement), then we do not make any changes for compatibility
reasons?
Thanks.

>
> Especially when using linear mappings (which are a totally pointless
> scale to use for a backlight) the extra steps are useful for backlight
> animation.
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26  2:20       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26  2:20 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
>
> On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > index a003e02..846dbe7 100644
> > --- a/drivers/video/backlight/Kconfig
> > +++ b/drivers/video/backlight/Kconfig
> > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> >         If you have a LCD backlight connected to the WLED output of MAX8925
> >         WLED output, say Y here to enable this driver.
> >
> > +config BACKLIGHT_MT6370
> > +     tristate "MediaTek MT6370 Backlight Driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       This enables support for Mediatek MT6370 Backlight driver.
> > +       It's commonly used to drive the display WLED. There are 4 channels
> > +       inside, and each channel supports up to 30mA of current capability
> > +       with 2048 current steps in exponential or linear mapping curves.
>
> Does the MT6372 support more steps than this? In other words does it use
> a fourteen bit scale or does it use an 11-bit scale at a different
> register location?

Hi Daniel,

Thanks for your reply.
Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
location. But the maximum current of each
channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
The main reason why MT6372 is designed this way is that one of the
customers asked for a more delicate
adjustment of the backlight brightness. But other customers actually
do not have such requirements.
Therefore, we designed it this way for maximum compatibility in software.

>
>
> > +
> > +       This driver can also be built as a module. If so, the module
> > +       will be called "mt6370-backlight".
> > +
> > [...]
> > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > new file mode 100644
> > index 0000000..ba00a8f
> > --- /dev/null
> > +++ b/drivers/video/backlight/mt6370-backlight.c
> > [...]
> > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > +{
> > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > +     int brightness = backlight_get_brightness(bl_dev);
> > +     unsigned int enable_val;
> > +     u8 brightness_val[2];
> > +     int ret;
> > +
> > +     if (brightness) {
> > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > +
> > +             /*
> > +              * To make MT6372 using 14 bits to control the brightness
> > +              * backward compatible with 11 bits brightness control
> > +              * (like MT6370 and MT6371 do), we left shift the value
> > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > +              * backlight brightness will be almost the same as MT6370's
> > +              * and MT6371's.
> > +              */
> > +             if (priv->vid_type == MT6370_VID_6372) {
> > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > +             }
>
> This somewhat depends on the answer to the first question above, but
> what is the point of this shifting? If the range is 14-bit then the
> driver should set max_brightness to 16384 and present the full range of
> the MT6372 to the user.

So should we make all 16384 steps of MT6372 available to users?
Does that mean the DTS needs to be modified as well?
Or, for the reasons, I have just explained (just one customer has this
requirement), then we do not make any changes for compatibility
reasons?
Thanks.

>
> Especially when using linear mappings (which are a totally pointless
> scale to use for a backlight) the extra steps are useful for backlight
> animation.
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26  2:20       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26  2:20 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
>
> On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > index a003e02..846dbe7 100644
> > --- a/drivers/video/backlight/Kconfig
> > +++ b/drivers/video/backlight/Kconfig
> > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> >         If you have a LCD backlight connected to the WLED output of MAX8925
> >         WLED output, say Y here to enable this driver.
> >
> > +config BACKLIGHT_MT6370
> > +     tristate "MediaTek MT6370 Backlight Driver"
> > +     depends on MFD_MT6370
> > +     help
> > +       This enables support for Mediatek MT6370 Backlight driver.
> > +       It's commonly used to drive the display WLED. There are 4 channels
> > +       inside, and each channel supports up to 30mA of current capability
> > +       with 2048 current steps in exponential or linear mapping curves.
>
> Does the MT6372 support more steps than this? In other words does it use
> a fourteen bit scale or does it use an 11-bit scale at a different
> register location?

Hi Daniel,

Thanks for your reply.
Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
location. But the maximum current of each
channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
The main reason why MT6372 is designed this way is that one of the
customers asked for a more delicate
adjustment of the backlight brightness. But other customers actually
do not have such requirements.
Therefore, we designed it this way for maximum compatibility in software.

>
>
> > +
> > +       This driver can also be built as a module. If so, the module
> > +       will be called "mt6370-backlight".
> > +
> > [...]
> > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > new file mode 100644
> > index 0000000..ba00a8f
> > --- /dev/null
> > +++ b/drivers/video/backlight/mt6370-backlight.c
> > [...]
> > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > +{
> > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > +     int brightness = backlight_get_brightness(bl_dev);
> > +     unsigned int enable_val;
> > +     u8 brightness_val[2];
> > +     int ret;
> > +
> > +     if (brightness) {
> > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > +
> > +             /*
> > +              * To make MT6372 using 14 bits to control the brightness
> > +              * backward compatible with 11 bits brightness control
> > +              * (like MT6370 and MT6371 do), we left shift the value
> > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > +              * backlight brightness will be almost the same as MT6370's
> > +              * and MT6371's.
> > +              */
> > +             if (priv->vid_type == MT6370_VID_6372) {
> > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > +             }
>
> This somewhat depends on the answer to the first question above, but
> what is the point of this shifting? If the range is 14-bit then the
> driver should set max_brightness to 16384 and present the full range of
> the MT6372 to the user.

So should we make all 16384 steps of MT6372 available to users?
Does that mean the DTS needs to be modified as well?
Or, for the reasons, I have just explained (just one customer has this
requirement), then we do not make any changes for compatibility
reasons?
Thanks.

>
> Especially when using linear mappings (which are a totally pointless
> scale to use for a backlight) the extra steps are useful for backlight
> animation.
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-25  8:55     ` Andy Shevchenko
  (?)
@ 2022-07-26  4:15       ` szuni chen
  -1 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-26  4:15 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Hi Andy,

>
> > +#define MT6370_ITORCH_MIN_UA           25000
> > +#define MT6370_ITORCH_STEP_UA          12500
> > +#define MT6370_ITORCH_MAX_UA           400000
> > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > +#define MT6370_ISTRB_MIN_UA            50000
> > +#define MT6370_ISTRB_STEP_UA           12500
> > +#define MT6370_ISTRB_MAX_UA            1500000
> > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
>
> Perhaps _uA would be better and consistent across your series
> regarding current units.
>

Yes, _uA will be more consistent, but in general, using upper case in
the define macro is a convention, doesn't it?

>
> > +       /*
> > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
>
> we need
>
> > +        * 5ms/500us to prevent the unexpected problem.
> > +        */
> > +       if (!prev && curr)
> > +               usleep_range(5000, 6000);
> > +       else if (prev && !curr)
> > +               udelay(500);
>
> This still remains unanswered, why in the first place we allow
> switching, and a busy loop in the other place?

If I refine the description to
"For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
If any flash led is already used, then the analog is settled done, we
don't need to wait again."
is it answer the question?


Best regards,
Alice

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-26  4:15       ` szuni chen
  0 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-26  4:15 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki, Pavel Machek,
	Alice Chen, linux-iio, dri-devel, Liam Girdwood, cy_huang,
	Krzysztof Kozlowski, Lee Jones, Linux LED Subsystem,
	Daniel Thompson, Helge Deller, Rob Herring, Chunfeng Yun,
	Guenter Roeck, devicetree, Linux PM, Mark Brown,
	moderated list:ARM/Mediatek SoC support, Matthias Brugger,
	ChiaEn Wu, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

Hi Andy,

>
> > +#define MT6370_ITORCH_MIN_UA           25000
> > +#define MT6370_ITORCH_STEP_UA          12500
> > +#define MT6370_ITORCH_MAX_UA           400000
> > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > +#define MT6370_ISTRB_MIN_UA            50000
> > +#define MT6370_ISTRB_STEP_UA           12500
> > +#define MT6370_ISTRB_MAX_UA            1500000
> > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
>
> Perhaps _uA would be better and consistent across your series
> regarding current units.
>

Yes, _uA will be more consistent, but in general, using upper case in
the define macro is a convention, doesn't it?

>
> > +       /*
> > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
>
> we need
>
> > +        * 5ms/500us to prevent the unexpected problem.
> > +        */
> > +       if (!prev && curr)
> > +               usleep_range(5000, 6000);
> > +       else if (prev && !curr)
> > +               udelay(500);
>
> This still remains unanswered, why in the first place we allow
> switching, and a busy loop in the other place?

If I refine the description to
"For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
If any flash led is already used, then the analog is settled done, we
don't need to wait again."
is it answer the question?


Best regards,
Alice

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-26  4:15       ` szuni chen
  0 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-26  4:15 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Hi Andy,

>
> > +#define MT6370_ITORCH_MIN_UA           25000
> > +#define MT6370_ITORCH_STEP_UA          12500
> > +#define MT6370_ITORCH_MAX_UA           400000
> > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > +#define MT6370_ISTRB_MIN_UA            50000
> > +#define MT6370_ISTRB_STEP_UA           12500
> > +#define MT6370_ISTRB_MAX_UA            1500000
> > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
>
> Perhaps _uA would be better and consistent across your series
> regarding current units.
>

Yes, _uA will be more consistent, but in general, using upper case in
the define macro is a convention, doesn't it?

>
> > +       /*
> > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
>
> we need
>
> > +        * 5ms/500us to prevent the unexpected problem.
> > +        */
> > +       if (!prev && curr)
> > +               usleep_range(5000, 6000);
> > +       else if (prev && !curr)
> > +               udelay(500);
>
> This still remains unanswered, why in the first place we allow
> switching, and a busy loop in the other place?

If I refine the description to
"For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
If any flash led is already used, then the analog is settled done, we
don't need to wait again."
is it answer the question?


Best regards,
Alice

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-26  4:15       ` szuni chen
  (?)
@ 2022-07-26  6:10         ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26  6:10 UTC (permalink / raw)
  To: szuni chen
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

On Tue, Jul 26, 2022 at 6:15 AM szuni chen <szunichen@gmail.com> wrote:

...

> > > +#define MT6370_ITORCH_MIN_UA           25000
> > > +#define MT6370_ITORCH_STEP_UA          12500
> > > +#define MT6370_ITORCH_MAX_UA           400000
> > > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > > +#define MT6370_ISTRB_MIN_UA            50000
> > > +#define MT6370_ISTRB_STEP_UA           12500
> > > +#define MT6370_ISTRB_MAX_UA            1500000
> > > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
> >
> > Perhaps _uA would be better and consistent across your series
> > regarding current units.
>
> Yes, _uA will be more consistent, but in general, using upper case in
> the define macro is a convention, doesn't it?

There is general convention, but there are also:
1) common sense;
2) usage in practice (e.g. _US, etc for *seconds and _HZ for *frequency).

My common sense tells me that it is convenient to use mA,uA, etc.
Plus "in practice" it's related to use as in your series and elsewhere.

But of course it's minor to me, decide yourself.

...

> > > +       /*
> > > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
> >
> > we need
> >
> > > +        * 5ms/500us to prevent the unexpected problem.
> > > +        */
> > > +       if (!prev && curr)
> > > +               usleep_range(5000, 6000);
> > > +       else if (prev && !curr)
> > > +               udelay(500);
> >
> > This still remains unanswered, why in the first place we allow
> > switching, and a busy loop in the other place?
>
> If I refine the description to
> "For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
> If any flash led is already used, then the analog is settled done, we
> don't need to wait again."
> is it answer the question?

No. I'm talking from the Linux APIs perspective. There is a huge
difference between those branches. Please, conduct research, read
documentation to understand what my question is about.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-26  6:10         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26  6:10 UTC (permalink / raw)
  To: szuni chen
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki, Pavel Machek,
	Alice Chen, linux-iio, dri-devel, Liam Girdwood, cy_huang,
	Krzysztof Kozlowski, Lee Jones, Linux LED Subsystem,
	Daniel Thompson, Helge Deller, Rob Herring, Chunfeng Yun,
	Guenter Roeck, devicetree, Linux PM, Mark Brown,
	moderated list:ARM/Mediatek SoC support, Matthias Brugger,
	ChiaEn Wu, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 6:15 AM szuni chen <szunichen@gmail.com> wrote:

...

> > > +#define MT6370_ITORCH_MIN_UA           25000
> > > +#define MT6370_ITORCH_STEP_UA          12500
> > > +#define MT6370_ITORCH_MAX_UA           400000
> > > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > > +#define MT6370_ISTRB_MIN_UA            50000
> > > +#define MT6370_ISTRB_STEP_UA           12500
> > > +#define MT6370_ISTRB_MAX_UA            1500000
> > > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
> >
> > Perhaps _uA would be better and consistent across your series
> > regarding current units.
>
> Yes, _uA will be more consistent, but in general, using upper case in
> the define macro is a convention, doesn't it?

There is general convention, but there are also:
1) common sense;
2) usage in practice (e.g. _US, etc for *seconds and _HZ for *frequency).

My common sense tells me that it is convenient to use mA,uA, etc.
Plus "in practice" it's related to use as in your series and elsewhere.

But of course it's minor to me, decide yourself.

...

> > > +       /*
> > > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
> >
> > we need
> >
> > > +        * 5ms/500us to prevent the unexpected problem.
> > > +        */
> > > +       if (!prev && curr)
> > > +               usleep_range(5000, 6000);
> > > +       else if (prev && !curr)
> > > +               udelay(500);
> >
> > This still remains unanswered, why in the first place we allow
> > switching, and a busy loop in the other place?
>
> If I refine the description to
> "For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
> If any flash led is already used, then the analog is settled done, we
> don't need to wait again."
> is it answer the question?

No. I'm talking from the Linux APIs perspective. There is a huge
difference between those branches. Please, conduct research, read
documentation to understand what my question is about.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-26  6:10         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26  6:10 UTC (permalink / raw)
  To: szuni chen
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

On Tue, Jul 26, 2022 at 6:15 AM szuni chen <szunichen@gmail.com> wrote:

...

> > > +#define MT6370_ITORCH_MIN_UA           25000
> > > +#define MT6370_ITORCH_STEP_UA          12500
> > > +#define MT6370_ITORCH_MAX_UA           400000
> > > +#define MT6370_ITORCH_DOUBLE_MAX_UA    800000
> > > +#define MT6370_ISTRB_MIN_UA            50000
> > > +#define MT6370_ISTRB_STEP_UA           12500
> > > +#define MT6370_ISTRB_MAX_UA            1500000
> > > +#define MT6370_ISTRB_DOUBLE_MAX_UA     3000000
> >
> > Perhaps _uA would be better and consistent across your series
> > regarding current units.
>
> Yes, _uA will be more consistent, but in general, using upper case in
> the define macro is a convention, doesn't it?

There is general convention, but there are also:
1) common sense;
2) usage in practice (e.g. _US, etc for *seconds and _HZ for *frequency).

My common sense tells me that it is convenient to use mA,uA, etc.
Plus "in practice" it's related to use as in your series and elsewhere.

But of course it's minor to me, decide yourself.

...

> > > +       /*
> > > +        * For the flash to turn on/off, need to wait for HW ramping up/down time
> >
> > we need
> >
> > > +        * 5ms/500us to prevent the unexpected problem.
> > > +        */
> > > +       if (!prev && curr)
> > > +               usleep_range(5000, 6000);
> > > +       else if (prev && !curr)
> > > +               udelay(500);
> >
> > This still remains unanswered, why in the first place we allow
> > switching, and a busy loop in the other place?
>
> If I refine the description to
> "For the flash to turn on/off, need to wait for 5ms/500us analog settling time.
> If any flash led is already used, then the analog is settled done, we
> don't need to wait again."
> is it answer the question?

No. I'm talking from the Linux APIs perspective. There is a huge
difference between those branches. Please, conduct research, read
documentation to understand what my question is about.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-26  2:20       ` ChiaEn Wu
  (?)
@ 2022-07-26  9:30         ` Daniel Thompson
  -1 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26  9:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 10:20:02AM +0800, ChiaEn Wu wrote:
> On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> >
> > On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > > index a003e02..846dbe7 100644
> > > --- a/drivers/video/backlight/Kconfig
> > > +++ b/drivers/video/backlight/Kconfig
> > > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> > >         If you have a LCD backlight connected to the WLED output of MAX8925
> > >         WLED output, say Y here to enable this driver.
> > >
> > > +config BACKLIGHT_MT6370
> > > +     tristate "MediaTek MT6370 Backlight Driver"
> > > +     depends on MFD_MT6370
> > > +     help
> > > +       This enables support for Mediatek MT6370 Backlight driver.
> > > +       It's commonly used to drive the display WLED. There are 4 channels
> > > +       inside, and each channel supports up to 30mA of current capability
> > > +       with 2048 current steps in exponential or linear mapping curves.
> >
> > Does the MT6372 support more steps than this? In other words does it use
> > a fourteen bit scale or does it use an 11-bit scale at a different
> > register location?
>
> Hi Daniel,
>
> Thanks for your reply.
> Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> location. But the maximum current of each
> channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> The main reason why MT6372 is designed this way is that one of the
> customers asked for a more delicate
> adjustment of the backlight brightness. But other customers actually
> do not have such requirements.
> Therefore, we designed it this way for maximum compatibility in software.

I don't think that is an acceptable approach for the upstream kernel.

To be "compatible" with (broken) software this driver ends up reducing
the capability of the upstream kernel to the point it becomes unable to
meet requirements for delicate adjustment (requirements that were
sufficiently important to change the hardware design so you could meet
them).


> > > +
> > > +       This driver can also be built as a module. If so, the module
> > > +       will be called "mt6370-backlight".
> > > +
> > > [...]
> > > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > > new file mode 100644
> > > index 0000000..ba00a8f
> > > --- /dev/null
> > > +++ b/drivers/video/backlight/mt6370-backlight.c
> > > [...]
> > > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > > +{
> > > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > > +     int brightness = backlight_get_brightness(bl_dev);
> > > +     unsigned int enable_val;
> > > +     u8 brightness_val[2];
> > > +     int ret;
> > > +
> > > +     if (brightness) {
> > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > +
> > > +             /*
> > > +              * To make MT6372 using 14 bits to control the brightness
> > > +              * backward compatible with 11 bits brightness control
> > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > +              * backlight brightness will be almost the same as MT6370's
> > > +              * and MT6371's.
> > > +              */
> > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > +             }
> >
> > This somewhat depends on the answer to the first question above, but
> > what is the point of this shifting? If the range is 14-bit then the
> > driver should set max_brightness to 16384 and present the full range of
> > the MT6372 to the user.
>
> So should we make all 16384 steps of MT6372 available to users?

Yes.


> Does that mean the DTS needs to be modified as well?

Yes... the property to set initial brightness needs a 14-bit range.

It would also be a good idea to discuss with the DT maintainers whether
you should introduce a second compatible string (ending 6372) in order
to allow the DT validation checks to detect accidental use of MT6372
ranges on MT6370 hardware.


> Or, for the reasons, I have just explained (just one customer has this
> requirement), then we do not make any changes for compatibility
> reasons?

I'd be curious what the compatiblity reasons are. In other words what
software breaks?

Normally the userspace backlight code reads the max_brightness property
and configures things accordingly (and therefore if you the component
that breaks is something like an Android HAL then fix the HAL instead).


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26  9:30         ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26  9:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 10:20:02AM +0800, ChiaEn Wu wrote:
> On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> >
> > On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > > index a003e02..846dbe7 100644
> > > --- a/drivers/video/backlight/Kconfig
> > > +++ b/drivers/video/backlight/Kconfig
> > > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> > >         If you have a LCD backlight connected to the WLED output of MAX8925
> > >         WLED output, say Y here to enable this driver.
> > >
> > > +config BACKLIGHT_MT6370
> > > +     tristate "MediaTek MT6370 Backlight Driver"
> > > +     depends on MFD_MT6370
> > > +     help
> > > +       This enables support for Mediatek MT6370 Backlight driver.
> > > +       It's commonly used to drive the display WLED. There are 4 channels
> > > +       inside, and each channel supports up to 30mA of current capability
> > > +       with 2048 current steps in exponential or linear mapping curves.
> >
> > Does the MT6372 support more steps than this? In other words does it use
> > a fourteen bit scale or does it use an 11-bit scale at a different
> > register location?
>
> Hi Daniel,
>
> Thanks for your reply.
> Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> location. But the maximum current of each
> channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> The main reason why MT6372 is designed this way is that one of the
> customers asked for a more delicate
> adjustment of the backlight brightness. But other customers actually
> do not have such requirements.
> Therefore, we designed it this way for maximum compatibility in software.

I don't think that is an acceptable approach for the upstream kernel.

To be "compatible" with (broken) software this driver ends up reducing
the capability of the upstream kernel to the point it becomes unable to
meet requirements for delicate adjustment (requirements that were
sufficiently important to change the hardware design so you could meet
them).


> > > +
> > > +       This driver can also be built as a module. If so, the module
> > > +       will be called "mt6370-backlight".
> > > +
> > > [...]
> > > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > > new file mode 100644
> > > index 0000000..ba00a8f
> > > --- /dev/null
> > > +++ b/drivers/video/backlight/mt6370-backlight.c
> > > [...]
> > > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > > +{
> > > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > > +     int brightness = backlight_get_brightness(bl_dev);
> > > +     unsigned int enable_val;
> > > +     u8 brightness_val[2];
> > > +     int ret;
> > > +
> > > +     if (brightness) {
> > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > +
> > > +             /*
> > > +              * To make MT6372 using 14 bits to control the brightness
> > > +              * backward compatible with 11 bits brightness control
> > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > +              * backlight brightness will be almost the same as MT6370's
> > > +              * and MT6371's.
> > > +              */
> > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > +             }
> >
> > This somewhat depends on the answer to the first question above, but
> > what is the point of this shifting? If the range is 14-bit then the
> > driver should set max_brightness to 16384 and present the full range of
> > the MT6372 to the user.
>
> So should we make all 16384 steps of MT6372 available to users?

Yes.


> Does that mean the DTS needs to be modified as well?

Yes... the property to set initial brightness needs a 14-bit range.

It would also be a good idea to discuss with the DT maintainers whether
you should introduce a second compatible string (ending 6372) in order
to allow the DT validation checks to detect accidental use of MT6372
ranges on MT6370 hardware.


> Or, for the reasons, I have just explained (just one customer has this
> requirement), then we do not make any changes for compatibility
> reasons?

I'd be curious what the compatiblity reasons are. In other words what
software breaks?

Normally the userspace backlight code reads the max_brightness property
and configures things accordingly (and therefore if you the component
that breaks is something like an Android HAL then fix the HAL instead).


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26  9:30         ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26  9:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 10:20:02AM +0800, ChiaEn Wu wrote:
> On Mon, Jul 25, 2022 at 6:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> >
> > On Fri, Jul 22, 2022 at 06:24:07PM +0800, ChiaEn Wu wrote:
> > > diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> > > index a003e02..846dbe7 100644
> > > --- a/drivers/video/backlight/Kconfig
> > > +++ b/drivers/video/backlight/Kconfig
> > > @@ -268,6 +268,18 @@ config BACKLIGHT_MAX8925
> > >         If you have a LCD backlight connected to the WLED output of MAX8925
> > >         WLED output, say Y here to enable this driver.
> > >
> > > +config BACKLIGHT_MT6370
> > > +     tristate "MediaTek MT6370 Backlight Driver"
> > > +     depends on MFD_MT6370
> > > +     help
> > > +       This enables support for Mediatek MT6370 Backlight driver.
> > > +       It's commonly used to drive the display WLED. There are 4 channels
> > > +       inside, and each channel supports up to 30mA of current capability
> > > +       with 2048 current steps in exponential or linear mapping curves.
> >
> > Does the MT6372 support more steps than this? In other words does it use
> > a fourteen bit scale or does it use an 11-bit scale at a different
> > register location?
>
> Hi Daniel,
>
> Thanks for your reply.
> Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> location. But the maximum current of each
> channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> The main reason why MT6372 is designed this way is that one of the
> customers asked for a more delicate
> adjustment of the backlight brightness. But other customers actually
> do not have such requirements.
> Therefore, we designed it this way for maximum compatibility in software.

I don't think that is an acceptable approach for the upstream kernel.

To be "compatible" with (broken) software this driver ends up reducing
the capability of the upstream kernel to the point it becomes unable to
meet requirements for delicate adjustment (requirements that were
sufficiently important to change the hardware design so you could meet
them).


> > > +
> > > +       This driver can also be built as a module. If so, the module
> > > +       will be called "mt6370-backlight".
> > > +
> > > [...]
> > > diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c
> > > new file mode 100644
> > > index 0000000..ba00a8f
> > > --- /dev/null
> > > +++ b/drivers/video/backlight/mt6370-backlight.c
> > > [...]
> > > +static int mt6370_bl_update_status(struct backlight_device *bl_dev)
> > > +{
> > > +     struct mt6370_priv *priv = bl_get_data(bl_dev);
> > > +     int brightness = backlight_get_brightness(bl_dev);
> > > +     unsigned int enable_val;
> > > +     u8 brightness_val[2];
> > > +     int ret;
> > > +
> > > +     if (brightness) {
> > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > +
> > > +             /*
> > > +              * To make MT6372 using 14 bits to control the brightness
> > > +              * backward compatible with 11 bits brightness control
> > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > +              * backlight brightness will be almost the same as MT6370's
> > > +              * and MT6371's.
> > > +              */
> > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > +             }
> >
> > This somewhat depends on the answer to the first question above, but
> > what is the point of this shifting? If the range is 14-bit then the
> > driver should set max_brightness to 16384 and present the full range of
> > the MT6372 to the user.
>
> So should we make all 16384 steps of MT6372 available to users?

Yes.


> Does that mean the DTS needs to be modified as well?

Yes... the property to set initial brightness needs a 14-bit range.

It would also be a good idea to discuss with the DT maintainers whether
you should introduce a second compatible string (ending 6372) in order
to allow the DT validation checks to detect accidental use of MT6372
ranges on MT6370 hardware.


> Or, for the reasons, I have just explained (just one customer has this
> requirement), then we do not make any changes for compatibility
> reasons?

I'd be curious what the compatiblity reasons are. In other words what
software breaks?

Normally the userspace backlight code reads the max_brightness property
and configures things accordingly (and therefore if you the component
that breaks is something like an Android HAL then fix the HAL instead).


Daniel.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-26  9:30         ` Daniel Thompson
  (?)
@ 2022-07-26 11:28           ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:28 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
...
> > > Does the MT6372 support more steps than this? In other words does it use
> > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > register location?
> >
> > Hi Daniel,
> >
> > Thanks for your reply.
> > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > location. But the maximum current of each
> > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > The main reason why MT6372 is designed this way is that one of the
> > customers asked for a more delicate
> > adjustment of the backlight brightness. But other customers actually
> > do not have such requirements.
> > Therefore, we designed it this way for maximum compatibility in software.

Sorry for I used of the wrong word, I mean is 'driver', not
higher-level software

>
> I don't think that is an acceptable approach for the upstream kernel.
>
> To be "compatible" with (broken) software this driver ends up reducing
> the capability of the upstream kernel to the point it becomes unable to
> meet requirements for delicate adjustment (requirements that were
> sufficiently important to change the hardware design so you could meet
> them).

Originally, we just wanted to use one version of the driver to cover
all the SubPMIC of the 6370 series(6370~6372).
And, the users who use this series SubPMIC can directly apply this
driver to drive the backlight device without knowing the underlying
hardware.
To achieve this goal, we have designed it to look like this.

>
>
...
> > > > +
> > > > +     if (brightness) {
> > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > +
> > > > +             /*
> > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > +              * backward compatible with 11 bits brightness control
> > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > +              * backlight brightness will be almost the same as MT6370's
> > > > +              * and MT6371's.
> > > > +              */
> > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > +             }
> > >
> > > This somewhat depends on the answer to the first question above, but
> > > what is the point of this shifting? If the range is 14-bit then the
> > > driver should set max_brightness to 16384 and present the full range of
> > > the MT6372 to the user.
> >
> > So should we make all 16384 steps of MT6372 available to users?
>
> Yes.
>
>
> > Does that mean the DTS needs to be modified as well?
>
> Yes... the property to set initial brightness needs a 14-bit range.
>
> It would also be a good idea to discuss with the DT maintainers whether
> you should introduce a second compatible string (ending 6372) in order
> to allow the DT validation checks to detect accidental use of MT6372
> ranges on MT6370 hardware.

hmmm... I have just thought about it,
maybe I can just modify the maximum value of default-brightness and
max-brightness in DT to 16384,
modify the description and add some comments.

And then on the driver side,
we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;

If I do this change, does this meet your requirements?

>
>
> > Or, for the reasons, I have just explained (just one customer has this
> > requirement), then we do not make any changes for compatibility
> > reasons?
>
> I'd be curious what the compatiblity reasons are. In other words what
> software breaks?

The reason is as above. We just hope the users who use this series SubPMIC can
directly apply this driver to drive the backlight device without
knowing the underlying hardware.
Not software breaks.

Thanks!

>
> Normally the userspace backlight code reads the max_brightness property
> and configures things accordingly (and therefore if you the component
> that breaks is something like an Android HAL then fix the HAL instead).
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26 11:28           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:28 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
...
> > > Does the MT6372 support more steps than this? In other words does it use
> > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > register location?
> >
> > Hi Daniel,
> >
> > Thanks for your reply.
> > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > location. But the maximum current of each
> > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > The main reason why MT6372 is designed this way is that one of the
> > customers asked for a more delicate
> > adjustment of the backlight brightness. But other customers actually
> > do not have such requirements.
> > Therefore, we designed it this way for maximum compatibility in software.

Sorry for I used of the wrong word, I mean is 'driver', not
higher-level software

>
> I don't think that is an acceptable approach for the upstream kernel.
>
> To be "compatible" with (broken) software this driver ends up reducing
> the capability of the upstream kernel to the point it becomes unable to
> meet requirements for delicate adjustment (requirements that were
> sufficiently important to change the hardware design so you could meet
> them).

Originally, we just wanted to use one version of the driver to cover
all the SubPMIC of the 6370 series(6370~6372).
And, the users who use this series SubPMIC can directly apply this
driver to drive the backlight device without knowing the underlying
hardware.
To achieve this goal, we have designed it to look like this.

>
>
...
> > > > +
> > > > +     if (brightness) {
> > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > +
> > > > +             /*
> > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > +              * backward compatible with 11 bits brightness control
> > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > +              * backlight brightness will be almost the same as MT6370's
> > > > +              * and MT6371's.
> > > > +              */
> > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > +             }
> > >
> > > This somewhat depends on the answer to the first question above, but
> > > what is the point of this shifting? If the range is 14-bit then the
> > > driver should set max_brightness to 16384 and present the full range of
> > > the MT6372 to the user.
> >
> > So should we make all 16384 steps of MT6372 available to users?
>
> Yes.
>
>
> > Does that mean the DTS needs to be modified as well?
>
> Yes... the property to set initial brightness needs a 14-bit range.
>
> It would also be a good idea to discuss with the DT maintainers whether
> you should introduce a second compatible string (ending 6372) in order
> to allow the DT validation checks to detect accidental use of MT6372
> ranges on MT6370 hardware.

hmmm... I have just thought about it,
maybe I can just modify the maximum value of default-brightness and
max-brightness in DT to 16384,
modify the description and add some comments.

And then on the driver side,
we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;

If I do this change, does this meet your requirements?

>
>
> > Or, for the reasons, I have just explained (just one customer has this
> > requirement), then we do not make any changes for compatibility
> > reasons?
>
> I'd be curious what the compatiblity reasons are. In other words what
> software breaks?

The reason is as above. We just hope the users who use this series SubPMIC can
directly apply this driver to drive the backlight device without
knowing the underlying hardware.
Not software breaks.

Thanks!

>
> Normally the userspace backlight code reads the max_brightness property
> and configures things accordingly (and therefore if you the component
> that breaks is something like an Android HAL then fix the HAL instead).
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26 11:28           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:28 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:
...
> > > Does the MT6372 support more steps than this? In other words does it use
> > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > register location?
> >
> > Hi Daniel,
> >
> > Thanks for your reply.
> > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > location. But the maximum current of each
> > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > The main reason why MT6372 is designed this way is that one of the
> > customers asked for a more delicate
> > adjustment of the backlight brightness. But other customers actually
> > do not have such requirements.
> > Therefore, we designed it this way for maximum compatibility in software.

Sorry for I used of the wrong word, I mean is 'driver', not
higher-level software

>
> I don't think that is an acceptable approach for the upstream kernel.
>
> To be "compatible" with (broken) software this driver ends up reducing
> the capability of the upstream kernel to the point it becomes unable to
> meet requirements for delicate adjustment (requirements that were
> sufficiently important to change the hardware design so you could meet
> them).

Originally, we just wanted to use one version of the driver to cover
all the SubPMIC of the 6370 series(6370~6372).
And, the users who use this series SubPMIC can directly apply this
driver to drive the backlight device without knowing the underlying
hardware.
To achieve this goal, we have designed it to look like this.

>
>
...
> > > > +
> > > > +     if (brightness) {
> > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > +
> > > > +             /*
> > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > +              * backward compatible with 11 bits brightness control
> > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > +              * backlight brightness will be almost the same as MT6370's
> > > > +              * and MT6371's.
> > > > +              */
> > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > +             }
> > >
> > > This somewhat depends on the answer to the first question above, but
> > > what is the point of this shifting? If the range is 14-bit then the
> > > driver should set max_brightness to 16384 and present the full range of
> > > the MT6372 to the user.
> >
> > So should we make all 16384 steps of MT6372 available to users?
>
> Yes.
>
>
> > Does that mean the DTS needs to be modified as well?
>
> Yes... the property to set initial brightness needs a 14-bit range.
>
> It would also be a good idea to discuss with the DT maintainers whether
> you should introduce a second compatible string (ending 6372) in order
> to allow the DT validation checks to detect accidental use of MT6372
> ranges on MT6370 hardware.

hmmm... I have just thought about it,
maybe I can just modify the maximum value of default-brightness and
max-brightness in DT to 16384,
modify the description and add some comments.

And then on the driver side,
we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;

If I do this change, does this meet your requirements?

>
>
> > Or, for the reasons, I have just explained (just one customer has this
> > requirement), then we do not make any changes for compatibility
> > reasons?
>
> I'd be curious what the compatiblity reasons are. In other words what
> software breaks?

The reason is as above. We just hope the users who use this series SubPMIC can
directly apply this driver to drive the backlight device without
knowing the underlying hardware.
Not software breaks.

Thanks!

>
> Normally the userspace backlight code reads the max_brightness property
> and configures things accordingly (and therefore if you the component
> that breaks is something like an Android HAL then fix the HAL instead).
>
>
> Daniel.

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-25  8:40     ` Andy Shevchenko
  (?)
@ 2022-07-26 11:45       ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:45 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
...
> > From: ChiYuan Huang <cy_huang@richtek.com>
>
> ^^^^ (Note this and read below)

...

> In conjunction with above what SoB of Alice means?
>
> You really need to take your time and (re-)read
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

Hi Andy,

Thanks for your reply.
We are very sorry for this mistake. We will revise it in the next patch.

>
> ...
>
> > + * Author: Alice Chen <alice_chen@richtek.com>
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
>
> Would
>  * Authors:
>  *    Name_of_Author 1
>  *    Name_of_Author 2
>
> work for you?

It looks good, thanks! We will apply this in the next patch.

 ...

> > +struct mt6370_led {
> > +       union {
> > +               struct led_classdev isink;
> > +               struct led_classdev_mc mc;
> > +       };
>
> Where is the field that makes union work?

Just for saving memory space.
Because these led_classdevs do not be used at the same time.
Or do you think it would be better to rewrite it as follows?
-------------------------------------------------------------------------------------
struct mt6370_led {
       struct led_classdev isink;
       struct led_classdev_mc mc;
       struct mt6370_priv *priv;
       u32 default_state;
       u32 index;
};
-------------------------------------------------------------------------------------

...

> > +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> > +                                    struct led_pattern *pattern, u32 len,
> > +                                    u8 *pattern_val, u32 val_len)
> > +{
> > +       enum mt6370_led_ranges sel_range;
> > +       struct led_pattern *curr;
> > +       unsigned int sel;
> > +       u8 val[P_MAX_PATTERNS / 2] = {};
> > +       int i;
> > +
> > +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> > +               return -EINVAL;
> > +
> > +       /*
> > +        * Pattern list
> > +        * tr1: byte 0, b'[7: 4]
> > +        * tr2: byte 0, b'[3: 0]
> > +        * tf1: byte 1, b'[7: 4]
> > +        * tf2: byte 1, b'[3: 0]
> > +        * ton: byte 2, b'[7: 4]
> > +        * toff: byte 2, b'[3: 0]
> > +        */
> > +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> > +               curr = pattern + i;
> > +
> > +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> > +
> > +               linear_range_get_selector_within(priv->ranges + sel_range,
> > +                                                curr->delta_t, &sel);
> > +
> > +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> > +       }
> > +
> > +       memcpy(pattern_val, val, 3);
>
> Isn't it something like put_unaligned_be24()/put_unaligned_le24()?

OK, we will try to apply this method in the next patch.
Thank you so much for reviewing our patches so many times and
providing so many great suggestions!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-26 11:45       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:45 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
...
> > From: ChiYuan Huang <cy_huang@richtek.com>
>
> ^^^^ (Note this and read below)

...

> In conjunction with above what SoB of Alice means?
>
> You really need to take your time and (re-)read
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

Hi Andy,

Thanks for your reply.
We are very sorry for this mistake. We will revise it in the next patch.

>
> ...
>
> > + * Author: Alice Chen <alice_chen@richtek.com>
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
>
> Would
>  * Authors:
>  *    Name_of_Author 1
>  *    Name_of_Author 2
>
> work for you?

It looks good, thanks! We will apply this in the next patch.

 ...

> > +struct mt6370_led {
> > +       union {
> > +               struct led_classdev isink;
> > +               struct led_classdev_mc mc;
> > +       };
>
> Where is the field that makes union work?

Just for saving memory space.
Because these led_classdevs do not be used at the same time.
Or do you think it would be better to rewrite it as follows?
-------------------------------------------------------------------------------------
struct mt6370_led {
       struct led_classdev isink;
       struct led_classdev_mc mc;
       struct mt6370_priv *priv;
       u32 default_state;
       u32 index;
};
-------------------------------------------------------------------------------------

...

> > +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> > +                                    struct led_pattern *pattern, u32 len,
> > +                                    u8 *pattern_val, u32 val_len)
> > +{
> > +       enum mt6370_led_ranges sel_range;
> > +       struct led_pattern *curr;
> > +       unsigned int sel;
> > +       u8 val[P_MAX_PATTERNS / 2] = {};
> > +       int i;
> > +
> > +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> > +               return -EINVAL;
> > +
> > +       /*
> > +        * Pattern list
> > +        * tr1: byte 0, b'[7: 4]
> > +        * tr2: byte 0, b'[3: 0]
> > +        * tf1: byte 1, b'[7: 4]
> > +        * tf2: byte 1, b'[3: 0]
> > +        * ton: byte 2, b'[7: 4]
> > +        * toff: byte 2, b'[3: 0]
> > +        */
> > +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> > +               curr = pattern + i;
> > +
> > +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> > +
> > +               linear_range_get_selector_within(priv->ranges + sel_range,
> > +                                                curr->delta_t, &sel);
> > +
> > +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> > +       }
> > +
> > +       memcpy(pattern_val, val, 3);
>
> Isn't it something like put_unaligned_be24()/put_unaligned_le24()?

OK, we will try to apply this method in the next patch.
Thank you so much for reviewing our patches so many times and
providing so many great suggestions!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-26 11:45       ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-26 11:45 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:
...
> > From: ChiYuan Huang <cy_huang@richtek.com>
>
> ^^^^ (Note this and read below)

...

> In conjunction with above what SoB of Alice means?
>
> You really need to take your time and (re-)read
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html.

Hi Andy,

Thanks for your reply.
We are very sorry for this mistake. We will revise it in the next patch.

>
> ...
>
> > + * Author: Alice Chen <alice_chen@richtek.com>
> > + * Author: ChiYuan Huang <cy_huang@richtek.com>
>
> Would
>  * Authors:
>  *    Name_of_Author 1
>  *    Name_of_Author 2
>
> work for you?

It looks good, thanks! We will apply this in the next patch.

 ...

> > +struct mt6370_led {
> > +       union {
> > +               struct led_classdev isink;
> > +               struct led_classdev_mc mc;
> > +       };
>
> Where is the field that makes union work?

Just for saving memory space.
Because these led_classdevs do not be used at the same time.
Or do you think it would be better to rewrite it as follows?
-------------------------------------------------------------------------------------
struct mt6370_led {
       struct led_classdev isink;
       struct led_classdev_mc mc;
       struct mt6370_priv *priv;
       u32 default_state;
       u32 index;
};
-------------------------------------------------------------------------------------

...

> > +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> > +                                    struct led_pattern *pattern, u32 len,
> > +                                    u8 *pattern_val, u32 val_len)
> > +{
> > +       enum mt6370_led_ranges sel_range;
> > +       struct led_pattern *curr;
> > +       unsigned int sel;
> > +       u8 val[P_MAX_PATTERNS / 2] = {};
> > +       int i;
> > +
> > +       if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> > +               return -EINVAL;
> > +
> > +       /*
> > +        * Pattern list
> > +        * tr1: byte 0, b'[7: 4]
> > +        * tr2: byte 0, b'[3: 0]
> > +        * tf1: byte 1, b'[7: 4]
> > +        * tf2: byte 1, b'[3: 0]
> > +        * ton: byte 2, b'[7: 4]
> > +        * toff: byte 2, b'[3: 0]
> > +        */
> > +       for (i = 0; i < P_MAX_PATTERNS; i++) {
> > +               curr = pattern + i;
> > +
> > +               sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> > +
> > +               linear_range_get_selector_within(priv->ranges + sel_range,
> > +                                                curr->delta_t, &sel);
> > +
> > +               val[i / 2] |= sel << (4 * ((i + 1) % 2));
> > +       }
> > +
> > +       memcpy(pattern_val, val, 3);
>
> Isn't it something like put_unaligned_be24()/put_unaligned_le24()?

OK, we will try to apply this method in the next patch.
Thank you so much for reviewing our patches so many times and
providing so many great suggestions!

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-26 11:28           ` ChiaEn Wu
  (?)
@ 2022-07-26 11:59             ` Daniel Thompson
  -1 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26 11:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 07:28:48PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> ...
> > > > Does the MT6372 support more steps than this? In other words does it use
> > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > register location?
> > >
> > > Hi Daniel,
> > >
> > > Thanks for your reply.
> > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > location. But the maximum current of each
> > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > The main reason why MT6372 is designed this way is that one of the
> > > customers asked for a more delicate
> > > adjustment of the backlight brightness. But other customers actually
> > > do not have such requirements.
> > > Therefore, we designed it this way for maximum compatibility in software.
>
> Sorry for I used of the wrong word, I mean is 'driver', not
> higher-level software
>
> >
> > I don't think that is an acceptable approach for the upstream kernel.
> >
> > To be "compatible" with (broken) software this driver ends up reducing
> > the capability of the upstream kernel to the point it becomes unable to
> > meet requirements for delicate adjustment (requirements that were
> > sufficiently important to change the hardware design so you could meet
> > them).
>
> Originally, we just wanted to use one version of the driver to cover
> all the SubPMIC of the 6370 series(6370~6372).
> And, the users who use this series SubPMIC can directly apply this
> driver to drive the backlight device without knowing the underlying
> hardware.
> To achieve this goal, we have designed it to look like this.

You don't need a second driver to support two different values for
max-brightness. The same driver can support both ranges with nothing but
a small tweak during the driver probe function.


> ...
> > > > > +
> > > > > +     if (brightness) {
> > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > +
> > > > > +             /*
> > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > +              * backward compatible with 11 bits brightness control
> > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > +              * and MT6371's.
> > > > > +              */
> > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > +             }
> > > >
> > > > This somewhat depends on the answer to the first question above, but
> > > > what is the point of this shifting? If the range is 14-bit then the
> > > > driver should set max_brightness to 16384 and present the full range of
> > > > the MT6372 to the user.
> > >
> > > So should we make all 16384 steps of MT6372 available to users?
> >
> > Yes.
> >
> >
> > > Does that mean the DTS needs to be modified as well?
> >
> > Yes... the property to set initial brightness needs a 14-bit range.
> >
> > It would also be a good idea to discuss with the DT maintainers whether
> > you should introduce a second compatible string (ending 6372) in order
> > to allow the DT validation checks to detect accidental use of MT6372
> > ranges on MT6370 hardware.
>
> hmmm... I have just thought about it,
> maybe I can just modify the maximum value of default-brightness and
> max-brightness in DT to 16384,
> modify the description and add some comments.

What for?

All the other backlight drivers (there are >130 of them) expose the hardware
range[1]. Most userspaces will already know how to handle that (by reading
the max_brightness and, if it is recent enough, also the scale
properties in sysfs).

I'm still don't understand why one should fix a bug in the userspace by
implementing a hack in the driver.


[1] Well almost. The PWM backlight driver does contain support for
    dead-spot avoidance and to allow the adoption of exponential scale.
    However this  purpose of these is based on how PWM backlights work



> And then on the driver side,
> we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
> If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
>
> If I do this change, does this meet your requirements?

Not really.

It's still misleading a sophisticated userspace, which may make bad
rounding decisions for backlight animation, in order to support a broken
one.


> > > Or, for the reasons, I have just explained (just one customer has this
> > > requirement), then we do not make any changes for compatibility
> > > reasons?
> >
> > I'd be curious what the compatiblity reasons are. In other words what
> > software breaks?
>
> The reason is as above. We just hope the users who use this series SubPMIC can
> directly apply this driver to drive the backlight device without
> knowing the underlying hardware.
> Not software breaks.

As above, ignoring the max_brightness property is a bug in the
userspace. I'm still unclear why sending faked ranges to userspace
it a better solution than fixing the userspace.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26 11:59             ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26 11:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 07:28:48PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> ...
> > > > Does the MT6372 support more steps than this? In other words does it use
> > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > register location?
> > >
> > > Hi Daniel,
> > >
> > > Thanks for your reply.
> > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > location. But the maximum current of each
> > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > The main reason why MT6372 is designed this way is that one of the
> > > customers asked for a more delicate
> > > adjustment of the backlight brightness. But other customers actually
> > > do not have such requirements.
> > > Therefore, we designed it this way for maximum compatibility in software.
>
> Sorry for I used of the wrong word, I mean is 'driver', not
> higher-level software
>
> >
> > I don't think that is an acceptable approach for the upstream kernel.
> >
> > To be "compatible" with (broken) software this driver ends up reducing
> > the capability of the upstream kernel to the point it becomes unable to
> > meet requirements for delicate adjustment (requirements that were
> > sufficiently important to change the hardware design so you could meet
> > them).
>
> Originally, we just wanted to use one version of the driver to cover
> all the SubPMIC of the 6370 series(6370~6372).
> And, the users who use this series SubPMIC can directly apply this
> driver to drive the backlight device without knowing the underlying
> hardware.
> To achieve this goal, we have designed it to look like this.

You don't need a second driver to support two different values for
max-brightness. The same driver can support both ranges with nothing but
a small tweak during the driver probe function.


> ...
> > > > > +
> > > > > +     if (brightness) {
> > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > +
> > > > > +             /*
> > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > +              * backward compatible with 11 bits brightness control
> > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > +              * and MT6371's.
> > > > > +              */
> > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > +             }
> > > >
> > > > This somewhat depends on the answer to the first question above, but
> > > > what is the point of this shifting? If the range is 14-bit then the
> > > > driver should set max_brightness to 16384 and present the full range of
> > > > the MT6372 to the user.
> > >
> > > So should we make all 16384 steps of MT6372 available to users?
> >
> > Yes.
> >
> >
> > > Does that mean the DTS needs to be modified as well?
> >
> > Yes... the property to set initial brightness needs a 14-bit range.
> >
> > It would also be a good idea to discuss with the DT maintainers whether
> > you should introduce a second compatible string (ending 6372) in order
> > to allow the DT validation checks to detect accidental use of MT6372
> > ranges on MT6370 hardware.
>
> hmmm... I have just thought about it,
> maybe I can just modify the maximum value of default-brightness and
> max-brightness in DT to 16384,
> modify the description and add some comments.

What for?

All the other backlight drivers (there are >130 of them) expose the hardware
range[1]. Most userspaces will already know how to handle that (by reading
the max_brightness and, if it is recent enough, also the scale
properties in sysfs).

I'm still don't understand why one should fix a bug in the userspace by
implementing a hack in the driver.


[1] Well almost. The PWM backlight driver does contain support for
    dead-spot avoidance and to allow the adoption of exponential scale.
    However this  purpose of these is based on how PWM backlights work



> And then on the driver side,
> we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
> If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
>
> If I do this change, does this meet your requirements?

Not really.

It's still misleading a sophisticated userspace, which may make bad
rounding decisions for backlight animation, in order to support a broken
one.


> > > Or, for the reasons, I have just explained (just one customer has this
> > > requirement), then we do not make any changes for compatibility
> > > reasons?
> >
> > I'd be curious what the compatiblity reasons are. In other words what
> > software breaks?
>
> The reason is as above. We just hope the users who use this series SubPMIC can
> directly apply this driver to drive the backlight device without
> knowing the underlying hardware.
> Not software breaks.

As above, ignoring the max_brightness property is a bug in the
userspace. I'm still unclear why sending faked ranges to userspace
it a better solution than fixing the userspace.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-26 11:59             ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-26 11:59 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 07:28:48PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 5:31 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> ...
> > > > Does the MT6372 support more steps than this? In other words does it use
> > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > register location?
> > >
> > > Hi Daniel,
> > >
> > > Thanks for your reply.
> > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > location. But the maximum current of each
> > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > The main reason why MT6372 is designed this way is that one of the
> > > customers asked for a more delicate
> > > adjustment of the backlight brightness. But other customers actually
> > > do not have such requirements.
> > > Therefore, we designed it this way for maximum compatibility in software.
>
> Sorry for I used of the wrong word, I mean is 'driver', not
> higher-level software
>
> >
> > I don't think that is an acceptable approach for the upstream kernel.
> >
> > To be "compatible" with (broken) software this driver ends up reducing
> > the capability of the upstream kernel to the point it becomes unable to
> > meet requirements for delicate adjustment (requirements that were
> > sufficiently important to change the hardware design so you could meet
> > them).
>
> Originally, we just wanted to use one version of the driver to cover
> all the SubPMIC of the 6370 series(6370~6372).
> And, the users who use this series SubPMIC can directly apply this
> driver to drive the backlight device without knowing the underlying
> hardware.
> To achieve this goal, we have designed it to look like this.

You don't need a second driver to support two different values for
max-brightness. The same driver can support both ranges with nothing but
a small tweak during the driver probe function.


> ...
> > > > > +
> > > > > +     if (brightness) {
> > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > +
> > > > > +             /*
> > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > +              * backward compatible with 11 bits brightness control
> > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > +              * and MT6371's.
> > > > > +              */
> > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > +             }
> > > >
> > > > This somewhat depends on the answer to the first question above, but
> > > > what is the point of this shifting? If the range is 14-bit then the
> > > > driver should set max_brightness to 16384 and present the full range of
> > > > the MT6372 to the user.
> > >
> > > So should we make all 16384 steps of MT6372 available to users?
> >
> > Yes.
> >
> >
> > > Does that mean the DTS needs to be modified as well?
> >
> > Yes... the property to set initial brightness needs a 14-bit range.
> >
> > It would also be a good idea to discuss with the DT maintainers whether
> > you should introduce a second compatible string (ending 6372) in order
> > to allow the DT validation checks to detect accidental use of MT6372
> > ranges on MT6370 hardware.
>
> hmmm... I have just thought about it,
> maybe I can just modify the maximum value of default-brightness and
> max-brightness in DT to 16384,
> modify the description and add some comments.

What for?

All the other backlight drivers (there are >130 of them) expose the hardware
range[1]. Most userspaces will already know how to handle that (by reading
the max_brightness and, if it is recent enough, also the scale
properties in sysfs).

I'm still don't understand why one should fix a bug in the userspace by
implementing a hack in the driver.


[1] Well almost. The PWM backlight driver does contain support for
    dead-spot avoidance and to allow the adoption of exponential scale.
    However this  purpose of these is based on how PWM backlights work



> And then on the driver side,
> we can use mt6370_check_vendor_info( ) to determine whether it is MT6372.
> If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
>
> If I do this change, does this meet your requirements?

Not really.

It's still misleading a sophisticated userspace, which may make bad
rounding decisions for backlight animation, in order to support a broken
one.


> > > Or, for the reasons, I have just explained (just one customer has this
> > > requirement), then we do not make any changes for compatibility
> > > reasons?
> >
> > I'd be curious what the compatiblity reasons are. In other words what
> > software breaks?
>
> The reason is as above. We just hope the users who use this series SubPMIC can
> directly apply this driver to drive the backlight device without
> knowing the underlying hardware.
> Not software breaks.

As above, ignoring the max_brightness property is a bug in the
userspace. I'm still unclear why sending faked ranges to userspace
it a better solution than fixing the userspace.


Daniel.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-26 11:45       ` ChiaEn Wu
  (?)
@ 2022-07-26 12:17         ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26 12:17 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 1:46 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +struct mt6370_led {
> > > +       union {
> > > +               struct led_classdev isink;
> > > +               struct led_classdev_mc mc;
> > > +       };
> >
> > Where is the field that makes union work?
>
> Just for saving memory space.
> Because these led_classdevs do not be used at the same time.
> Or do you think it would be better to rewrite it as follows?
> -------------------------------------------------------------------------------------
> struct mt6370_led {
>        struct led_classdev isink;
>        struct led_classdev_mc mc;
>        struct mt6370_priv *priv;
>        u32 default_state;
>        u32 index;
> };
> -------------------------------------------------------------------------------------

You obviously didn't get what I'm talking about...
Each union to work properly should have an associated variable that
holds the information of which field of the union is in use. Do you
have such a variable? If not, how does your code know which one to
use? If yes, add a proper comment there.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-26 12:17         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26 12:17 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 1:46 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +struct mt6370_led {
> > > +       union {
> > > +               struct led_classdev isink;
> > > +               struct led_classdev_mc mc;
> > > +       };
> >
> > Where is the field that makes union work?
>
> Just for saving memory space.
> Because these led_classdevs do not be used at the same time.
> Or do you think it would be better to rewrite it as follows?
> -------------------------------------------------------------------------------------
> struct mt6370_led {
>        struct led_classdev isink;
>        struct led_classdev_mc mc;
>        struct mt6370_priv *priv;
>        u32 default_state;
>        u32 index;
> };
> -------------------------------------------------------------------------------------

You obviously didn't get what I'm talking about...
Each union to work properly should have an associated variable that
holds the information of which field of the union is in use. Do you
have such a variable? If not, how does your code know which one to
use? If yes, add a proper comment there.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-26 12:17         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-26 12:17 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 1:46 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Mon, Jul 25, 2022 at 4:41 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:

...

> > > +struct mt6370_led {
> > > +       union {
> > > +               struct led_classdev isink;
> > > +               struct led_classdev_mc mc;
> > > +       };
> >
> > Where is the field that makes union work?
>
> Just for saving memory space.
> Because these led_classdevs do not be used at the same time.
> Or do you think it would be better to rewrite it as follows?
> -------------------------------------------------------------------------------------
> struct mt6370_led {
>        struct led_classdev isink;
>        struct led_classdev_mc mc;
>        struct mt6370_priv *priv;
>        u32 default_state;
>        u32 index;
> };
> -------------------------------------------------------------------------------------

You obviously didn't get what I'm talking about...
Each union to work properly should have an associated variable that
holds the information of which field of the union is in use. Do you
have such a variable? If not, how does your code know which one to
use? If yes, add a proper comment there.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-26 11:59             ` Daniel Thompson
  (?)
@ 2022-07-27  6:24               ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  6:24 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:

 ...

> > > > > Does the MT6372 support more steps than this? In other words does it use
> > > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > > register location?
> > > >
> > > > Hi Daniel,
> > > >
> > > > Thanks for your reply.
> > > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > > location. But the maximum current of each
> > > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > > The main reason why MT6372 is designed this way is that one of the
> > > > customers asked for a more delicate
> > > > adjustment of the backlight brightness. But other customers actually
> > > > do not have such requirements.
> > > > Therefore, we designed it this way for maximum compatibility in software.
> >
> > Sorry for I used of the wrong word, I mean is 'driver', not
> > higher-level software
> >
> > >
> > > I don't think that is an acceptable approach for the upstream kernel.
> > >
> > > To be "compatible" with (broken) software this driver ends up reducing
> > > the capability of the upstream kernel to the point it becomes unable to
> > > meet requirements for delicate adjustment (requirements that were
> > > sufficiently important to change the hardware design so you could meet
> > > them).
> >
> > Originally, we just wanted to use one version of the driver to cover
> > all the SubPMIC of the 6370 series(6370~6372).
> > And, the users who use this series SubPMIC can directly apply this
> > driver to drive the backlight device without knowing the underlying
> > hardware.
> > To achieve this goal, we have designed it to look like this.
>
> You don't need a second driver to support two different values for
> max-brightness. The same driver can support both ranges with nothing but
> a small tweak during the driver probe function.
>
>
> > ...
> > > > > > +
> > > > > > +     if (brightness) {
> > > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > > +
> > > > > > +             /*
> > > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > > +              * backward compatible with 11 bits brightness control
> > > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > > +              * and MT6371's.
> > > > > > +              */
> > > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > > +             }
> > > > >
> > > > > This somewhat depends on the answer to the first question above, but
> > > > > what is the point of this shifting? If the range is 14-bit then the
> > > > > driver should set max_brightness to 16384 and present the full range of
> > > > > the MT6372 to the user.
> > > >
> > > > So should we make all 16384 steps of MT6372 available to users?
> > >
> > > Yes.
> > >
> > >
> > > > Does that mean the DTS needs to be modified as well?
> > >
> > > Yes... the property to set initial brightness needs a 14-bit range.
> > >
> > > It would also be a good idea to discuss with the DT maintainers whether
> > > you should introduce a second compatible string (ending 6372) in order
> > > to allow the DT validation checks to detect accidental use of MT6372
> > > ranges on MT6370 hardware.
> >
> > hmmm... I have just thought about it,
> > maybe I can just modify the maximum value of default-brightness and
> > max-brightness in DT to 16384,
> > modify the description and add some comments.
>
> What for?
>
> All the other backlight drivers (there are >130 of them) expose the hardware
> range[1]. Most userspaces will already know how to handle that (by reading
> the max_brightness and, if it is recent enough, also the scale
> properties in sysfs).
>
> I'm still don't understand why one should fix a bug in the userspace by
> implementing a hack in the driver.
>
>
> [1] Well almost. The PWM backlight driver does contain support for
>     dead-spot avoidance and to allow the adoption of exponential scale.
>     However this  purpose of these is based on how PWM backlights work
>
> > And then on the driver side,
> > we can use mt6370_check_vendor_info() to determine whether it is MT6372.
> > If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> > In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
> >
> > If I do this change, does this meet your requirements?
>
> Not really.
>
> It's still misleading a sophisticated userspace, which may make bad
> rounding decisions for backlight animation, in order to support a broken
> one.
>
>
> > > > Or, for the reasons, I have just explained (just one customer has this
> > > > requirement), then we do not make any changes for compatibility
> > > > reasons?
> > >
> > > I'd be curious what the compatiblity reasons are. In other words what
> > > software breaks?
> >
> > The reason is as above. We just hope the users who use this series SubPMIC can
> > directly apply this driver to drive the backlight device without
> > knowing the underlying hardware.
> > Not software breaks.
>
> As above, ignoring the max_brightness property is a bug in the
> userspace. I'm still unclear why sending faked ranges to userspace
> it a better solution than fixing the userspace.

Ok, I got it!
If I add a second compatible string (like 'mediatek,mt6372-backlight')
in the DT section,
and append 'if-then-else' to determine the correct maximum value of
'default-brightness' and 'max-brightness',
Also, I will append 'bled exponential mode' to make user control using
linear or exponential mode.
These changes I will explain to DT's maintainer again.

Back to the driver section,
do I still need to use the register to confirm again whether this
SubPMIC used now is MT6372 and record this information? (using
'mt6370_check_vendor_info()')
I am afraid that the user who uses the MT6370 hardware, but the DT
compatible string is set to 'mediatek,mt6372-backlight'.
This may cause errors when update/get brightness values.
So I hope the driver here can check again to make sure the
'default-brightness', 'max-brightness', can be updated/got correctly.
I don't know if this will make you feel redundant if I do this??

Thank you so much!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-27  6:24               ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  6:24 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:

 ...

> > > > > Does the MT6372 support more steps than this? In other words does it use
> > > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > > register location?
> > > >
> > > > Hi Daniel,
> > > >
> > > > Thanks for your reply.
> > > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > > location. But the maximum current of each
> > > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > > The main reason why MT6372 is designed this way is that one of the
> > > > customers asked for a more delicate
> > > > adjustment of the backlight brightness. But other customers actually
> > > > do not have such requirements.
> > > > Therefore, we designed it this way for maximum compatibility in software.
> >
> > Sorry for I used of the wrong word, I mean is 'driver', not
> > higher-level software
> >
> > >
> > > I don't think that is an acceptable approach for the upstream kernel.
> > >
> > > To be "compatible" with (broken) software this driver ends up reducing
> > > the capability of the upstream kernel to the point it becomes unable to
> > > meet requirements for delicate adjustment (requirements that were
> > > sufficiently important to change the hardware design so you could meet
> > > them).
> >
> > Originally, we just wanted to use one version of the driver to cover
> > all the SubPMIC of the 6370 series(6370~6372).
> > And, the users who use this series SubPMIC can directly apply this
> > driver to drive the backlight device without knowing the underlying
> > hardware.
> > To achieve this goal, we have designed it to look like this.
>
> You don't need a second driver to support two different values for
> max-brightness. The same driver can support both ranges with nothing but
> a small tweak during the driver probe function.
>
>
> > ...
> > > > > > +
> > > > > > +     if (brightness) {
> > > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > > +
> > > > > > +             /*
> > > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > > +              * backward compatible with 11 bits brightness control
> > > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > > +              * and MT6371's.
> > > > > > +              */
> > > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > > +             }
> > > > >
> > > > > This somewhat depends on the answer to the first question above, but
> > > > > what is the point of this shifting? If the range is 14-bit then the
> > > > > driver should set max_brightness to 16384 and present the full range of
> > > > > the MT6372 to the user.
> > > >
> > > > So should we make all 16384 steps of MT6372 available to users?
> > >
> > > Yes.
> > >
> > >
> > > > Does that mean the DTS needs to be modified as well?
> > >
> > > Yes... the property to set initial brightness needs a 14-bit range.
> > >
> > > It would also be a good idea to discuss with the DT maintainers whether
> > > you should introduce a second compatible string (ending 6372) in order
> > > to allow the DT validation checks to detect accidental use of MT6372
> > > ranges on MT6370 hardware.
> >
> > hmmm... I have just thought about it,
> > maybe I can just modify the maximum value of default-brightness and
> > max-brightness in DT to 16384,
> > modify the description and add some comments.
>
> What for?
>
> All the other backlight drivers (there are >130 of them) expose the hardware
> range[1]. Most userspaces will already know how to handle that (by reading
> the max_brightness and, if it is recent enough, also the scale
> properties in sysfs).
>
> I'm still don't understand why one should fix a bug in the userspace by
> implementing a hack in the driver.
>
>
> [1] Well almost. The PWM backlight driver does contain support for
>     dead-spot avoidance and to allow the adoption of exponential scale.
>     However this  purpose of these is based on how PWM backlights work
>
> > And then on the driver side,
> > we can use mt6370_check_vendor_info() to determine whether it is MT6372.
> > If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> > In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
> >
> > If I do this change, does this meet your requirements?
>
> Not really.
>
> It's still misleading a sophisticated userspace, which may make bad
> rounding decisions for backlight animation, in order to support a broken
> one.
>
>
> > > > Or, for the reasons, I have just explained (just one customer has this
> > > > requirement), then we do not make any changes for compatibility
> > > > reasons?
> > >
> > > I'd be curious what the compatiblity reasons are. In other words what
> > > software breaks?
> >
> > The reason is as above. We just hope the users who use this series SubPMIC can
> > directly apply this driver to drive the backlight device without
> > knowing the underlying hardware.
> > Not software breaks.
>
> As above, ignoring the max_brightness property is a bug in the
> userspace. I'm still unclear why sending faked ranges to userspace
> it a better solution than fixing the userspace.

Ok, I got it!
If I add a second compatible string (like 'mediatek,mt6372-backlight')
in the DT section,
and append 'if-then-else' to determine the correct maximum value of
'default-brightness' and 'max-brightness',
Also, I will append 'bled exponential mode' to make user control using
linear or exponential mode.
These changes I will explain to DT's maintainer again.

Back to the driver section,
do I still need to use the register to confirm again whether this
SubPMIC used now is MT6372 and record this information? (using
'mt6370_check_vendor_info()')
I am afraid that the user who uses the MT6370 hardware, but the DT
compatible string is set to 'mediatek,mt6372-backlight'.
This may cause errors when update/get brightness values.
So I hope the driver here can check again to make sure the
'default-brightness', 'max-brightness', can be updated/got correctly.
I don't know if this will make you feel redundant if I do this??

Thank you so much!

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-27  6:24               ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  6:24 UTC (permalink / raw)
  To: Daniel Thompson
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
<daniel.thompson@linaro.org> wrote:

 ...

> > > > > Does the MT6372 support more steps than this? In other words does it use
> > > > > a fourteen bit scale or does it use an 11-bit scale at a different
> > > > > register location?
> > > >
> > > > Hi Daniel,
> > > >
> > > > Thanks for your reply.
> > > > Yes, MT6372 can support 16384 steps and uses a 14-bit scale register
> > > > location. But the maximum current of each
> > > > channel of MT6372 is the same as MT6370 and MT6371, both 30mA.
> > > > The main reason why MT6372 is designed this way is that one of the
> > > > customers asked for a more delicate
> > > > adjustment of the backlight brightness. But other customers actually
> > > > do not have such requirements.
> > > > Therefore, we designed it this way for maximum compatibility in software.
> >
> > Sorry for I used of the wrong word, I mean is 'driver', not
> > higher-level software
> >
> > >
> > > I don't think that is an acceptable approach for the upstream kernel.
> > >
> > > To be "compatible" with (broken) software this driver ends up reducing
> > > the capability of the upstream kernel to the point it becomes unable to
> > > meet requirements for delicate adjustment (requirements that were
> > > sufficiently important to change the hardware design so you could meet
> > > them).
> >
> > Originally, we just wanted to use one version of the driver to cover
> > all the SubPMIC of the 6370 series(6370~6372).
> > And, the users who use this series SubPMIC can directly apply this
> > driver to drive the backlight device without knowing the underlying
> > hardware.
> > To achieve this goal, we have designed it to look like this.
>
> You don't need a second driver to support two different values for
> max-brightness. The same driver can support both ranges with nothing but
> a small tweak during the driver probe function.
>
>
> > ...
> > > > > > +
> > > > > > +     if (brightness) {
> > > > > > +             brightness_val[0] = (brightness - 1) & MT6370_BL_DIM2_MASK;
> > > > > > +             brightness_val[1] = (brightness - 1) >> fls(MT6370_BL_DIM2_MASK);
> > > > > > +
> > > > > > +             /*
> > > > > > +              * To make MT6372 using 14 bits to control the brightness
> > > > > > +              * backward compatible with 11 bits brightness control
> > > > > > +              * (like MT6370 and MT6371 do), we left shift the value
> > > > > > +              * and pad with 1 to remaining bits. Hence, the MT6372's
> > > > > > +              * backlight brightness will be almost the same as MT6370's
> > > > > > +              * and MT6371's.
> > > > > > +              */
> > > > > > +             if (priv->vid_type == MT6370_VID_6372) {
> > > > > > +                     brightness_val[0] <<= MT6370_BL_DIM2_6372_SHIFT;
> > > > > > +                     brightness_val[0] |= MT6370_BL_DUMMY_6372_MASK;
> > > > > > +             }
> > > > >
> > > > > This somewhat depends on the answer to the first question above, but
> > > > > what is the point of this shifting? If the range is 14-bit then the
> > > > > driver should set max_brightness to 16384 and present the full range of
> > > > > the MT6372 to the user.
> > > >
> > > > So should we make all 16384 steps of MT6372 available to users?
> > >
> > > Yes.
> > >
> > >
> > > > Does that mean the DTS needs to be modified as well?
> > >
> > > Yes... the property to set initial brightness needs a 14-bit range.
> > >
> > > It would also be a good idea to discuss with the DT maintainers whether
> > > you should introduce a second compatible string (ending 6372) in order
> > > to allow the DT validation checks to detect accidental use of MT6372
> > > ranges on MT6370 hardware.
> >
> > hmmm... I have just thought about it,
> > maybe I can just modify the maximum value of default-brightness and
> > max-brightness in DT to 16384,
> > modify the description and add some comments.
>
> What for?
>
> All the other backlight drivers (there are >130 of them) expose the hardware
> range[1]. Most userspaces will already know how to handle that (by reading
> the max_brightness and, if it is recent enough, also the scale
> properties in sysfs).
>
> I'm still don't understand why one should fix a bug in the userspace by
> implementing a hack in the driver.
>
>
> [1] Well almost. The PWM backlight driver does contain support for
>     dead-spot avoidance and to allow the adoption of exponential scale.
>     However this  purpose of these is based on how PWM backlights work
>
> > And then on the driver side,
> > we can use mt6370_check_vendor_info() to determine whether it is MT6372.
> > If no, then in mt6370_bl_update_status(), first brightness_val / 8 and then set.
> > In mt6370_bl_get_brightness(), first brightness_val * 8 and then return;
> >
> > If I do this change, does this meet your requirements?
>
> Not really.
>
> It's still misleading a sophisticated userspace, which may make bad
> rounding decisions for backlight animation, in order to support a broken
> one.
>
>
> > > > Or, for the reasons, I have just explained (just one customer has this
> > > > requirement), then we do not make any changes for compatibility
> > > > reasons?
> > >
> > > I'd be curious what the compatiblity reasons are. In other words what
> > > software breaks?
> >
> > The reason is as above. We just hope the users who use this series SubPMIC can
> > directly apply this driver to drive the backlight device without
> > knowing the underlying hardware.
> > Not software breaks.
>
> As above, ignoring the max_brightness property is a bug in the
> userspace. I'm still unclear why sending faked ranges to userspace
> it a better solution than fixing the userspace.

Ok, I got it!
If I add a second compatible string (like 'mediatek,mt6372-backlight')
in the DT section,
and append 'if-then-else' to determine the correct maximum value of
'default-brightness' and 'max-brightness',
Also, I will append 'bled exponential mode' to make user control using
linear or exponential mode.
These changes I will explain to DT's maintainer again.

Back to the driver section,
do I still need to use the register to confirm again whether this
SubPMIC used now is MT6372 and record this information? (using
'mt6370_check_vendor_info()')
I am afraid that the user who uses the MT6370 hardware, but the DT
compatible string is set to 'mediatek,mt6372-backlight'.
This may cause errors when update/get brightness values.
So I hope the driver here can check again to make sure the
'default-brightness', 'max-brightness', can be updated/got correctly.
I don't know if this will make you feel redundant if I do this??

Thank you so much!

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-26 12:17         ` Andy Shevchenko
  (?)
@ 2022-07-27  7:36           ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  7:36 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:

...

> > Just for saving memory space.
> > Because these led_classdevs do not be used at the same time.
> > Or do you think it would be better to rewrite it as follows?
> > -------------------------------------------------------------------------------------
> > struct mt6370_led {
> >        struct led_classdev isink;
> >        struct led_classdev_mc mc;
> >        struct mt6370_priv *priv;
> >        u32 default_state;
> >        u32 index;
> > };
> > -------------------------------------------------------------------------------------
>
> You obviously didn't get what I'm talking about...
> Each union to work properly should have an associated variable that
> holds the information of which field of the union is in use. Do you
> have such a variable? If not, how does your code know which one to
> use? If yes, add a proper comment there.
>

Ummm... from my understanding,
if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
'LED_COLOR_ID_MULTI' in DT,
their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
'mt6370_leds_probe()'.
If so, these led devices will be set as 'struct led_classdev_mc' and
use related ops functions in 'mt6370_init_led_properties()'.
Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
will be set as 'struct led_classdev'.
So, maybe the member 'index' of the 'struct mt6370_led' is what you
describe the information of which field of the union is in use?
I will add the proper comment here to describe this thing. I'm so
sorry for misunderstanding your mean last time.
Thanks again for your review.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-27  7:36           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  7:36 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:

...

> > Just for saving memory space.
> > Because these led_classdevs do not be used at the same time.
> > Or do you think it would be better to rewrite it as follows?
> > -------------------------------------------------------------------------------------
> > struct mt6370_led {
> >        struct led_classdev isink;
> >        struct led_classdev_mc mc;
> >        struct mt6370_priv *priv;
> >        u32 default_state;
> >        u32 index;
> > };
> > -------------------------------------------------------------------------------------
>
> You obviously didn't get what I'm talking about...
> Each union to work properly should have an associated variable that
> holds the information of which field of the union is in use. Do you
> have such a variable? If not, how does your code know which one to
> use? If yes, add a proper comment there.
>

Ummm... from my understanding,
if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
'LED_COLOR_ID_MULTI' in DT,
their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
'mt6370_leds_probe()'.
If so, these led devices will be set as 'struct led_classdev_mc' and
use related ops functions in 'mt6370_init_led_properties()'.
Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
will be set as 'struct led_classdev'.
So, maybe the member 'index' of the 'struct mt6370_led' is what you
describe the information of which field of the union is in use?
I will add the proper comment here to describe this thing. I'm so
sorry for misunderstanding your mean last time.
Thanks again for your review.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-27  7:36           ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-07-27  7:36 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
<andy.shevchenko@gmail.com> wrote:

...

> > Just for saving memory space.
> > Because these led_classdevs do not be used at the same time.
> > Or do you think it would be better to rewrite it as follows?
> > -------------------------------------------------------------------------------------
> > struct mt6370_led {
> >        struct led_classdev isink;
> >        struct led_classdev_mc mc;
> >        struct mt6370_priv *priv;
> >        u32 default_state;
> >        u32 index;
> > };
> > -------------------------------------------------------------------------------------
>
> You obviously didn't get what I'm talking about...
> Each union to work properly should have an associated variable that
> holds the information of which field of the union is in use. Do you
> have such a variable? If not, how does your code know which one to
> use? If yes, add a proper comment there.
>

Ummm... from my understanding,
if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
'LED_COLOR_ID_MULTI' in DT,
their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
'mt6370_leds_probe()'.
If so, these led devices will be set as 'struct led_classdev_mc' and
use related ops functions in 'mt6370_init_led_properties()'.
Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
will be set as 'struct led_classdev'.
So, maybe the member 'index' of the 'struct mt6370_led' is what you
describe the information of which field of the union is in use?
I will add the proper comment here to describe this thing. I'm so
sorry for misunderstanding your mean last time.
Thanks again for your review.

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-27  7:36           ` ChiaEn Wu
  (?)
@ 2022-07-27 10:03             ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-27 10:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Wed, Jul 27, 2022 at 9:37 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > Just for saving memory space.
> > > Because these led_classdevs do not be used at the same time.
> > > Or do you think it would be better to rewrite it as follows?
> > > -------------------------------------------------------------------------------------
> > > struct mt6370_led {
> > >        struct led_classdev isink;
> > >        struct led_classdev_mc mc;
> > >        struct mt6370_priv *priv;
> > >        u32 default_state;
> > >        u32 index;
> > > };
> > > -------------------------------------------------------------------------------------
> >
> > You obviously didn't get what I'm talking about...
> > Each union to work properly should have an associated variable that
> > holds the information of which field of the union is in use. Do you
> > have such a variable? If not, how does your code know which one to
> > use? If yes, add a proper comment there.
> >
>
> Ummm... from my understanding,
> if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
> 'LED_COLOR_ID_MULTI' in DT,
> their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
> 'mt6370_leds_probe()'.
> If so, these led devices will be set as 'struct led_classdev_mc' and
> use related ops functions in 'mt6370_init_led_properties()'.
> Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
> will be set as 'struct led_classdev'.
> So, maybe the member 'index' of the 'struct mt6370_led' is what you
> describe the information of which field of the union is in use?

From this description it sounds like it is.

> I will add the proper comment here to describe this thing. I'm so
> sorry for misunderstanding your mean last time.

Yes, please add a compressed version of what you said above to the code.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-27 10:03             ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-27 10:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, cy_huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Daniel Thompson, Helge Deller, Rob Herring,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Wed, Jul 27, 2022 at 9:37 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > Just for saving memory space.
> > > Because these led_classdevs do not be used at the same time.
> > > Or do you think it would be better to rewrite it as follows?
> > > -------------------------------------------------------------------------------------
> > > struct mt6370_led {
> > >        struct led_classdev isink;
> > >        struct led_classdev_mc mc;
> > >        struct mt6370_priv *priv;
> > >        u32 default_state;
> > >        u32 index;
> > > };
> > > -------------------------------------------------------------------------------------
> >
> > You obviously didn't get what I'm talking about...
> > Each union to work properly should have an associated variable that
> > holds the information of which field of the union is in use. Do you
> > have such a variable? If not, how does your code know which one to
> > use? If yes, add a proper comment there.
> >
>
> Ummm... from my understanding,
> if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
> 'LED_COLOR_ID_MULTI' in DT,
> their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
> 'mt6370_leds_probe()'.
> If so, these led devices will be set as 'struct led_classdev_mc' and
> use related ops functions in 'mt6370_init_led_properties()'.
> Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
> will be set as 'struct led_classdev'.
> So, maybe the member 'index' of the 'struct mt6370_led' is what you
> describe the information of which field of the union is in use?

From this description it sounds like it is.

> I will add the proper comment here to describe this thing. I'm so
> sorry for misunderstanding your mean last time.

Yes, please add a compressed version of what you said above to the code.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-27 10:03             ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-27 10:03 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Wed, Jul 27, 2022 at 9:37 AM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> On Tue, Jul 26, 2022 at 8:18 PM Andy Shevchenko
> <andy.shevchenko@gmail.com> wrote:
>
> ...
>
> > > Just for saving memory space.
> > > Because these led_classdevs do not be used at the same time.
> > > Or do you think it would be better to rewrite it as follows?
> > > -------------------------------------------------------------------------------------
> > > struct mt6370_led {
> > >        struct led_classdev isink;
> > >        struct led_classdev_mc mc;
> > >        struct mt6370_priv *priv;
> > >        u32 default_state;
> > >        u32 index;
> > > };
> > > -------------------------------------------------------------------------------------
> >
> > You obviously didn't get what I'm talking about...
> > Each union to work properly should have an associated variable that
> > holds the information of which field of the union is in use. Do you
> > have such a variable? If not, how does your code know which one to
> > use? If yes, add a proper comment there.
> >
>
> Ummm... from my understanding,
> if the colors of these four LEDs are set to 'LED_COLOR_ID_RGB' or
> 'LED_COLOR_ID_MULTI' in DT,
> their 'led->index' will be set to 'MT6370_VIRTUAL_MULTICOLOR' in
> 'mt6370_leds_probe()'.
> If so, these led devices will be set as 'struct led_classdev_mc' and
> use related ops functions in 'mt6370_init_led_properties()'.
> Instead, they whose 'led->index' is not 'MT6370_VIRTUAL_MULTICOLOR'
> will be set as 'struct led_classdev'.
> So, maybe the member 'index' of the 'struct mt6370_led' is what you
> describe the information of which field of the union is in use?

From this description it sounds like it is.

> I will add the proper comment here to describe this thing. I'm so
> sorry for misunderstanding your mean last time.

Yes, please add a compressed version of what you said above to the code.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
  2022-07-27  6:24               ` ChiaEn Wu
  (?)
@ 2022-07-28 11:31                 ` Daniel Thompson
  -1 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-28 11:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Wed, Jul 27, 2022 at 02:24:46PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> > > > > So should we make all 16384 steps of MT6372 available to users?
> > > >
> > > > Yes.
> > > >
> > > >
> > > > > Does that mean the DTS needs to be modified as well?
> > > >
> > > > Yes... the property to set initial brightness needs a 14-bit range.
> > > >
> > > > It would also be a good idea to discuss with the DT maintainers whether
> > > > you should introduce a second compatible string (ending 6372) in order
> > > > to allow the DT validation checks to detect accidental use of MT6372
> > > > ranges on MT6370 hardware.

[snip]

> > > > I'd be curious what the compatiblity reasons are. In other words what
> > > > software breaks?
> > >
> > > The reason is as above. We just hope the users who use this series SubPMIC can
> > > directly apply this driver to drive the backlight device without
> > > knowing the underlying hardware.
> > > Not software breaks.
> >
> > As above, ignoring the max_brightness property is a bug in the
> > userspace. I'm still unclear why sending faked ranges to userspace
> > it a better solution than fixing the userspace.
>
> Ok, I got it!
> If I add a second compatible string (like 'mediatek,mt6372-backlight')
> in the DT section,
> and append 'if-then-else' to determine the correct maximum value of
> 'default-brightness' and 'max-brightness',
> Also, I will append 'bled exponential mode' to make user control using
> linear or exponential mode.

I'd be very pleased to see support for exponential mode added: it's a
much better way to control LEDs and backlights.


> These changes I will explain to DT's maintainer again.

Excellent. I know DT maintainers are copied into this thread but they
will probably not be following this patch's thread so it is better to
discuss in the mail thread for the DT bindings!


> Back to the driver section,
> do I still need to use the register to confirm again whether this
> SubPMIC used now is MT6372 and record this information? (using
> 'mt6370_check_vendor_info()')
> I am afraid that the user who uses the MT6370 hardware, but the DT
> compatible string is set to 'mediatek,mt6372-backlight'.
> This may cause errors when update/get brightness values.
> So I hope the driver here can check again to make sure the
> 'default-brightness', 'max-brightness', can be updated/got correctly.
> I don't know if this will make you feel redundant if I do this??

Yes, it's good idea to check the hardware model during probe. I'd
suggest just reporting this as an error ("Buggy DT, wrong compatible
string") rather than trying to re-intepret the parameters.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-28 11:31                 ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-28 11:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki,
	Krzysztof Kozlowski, Alice Chen, linux-iio, dri-devel,
	Liam Girdwood, ChiYuan Huang, Pavel Machek, Lee Jones,
	Linux LED Subsystem, Helge Deller, Rob Herring, Andy Shevchenko,
	Chunfeng Yun, Guenter Roeck, devicetree, Linux PM, szuni chen,
	Mark Brown, moderated list:ARM/Mediatek SoC support,
	Matthias Brugger, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Wed, Jul 27, 2022 at 02:24:46PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> > > > > So should we make all 16384 steps of MT6372 available to users?
> > > >
> > > > Yes.
> > > >
> > > >
> > > > > Does that mean the DTS needs to be modified as well?
> > > >
> > > > Yes... the property to set initial brightness needs a 14-bit range.
> > > >
> > > > It would also be a good idea to discuss with the DT maintainers whether
> > > > you should introduce a second compatible string (ending 6372) in order
> > > > to allow the DT validation checks to detect accidental use of MT6372
> > > > ranges on MT6370 hardware.

[snip]

> > > > I'd be curious what the compatiblity reasons are. In other words what
> > > > software breaks?
> > >
> > > The reason is as above. We just hope the users who use this series SubPMIC can
> > > directly apply this driver to drive the backlight device without
> > > knowing the underlying hardware.
> > > Not software breaks.
> >
> > As above, ignoring the max_brightness property is a bug in the
> > userspace. I'm still unclear why sending faked ranges to userspace
> > it a better solution than fixing the userspace.
>
> Ok, I got it!
> If I add a second compatible string (like 'mediatek,mt6372-backlight')
> in the DT section,
> and append 'if-then-else' to determine the correct maximum value of
> 'default-brightness' and 'max-brightness',
> Also, I will append 'bled exponential mode' to make user control using
> linear or exponential mode.

I'd be very pleased to see support for exponential mode added: it's a
much better way to control LEDs and backlights.


> These changes I will explain to DT's maintainer again.

Excellent. I know DT maintainers are copied into this thread but they
will probably not be following this patch's thread so it is better to
discuss in the mail thread for the DT bindings!


> Back to the driver section,
> do I still need to use the register to confirm again whether this
> SubPMIC used now is MT6372 and record this information? (using
> 'mt6370_check_vendor_info()')
> I am afraid that the user who uses the MT6370 hardware, but the DT
> compatible string is set to 'mediatek,mt6372-backlight'.
> This may cause errors when update/get brightness values.
> So I hope the driver here can check again to make sure the
> 'default-brightness', 'max-brightness', can be updated/got correctly.
> I don't know if this will make you feel redundant if I do this??

Yes, it's good idea to check the hardware model during probe. I'd
suggest just reporting this as an error ("Buggy DT, wrong compatible
string") rather than trying to re-intepret the parameters.


Daniel.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support
@ 2022-07-28 11:31                 ` Daniel Thompson
  0 siblings, 0 replies; 154+ messages in thread
From: Daniel Thompson @ 2022-07-28 11:31 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen

On Wed, Jul 27, 2022 at 02:24:46PM +0800, ChiaEn Wu wrote:
> On Tue, Jul 26, 2022 at 7:59 PM Daniel Thompson
> <daniel.thompson@linaro.org> wrote:
> > > > > So should we make all 16384 steps of MT6372 available to users?
> > > >
> > > > Yes.
> > > >
> > > >
> > > > > Does that mean the DTS needs to be modified as well?
> > > >
> > > > Yes... the property to set initial brightness needs a 14-bit range.
> > > >
> > > > It would also be a good idea to discuss with the DT maintainers whether
> > > > you should introduce a second compatible string (ending 6372) in order
> > > > to allow the DT validation checks to detect accidental use of MT6372
> > > > ranges on MT6370 hardware.

[snip]

> > > > I'd be curious what the compatiblity reasons are. In other words what
> > > > software breaks?
> > >
> > > The reason is as above. We just hope the users who use this series SubPMIC can
> > > directly apply this driver to drive the backlight device without
> > > knowing the underlying hardware.
> > > Not software breaks.
> >
> > As above, ignoring the max_brightness property is a bug in the
> > userspace. I'm still unclear why sending faked ranges to userspace
> > it a better solution than fixing the userspace.
>
> Ok, I got it!
> If I add a second compatible string (like 'mediatek,mt6372-backlight')
> in the DT section,
> and append 'if-then-else' to determine the correct maximum value of
> 'default-brightness' and 'max-brightness',
> Also, I will append 'bled exponential mode' to make user control using
> linear or exponential mode.

I'd be very pleased to see support for exponential mode added: it's a
much better way to control LEDs and backlights.


> These changes I will explain to DT's maintainer again.

Excellent. I know DT maintainers are copied into this thread but they
will probably not be following this patch's thread so it is better to
discuss in the mail thread for the DT bindings!


> Back to the driver section,
> do I still need to use the register to confirm again whether this
> SubPMIC used now is MT6372 and record this information? (using
> 'mt6370_check_vendor_info()')
> I am afraid that the user who uses the MT6370 hardware, but the DT
> compatible string is set to 'mediatek,mt6372-backlight'.
> This may cause errors when update/get brightness values.
> So I hope the driver here can check again to make sure the
> 'default-brightness', 'max-brightness', can be updated/got correctly.
> I don't know if this will make you feel redundant if I do this??

Yes, it's good idea to check the hardware model during probe. I'd
suggest just reporting this as an error ("Buggy DT, wrong compatible
string") rather than trying to re-intepret the parameters.


Daniel.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-25  8:51     ` Andy Shevchenko
  (?)
@ 2022-07-29  6:17       ` szuni chen
  -1 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-29  6:17 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
>
> On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> >
> > From: Alice Chen <alice_chen@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> > LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> > Add the support of MT6370 FLASH LED.
> >
> > Signed-off-by: Alice Chen <alice_chen@richtek.com>
>
> This SoB chain is wrong. Prioritize and read Submitting Patches!
>
Hi Andy,

After reading the Submitted Patches,
ChiaEn Wu wasn't involved in the development but he submitted the patch,
So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?
I will revise SoB to

Signed-off-by: SzuNi Chen <alice_chen@richtek.com>
Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>

If there is anything else I need to fix, please let me know. Thank you.


Best Regards,
Szuni Chen

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-29  6:17       ` szuni chen
  0 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-29  6:17 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki, Pavel Machek,
	Alice Chen, linux-iio, dri-devel, Liam Girdwood, cy_huang,
	Krzysztof Kozlowski, Lee Jones, Linux LED Subsystem,
	Daniel Thompson, Helge Deller, Rob Herring, Chunfeng Yun,
	Guenter Roeck, devicetree, Linux PM, Mark Brown,
	moderated list:ARM/Mediatek SoC support, Matthias Brugger,
	ChiaEn Wu, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
>
> On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> >
> > From: Alice Chen <alice_chen@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> > LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> > Add the support of MT6370 FLASH LED.
> >
> > Signed-off-by: Alice Chen <alice_chen@richtek.com>
>
> This SoB chain is wrong. Prioritize and read Submitting Patches!
>
Hi Andy,

After reading the Submitted Patches,
ChiaEn Wu wasn't involved in the development but he submitted the patch,
So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?
I will revise SoB to

Signed-off-by: SzuNi Chen <alice_chen@richtek.com>
Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>

If there is anything else I need to fix, please let me know. Thank you.


Best Regards,
Szuni Chen

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-29  6:17       ` szuni chen
  0 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-07-29  6:17 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
>
> On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> >
> > From: Alice Chen <alice_chen@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> > LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> > Add the support of MT6370 FLASH LED.
> >
> > Signed-off-by: Alice Chen <alice_chen@richtek.com>
>
> This SoB chain is wrong. Prioritize and read Submitting Patches!
>
Hi Andy,

After reading the Submitted Patches,
ChiaEn Wu wasn't involved in the development but he submitted the patch,
So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?
I will revise SoB to

Signed-off-by: SzuNi Chen <alice_chen@richtek.com>
Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>

If there is anything else I need to fix, please let me know. Thank you.


Best Regards,
Szuni Chen

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-29  6:17       ` szuni chen
  (?)
@ 2022-07-29 10:34         ` Andy Shevchenko
  -1 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-29 10:34 UTC (permalink / raw)
  To: szuni chen
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

On Fri, Jul 29, 2022 at 8:17 AM szuni chen <szunichen@gmail.com> wrote:
> Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
> > On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> > >
> > > From: Alice Chen <alice_chen@richtek.com>

...

> > > Signed-off-by: Alice Chen <alice_chen@richtek.com>
> >
> > This SoB chain is wrong. Prioritize and read Submitting Patches!
>
> After reading the Submitted Patches,
> ChiaEn Wu wasn't involved in the development but he submitted the patch,
> So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?

Right. Submitter's SoB is the last SoB in the chain.

> I will revise SoB to
>
> Signed-off-by: SzuNi Chen <alice_chen@richtek.com>

Not sure I understand the SzuNi <--> Alice transformation...

> Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
>
> If there is anything else I need to fix, please let me know. Thank you.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-29 10:34         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-29 10:34 UTC (permalink / raw)
  To: szuni chen
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, ChiaEn Wu,
	Alice Chen, cy_huang, dri-devel, Linux LED Subsystem, devicetree,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

On Fri, Jul 29, 2022 at 8:17 AM szuni chen <szunichen@gmail.com> wrote:
> Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
> > On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> > >
> > > From: Alice Chen <alice_chen@richtek.com>

...

> > > Signed-off-by: Alice Chen <alice_chen@richtek.com>
> >
> > This SoB chain is wrong. Prioritize and read Submitting Patches!
>
> After reading the Submitted Patches,
> ChiaEn Wu wasn't involved in the development but he submitted the patch,
> So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?

Right. Submitter's SoB is the last SoB in the chain.

> I will revise SoB to
>
> Signed-off-by: SzuNi Chen <alice_chen@richtek.com>

Not sure I understand the SzuNi <--> Alice transformation...

> Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
>
> If there is anything else I need to fix, please let me know. Thank you.

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-29 10:34         ` Andy Shevchenko
  0 siblings, 0 replies; 154+ messages in thread
From: Andy Shevchenko @ 2022-07-29 10:34 UTC (permalink / raw)
  To: szuni chen
  Cc: open list:FRAMEBUFFER LAYER, Krogerus, Heikki, Pavel Machek,
	Alice Chen, linux-iio, dri-devel, Liam Girdwood, cy_huang,
	Krzysztof Kozlowski, Lee Jones, Linux LED Subsystem,
	Daniel Thompson, Helge Deller, Rob Herring, Chunfeng Yun,
	Guenter Roeck, devicetree, Linux PM, Mark Brown,
	moderated list:ARM/Mediatek SoC support, Matthias Brugger,
	ChiaEn Wu, linux-arm Mailing List, Jingoo Han, USB,
	Sebastian Reichel, Linux Kernel Mailing List, ChiaEn Wu,
	Greg Kroah-Hartman, Jonathan Cameron

On Fri, Jul 29, 2022 at 8:17 AM szuni chen <szunichen@gmail.com> wrote:
> Andy Shevchenko <andy.shevchenko@gmail.com> 於 2022年7月25日 週一 下午4:51寫道:
> > On Fri, Jul 22, 2022 at 12:25 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
> > >
> > > From: Alice Chen <alice_chen@richtek.com>

...

> > > Signed-off-by: Alice Chen <alice_chen@richtek.com>
> >
> > This SoB chain is wrong. Prioritize and read Submitting Patches!
>
> After reading the Submitted Patches,
> ChiaEn Wu wasn't involved in the development but he submitted the patch,
> So, ChiaEn Wu <chiaen_wu@richtek.com> should be the last SoB, right?

Right. Submitter's SoB is the last SoB in the chain.

> I will revise SoB to
>
> Signed-off-by: SzuNi Chen <alice_chen@richtek.com>

Not sure I understand the SzuNi <--> Alice transformation...

> Signed-off-by: ChiaEn Wu <chiaen_wu@richtek.com>
>
> If there is anything else I need to fix, please let me know. Thank you.

-- 
With Best Regards,
Andy Shevchenko

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
  2022-07-22 10:23   ` ChiaEn Wu
  (?)
@ 2022-07-30 21:30     ` Pavel Machek
  -1 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen, Krzysztof Kozlowski

[-- Attachment #1: Type: text/plain, Size: 487 bytes --]

On Fri 2022-07-22 18:23:58, ChiaEn Wu wrote:
> From: Alice Chen <alice_chen@richtek.com>
> 
> Add MediaTek MT6370 flashlight binding documentation.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

You'll need to get sign-offs right... And review from dt people before
this can be applied.

Best regards,
								Pavel
								-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
@ 2022-07-30 21:30     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: linux-fbdev, heikki.krogerus, alice_chen, linux-iio, dri-devel,
	lgirdwood, cy_huang, krzysztof.kozlowski+dt, lee.jones,
	linux-leds, daniel.thompson, deller, robh+dt, andy.shevchenko,
	chunfeng.yun, linux, devicetree, linux-pm, szunichen, broonie,
	linux-mediatek, matthias.bgg, linux-arm-kernel, jingoohan1,
	linux-usb, sre, linux-kernel, Krzysztof Kozlowski, chiaen_wu,
	gregkh, jic23

[-- Attachment #1: Type: text/plain, Size: 487 bytes --]

On Fri 2022-07-22 18:23:58, ChiaEn Wu wrote:
> From: Alice Chen <alice_chen@richtek.com>
> 
> Add MediaTek MT6370 flashlight binding documentation.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

You'll need to get sign-offs right... And review from dt people before
this can be applied.

Best regards,
								Pavel
								-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight
@ 2022-07-30 21:30     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:30 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen, Krzysztof Kozlowski


[-- Attachment #1.1: Type: text/plain, Size: 487 bytes --]

On Fri 2022-07-22 18:23:58, ChiaEn Wu wrote:
> From: Alice Chen <alice_chen@richtek.com>
> 
> Add MediaTek MT6370 flashlight binding documentation.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

You'll need to get sign-offs right... And review from dt people before
this can be applied.

Best regards,
								Pavel
								-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-30 21:39     ` Pavel Machek
  -1 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:39 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen

[-- Attachment #1: Type: text/plain, Size: 3649 bytes --]

Hi!

> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
>

> +config LEDS_MT6370_RGB
> +	tristate "LED Support for MediaTek MT6370 PMIC"
> +	depends on MFD_MT6370
> +	select LINEAR_RANGE
> +	help
> +	  Say Y here to enable support for MT6370_RGB LED device.
> +	  In MT6370, there are four channel current-sink LED drivers that
> +	  support hardware pattern for constant current, PWM, and breath mode.


> +	  Isink4 channel can also be used as a CHG_VIN power good  indicator.

That does not really belong here.

> +struct mt6370_priv {
> +	/* Per LED access lock */
> +	struct mutex lock;

Do we really need per-led locking?

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +				     struct led_pattern *pattern, u32 len,
> +				     u8 *pattern_val, u32 val_len)
> +{
> +	enum mt6370_led_ranges sel_range;
> +	struct led_pattern *curr;
> +	unsigned int sel;
> +	u8 val[P_MAX_PATTERNS / 2] = {};
> +	int i;
> +
> +	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +		return -EINVAL;
> +
> +	/*
> +	 * Pattern list
> +	 * tr1:	byte 0, b'[7: 4]
> +	 * tr2:	byte 0, b'[3: 0]
> +	 * tf1:	byte 1, b'[7: 4]
> +	 * tf2:	byte 1, b'[3: 0]
> +	 * ton:	byte 2, b'[7: 4]
> +	 * toff: byte 2, b'[3: 0]
> +	 */
> +	for (i = 0; i < P_MAX_PATTERNS; i++) {
> +		curr = pattern + i;
> +
> +		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +		linear_range_get_selector_within(priv->ranges + sel_range,
> +						 curr->delta_t, &sel);
> +
> +		val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +	}
> +
> +	memcpy(pattern_val, val, 3);
> +
> +	return 0;
> +}

I wonder how this works... you are not creating private sysfs
interface, are you?

> +static int mt6370_init_led_properties(struct mt6370_led *led,
> +				      struct led_init_data *init_data)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	struct device *dev = priv->dev;
> +	struct led_classdev *lcdev;
> +	struct fwnode_handle *child;
> +	enum mt6370_led_ranges sel_range;
> +	u32 max_uA, max_level;
> +	const char * const states[] = { "off", "keep", "on" };

We'd really preffer not to add "keep" / "on" support unless you need
it.

> +			if (ret)
> +				return dev_err_probe(dev, ret,
> +						     "led %d, no color specified\n",
> +						     led->index);

led->LED.

> +		if (num_color < 2)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Multicolor must include
> 2 or more led channel\n");

"LED channels".

> +static int mt6370_isnk_init_default_state(struct mt6370_led *led)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	unsigned int enable, level;
> +	int ret;
> +
> +	ret = mt6370_get_led_brightness(priv, led->index, &level);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
> +	if (ret)
> +		return ret;
> +
> +	if (!(enable & MT6370_CHEN_BIT(led->index)))
> +		level = LED_OFF;

Just use 0 instead of LED_OFF.

Best regards,
							Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-30 21:39     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:39 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: linux-fbdev, heikki.krogerus, alice_chen, linux-iio, dri-devel,
	lgirdwood, cy_huang, krzysztof.kozlowski+dt, lee.jones,
	linux-leds, daniel.thompson, deller, robh+dt, andy.shevchenko,
	chunfeng.yun, linux, devicetree, linux-pm, szunichen, broonie,
	linux-mediatek, matthias.bgg, linux-arm-kernel, jingoohan1,
	linux-usb, sre, linux-kernel, chiaen_wu, gregkh, jic23

[-- Attachment #1: Type: text/plain, Size: 3649 bytes --]

Hi!

> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
>

> +config LEDS_MT6370_RGB
> +	tristate "LED Support for MediaTek MT6370 PMIC"
> +	depends on MFD_MT6370
> +	select LINEAR_RANGE
> +	help
> +	  Say Y here to enable support for MT6370_RGB LED device.
> +	  In MT6370, there are four channel current-sink LED drivers that
> +	  support hardware pattern for constant current, PWM, and breath mode.


> +	  Isink4 channel can also be used as a CHG_VIN power good  indicator.

That does not really belong here.

> +struct mt6370_priv {
> +	/* Per LED access lock */
> +	struct mutex lock;

Do we really need per-led locking?

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +				     struct led_pattern *pattern, u32 len,
> +				     u8 *pattern_val, u32 val_len)
> +{
> +	enum mt6370_led_ranges sel_range;
> +	struct led_pattern *curr;
> +	unsigned int sel;
> +	u8 val[P_MAX_PATTERNS / 2] = {};
> +	int i;
> +
> +	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +		return -EINVAL;
> +
> +	/*
> +	 * Pattern list
> +	 * tr1:	byte 0, b'[7: 4]
> +	 * tr2:	byte 0, b'[3: 0]
> +	 * tf1:	byte 1, b'[7: 4]
> +	 * tf2:	byte 1, b'[3: 0]
> +	 * ton:	byte 2, b'[7: 4]
> +	 * toff: byte 2, b'[3: 0]
> +	 */
> +	for (i = 0; i < P_MAX_PATTERNS; i++) {
> +		curr = pattern + i;
> +
> +		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +		linear_range_get_selector_within(priv->ranges + sel_range,
> +						 curr->delta_t, &sel);
> +
> +		val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +	}
> +
> +	memcpy(pattern_val, val, 3);
> +
> +	return 0;
> +}

I wonder how this works... you are not creating private sysfs
interface, are you?

> +static int mt6370_init_led_properties(struct mt6370_led *led,
> +				      struct led_init_data *init_data)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	struct device *dev = priv->dev;
> +	struct led_classdev *lcdev;
> +	struct fwnode_handle *child;
> +	enum mt6370_led_ranges sel_range;
> +	u32 max_uA, max_level;
> +	const char * const states[] = { "off", "keep", "on" };

We'd really preffer not to add "keep" / "on" support unless you need
it.

> +			if (ret)
> +				return dev_err_probe(dev, ret,
> +						     "led %d, no color specified\n",
> +						     led->index);

led->LED.

> +		if (num_color < 2)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Multicolor must include
> 2 or more led channel\n");

"LED channels".

> +static int mt6370_isnk_init_default_state(struct mt6370_led *led)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	unsigned int enable, level;
> +	int ret;
> +
> +	ret = mt6370_get_led_brightness(priv, led->index, &level);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
> +	if (ret)
> +		return ret;
> +
> +	if (!(enable & MT6370_CHEN_BIT(led->index)))
> +		level = LED_OFF;

Just use 0 instead of LED_OFF.

Best regards,
							Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-07-30 21:39     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:39 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen


[-- Attachment #1.1: Type: text/plain, Size: 3649 bytes --]

Hi!

> From: ChiYuan Huang <cy_huang@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual
> Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> support hardware pattern for constant current, PWM, and breath mode.
> Isink4 channel can also be used as a CHG_VIN power good indicator.
>

> +config LEDS_MT6370_RGB
> +	tristate "LED Support for MediaTek MT6370 PMIC"
> +	depends on MFD_MT6370
> +	select LINEAR_RANGE
> +	help
> +	  Say Y here to enable support for MT6370_RGB LED device.
> +	  In MT6370, there are four channel current-sink LED drivers that
> +	  support hardware pattern for constant current, PWM, and breath mode.


> +	  Isink4 channel can also be used as a CHG_VIN power good  indicator.

That does not really belong here.

> +struct mt6370_priv {
> +	/* Per LED access lock */
> +	struct mutex lock;

Do we really need per-led locking?

> +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> +				     struct led_pattern *pattern, u32 len,
> +				     u8 *pattern_val, u32 val_len)
> +{
> +	enum mt6370_led_ranges sel_range;
> +	struct led_pattern *curr;
> +	unsigned int sel;
> +	u8 val[P_MAX_PATTERNS / 2] = {};
> +	int i;
> +
> +	if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> +		return -EINVAL;
> +
> +	/*
> +	 * Pattern list
> +	 * tr1:	byte 0, b'[7: 4]
> +	 * tr2:	byte 0, b'[3: 0]
> +	 * tf1:	byte 1, b'[7: 4]
> +	 * tf2:	byte 1, b'[3: 0]
> +	 * ton:	byte 2, b'[7: 4]
> +	 * toff: byte 2, b'[3: 0]
> +	 */
> +	for (i = 0; i < P_MAX_PATTERNS; i++) {
> +		curr = pattern + i;
> +
> +		sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> +
> +		linear_range_get_selector_within(priv->ranges + sel_range,
> +						 curr->delta_t, &sel);
> +
> +		val[i / 2] |= sel << (4 * ((i + 1) % 2));
> +	}
> +
> +	memcpy(pattern_val, val, 3);
> +
> +	return 0;
> +}

I wonder how this works... you are not creating private sysfs
interface, are you?

> +static int mt6370_init_led_properties(struct mt6370_led *led,
> +				      struct led_init_data *init_data)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	struct device *dev = priv->dev;
> +	struct led_classdev *lcdev;
> +	struct fwnode_handle *child;
> +	enum mt6370_led_ranges sel_range;
> +	u32 max_uA, max_level;
> +	const char * const states[] = { "off", "keep", "on" };

We'd really preffer not to add "keep" / "on" support unless you need
it.

> +			if (ret)
> +				return dev_err_probe(dev, ret,
> +						     "led %d, no color specified\n",
> +						     led->index);

led->LED.

> +		if (num_color < 2)
> +			return dev_err_probe(dev, -EINVAL,
> +					     "Multicolor must include
> 2 or more led channel\n");

"LED channels".

> +static int mt6370_isnk_init_default_state(struct mt6370_led *led)
> +{
> +	struct mt6370_priv *priv = led->priv;
> +	unsigned int enable, level;
> +	int ret;
> +
> +	ret = mt6370_get_led_brightness(priv, led->index, &level);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
> +	if (ret)
> +		return ret;
> +
> +	if (!(enable & MT6370_CHEN_BIT(led->index)))
> +		level = LED_OFF;

Just use 0 instead of LED_OFF.

Best regards,
							Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-22 10:24   ` ChiaEn Wu
  (?)
@ 2022-07-30 21:42     ` Pavel Machek
  -1 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:42 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen

[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]

Hi!

> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS

I'd name it just LEDS_MT6370_FLASH.

> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com

Add ">" at end of line.

The series is quite big, would it be possible to submit LED changes
in separate series?

Thanks,
								Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-30 21:42     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:42 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev,
	szunichen


[-- Attachment #1.1: Type: text/plain, Size: 1116 bytes --]

Hi!

> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS

I'd name it just LEDS_MT6370_FLASH.

> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com

Add ">" at end of line.

The series is quite big, would it be possible to submit LED changes
in separate series?

Thanks,
								Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-07-30 21:42     ` Pavel Machek
  0 siblings, 0 replies; 154+ messages in thread
From: Pavel Machek @ 2022-07-30 21:42 UTC (permalink / raw)
  To: ChiaEn Wu
  Cc: linux-fbdev, heikki.krogerus, alice_chen, linux-iio, dri-devel,
	lgirdwood, cy_huang, krzysztof.kozlowski+dt, lee.jones,
	linux-leds, daniel.thompson, deller, robh+dt, andy.shevchenko,
	chunfeng.yun, linux, devicetree, linux-pm, szunichen, broonie,
	linux-mediatek, matthias.bgg, linux-arm-kernel, jingoohan1,
	linux-usb, sre, linux-kernel, chiaen_wu, gregkh, jic23

[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]

Hi!

> From: Alice Chen <alice_chen@richtek.com>
> 
> The MediaTek MT6370 is a highly-integrated smart power management IC,
> which includes a single cell Li-Ion/Li-Polymer switching battery
> charger, a USB Type-C & Power Delivery (PD) controller, dual Flash
> LED current sources, a RGB LED driver, a backlight WLED driver,
> a display bias driver and a general LDO for portable devices.
> 
> The Flash LED in MT6370 has 2 channels and support torch/strobe mode.
> Add the support of MT6370 FLASH LED.
> 
> Signed-off-by: Alice Chen <alice_chen@richtek.com>

> +config LEDS_MT6370_FLASHLIGHT
> +	tristate "Flash LED Support for MediaTek MT6370 PMIC"
> +	depends on LEDS_CLASS

I'd name it just LEDS_MT6370_FLASH.

> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Richtek Technology Corp.
> + *
> + * Author: Alice Chen <alice_chen@richtek.com

Add ">" at end of line.

The series is quite big, would it be possible to submit LED changes
in separate series?

Thanks,
								Pavel

-- 
People of Russia, stop Putin before his war on Ukraine escalates.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight
  2022-07-22 10:23   ` ChiaEn Wu
@ 2022-08-01  6:47     ` ChiaEn Wu
  -1 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-08-01  6:47 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, Andy Shevchenko
  Cc: ChiaEn Wu, Alice Chen, ChiYuan Huang, dri-devel,
	Linux LED Subsystem, devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen, Rob Herring

On Fri, Jul 22, 2022 at 6:24 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---

[snip]

> +  compatible:
> +    const: mediatek,mt6370-backlight
> +
> +  default-brightness:
> +    minimum: 0
> +    maximum: 2048
> +
> +  max-brightness:
> +    minimum: 0
> +    maximum: 2048
> +

Hi Rob, Krzysztof,

First, I'm so sorry for our SoB writing wrong, I'll fix it in the next patch.
Because of this mail thread
(https://lore.kernel.org/all/20220728113109.7gf3b36mqjxlhcq3@maple.lan/),
I would like to discuss with you that I may change the following in
this DT document, I am not sure whether you agree or not.

1. Add some descriptions about MT6372, which supports 16384 steps (14
bits) and is different from MT6370/MT6371 (2048 steps, 11 bits)
2. Modify the format of 'compatible' as follows to distinguish between
MT6370/MT6371 or MT6372
------------------------------------------
properties:
  compatible:
    enum:
      - mediatek,mt6370-backlight
      - mediatek,mt6372-backlight
------------------------------------------

3. Remove the 'maximum' value of 'default-brightness' and
'max-brightness', and add "if-else" to determine the "maximum" value
as follows
------------------------------------------
  default-brightness:
    minimum: 0

  max-brightness:
    minimum: 0

...

if:
  properties:
    compatible:
      contains:
        const: mediatek,mt6372-backlight

then:
  properties:
    default-brightness:
      maximum: 16384

    max-brightness:
      maximum: 16384

else:
  properties:
    default-brightness:
      maximum: 2048

    max-brightness:
      maximum: 2048
------------------------------------------

4. Add a new boolean property to allow the user to determine whether
to enable the exponential mode of backlight brightness or not. Like
this,
------------------------------------------
  mediatek,bled-exponential-mode-enable:
    description: |
      Enable the exponential mode of backlight brightness. If this property
      is not enabled, the default is to use linear mode.
    type: boolean
------------------------------------------

I hope these changes I have added will meet your expectations.
And I'm not sure if I should remove 'Reviewed-By' first until it
passes your review.
Thanks.

-- 
Best Regards,
ChiaEn Wu

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight
@ 2022-08-01  6:47     ` ChiaEn Wu
  0 siblings, 0 replies; 154+ messages in thread
From: ChiaEn Wu @ 2022-08-01  6:47 UTC (permalink / raw)
  To: Lee Jones, Daniel Thompson, Jingoo Han, Pavel Machek,
	Rob Herring, Krzysztof Kozlowski, Matthias Brugger,
	Sebastian Reichel, Chunfeng Yun, Greg Kroah-Hartman,
	Jonathan Cameron, Lars-Peter Clausen, Liam Girdwood, Mark Brown,
	Guenter Roeck, Krogerus, Heikki, Helge Deller, Andy Shevchenko
  Cc: ChiaEn Wu, Alice Chen, ChiYuan Huang, dri-devel,
	Linux LED Subsystem, devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER, szuni chen, Rob Herring

On Fri, Jul 22, 2022 at 6:24 PM ChiaEn Wu <peterwu.pub@gmail.com> wrote:
>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>
> ---

[snip]

> +  compatible:
> +    const: mediatek,mt6370-backlight
> +
> +  default-brightness:
> +    minimum: 0
> +    maximum: 2048
> +
> +  max-brightness:
> +    minimum: 0
> +    maximum: 2048
> +

Hi Rob, Krzysztof,

First, I'm so sorry for our SoB writing wrong, I'll fix it in the next patch.
Because of this mail thread
(https://lore.kernel.org/all/20220728113109.7gf3b36mqjxlhcq3@maple.lan/),
I would like to discuss with you that I may change the following in
this DT document, I am not sure whether you agree or not.

1. Add some descriptions about MT6372, which supports 16384 steps (14
bits) and is different from MT6370/MT6371 (2048 steps, 11 bits)
2. Modify the format of 'compatible' as follows to distinguish between
MT6370/MT6371 or MT6372
------------------------------------------
properties:
  compatible:
    enum:
      - mediatek,mt6370-backlight
      - mediatek,mt6372-backlight
------------------------------------------

3. Remove the 'maximum' value of 'default-brightness' and
'max-brightness', and add "if-else" to determine the "maximum" value
as follows
------------------------------------------
  default-brightness:
    minimum: 0

  max-brightness:
    minimum: 0

...

if:
  properties:
    compatible:
      contains:
        const: mediatek,mt6372-backlight

then:
  properties:
    default-brightness:
      maximum: 16384

    max-brightness:
      maximum: 16384

else:
  properties:
    default-brightness:
      maximum: 2048

    max-brightness:
      maximum: 2048
------------------------------------------

4. Add a new boolean property to allow the user to determine whether
to enable the exponential mode of backlight brightness or not. Like
this,
------------------------------------------
  mediatek,bled-exponential-mode-enable:
    description: |
      Enable the exponential mode of backlight brightness. If this property
      is not enabled, the default is to use linear mode.
    type: boolean
------------------------------------------

I hope these changes I have added will meet your expectations.
And I'm not sure if I should remove 'Reviewed-By' first until it
passes your review.
Thanks.

-- 
Best Regards,
ChiaEn Wu

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
  2022-07-30 21:39     ` Pavel Machek
@ 2022-08-01  7:55       ` szuni chen
  -1 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-08-01  7:55 UTC (permalink / raw)
  To: Pavel Machek
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Hi Pavel,
Sorry for resending the mail, I add all reviewers this time.


Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:39寫道:
>
> Hi!
>
...

>
> > +config LEDS_MT6370_RGB
> > +     tristate "LED Support for MediaTek MT6370 PMIC"
> > +     depends on MFD_MT6370
> > +     select LINEAR_RANGE
> > +     help
> > +       Say Y here to enable support for MT6370_RGB LED device.
> > +       In MT6370, there are four channel current-sink LED drivers that
> > +       support hardware pattern for constant current, PWM, and breath mode.
>
>
> > +       Isink4 channel can also be used as a CHG_VIN power good  indicator.
>
> That does not really belong here.
>
Should we just remove it, or describe Isink4 in another position?

> > +struct mt6370_priv {
> > +     /* Per LED access lock */
> > +     struct mutex lock;
>
> Do we really need per-led locking?
>
Sorry, maybe the comment is not precise.
The lock is used to prevent LEDs from accessing the HW at the same time.

If I use
/* LED access lock, only one LED can access the HW at the same time */
will it look better?
No, we aren't.
There are six steps tr1, tr2, tf1, tf2, ton, and toff in MT6370 led breath mode.
We parse duration settings from node "hw_pattern" and set them to the registers.

This function is used to generate duration settings from hw_pattern.

The brightness of the six steps mentioned above in breath mode is
limited to the node "brightness".
The target brightness of tr1 and tf1 is 25% of node "brightness", and
they are automatically set by HW.

> > +static int mt6370_init_led_properties(struct mt6370_led *led,
> > +                                   struct led_init_data *init_data)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     struct device *dev = priv->dev;
> > +     struct led_classdev *lcdev;
> > +     struct fwnode_handle *child;
> > +     enum mt6370_led_ranges sel_range;
> > +     u32 max_uA, max_level;
> > +     const char * const states[] = { "off", "keep", "on" };
>
> We'd really preffer not to add "keep" / "on" support unless you need
> it.
>
Forgive me, but I would like to know why "keep" / "on" is not preferred.
We think the users might have some conditions that need them.


Best Regards,
Alice

Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:39寫道:
>
> Hi!
>
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual
> > Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> > support hardware pattern for constant current, PWM, and breath mode.
> > Isink4 channel can also be used as a CHG_VIN power good indicator.
> >
>
> > +config LEDS_MT6370_RGB
> > +     tristate "LED Support for MediaTek MT6370 PMIC"
> > +     depends on MFD_MT6370
> > +     select LINEAR_RANGE
> > +     help
> > +       Say Y here to enable support for MT6370_RGB LED device.
> > +       In MT6370, there are four channel current-sink LED drivers that
> > +       support hardware pattern for constant current, PWM, and breath mode.
>
>
> > +       Isink4 channel can also be used as a CHG_VIN power good  indicator.
>
> That does not really belong here.
>
> > +struct mt6370_priv {
> > +     /* Per LED access lock */
> > +     struct mutex lock;
>
> Do we really need per-led locking?
>
> > +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> > +                                  struct led_pattern *pattern, u32 len,
> > +                                  u8 *pattern_val, u32 val_len)
> > +{
> > +     enum mt6370_led_ranges sel_range;
> > +     struct led_pattern *curr;
> > +     unsigned int sel;
> > +     u8 val[P_MAX_PATTERNS / 2] = {};
> > +     int i;
> > +
> > +     if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> > +             return -EINVAL;
> > +
> > +     /*
> > +      * Pattern list
> > +      * tr1: byte 0, b'[7: 4]
> > +      * tr2: byte 0, b'[3: 0]
> > +      * tf1: byte 1, b'[7: 4]
> > +      * tf2: byte 1, b'[3: 0]
> > +      * ton: byte 2, b'[7: 4]
> > +      * toff: byte 2, b'[3: 0]
> > +      */
> > +     for (i = 0; i < P_MAX_PATTERNS; i++) {
> > +             curr = pattern + i;
> > +
> > +             sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> > +
> > +             linear_range_get_selector_within(priv->ranges + sel_range,
> > +                                              curr->delta_t, &sel);
> > +
> > +             val[i / 2] |= sel << (4 * ((i + 1) % 2));
> > +     }
> > +
> > +     memcpy(pattern_val, val, 3);
> > +
> > +     return 0;
> > +}
>
> I wonder how this works... you are not creating private sysfs
> interface, are you?
>
> > +static int mt6370_init_led_properties(struct mt6370_led *led,
> > +                                   struct led_init_data *init_data)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     struct device *dev = priv->dev;
> > +     struct led_classdev *lcdev;
> > +     struct fwnode_handle *child;
> > +     enum mt6370_led_ranges sel_range;
> > +     u32 max_uA, max_level;
> > +     const char * const states[] = { "off", "keep", "on" };
>
> We'd really preffer not to add "keep" / "on" support unless you need
> it.
>
> > +                     if (ret)
> > +                             return dev_err_probe(dev, ret,
> > +                                                  "led %d, no color specified\n",
> > +                                                  led->index);
>
> led->LED.
>
> > +             if (num_color < 2)
> > +                     return dev_err_probe(dev, -EINVAL,
> > +                                          "Multicolor must include
> > 2 or more led channel\n");
>
> "LED channels".
>
> > +static int mt6370_isnk_init_default_state(struct mt6370_led *led)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     unsigned int enable, level;
> > +     int ret;
> > +
> > +     ret = mt6370_get_led_brightness(priv, led->index, &level);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (!(enable & MT6370_CHEN_BIT(led->index)))
> > +             level = LED_OFF;
>
> Just use 0 instead of LED_OFF.
>
> Best regards,
>                                                         Pavel
>
> --
> People of Russia, stop Putin before his war on Ukraine escalates.

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support
@ 2022-08-01  7:55       ` szuni chen
  0 siblings, 0 replies; 154+ messages in thread
From: szuni chen @ 2022-08-01  7:55 UTC (permalink / raw)
  To: Pavel Machek
  Cc: ChiaEn Wu, Lee Jones, Daniel Thompson, Jingoo Han, Rob Herring,
	Krzysztof Kozlowski, Matthias Brugger, Sebastian Reichel,
	Chunfeng Yun, Greg Kroah-Hartman, Jonathan Cameron,
	Lars-Peter Clausen, Liam Girdwood, Mark Brown, Guenter Roeck,
	Krogerus, Heikki, Helge Deller, Andy Shevchenko, ChiaEn Wu,
	Alice Chen, ChiYuan Huang, dri-devel, Linux LED Subsystem,
	devicetree, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List, Linux PM, USB, linux-iio,
	open list:FRAMEBUFFER LAYER

Hi Pavel,
Sorry for resending the mail, I add all reviewers this time.


Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:39寫道:
>
> Hi!
>
...

>
> > +config LEDS_MT6370_RGB
> > +     tristate "LED Support for MediaTek MT6370 PMIC"
> > +     depends on MFD_MT6370
> > +     select LINEAR_RANGE
> > +     help
> > +       Say Y here to enable support for MT6370_RGB LED device.
> > +       In MT6370, there are four channel current-sink LED drivers that
> > +       support hardware pattern for constant current, PWM, and breath mode.
>
>
> > +       Isink4 channel can also be used as a CHG_VIN power good  indicator.
>
> That does not really belong here.
>
Should we just remove it, or describe Isink4 in another position?

> > +struct mt6370_priv {
> > +     /* Per LED access lock */
> > +     struct mutex lock;
>
> Do we really need per-led locking?
>
Sorry, maybe the comment is not precise.
The lock is used to prevent LEDs from accessing the HW at the same time.

If I use
/* LED access lock, only one LED can access the HW at the same time */
will it look better?
No, we aren't.
There are six steps tr1, tr2, tf1, tf2, ton, and toff in MT6370 led breath mode.
We parse duration settings from node "hw_pattern" and set them to the registers.

This function is used to generate duration settings from hw_pattern.

The brightness of the six steps mentioned above in breath mode is
limited to the node "brightness".
The target brightness of tr1 and tf1 is 25% of node "brightness", and
they are automatically set by HW.

> > +static int mt6370_init_led_properties(struct mt6370_led *led,
> > +                                   struct led_init_data *init_data)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     struct device *dev = priv->dev;
> > +     struct led_classdev *lcdev;
> > +     struct fwnode_handle *child;
> > +     enum mt6370_led_ranges sel_range;
> > +     u32 max_uA, max_level;
> > +     const char * const states[] = { "off", "keep", "on" };
>
> We'd really preffer not to add "keep" / "on" support unless you need
> it.
>
Forgive me, but I would like to know why "keep" / "on" is not preferred.
We think the users might have some conditions that need them.


Best Regards,
Alice

Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:39寫道:
>
> Hi!
>
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > The MediaTek MT6370 is a highly-integrated smart power management IC,
> > which includes a single cell Li-Ion/Li-Polymer switching battery
> > charger, a USB Type-C & Power Delivery (PD) controller, dual
> > Flash LED current sources, a RGB LED driver, a backlight WLED driver,
> > a display bias driver and a general LDO for portable devices.
> >
> > In MediaTek MT6370, there are four channel current-sink RGB LEDs that
> > support hardware pattern for constant current, PWM, and breath mode.
> > Isink4 channel can also be used as a CHG_VIN power good indicator.
> >
>
> > +config LEDS_MT6370_RGB
> > +     tristate "LED Support for MediaTek MT6370 PMIC"
> > +     depends on MFD_MT6370
> > +     select LINEAR_RANGE
> > +     help
> > +       Say Y here to enable support for MT6370_RGB LED device.
> > +       In MT6370, there are four channel current-sink LED drivers that
> > +       support hardware pattern for constant current, PWM, and breath mode.
>
>
> > +       Isink4 channel can also be used as a CHG_VIN power good  indicator.
>
> That does not really belong here.
>
> > +struct mt6370_priv {
> > +     /* Per LED access lock */
> > +     struct mutex lock;
>
> Do we really need per-led locking?
>
> > +static int mt6370_gen_breath_pattern(struct mt6370_priv *priv,
> > +                                  struct led_pattern *pattern, u32 len,
> > +                                  u8 *pattern_val, u32 val_len)
> > +{
> > +     enum mt6370_led_ranges sel_range;
> > +     struct led_pattern *curr;
> > +     unsigned int sel;
> > +     u8 val[P_MAX_PATTERNS / 2] = {};
> > +     int i;
> > +
> > +     if (len < P_MAX_PATTERNS && val_len < P_MAX_PATTERNS / 2)
> > +             return -EINVAL;
> > +
> > +     /*
> > +      * Pattern list
> > +      * tr1: byte 0, b'[7: 4]
> > +      * tr2: byte 0, b'[3: 0]
> > +      * tf1: byte 1, b'[7: 4]
> > +      * tf2: byte 1, b'[3: 0]
> > +      * ton: byte 2, b'[7: 4]
> > +      * toff: byte 2, b'[3: 0]
> > +      */
> > +     for (i = 0; i < P_MAX_PATTERNS; i++) {
> > +             curr = pattern + i;
> > +
> > +             sel_range = i == P_LED_TOFF ? R_LED_TOFF : R_LED_TRFON;
> > +
> > +             linear_range_get_selector_within(priv->ranges + sel_range,
> > +                                              curr->delta_t, &sel);
> > +
> > +             val[i / 2] |= sel << (4 * ((i + 1) % 2));
> > +     }
> > +
> > +     memcpy(pattern_val, val, 3);
> > +
> > +     return 0;
> > +}
>
> I wonder how this works... you are not creating private sysfs
> interface, are you?
>
> > +static int mt6370_init_led_properties(struct mt6370_led *led,
> > +                                   struct led_init_data *init_data)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     struct device *dev = priv->dev;
> > +     struct led_classdev *lcdev;
> > +     struct fwnode_handle *child;
> > +     enum mt6370_led_ranges sel_range;
> > +     u32 max_uA, max_level;
> > +     const char * const states[] = { "off", "keep", "on" };
>
> We'd really preffer not to add "keep" / "on" support unless you need
> it.
>
> > +                     if (ret)
> > +                             return dev_err_probe(dev, ret,
> > +                                                  "led %d, no color specified\n",
> > +                                                  led->index);
>
> led->LED.
>
> > +             if (num_color < 2)
> > +                     return dev_err_probe(dev, -EINVAL,
> > +                                          "Multicolor must include
> > 2 or more led channel\n");
>
> "LED channels".
>
> > +static int mt6370_isnk_init_default_state(struct mt6370_led *led)
> > +{
> > +     struct mt6370_priv *priv = led->priv;
> > +     unsigned int enable, level;
> > +     int ret;
> > +
> > +     ret = mt6370_get_led_brightness(priv, led->index, &level);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = regmap_field_read(priv->fields[F_RGB_EN], &enable);
> > +     if (ret)
> > +             return ret;
> > +
> > +     if (!(enable & MT6370_CHEN_BIT(led->index)))
> > +             level = LED_OFF;
>
> Just use 0 instead of LED_OFF.
>
> Best regards,
>                                                         Pavel
>
> --
> People of Russia, stop Putin before his war on Ukraine escalates.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
  2022-07-30 21:42     ` Pavel Machek
  (?)
@ 2022-08-04  9:53       ` Alice Chen
  -1 siblings, 0 replies; 154+ messages in thread
From: Alice Chen @ 2022-08-04  9:53 UTC (permalink / raw)
  To: Pavel Machek
  Cc: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev

Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:42寫道:

> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: Alice Chen <alice_chen@richtek.com
>
> Add ">" at end of line.
>
> The series is quite big, would it be possible to submit LED changes
> in separate series?
>
Hi Pavel,

Our mfd dt-bindings depends on flash and LED dt-bindings,
but our flash and LED config depend on mfd config.
For the dependency consideration,
we think submitting them in a patch series is better.

Best Regards,
Alice

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-08-04  9:53       ` Alice Chen
  0 siblings, 0 replies; 154+ messages in thread
From: Alice Chen @ 2022-08-04  9:53 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-fbdev, heikki.krogerus, alice_chen, linux-iio, dri-devel,
	lgirdwood, cy_huang, krzysztof.kozlowski+dt, lee.jones,
	linux-leds, daniel.thompson, deller, robh+dt, andy.shevchenko,
	chunfeng.yun, linux, devicetree, linux-pm, broonie,
	linux-mediatek, matthias.bgg, ChiaEn Wu, linux-arm-kernel,
	jingoohan1, linux-usb, sre, linux-kernel, chiaen_wu, gregkh,
	jic23

Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:42寫道:

> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: Alice Chen <alice_chen@richtek.com
>
> Add ">" at end of line.
>
> The series is quite big, would it be possible to submit LED changes
> in separate series?
>
Hi Pavel,

Our mfd dt-bindings depends on flash and LED dt-bindings,
but our flash and LED config depend on mfd config.
For the dependency consideration,
we think submitting them in a patch series is better.

Best Regards,
Alice

^ permalink raw reply	[flat|nested] 154+ messages in thread

* Re: [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support
@ 2022-08-04  9:53       ` Alice Chen
  0 siblings, 0 replies; 154+ messages in thread
From: Alice Chen @ 2022-08-04  9:53 UTC (permalink / raw)
  To: Pavel Machek
  Cc: ChiaEn Wu, lee.jones, daniel.thompson, jingoohan1, robh+dt,
	krzysztof.kozlowski+dt, matthias.bgg, sre, chunfeng.yun, gregkh,
	jic23, lars, lgirdwood, broonie, linux, heikki.krogerus, deller,
	andy.shevchenko, chiaen_wu, alice_chen, cy_huang, dri-devel,
	linux-leds, devicetree, linux-arm-kernel, linux-mediatek,
	linux-kernel, linux-pm, linux-usb, linux-iio, linux-fbdev

Pavel Machek <pavel@ucw.cz> 於 2022年7月31日 週日 清晨5:42寫道:

> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (C) 2022 Richtek Technology Corp.
> > + *
> > + * Author: Alice Chen <alice_chen@richtek.com
>
> Add ">" at end of line.
>
> The series is quite big, would it be possible to submit LED changes
> in separate series?
>
Hi Pavel,

Our mfd dt-bindings depends on flash and LED dt-bindings,
but our flash and LED config depend on mfd config.
For the dependency consideration,
we think submitting them in a patch series is better.

Best Regards,
Alice

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 154+ messages in thread

end of thread, other threads:[~2022-08-04  9:54 UTC | newest]

Thread overview: 154+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-22 10:23 [PATCH v6 00/13] Add MediaTek MT6370 PMIC support ChiaEn Wu
2022-07-22 10:23 ` ChiaEn Wu
2022-07-22 10:23 ` ChiaEn Wu
2022-07-22 10:23 ` [PATCH v6 01/13] dt-bindings: usb: Add MediaTek MT6370 TCPC ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23 ` [PATCH v6 02/13] dt-bindings: power: supply: Add MediaTek MT6370 Charger ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23 ` [PATCH v6 03/13] dt-bindings: leds: mt6370: Add MediaTek MT6370 current sink type LED indicator ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23 ` [PATCH v6 04/13] dt-bindings: leds: Add MediaTek MT6370 flashlight ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-30 21:30   ` Pavel Machek
2022-07-30 21:30     ` Pavel Machek
2022-07-30 21:30     ` Pavel Machek
2022-07-22 10:23 ` [PATCH v6 05/13] dt-bindings: backlight: Add MediaTek MT6370 backlight ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-07-22 10:23   ` ChiaEn Wu
2022-08-01  6:47   ` ChiaEn Wu
2022-08-01  6:47     ` ChiaEn Wu
2022-07-22 10:24 ` [PATCH v6 06/13] dt-bindings: mfd: Add MediaTek MT6370 ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24 ` [PATCH v6 07/13] mfd: mt6370: Add MediaTek MT6370 support ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-25  7:59   ` Andy Shevchenko
2022-07-25  7:59     ` Andy Shevchenko
2022-07-25  7:59     ` Andy Shevchenko
2022-07-25  8:29     ` ChiaEn Wu
2022-07-25  8:29       ` ChiaEn Wu
2022-07-25  8:29       ` ChiaEn Wu
2022-07-25  8:43       ` Andy Shevchenko
2022-07-25  8:43         ` Andy Shevchenko
2022-07-25  8:43         ` Andy Shevchenko
2022-07-25  9:06         ` ChiaEn Wu
2022-07-25  9:06           ` ChiaEn Wu
2022-07-25  9:06           ` ChiaEn Wu
2022-07-25  9:09           ` Andy Shevchenko
2022-07-25  9:09             ` Andy Shevchenko
2022-07-25  9:09             ` Andy Shevchenko
2022-07-22 10:24 ` [PATCH v6 08/13] usb: typec: tcpci_mt6370: Add MediaTek MT6370 tcpci driver ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 14:19   ` Guenter Roeck
2022-07-22 14:19     ` Guenter Roeck
2022-07-22 14:19     ` Guenter Roeck
2022-07-25  7:06   ` Chunfeng Yun
2022-07-25  7:06     ` Chunfeng Yun
2022-07-25  7:06     ` Chunfeng Yun
2022-07-25  7:17     ` ChiaEn Wu
2022-07-25  7:17       ` ChiaEn Wu
2022-07-25  7:17       ` ChiaEn Wu
2022-07-25  8:03   ` Andy Shevchenko
2022-07-25  8:03     ` Andy Shevchenko
2022-07-25  8:03     ` Andy Shevchenko
2022-07-22 10:24 ` [PATCH v6 09/13] iio: adc: mt6370: Add MediaTek MT6370 support ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-25  8:10   ` Andy Shevchenko
2022-07-25  8:10     ` Andy Shevchenko
2022-07-25  8:10     ` Andy Shevchenko
2022-07-22 10:24 ` [PATCH v6 10/13] power: supply: mt6370: Add MediaTek MT6370 charger driver ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-25  8:25   ` Andy Shevchenko
2022-07-25  8:25     ` Andy Shevchenko
2022-07-25  8:25     ` Andy Shevchenko
2022-07-22 10:24 ` [PATCH v6 11/13] leds: rgb: mt6370: Add MediaTek MT6370 current sink type LED Indicator support ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:52   ` AngeloGioacchino Del Regno
2022-07-22 10:52     ` AngeloGioacchino Del Regno
2022-07-22 10:52     ` AngeloGioacchino Del Regno
2022-07-25  8:40   ` Andy Shevchenko
2022-07-25  8:40     ` Andy Shevchenko
2022-07-25  8:40     ` Andy Shevchenko
2022-07-26 11:45     ` ChiaEn Wu
2022-07-26 11:45       ` ChiaEn Wu
2022-07-26 11:45       ` ChiaEn Wu
2022-07-26 12:17       ` Andy Shevchenko
2022-07-26 12:17         ` Andy Shevchenko
2022-07-26 12:17         ` Andy Shevchenko
2022-07-27  7:36         ` ChiaEn Wu
2022-07-27  7:36           ` ChiaEn Wu
2022-07-27  7:36           ` ChiaEn Wu
2022-07-27 10:03           ` Andy Shevchenko
2022-07-27 10:03             ` Andy Shevchenko
2022-07-27 10:03             ` Andy Shevchenko
2022-07-30 21:39   ` Pavel Machek
2022-07-30 21:39     ` Pavel Machek
2022-07-30 21:39     ` Pavel Machek
2022-08-01  7:55     ` szuni chen
2022-08-01  7:55       ` szuni chen
2022-07-22 10:24 ` [PATCH v6 12/13] leds: flash: mt6370: Add MediaTek MT6370 flashlight support ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:48   ` AngeloGioacchino Del Regno
2022-07-22 10:48     ` AngeloGioacchino Del Regno
2022-07-22 10:48     ` AngeloGioacchino Del Regno
2022-07-25  8:51   ` Andy Shevchenko
2022-07-25  8:51     ` Andy Shevchenko
2022-07-25  8:51     ` Andy Shevchenko
2022-07-29  6:17     ` szuni chen
2022-07-29  6:17       ` szuni chen
2022-07-29  6:17       ` szuni chen
2022-07-29 10:34       ` Andy Shevchenko
2022-07-29 10:34         ` Andy Shevchenko
2022-07-29 10:34         ` Andy Shevchenko
2022-07-25  8:55   ` Andy Shevchenko
2022-07-25  8:55     ` Andy Shevchenko
2022-07-25  8:55     ` Andy Shevchenko
2022-07-26  4:15     ` szuni chen
2022-07-26  4:15       ` szuni chen
2022-07-26  4:15       ` szuni chen
2022-07-26  6:10       ` Andy Shevchenko
2022-07-26  6:10         ` Andy Shevchenko
2022-07-26  6:10         ` Andy Shevchenko
2022-07-30 21:42   ` Pavel Machek
2022-07-30 21:42     ` Pavel Machek
2022-07-30 21:42     ` Pavel Machek
2022-08-04  9:53     ` Alice Chen
2022-08-04  9:53       ` Alice Chen
2022-08-04  9:53       ` Alice Chen
2022-07-22 10:24 ` [PATCH v6 13/13] video: backlight: mt6370: Add MediaTek MT6370 support ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-22 10:24   ` ChiaEn Wu
2022-07-25  9:07   ` Andy Shevchenko
2022-07-25  9:07     ` Andy Shevchenko
2022-07-25  9:07     ` Andy Shevchenko
2022-07-25 10:31   ` Daniel Thompson
2022-07-25 10:31     ` Daniel Thompson
2022-07-25 10:31     ` Daniel Thompson
2022-07-26  2:20     ` ChiaEn Wu
2022-07-26  2:20       ` ChiaEn Wu
2022-07-26  2:20       ` ChiaEn Wu
2022-07-26  9:30       ` Daniel Thompson
2022-07-26  9:30         ` Daniel Thompson
2022-07-26  9:30         ` Daniel Thompson
2022-07-26 11:28         ` ChiaEn Wu
2022-07-26 11:28           ` ChiaEn Wu
2022-07-26 11:28           ` ChiaEn Wu
2022-07-26 11:59           ` Daniel Thompson
2022-07-26 11:59             ` Daniel Thompson
2022-07-26 11:59             ` Daniel Thompson
2022-07-27  6:24             ` ChiaEn Wu
2022-07-27  6:24               ` ChiaEn Wu
2022-07-27  6:24               ` ChiaEn Wu
2022-07-28 11:31               ` Daniel Thompson
2022-07-28 11:31                 ` Daniel Thompson
2022-07-28 11:31                 ` Daniel Thompson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.