- Core Frameworks
- Add support for Software Nodes to MFD Core
    - Remove support for Device Properties from MFD Core
    - Use standard APIs in MFD Core
 
  - New Drivers
    - Add support for ROHM BD9576MUF and BD9573MUF PMICs
    - Add support for Netronix Embedded Controller, PWM and RTC
    - Add support for Actions Semi ATC260x PMICs and OnKey
 
  - New Device Support
    - Add support for DG1 PCIe Graphics Card to Intel PMT
    - Add support for ROHM BD71815 PMIC to ROHM BD71828
    - Add support for Tolino Shine 2 HD to Netronix Embedded Controller
    - Add support for AX10 BMC Secure Updates to Intel M10 BMC
 
  - Removed Device Support
    - Remove Arizona Extcon support from MFD
    - Remove ST-E AB8500 Power Supply code from MFD
    - Remove AB3100 altogether
 
  - New Functionality
    - Add support for SMBus and I2C modes to Dialog DA9063
    - Switch to using Software Nodes in Intel (various)
 
  - New/converted Device Tree bindings; rohm,bd71815-pmic, rohm,bd9576-pmic,
                                        netronix,ntxec, actions,atc260x,
 				       ricoh,rn5t618, qcom-pm8xxx
 
 - Fix-ups
    - Fix error handling/path; intel_pmt
    - Simplify code; rohm-bd718x7, ab8500-core, intel-m10-bmc
    - Trivial clean-ups (reordering, spelling); rohm-generic, rn5t618, max8997
    - Use correct data-type; db8500-prcmu
    - Remove superfluous code; lp87565, intel_quark_i2c_gpi, lpc_sch, twl
    - Use generic APIs/defines; lm3533-core, intel_quark_i2c_gpio
    - Regmap related fix-ups; intel-m10-bmc, sec-core
    - Reorder resource freeing during remove; intel_quark_i2c_gpio
    - Make table indexing more robust; intel_quark_i2c_gpio
    - Fix reference imbalances; arizona-irq
    - Staticify and (un)constify things; arizona-spi, stmpe, ene-kb3930,
                                         intel-lpss-acpi, intel-lpss-pci,
                                         atc260x-i2c, intel_quark_i2c_gpio
 
  - Bug Fixes
    - Fix incorrect (register) values; intel-m10-bmc
    - Kconfig related fixes; ABX500_CORE
    - Do not clear the Auto Reload Register; stm32-timers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAmCJIPEACgkQUa+KL4f8
 d2FRZA//Xu9f8u2uLuIfuhxIjUUXOqIjRAFnkhKlgGZhKsY8BohjQ80Tj9yp6UKy
 St6ABwACO0hJap4zL4FxPW9+HXTmqZvAibnvHnvZdYSQ3ai6x9h6kTNvhSNLeRQU
 fuY7eN8kpAHHiHNKNJCsQLQMvcIyP7+0KAP6qir5GYsMjiXspWq7THUnfBi2JXC6
 y60guDo9XrgmQTO+pB870UJrKLM/h+iiohNRGxLFlShKhFCgbTB/wyw6bFeKy1SB
 0/6XuY6fOt1IQyBDuzw383Q2faMWO9U+es29bwvFxdqJDK0MHQXC47zBba2q94wL
 /9i/HSoz9dRHnTJNYUKWsVcPv4T84w/Iq7scyDvE00ubehJ+oo/M7Au3M6Tt3M1/
 6lBAwFYXiwhQnp9EP3nwPwgJF6JzX1IGuMOsUAqrVFOEMuIkZKbRdUlatUhqepJT
 spV4/TOfztAhY/7BzEOZLnF8cFNjmL5sn42/UzSRW708V5SxuTNsS48KJ4l0c7Er
 CZSTlR/T1rKkWqf7ejaS2TNqMCdYyB3vZW0quDxZTHTZHv9huNUvtbKPR7jmd+4p
 mrMIik7EE4BzC5m8tBPnXXZl+Og0keeYv4LUDBuLDX1agrxYIErl4ITvQTqqMfX1
 Jt14SIjSO56iu2ngQuvGWwegVK4/urO2kBJKUAH1QN1OocNaajQ=
 =IJSL
 -----END PGP SIGNATURE-----
Merge tag 'mfd-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
 "Core Framework:
   - Add support for Software Nodes to MFD Core
   - Remove support for Device Properties from MFD Core
   - Use standard APIs in MFD Core
  New Drivers:
   - Add support for ROHM BD9576MUF and BD9573MUF PMICs
   - Add support for Netronix Embedded Controller, PWM and RTC
   - Add support for Actions Semi ATC260x PMICs and OnKey
  New Device Support:
   - Add support for DG1 PCIe Graphics Card to Intel PMT
   - Add support for ROHM BD71815 PMIC to ROHM BD71828
   - Add support for Tolino Shine 2 HD to Netronix Embedded Controller
   - Add support for AX10 BMC Secure Updates to Intel M10 BMC
  Removed Device Support:
   - Remove Arizona Extcon support from MFD
   - Remove ST-E AB8500 Power Supply code from MFD
   - Remove AB3100 altogether
  New Functionality:
   - Add support for SMBus and I2C modes to Dialog DA9063
   - Switch to using Software Nodes in Intel (various)
  New/converted Device Tree bindings:
   - rohm bd71815-pmic, rohm bd9576-pmic, netronix ntxec, actions
     atc260x, ricoh rn5t618, qcom pm8xxx
- Fix-ups:
   - Fix error handling/path; intel_pmt
   - Simplify code; rohm-bd718x7, ab8500-core, intel-m10-bmc
   - Trivial clean-ups (reordering, spelling); rohm-generic, rn5t618,
     max8997
   - Use correct data-type; db8500-prcmu
   - Remove superfluous code; lp87565, intel_quark_i2c_gpi, lpc_sch, twl
   - Use generic APIs/defines; lm3533-core, intel_quark_i2c_gpio
   - Regmap related fix-ups; intel-m10-bmc, sec-core
   - Reorder resource freeing during remove; intel_quark_i2c_gpio
   - Make table indexing more robust; intel_quark_i2c_gpio
   - Fix reference imbalances; arizona-irq
   - Staticify and (un)constify things; arizona-spi, stmpe, ene-kb3930,
     intel-lpss-acpi, intel-lpss-pci, atc260x-i2c, intel_quark_i2c_gpio
  Bug Fixes:
   - Fix incorrect (register) values; intel-m10-bmc
   - Kconfig related fixes; ABX500_CORE
   - Do not clear the Auto Reload Register; stm32-timers"
* tag 'mfd-next-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (84 commits)
  mfd: intel-m10-bmc: Add support for MAX10 BMC Secure Updates
  Revert "mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell"
  mfd: twl: Remove unused inline function twl4030charger_usb_en()
  dt-bindings: mfd: Convert pm8xxx bindings to yaml
  dt-bindings: mfd: Add compatible for pmk8350 rtc
  i2c: designware: Get rid of legacy platform data
  mfd: intel_quark_i2c_gpio: Convert I²C to use software nodes
  mfd: lpc_sch: Partially revert "Add support for Intel Quark X1000"
  mfd: arizona: Fix rumtime PM imbalance on error
  mfd: max8997: Replace 8998 with 8997
  mfd: core: Use acpi_find_child_device() for child devices lookup
  mfd: intel_quark_i2c_gpio: Don't play dirty trick with const
  mfd: intel_quark_i2c_gpio: Enable MSI interrupt
  mfd: intel_quark_i2c_gpio: Reuse BAR definitions for MFD cell indexing
  mfd: ntxec: Support for EC in Tolino Shine 2 HD
  mfd: stm32-timers: Avoid clearing auto reload register
  mfd: intel_quark_i2c_gpio: Replace I²C speeds with descriptive definitions
  mfd: intel_quark_i2c_gpio: Remove unused struct device member
  mfd: intel_quark_i2c_gpio: Unregister resources in reversed order
  mfd: Kconfig: ABX500_CORE should depend on ARCH_U8500
  ...
			
			
This commit is contained in:
		
						commit
						71a5cc28e8
					
				
							
								
								
									
										3
									
								
								CREDITS
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								CREDITS
									
									
									
									
									
								
							| @ -1933,6 +1933,9 @@ N: Kukjin Kim | ||||
| E: kgene@kernel.org | ||||
| D: Samsung S3C, S5P and Exynos ARM architectures | ||||
| 
 | ||||
| N: Milo Kim | ||||
| D: TI LP855x, LP8727 and LP8788 drivers | ||||
| 
 | ||||
| N: Sangbeom Kim | ||||
| E: sbkim73@samsung.com | ||||
| D: Samsung SoC Audio (ASoC) drivers | ||||
|  | ||||
| @ -33,4 +33,11 @@ properties: | ||||
|       power off automatically. Device with key pressed shutdown feature can | ||||
|       specify this property. | ||||
| 
 | ||||
|   reset-time-sec: | ||||
|     description: | ||||
|       Duration in seconds which the key should be kept pressed for device to | ||||
|       reset automatically. Device with key pressed reset feature can specify | ||||
|       this property. | ||||
|     $ref: /schemas/types.yaml#/definitions/uint32 | ||||
| 
 | ||||
| additionalProperties: true | ||||
|  | ||||
							
								
								
									
										183
									
								
								Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								Documentation/devicetree/bindings/mfd/actions,atc260x.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,183 @@ | ||||
| # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/actions,atc260x.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: Actions Semi ATC260x Power Management IC bindings | ||||
| 
 | ||||
| maintainers: | ||||
|   - Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
|   - Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
| 
 | ||||
| description: | | ||||
|   ATC260x series PMICs integrates Audio Codec, Power Management, RTC, IR | ||||
|   and GPIO controller blocks. Currently only the PM related functionalities | ||||
|   (i.e. regulators and system power-off/reboot) for the ATC2603C and ATC2609A | ||||
|   chip variants are supported. | ||||
|   ATC2603C includes 3 programmable DC-DC converters, 9 programmable LDO | ||||
|   regulators and 1 fixed LDO regulator. | ||||
|   ATC2609A includes 5 programmable DC-DC converters and 10 programmable LDO | ||||
|   regulators. | ||||
| 
 | ||||
| allOf: | ||||
|   - $ref: ../input/input.yaml | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     enum: | ||||
|       - actions,atc2603c | ||||
|       - actions,atc2609a | ||||
| 
 | ||||
|   reg: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   interrupts: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   reset-time-sec: | ||||
|     description: | | ||||
|       Duration in seconds which the key should be kept pressed for device | ||||
|       to reset automatically. The hardware default is 8. Use 0 to disable | ||||
|       this functionality. | ||||
|     enum: [0, 6, 8, 10, 12] | ||||
| 
 | ||||
|   regulators: | ||||
|     type: object | ||||
|     description: | | ||||
|       List of child nodes specifying the regulators, depending on chip variant: | ||||
|       * ATC2603C: dcdc[1-3], ldo[1-3,5-8,11,12], switchldo1 | ||||
|       * ATC2609A: dcdc[0-4], ldo[0-9] | ||||
| 
 | ||||
|     properties: | ||||
|       compatible: | ||||
|         enum: | ||||
|           - actions,atc2603c-regulator | ||||
|           - actions,atc2609a-regulator | ||||
| 
 | ||||
|       switchldo1: | ||||
|         type: object | ||||
|         $ref: ../regulator/regulator.yaml | ||||
| 
 | ||||
|         properties: | ||||
|           regulator-name: true | ||||
|           regulator-boot-on: true | ||||
|           regulator-always-on: true | ||||
|           regulator-min-microvolt: true | ||||
|           regulator-max-microvolt: true | ||||
|           regulator-allow-bypass: true | ||||
|           regulator-active-discharge: true | ||||
| 
 | ||||
|         additionalProperties: false | ||||
| 
 | ||||
|     patternProperties: | ||||
|       "^(dcdc[0-4]|ldo[0-9]|ldo1[1-2]|switchldo1)-supply$": | ||||
|         description: ATC260x voltage regulators supplies | ||||
| 
 | ||||
|       "^(dcdc[0-4]|ldo[0-9]|ldo1[1-2])$": | ||||
|         type: object | ||||
|         $ref: ../regulator/regulator.yaml | ||||
| 
 | ||||
|         properties: | ||||
|           regulator-name: true | ||||
|           regulator-boot-on: true | ||||
|           regulator-always-on: true | ||||
|           regulator-min-microvolt: true | ||||
|           regulator-max-microvolt: true | ||||
|           regulator-allow-bypass: true | ||||
| 
 | ||||
|         additionalProperties: false | ||||
| 
 | ||||
|     allOf: | ||||
|       - if: | ||||
|           properties: | ||||
|             compatible: | ||||
|               contains: | ||||
|                 const: actions,atc2603c-regulator | ||||
|         then: | ||||
|           patternProperties: | ||||
|             "^(dcdc[0,4]|ldo[0,4,9])(-supply)?$": false | ||||
| 
 | ||||
|             "^(ldo|dcdc)": | ||||
|               properties: | ||||
|                 regulator-allow-bypass: false | ||||
|       - if: | ||||
|           properties: | ||||
|             compatible: | ||||
|               contains: | ||||
|                 const: actions,atc2609a-regulator | ||||
|         then: | ||||
|           patternProperties: | ||||
|             "^(ldo1[1-2]|switchldo1)(-supply)?$": false | ||||
| 
 | ||||
|             "^(dcdc|ldo[3-9])": | ||||
|               properties: | ||||
|                 regulator-allow-bypass: false | ||||
| 
 | ||||
|     required: | ||||
|       - compatible | ||||
| 
 | ||||
|     additionalProperties: false | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
|   - interrupts | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     #include <dt-bindings/interrupt-controller/arm-gic.h> | ||||
|     i2c0 { | ||||
|         #address-cells = <1>; | ||||
|         #size-cells = <0>; | ||||
| 
 | ||||
|         pmic@65 { | ||||
|             compatible = "actions,atc2603c"; | ||||
|             reg = <0x65>; | ||||
|             interrupt-parent = <&sirq>; | ||||
|             interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; | ||||
| 
 | ||||
|             reset-time-sec = <6>; | ||||
| 
 | ||||
|             regulators { | ||||
|                 compatible = "actions,atc2603c-regulator"; | ||||
| 
 | ||||
|                 dcdc1-supply = <®_5v0>; | ||||
|                 dcdc3-supply = <®_5v0>; | ||||
|                 ldo5-supply = <®_5v0>; | ||||
|                 switchldo1-supply = <&vcc>; | ||||
| 
 | ||||
|                 vdd_cpu: dcdc1 { | ||||
|                     regulator-name = "VDD_CPU"; | ||||
|                     regulator-min-microvolt = <700000>; | ||||
|                     regulator-max-microvolt = <1400000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
| 
 | ||||
|                 vcc: dcdc3 { | ||||
|                     regulator-name = "VCC"; | ||||
|                     regulator-min-microvolt = <2600000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
| 
 | ||||
|                 vcc_3v1: ldo5 { | ||||
|                     regulator-name = "VCC_3V1"; | ||||
|                     regulator-min-microvolt = <2600000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                 }; | ||||
| 
 | ||||
|                 sd_vcc: switchldo1 { | ||||
|                     regulator-name = "SD_VCC"; | ||||
|                     regulator-min-microvolt = <3000000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                     regulator-boot-on; | ||||
|                 }; | ||||
|             }; | ||||
|         }; | ||||
|     }; | ||||
| 
 | ||||
| ... | ||||
							
								
								
									
										76
									
								
								Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | ||||
| # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/netronix,ntxec.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: Netronix Embedded Controller | ||||
| 
 | ||||
| maintainers: | ||||
|   - Jonathan Neuschäfer <j.neuschaefer@gmx.net> | ||||
| 
 | ||||
| description: | | ||||
|   This EC is found in e-book readers of multiple brands (e.g. Kobo, Tolino), and | ||||
|   is typically implemented as a TI MSP430 microcontroller. | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     const: netronix,ntxec | ||||
| 
 | ||||
|   reg: | ||||
|     items: | ||||
|       - description: The I2C address of the EC | ||||
| 
 | ||||
|   system-power-controller: | ||||
|     type: boolean | ||||
|     description: See Documentation/devicetree/bindings/power/power-controller.txt | ||||
| 
 | ||||
|   interrupts: | ||||
|     minItems: 1 | ||||
|     description: | ||||
|       The EC can signal interrupts via a GPIO line | ||||
| 
 | ||||
|   "#pwm-cells": | ||||
|     const: 2 | ||||
|     description: | | ||||
|       Number of cells in a PWM specifier. | ||||
| 
 | ||||
|       The following PWM channels are supported: | ||||
|         - 0: The PWM channel controlled by registers 0xa1-0xa7 | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     #include <dt-bindings/interrupt-controller/irq.h> | ||||
|     i2c { | ||||
|             #address-cells = <1>; | ||||
|             #size-cells = <0>; | ||||
| 
 | ||||
|             ec: embedded-controller@43 { | ||||
|                     pinctrl-names = "default"; | ||||
|                     pinctrl-0 = <&pinctrl_ntxec>; | ||||
| 
 | ||||
|                     compatible = "netronix,ntxec"; | ||||
|                     reg = <0x43>; | ||||
|                     system-power-controller; | ||||
|                     interrupt-parent = <&gpio4>; | ||||
|                     interrupts = <11 IRQ_TYPE_EDGE_FALLING>; | ||||
|                     #pwm-cells = <2>; | ||||
|             }; | ||||
|     }; | ||||
| 
 | ||||
|     backlight { | ||||
|             compatible = "pwm-backlight"; | ||||
|             pwms = <&ec 0 50000>; | ||||
|             power-supply = <&backlight_regulator>; | ||||
|     }; | ||||
| 
 | ||||
|     backlight_regulator: regulator-dummy { | ||||
|             compatible = "regulator-fixed"; | ||||
|             regulator-name = "backlight"; | ||||
|     }; | ||||
| @ -1,99 +0,0 @@ | ||||
| Qualcomm PM8xxx PMIC multi-function devices | ||||
| 
 | ||||
| The PM8xxx family of Power Management ICs are used to provide regulated | ||||
| voltages and other various functionality to Qualcomm SoCs. | ||||
| 
 | ||||
| = PROPERTIES | ||||
| 
 | ||||
| - compatible: | ||||
| 	Usage: required | ||||
| 	Value type: <string> | ||||
| 	Definition: must be one of: | ||||
| 		    "qcom,pm8058" | ||||
| 		    "qcom,pm8821" | ||||
| 		    "qcom,pm8921" | ||||
| 
 | ||||
| - #address-cells: | ||||
| 	Usage: required | ||||
| 	Value type: <u32> | ||||
| 	Definition: must be 1 | ||||
| 
 | ||||
| - #size-cells: | ||||
| 	Usage: required | ||||
| 	Value type: <u32> | ||||
| 	Definition: must be 0 | ||||
| 
 | ||||
| - interrupts: | ||||
| 	Usage: required | ||||
| 	Value type: <prop-encoded-array> | ||||
| 	Definition: specifies the interrupt that indicates a subdevice | ||||
| 		    has generated an interrupt (summary interrupt). The | ||||
| 		    format of the specifier is defined by the binding document | ||||
| 		    describing the node's interrupt parent. | ||||
| 
 | ||||
| - #interrupt-cells: | ||||
| 	Usage: required | ||||
| 	Value type : <u32> | ||||
| 	Definition: must be 2. Specifies the number of cells needed to encode | ||||
| 		    an interrupt source. The 1st cell contains the interrupt | ||||
| 		    number. The 2nd cell is the trigger type and level flags | ||||
| 		    encoded as follows: | ||||
| 
 | ||||
| 			1 = low-to-high edge triggered | ||||
| 			2 = high-to-low edge triggered | ||||
| 			4 = active high level-sensitive | ||||
| 			8 = active low level-sensitive | ||||
| 
 | ||||
| - interrupt-controller: | ||||
| 	Usage: required | ||||
| 	Value type: <empty> | ||||
| 	Definition: identifies this node as an interrupt controller | ||||
| 
 | ||||
| = SUBCOMPONENTS | ||||
| 
 | ||||
| The PMIC contains multiple independent functions, each described in a subnode. | ||||
| The below bindings specify the set of valid subnodes. | ||||
| 
 | ||||
| == Real-Time Clock | ||||
| 
 | ||||
| - compatible: | ||||
| 	Usage: required | ||||
| 	Value type: <string> | ||||
| 	Definition: must be one of: | ||||
| 		    "qcom,pm8058-rtc" | ||||
| 		    "qcom,pm8921-rtc" | ||||
| 		    "qcom,pm8941-rtc" | ||||
| 		    "qcom,pm8018-rtc" | ||||
| 
 | ||||
| - reg: | ||||
| 	Usage: required | ||||
| 	Value type: <prop-encoded-array> | ||||
| 	Definition: single entry specifying the base address of the RTC registers | ||||
| 
 | ||||
| - interrupts: | ||||
| 	Usage: required | ||||
| 	Value type: <prop-encoded-array> | ||||
| 	Definition: single entry specifying the RTC's alarm interrupt | ||||
| 
 | ||||
| - allow-set-time: | ||||
| 	Usage: optional | ||||
| 	Value type: <empty> | ||||
| 	Definition: indicates that the setting of RTC time is allowed by | ||||
| 		    the host CPU | ||||
| 
 | ||||
| = EXAMPLE | ||||
| 
 | ||||
| 	pmicintc: pmic@0 { | ||||
| 		compatible = "qcom,pm8921"; | ||||
| 		interrupts = <104 8>; | ||||
| 		#interrupt-cells = <2>; | ||||
| 		interrupt-controller; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
| 
 | ||||
| 		rtc@11d { | ||||
| 			compatible = "qcom,pm8921-rtc"; | ||||
| 			reg = <0x11d>; | ||||
| 			interrupts = <0x27 0>; | ||||
| 		}; | ||||
| 	}; | ||||
							
								
								
									
										54
									
								
								Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								Documentation/devicetree/bindings/mfd/qcom-pm8xxx.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,54 @@ | ||||
| # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/qcom-pm8xxx.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: Qualcomm PM8xxx PMIC multi-function devices | ||||
| 
 | ||||
| maintainers: | ||||
|   - Satya Priya <skakit@codeaurora.org> | ||||
| 
 | ||||
| description: | | ||||
|   The PM8xxx family of Power Management ICs are used to provide regulated | ||||
|   voltages and other various functionality to Qualcomm SoCs. | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     enum: | ||||
|       - qcom,pm8058 | ||||
|       - qcom,pm8821 | ||||
|       - qcom,pm8921 | ||||
| 
 | ||||
|   reg: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   '#address-cells': | ||||
|     const: 1 | ||||
| 
 | ||||
|   '#size-cells': | ||||
|     const: 0 | ||||
| 
 | ||||
|   interrupts: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   '#interrupt-cells': | ||||
|     const: 2 | ||||
| 
 | ||||
|   interrupt-controller: true | ||||
| 
 | ||||
| patternProperties: | ||||
|   "rtc@[0-9a-f]+$": | ||||
|     type: object | ||||
|     $ref: "../rtc/qcom-pm8xxx-rtc.yaml" | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - '#address-cells' | ||||
|   - '#size-cells' | ||||
|   - interrupts | ||||
|   - '#interrupt-cells' | ||||
|   - interrupt-controller | ||||
| 
 | ||||
| additionalProperties: false | ||||
| ... | ||||
							
								
								
									
										111
									
								
								Documentation/devicetree/bindings/mfd/ricoh,rn5t618.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								Documentation/devicetree/bindings/mfd/ricoh,rn5t618.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0 | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/ricoh,rn5t618.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: Ricoh RN5T567/RN5T618/RC5T619 PMIC | ||||
| 
 | ||||
| maintainers: | ||||
|   - Andreas Kemnade <andreas@kemnade.info> | ||||
| 
 | ||||
| description: | | ||||
|   Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which | ||||
|   integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators, | ||||
|   GPIOs, and a watchdog timer. It can be controlled through an I2C interface. | ||||
|   The RN5T618/RC5T619 provides additionally a Li-ion battery charger, | ||||
|   fuel gauge, and an ADC. | ||||
|   The RC5T619 additionally includes USB charger detection and an RTC. | ||||
| 
 | ||||
| allOf: | ||||
|   - if: | ||||
|       properties: | ||||
|         compatible: | ||||
|           contains: | ||||
|             const: ricoh,rn5t567 | ||||
|     then: | ||||
|       properties: | ||||
|         regulators: | ||||
|           patternProperties: | ||||
|             "^(DCDC[1-4]|LDO[1-5]|LDORTC[12])$": | ||||
|               $ref: ../regulator/regulator.yaml | ||||
|           additionalProperties: false | ||||
|   - if: | ||||
|       properties: | ||||
|         compatible: | ||||
|           contains: | ||||
|             const: ricoh,rn5t618 | ||||
|     then: | ||||
|       properties: | ||||
|         regulators: | ||||
|           patternProperties: | ||||
|             "^(DCDC[1-3]|LDO[1-5]|LDORTC[12])$": | ||||
|               $ref: ../regulator/regulator.yaml | ||||
|           additionalProperties: false | ||||
|   - if: | ||||
|       properties: | ||||
|         compatible: | ||||
|           contains: | ||||
|             const: ricoh,rc5t619 | ||||
|     then: | ||||
|       properties: | ||||
|         regulators: | ||||
|           patternProperties: | ||||
|             "^(DCDC[1-5]|LDO[1-9]|LDO10|LDORTC[12])$": | ||||
|               $ref: ../regulator/regulator.yaml | ||||
|           additionalProperties: false | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     enum: | ||||
|       - ricoh,rn5t567 | ||||
|       - ricoh,rn5t618 | ||||
|       - ricoh,rc5t619 | ||||
| 
 | ||||
|   reg: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   interrupts: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   system-power-controller: | ||||
|     type: boolean | ||||
|     description: | | ||||
|       See Documentation/devicetree/bindings/power/power-controller.txt | ||||
| 
 | ||||
|   regulators: | ||||
|     type: object | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     #include <dt-bindings/interrupt-controller/irq.h> | ||||
|     i2c { | ||||
|       #address-cells = <1>; | ||||
|       #size-cells = <0>; | ||||
| 
 | ||||
|       pmic@32 { | ||||
|         compatible = "ricoh,rn5t618"; | ||||
|         reg = <0x32>; | ||||
|         interrupt-parent = <&gpio5>; | ||||
|         interrupts = <11 IRQ_TYPE_EDGE_FALLING>; | ||||
|         system-power-controller; | ||||
| 
 | ||||
|         regulators { | ||||
|           DCDC1 { | ||||
|             regulator-min-microvolt = <1050000>; | ||||
|             regulator-max-microvolt = <1050000>; | ||||
|           }; | ||||
| 
 | ||||
|           DCDC2 { | ||||
|             regulator-min-microvolt = <1175000>; | ||||
|             regulator-max-microvolt = <1175000>; | ||||
|           }; | ||||
|         }; | ||||
|       }; | ||||
|     }; | ||||
| @ -1,52 +0,0 @@ | ||||
| * Ricoh RN5T567/RN5T618 PMIC | ||||
| 
 | ||||
| Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which | ||||
| integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators, | ||||
| GPIOs, and a watchdog timer. It can be controlled through an I2C interface. | ||||
| The RN5T618/RC5T619 provides additionally a Li-ion battery charger, | ||||
| fuel gauge, and an ADC. | ||||
| The RC5T619 additionnally includes USB charger detection and an RTC. | ||||
| 
 | ||||
| Required properties: | ||||
|  - compatible: must be one of | ||||
| 		"ricoh,rn5t567" | ||||
| 		"ricoh,rn5t618" | ||||
| 		"ricoh,rc5t619" | ||||
|  - reg: the I2C slave address of the device | ||||
| 
 | ||||
| Optional properties: | ||||
|  - interrupts: interrupt mapping for IRQ | ||||
|    See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | ||||
|  - system-power-controller: | ||||
|    See Documentation/devicetree/bindings/power/power-controller.txt | ||||
| 
 | ||||
| Sub-nodes: | ||||
|  - regulators: the node is required if the regulator functionality is | ||||
|    needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4 | ||||
|    (RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8, | ||||
|    LDO9, LDO10, LDORTC1 and LDORTC2. | ||||
|    LDO7-10 are specific to RC5T619. | ||||
|    The common bindings for each individual regulator can be found in: | ||||
|    Documentation/devicetree/bindings/regulator/regulator.txt | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| 	pmic@32 { | ||||
| 		compatible = "ricoh,rn5t618"; | ||||
| 		reg = <0x32>; | ||||
| 		interrupt-parent = <&gpio5>; | ||||
| 		interrupts = <11 IRQ_TYPE_EDGE_FALLING>; | ||||
| 		system-power-controller; | ||||
| 
 | ||||
| 		regulators { | ||||
| 			DCDC1 { | ||||
| 				regulator-min-microvolt = <1050000>; | ||||
| 				regulator-max-microvolt = <1050000>; | ||||
| 			}; | ||||
| 
 | ||||
| 			DCDC2 { | ||||
| 				regulator-min-microvolt = <1175000>; | ||||
| 				regulator-max-microvolt = <1175000>; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
							
								
								
									
										201
									
								
								Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/rohm,bd71815-pmic.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: ROHM BD71815 Power Management Integrated Circuit bindings | ||||
| 
 | ||||
| maintainers: | ||||
|   - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | ||||
| 
 | ||||
| description: | | ||||
|   BD71815AGW is a single-chip power management ICs for battery-powered | ||||
|   portable devices. It integrates 5 buck converters, 8 LDOs, a boost driver | ||||
|   for LED and a 500 mA single-cell linear charger. Also included is a Coulomb | ||||
|   counter, a real-time clock (RTC), and a 32.768 kHz clock gate and two GPOs. | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     const: rohm,bd71815 | ||||
| 
 | ||||
|   reg: | ||||
|     description: | ||||
|       I2C slave address. | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   interrupts: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   gpio-controller: true | ||||
| 
 | ||||
|   "#gpio-cells": | ||||
|     const: 2 | ||||
|     description: | | ||||
|       The first cell is the pin number and the second cell is used to specify | ||||
|       flags. See ../gpio/gpio.txt for more information. | ||||
| 
 | ||||
|   clocks: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   "#clock-cells": | ||||
|     const: 0 | ||||
| 
 | ||||
|   clock-output-names: | ||||
|     const: bd71815-32k-out | ||||
| 
 | ||||
|   rohm,clkout-open-drain: | ||||
|     description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". | ||||
|     $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|     minimum: 0 | ||||
|     maximum: 1 | ||||
| 
 | ||||
|   rohm,charger-sense-resistor-ohms: | ||||
|     minimum: 10000000 | ||||
|     maximum: 50000000 | ||||
|     description: | | ||||
|       BD71827 and BD71828 have SAR ADC for measuring charging currents. | ||||
|       External sense resistor (RSENSE in data sheet) should be used. If | ||||
|       something other but 30MOhm resistor is used the resistance value | ||||
|       should be given here in Ohms. | ||||
|     default: 30000000 | ||||
| 
 | ||||
|   regulators: | ||||
|     $ref: ../regulator/rohm,bd71815-regulator.yaml | ||||
|     description: | ||||
|       List of child nodes that specify the regulators. | ||||
| 
 | ||||
|   gpio-reserved-ranges: | ||||
|     description: | | ||||
|       Usage of BD71828 GPIO pins can be changed via OTP. This property can be | ||||
|       used to mark the pins which should not be configured for GPIO. Please see | ||||
|       the ../gpio/gpio.txt for more information. | ||||
| 
 | ||||
|   rohm,enable-hidden-gpo: | ||||
|     description: | | ||||
|       The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the | ||||
|       data-sheet as it's location in the middle of GND pins makes it hard to | ||||
|       use on PCB. If your board has managed to use this pin you can enable the | ||||
|       second GPO by defining this property. Dont enable this if you are unsure | ||||
|       about how the E5 pin is connected on your board. | ||||
|     type: boolean | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
|   - interrupts | ||||
|   - clocks | ||||
|   - "#clock-cells" | ||||
|   - regulators | ||||
|   - gpio-controller | ||||
|   - "#gpio-cells" | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     #include <dt-bindings/interrupt-controller/irq.h> | ||||
|     #include <dt-bindings/leds/common.h> | ||||
|     i2c { | ||||
|         #address-cells = <1>; | ||||
|         #size-cells = <0>; | ||||
|         pmic: pmic@4b { | ||||
|             compatible = "rohm,bd71815"; | ||||
|             reg = <0x4b>; | ||||
| 
 | ||||
|             interrupt-parent = <&gpio1>; | ||||
|             interrupts = <29 IRQ_TYPE_LEVEL_LOW>; | ||||
| 
 | ||||
|             clocks = <&osc 0>; | ||||
|             #clock-cells = <0>; | ||||
|             clock-output-names = "bd71815-32k-out"; | ||||
| 
 | ||||
|             gpio-controller; | ||||
|             #gpio-cells = <2>; | ||||
| 
 | ||||
|             rohm,charger-sense-resistor-ohms = <10000000>; | ||||
| 
 | ||||
|             regulators { | ||||
|                 buck1: buck1 { | ||||
|                     regulator-name = "buck1"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <2000000>; | ||||
|                     regulator-always-on; | ||||
|                     regulator-ramp-delay = <1250>; | ||||
|                     rohm,dvs-run-voltage = <1150000>; | ||||
|                     rohm,dvs-suspend-voltage = <950000>; | ||||
|                 }; | ||||
|                 buck2: buck2 { | ||||
|                     regulator-name = "buck2"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <2000000>; | ||||
|                     regulator-always-on; | ||||
|                     regulator-ramp-delay = <1250>; | ||||
|                     rohm,dvs-run-voltage = <1150000>; | ||||
|                     rohm,dvs-suspend-voltage = <950000>; | ||||
|                 }; | ||||
|                 buck3: buck3 { | ||||
|                     regulator-name = "buck3"; | ||||
|                     regulator-min-microvolt = <1200000>; | ||||
|                     regulator-max-microvolt = <2700000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 buck4: buck4 { | ||||
|                     regulator-name = "buck4"; | ||||
|                     regulator-min-microvolt = <1100000>; | ||||
|                     regulator-max-microvolt = <1850000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 buck5: buck5 { | ||||
|                     regulator-name = "buck5"; | ||||
|                     regulator-min-microvolt = <1800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo1: ldo1 { | ||||
|                     regulator-name = "ldo1"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo2: ldo2 { | ||||
|                     regulator-name = "ldo2"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo3: ldo3 { | ||||
|                     regulator-name = "ldo3"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo4: ldo4 { | ||||
|                     regulator-name = "ldo4"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo5: ldo5 { | ||||
|                     regulator-name = "ldo5"; | ||||
|                     regulator-min-microvolt = <800000>; | ||||
|                     regulator-max-microvolt = <3300000>; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo6: ldodvref { | ||||
|                     regulator-name = "ldodvref"; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
|                 ldo7: ldolpsr { | ||||
|                     regulator-name = "ldolpsr"; | ||||
|                     regulator-always-on; | ||||
|                 }; | ||||
| 
 | ||||
|                 boost: wled { | ||||
|                     regulator-name = "wled"; | ||||
|                     regulator-min-microamp = <10>; | ||||
|                     regulator-max-microamp = <25000>; | ||||
|                 }; | ||||
|             }; | ||||
|         }; | ||||
|     }; | ||||
| @ -44,6 +44,12 @@ properties: | ||||
|   clock-output-names: | ||||
|     const: bd71828-32k-out | ||||
| 
 | ||||
|   rohm,clkout-open-drain: | ||||
|     description: clk32kout mode. Set to 1 for "open-drain" or 0 for "cmos". | ||||
|     $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|     minimum: 0 | ||||
|     maximum: 1 | ||||
| 
 | ||||
|   rohm,charger-sense-resistor-ohms: | ||||
|     minimum: 10000000 | ||||
|     maximum: 50000000 | ||||
|  | ||||
							
								
								
									
										123
									
								
								Documentation/devicetree/bindings/mfd/rohm,bd9576-pmic.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								Documentation/devicetree/bindings/mfd/rohm,bd9576-pmic.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,123 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/mfd/rohm,bd9576-pmic.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: ROHM BD9576MUF and BD9573MUF Power Management Integrated Circuit bindings | ||||
| 
 | ||||
| maintainers: | ||||
|   - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | ||||
| 
 | ||||
| description: | | ||||
|   BD9576MUF and BD9573MUF are power management ICs primarily intended for | ||||
|   powering the R-Car series processors. | ||||
|   The IC provides 6 power outputs with configurable sequencing and safety | ||||
|   monitoring. A watchdog logic with slow ping/windowed modes is also included. | ||||
| 
 | ||||
| properties: | ||||
|   compatible: | ||||
|     enum: | ||||
|       - rohm,bd9576 | ||||
|       - rohm,bd9573 | ||||
| 
 | ||||
|   reg: | ||||
|     description: | ||||
|       I2C slave address. | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   interrupts: | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   rohm,vout1-en-low: | ||||
|     description: | ||||
|       BD9576 and BD9573 VOUT1 regulator enable state can be individually | ||||
|       controlled by a GPIO. This is dictated by state of vout1-en pin during | ||||
|       the PMIC startup. If vout1-en is LOW during PMIC startup then the VOUT1 | ||||
|       enable sate is controlled via this pin. Set this property if vout1-en | ||||
|       is wired to be down at PMIC start-up. | ||||
|     type: boolean | ||||
| 
 | ||||
|   rohm,vout1-en-gpios: | ||||
|     description: | ||||
|       GPIO specifier to specify the GPIO connected to vout1-en for vout1 ON/OFF | ||||
|       state control. | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   rohm,ddr-sel-low: | ||||
|     description: | ||||
|       The BD9576 and BD9573 output voltage for DDR can be selected by setting | ||||
|       the ddr-sel pin low or high. Set this property if ddr-sel is grounded. | ||||
|     type: boolean | ||||
| 
 | ||||
|   rohm,watchdog-enable-gpios: | ||||
|     description: The GPIO line used to enable the watchdog. | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   rohm,watchdog-ping-gpios: | ||||
|     description: The GPIO line used to ping the watchdog. | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   rohm,hw-timeout-ms: | ||||
|     maxItems: 2 | ||||
|     description: | ||||
|       Watchog timeout in milliseconds. If single value is given it is | ||||
|       the maximum timeout. Eg. if pinging watchdog is not done within this time | ||||
|       limit the watchdog will be triggered. If two values are given watchdog | ||||
|       is configured in "window mode". Then first value is limit for short-ping | ||||
|       Eg. if watchdog is pinged sooner than that the watchdog will trigger. | ||||
|       When two values is given the second value is the maximum timeout. | ||||
|       # (HW) minimum for short timeout is 2ms, maximum 220 ms. | ||||
|       # (HW) minimum for max timeout is 4ms, maximum 4416 ms. | ||||
| 
 | ||||
|   regulators: | ||||
|     $ref: ../regulator/rohm,bd9576-regulator.yaml | ||||
|     description: | ||||
|       List of child nodes that specify the regulators. | ||||
| 
 | ||||
| required: | ||||
|   - compatible | ||||
|   - reg | ||||
|   - regulators | ||||
| 
 | ||||
| additionalProperties: false | ||||
| 
 | ||||
| examples: | ||||
|   - | | ||||
|     #include <dt-bindings/gpio/gpio.h> | ||||
|     #include <dt-bindings/leds/common.h> | ||||
|     i2c { | ||||
|         #address-cells = <1>; | ||||
|         #size-cells = <0>; | ||||
|         pmic: pmic@30 { | ||||
|             compatible = "rohm,bd9576"; | ||||
|             reg = <0x30>; | ||||
|             rohm,vout1-en-low; | ||||
|             rohm,vout1-en-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; | ||||
|             rohm,ddr-sel-low; | ||||
|             rohm,watchdog-enable-gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; | ||||
|             rohm,watchdog-ping-gpios = <&gpio2 7 GPIO_ACTIVE_HIGH>; | ||||
|             rohm,hw-timeout-ms = <150>, <2300>; | ||||
| 
 | ||||
|             regulators { | ||||
|                 boost1: regulator-vd50 { | ||||
|                     regulator-name = "VD50"; | ||||
|                 }; | ||||
|                 buck1: regulator-vd18 { | ||||
|                     regulator-name = "VD18"; | ||||
|                 }; | ||||
|                 buck2: regulator-vdddr { | ||||
|                     regulator-name = "VDDDR"; | ||||
|                 }; | ||||
|                 buck3: regulator-vd10 { | ||||
|                     regulator-name = "VD10"; | ||||
|                 }; | ||||
|                 ldo: regulator-voutl1 { | ||||
|                     regulator-name = "VOUTL1"; | ||||
|                 }; | ||||
|                 sw: regulator-vouts1 { | ||||
|                     regulator-name = "VOUTS1"; | ||||
|                 }; | ||||
|             }; | ||||
|         }; | ||||
|     }; | ||||
| @ -17,6 +17,10 @@ properties: | ||||
|     description: I2C slave address | ||||
|     const: 0x60 | ||||
| 
 | ||||
|   reset-gpios: | ||||
|     description: GPIO connected to NRST pin (active low reset, pin 20) | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   gpio-controller: true | ||||
| 
 | ||||
|   '#gpio-cells': | ||||
|  | ||||
| @ -17,6 +17,10 @@ properties: | ||||
|     description: I2C slave address | ||||
|     const: 0x60 | ||||
| 
 | ||||
|   reset-gpios: | ||||
|     description: GPIO connected to NRST pin (active low reset, pin 20) | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   gpio-controller: true | ||||
| 
 | ||||
|   '#gpio-cells': | ||||
|  | ||||
| @ -19,6 +19,10 @@ properties: | ||||
|     description: I2C slave address | ||||
|     const: 0x60 | ||||
| 
 | ||||
|   reset-gpios: | ||||
|     description: GPIO connected to NRST pin (active low reset, pin 20) | ||||
|     maxItems: 1 | ||||
| 
 | ||||
|   gpio-controller: true | ||||
| 
 | ||||
|   '#gpio-cells': | ||||
|  | ||||
| @ -0,0 +1,116 @@ | ||||
| # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | ||||
| %YAML 1.2 | ||||
| --- | ||||
| $id: http://devicetree.org/schemas/regulator/rohm,bd71815-regulator.yaml# | ||||
| $schema: http://devicetree.org/meta-schemas/core.yaml# | ||||
| 
 | ||||
| title: ROHM BD71815 Power Management Integrated Circuit regulators | ||||
| 
 | ||||
| maintainers: | ||||
|   - Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | ||||
| 
 | ||||
| description: | | ||||
|   This module is part of the ROHM BD718215 MFD device. For more details | ||||
|   see Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml. | ||||
| 
 | ||||
|   The regulator controller is represented as a sub-node of the PMIC node | ||||
|   on the device tree. | ||||
| 
 | ||||
|   The valid names for BD71815 regulator nodes are | ||||
|   buck1, buck2, buck3, buck4, buck5, | ||||
|   ldo1, ldo2, ldo3, ldo4, ldo5, | ||||
|   ldodvref, ldolpsr, wled | ||||
| 
 | ||||
| properties: | ||||
|   wled: | ||||
|     type: object | ||||
|     description: | ||||
|       properties for wled regulator | ||||
|     $ref: regulator.yaml# | ||||
| 
 | ||||
|     properties: | ||||
|       regulator-name: | ||||
|         const: wled | ||||
| 
 | ||||
| patternProperties: | ||||
|   "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$": | ||||
|     type: object | ||||
|     description: | ||||
|       Properties for single LDO/BUCK regulator. | ||||
|     $ref: regulator.yaml# | ||||
| 
 | ||||
|     properties: | ||||
|       regulator-name: | ||||
|         pattern: "^((ldo|buck)[1-5]|ldolpsr|ldodvref)$" | ||||
|         description: | ||||
|           should be "ldo1", ..., "ldo5", "buck1", ..., "buck5" and "ldolpsr" | ||||
|           for ldolpsr regulator, "ldodvref" for ldodvref reglator. | ||||
| 
 | ||||
|       rohm,vsel-gpios: | ||||
|         description: | ||||
|           GPIO used to control ldo4 state (when ldo4 is controlled by GPIO). | ||||
| 
 | ||||
|       rohm,dvs-run-voltage: | ||||
|         description: | ||||
|           PMIC "RUN" state voltage in uV when PMIC HW states are used. See | ||||
|           comments below for bucks/LDOs which support this. 0 means | ||||
|           regulator should be disabled at RUN state. | ||||
|         $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|         minimum: 0 | ||||
|         maximum: 3300000 | ||||
| 
 | ||||
|       rohm,dvs-snvs-voltage: | ||||
|         description: | ||||
|           Whether to keep regulator enabled at "SNVS" state or not. | ||||
|           0 means regulator should be disabled at SNVS state, non zero voltage | ||||
|           keeps regulator enabled. BD71815 does not change voltage level | ||||
|           when PMIC transitions to SNVS.SNVS voltage depends on the previous | ||||
|           state (from which the PMIC transitioned to SNVS). | ||||
|         $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|         minimum: 0 | ||||
|         maximum: 3300000 | ||||
| 
 | ||||
|       rohm,dvs-suspend-voltage: | ||||
|         description: | ||||
|           PMIC "SUSPEND" state voltage in uV when PMIC HW states are used. See | ||||
|           comments below for bucks/LDOs which support this. 0 means | ||||
|           regulator should be disabled at SUSPEND state. | ||||
|         $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|         minimum: 0 | ||||
|         maximum: 3300000 | ||||
| 
 | ||||
|       rohm,dvs-lpsr-voltage: | ||||
|         description: | ||||
|           PMIC "LPSR" state voltage in uV when PMIC HW states are used. See | ||||
|           comments below for bucks/LDOs which support this. 0 means | ||||
|           regulator should be disabled at LPSR state. | ||||
|         $ref: "/schemas/types.yaml#/definitions/uint32" | ||||
|         minimum: 0 | ||||
|         maximum: 3300000 | ||||
| 
 | ||||
|         # Bucks 1 and 2 support giving separate voltages for operational states | ||||
|         # (RUN /CLEAN according to data-sheet) and non operational states | ||||
|         # (LPSR/SUSPEND). The voltage is automatically changed when HW | ||||
|         # state changes. Omitting these properties from bucks 1 and 2 leave | ||||
|         # buck voltages to not be toggled by HW state. Enable status may still | ||||
|         # be toggled by state changes depending on HW default settings. | ||||
|         # | ||||
|         # Bucks 3-5 and ldos 1-5 support setting the RUN state voltage here. | ||||
|         # Given RUN voltage is used at all states if regulator is enabled at | ||||
|         # given state. | ||||
|         # Values given for other states are regarded as enable/disable at | ||||
|         # given state (see below). | ||||
|         # | ||||
|         # All regulators except WLED support specifying enable/disable status | ||||
|         # for each of the HW states (RUN/SNVS/SUSPEND/LPSR). HW defaults can | ||||
|         # be overridden by setting voltage to 0 (regulator disabled at given | ||||
|         # state) or non-zero (regulator enabled at given state). Please note | ||||
|         # that setting non zero voltages for bucks 1/2 will also enable voltage | ||||
|         # changes according to state change. | ||||
| 
 | ||||
|     required: | ||||
|       - regulator-name | ||||
| 
 | ||||
|     unevaluatedProperties: false | ||||
| 
 | ||||
| additionalProperties: false | ||||
| @ -772,6 +772,8 @@ patternProperties: | ||||
|     description: Broadcom Corporation (formerly NetLogic Microsystems) | ||||
|   "^netron-dy,.*": | ||||
|     description: Netron DY | ||||
|   "^netronix,.*": | ||||
|     description: Netronix, Inc. | ||||
|   "^netxeon,.*": | ||||
|     description: Shenzhen Netxeon Technology CO., LTD | ||||
|   "^neweast,.*": | ||||
|  | ||||
							
								
								
									
										74
									
								
								MAINTAINERS
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								MAINTAINERS
									
									
									
									
									
								
							| @ -2894,6 +2894,18 @@ W:	http://www.openaoe.org/ | ||||
| F:	Documentation/admin-guide/aoe/ | ||||
| F:	drivers/block/aoe/ | ||||
| 
 | ||||
| ATC260X PMIC MFD DRIVER | ||||
| M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
| M:	Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
| L:	linux-actions@lists.infradead.org | ||||
| S:	Maintained | ||||
| F:	Documentation/devicetree/bindings/mfd/actions,atc260x.yaml | ||||
| F:	drivers/input/misc/atc260x-onkey.c | ||||
| F:	drivers/mfd/atc260* | ||||
| F:	drivers/power/reset/atc260x-poweroff.c | ||||
| F:	drivers/regulator/atc260x-regulator.c | ||||
| F:	include/linux/mfd/atc260x/* | ||||
| 
 | ||||
| ATHEROS 71XX/9XXX GPIO DRIVER | ||||
| M:	Alban Bedel <albeu@free.fr> | ||||
| S:	Maintained | ||||
| @ -9221,6 +9233,26 @@ F:	include/linux/mei_cl_bus.h | ||||
| F:	include/uapi/linux/mei.h | ||||
| F:	samples/mei/* | ||||
| 
 | ||||
| INTEL MAX 10 BMC MFD DRIVER | ||||
| M:	Xu Yilun <yilun.xu@intel.com> | ||||
| R:	Tom Rix <trix@redhat.com> | ||||
| S:	Maintained | ||||
| F:	Documentation/ABI/testing/sysfs-driver-intel-m10-bmc | ||||
| F:	Documentation/hwmon/intel-m10-bmc-hwmon.rst | ||||
| F:	drivers/hwmon/intel-m10-bmc-hwmon.c | ||||
| F:	drivers/mfd/intel-m10-bmc.c | ||||
| F:	include/linux/mfd/intel-m10-bmc.h | ||||
| 
 | ||||
| INTEL MAX 10 BMC MFD DRIVER | ||||
| M:	Xu Yilun <yilun.xu@intel.com> | ||||
| R:	Tom Rix <trix@redhat.com> | ||||
| S:	Maintained | ||||
| F:	Documentation/ABI/testing/sysfs-driver-intel-m10-bmc | ||||
| F:	Documentation/hwmon/intel-m10-bmc-hwmon.rst | ||||
| F:	drivers/hwmon/intel-m10-bmc-hwmon.c | ||||
| F:	drivers/mfd/intel-m10-bmc.c | ||||
| F:	include/linux/mfd/intel-m10-bmc.h | ||||
| 
 | ||||
| INTEL MENLOW THERMAL DRIVER | ||||
| M:	Sujith Thomas <sujith.thomas@intel.com> | ||||
| L:	platform-driver-x86@vger.kernel.org | ||||
| @ -12543,6 +12575,15 @@ F:	include/net/netrom.h | ||||
| F:	include/uapi/linux/netrom.h | ||||
| F:	net/netrom/ | ||||
| 
 | ||||
| NETRONIX EMBEDDED CONTROLLER | ||||
| M:	Jonathan Neuschäfer <j.neuschaefer@gmx.net> | ||||
| S:	Maintained | ||||
| F:	Documentation/devicetree/bindings/mfd/netronix,ntxec.yaml | ||||
| F:	drivers/mfd/ntxec.c | ||||
| F:	drivers/pwm/pwm-ntxec.c | ||||
| F:	drivers/rtc/rtc-ntxec.c | ||||
| F:	include/linux/mfd/ntxec.h | ||||
| 
 | ||||
| NETRONOME ETHERNET DRIVERS | ||||
| M:	Simon Horman <simon.horman@netronome.com> | ||||
| R:	Jakub Kicinski <kuba@kernel.org> | ||||
| @ -15634,20 +15675,27 @@ F:	Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt | ||||
| F:	Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt | ||||
| F:	drivers/clk/clk-bd718x7.c | ||||
| F:	drivers/gpio/gpio-bd70528.c | ||||
| F:	drivers/gpio/gpio-bd71815.c | ||||
| F:	drivers/gpio/gpio-bd71828.c | ||||
| F:	drivers/mfd/rohm-bd70528.c | ||||
| F:	drivers/mfd/rohm-bd71828.c | ||||
| F:	drivers/mfd/rohm-bd718x7.c | ||||
| F:	drivers/mfd/rohm-bd9576.c | ||||
| F:	drivers/power/supply/bd70528-charger.c | ||||
| F:	drivers/regulator/bd70528-regulator.c | ||||
| F:	drivers/regulator/bd71815-regulator.c | ||||
| F:	drivers/regulator/bd71828-regulator.c | ||||
| F:	drivers/regulator/bd718x7-regulator.c | ||||
| F:	drivers/regulator/bd9576-regulator.c | ||||
| F:	drivers/regulator/rohm-regulator.c | ||||
| F:	drivers/rtc/rtc-bd70528.c | ||||
| F:	drivers/watchdog/bd70528_wdt.c | ||||
| F:	drivers/watchdog/bd9576_wdt.c | ||||
| F:	include/linux/mfd/rohm-bd70528.h | ||||
| F:	include/linux/mfd/rohm-bd71815.h | ||||
| F:	include/linux/mfd/rohm-bd71828.h | ||||
| F:	include/linux/mfd/rohm-bd718x7.h | ||||
| F:	include/linux/mfd/rohm-bd957x.h | ||||
| F:	include/linux/mfd/rohm-generic.h | ||||
| F:	include/linux/mfd/rohm-shared.h | ||||
| 
 | ||||
| @ -18147,29 +18195,6 @@ S:	Maintained | ||||
| F:	sound/soc/codecs/isabelle* | ||||
| F:	sound/soc/codecs/lm49453* | ||||
| 
 | ||||
| TI LP855x BACKLIGHT DRIVER | ||||
| M:	Milo Kim <milo.kim@ti.com> | ||||
| S:	Maintained | ||||
| F:	Documentation/driver-api/backlight/lp855x-driver.rst | ||||
| F:	drivers/video/backlight/lp855x_bl.c | ||||
| F:	include/linux/platform_data/lp855x.h | ||||
| 
 | ||||
| TI LP8727 CHARGER DRIVER | ||||
| M:	Milo Kim <milo.kim@ti.com> | ||||
| S:	Maintained | ||||
| F:	drivers/power/supply/lp8727_charger.c | ||||
| F:	include/linux/platform_data/lp8727.h | ||||
| 
 | ||||
| TI LP8788 MFD DRIVER | ||||
| M:	Milo Kim <milo.kim@ti.com> | ||||
| S:	Maintained | ||||
| F:	drivers/iio/adc/lp8788_adc.c | ||||
| F:	drivers/leds/leds-lp8788.c | ||||
| F:	drivers/mfd/lp8788*.c | ||||
| F:	drivers/power/supply/lp8788-charger.c | ||||
| F:	drivers/regulator/lp8788-*.c | ||||
| F:	include/linux/mfd/lp8788*.h | ||||
| 
 | ||||
| TI NETCP ETHERNET DRIVER | ||||
| M:	Wingman Kwok <w-kwok2@ti.com> | ||||
| M:	Murali Karicheri <m-karicheri2@ti.com> | ||||
| @ -19587,7 +19612,6 @@ F:	Documentation/devicetree/bindings/sound/wlf,arizona.yaml | ||||
| F:	Documentation/hwmon/wm83??.rst | ||||
| F:	arch/arm/mach-s3c/mach-crag6410* | ||||
| F:	drivers/clk/clk-wm83*.c | ||||
| F:	drivers/extcon/extcon-arizona.c | ||||
| F:	drivers/gpio/gpio-*wm*.c | ||||
| F:	drivers/gpio/gpio-arizona.c | ||||
| F:	drivers/hwmon/wm83??-hwmon.c | ||||
| @ -19611,7 +19635,7 @@ F:	include/linux/mfd/wm8400* | ||||
| F:	include/linux/regulator/arizona* | ||||
| F:	include/linux/wm97xx.h | ||||
| F:	include/sound/wm????.h | ||||
| F:	sound/soc/codecs/arizona.? | ||||
| F:	sound/soc/codecs/arizona* | ||||
| F:	sound/soc/codecs/cs47l24* | ||||
| F:	sound/soc/codecs/wm* | ||||
| 
 | ||||
|  | ||||
| @ -13,6 +13,8 @@ | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| /* clk control registers */ | ||||
| /* BD71815 */ | ||||
| #define BD71815_REG_OUT32K	0x1d | ||||
| /* BD70528 */ | ||||
| #define BD70528_REG_OUT32K	0x2c | ||||
| /* BD71828 */ | ||||
| @ -118,6 +120,10 @@ static int bd71837_clk_probe(struct platform_device *pdev) | ||||
| 		c->reg = BD70528_REG_OUT32K; | ||||
| 		c->mask = CLK_OUT_EN_MASK; | ||||
| 		break; | ||||
| 	case ROHM_CHIP_TYPE_BD71815: | ||||
| 		c->reg = BD71815_REG_OUT32K; | ||||
| 		c->mask = CLK_OUT_EN_MASK; | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(&pdev->dev, "Unknown clk chip\n"); | ||||
| 		return -EINVAL; | ||||
| @ -146,6 +152,7 @@ static const struct platform_device_id bd718x7_clk_id[] = { | ||||
| 	{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 }, | ||||
| 	{ "bd70528-clk", ROHM_CHIP_TYPE_BD70528 }, | ||||
| 	{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 }, | ||||
| 	{ "bd71815-clk", ROHM_CHIP_TYPE_BD71815 }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(platform, bd718x7_clk_id); | ||||
| @ -161,6 +168,6 @@ static struct platform_driver bd71837_clk = { | ||||
| module_platform_driver(bd71837_clk); | ||||
| 
 | ||||
| MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | ||||
| MODULE_DESCRIPTION("BD71837/BD71847/BD70528 chip clk driver"); | ||||
| MODULE_DESCRIPTION("BD718(15/18/28/37/47/50) and BD70528 chip clk driver"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_ALIAS("platform:bd718xx-clk"); | ||||
|  | ||||
| @ -21,14 +21,6 @@ config EXTCON_ADC_JACK | ||||
| 	help | ||||
| 	  Say Y here to enable extcon device driver based on ADC values. | ||||
| 
 | ||||
| config EXTCON_ARIZONA | ||||
| 	tristate "Wolfson Arizona EXTCON support" | ||||
| 	depends on MFD_ARIZONA && INPUT && SND_SOC | ||||
| 	help | ||||
| 	  Say Y here to enable support for external accessory detection | ||||
| 	  with Wolfson Arizona devices. These are audio CODECs with | ||||
| 	  advanced audio accessory detection support. | ||||
| 
 | ||||
| config EXTCON_AXP288 | ||||
| 	tristate "X-Power AXP288 EXTCON support" | ||||
| 	depends on MFD_AXP20X && USB_SUPPORT && X86 && ACPI | ||||
|  | ||||
| @ -6,7 +6,6 @@ | ||||
| obj-$(CONFIG_EXTCON)		+= extcon-core.o | ||||
| extcon-core-objs		+= extcon.o devres.o | ||||
| obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o | ||||
| obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o | ||||
| obj-$(CONFIG_EXTCON_AXP288)	+= extcon-axp288.o | ||||
| obj-$(CONFIG_EXTCON_FSA9480)	+= extcon-fsa9480.o | ||||
| obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o | ||||
|  | ||||
| @ -1105,6 +1105,16 @@ config GPIO_BD70528 | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called gpio-bd70528. | ||||
| 
 | ||||
| config GPIO_BD71815 | ||||
| 	tristate "ROHM BD71815 PMIC GPIO support" | ||||
| 	depends on MFD_ROHM_BD71828 | ||||
| 	help | ||||
| 	  Support for GPO(s) on ROHM BD71815 PMIC. There are two GPOs | ||||
| 	  available on the ROHM PMIC. | ||||
| 
 | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called gpio-bd71815. | ||||
| 
 | ||||
| config GPIO_BD71828 | ||||
| 	tristate "ROHM BD71828 GPIO support" | ||||
| 	depends on MFD_ROHM_BD71828 | ||||
|  | ||||
| @ -39,6 +39,7 @@ obj-$(CONFIG_GPIO_ATH79)		+= gpio-ath79.o | ||||
| obj-$(CONFIG_GPIO_BCM_KONA)		+= gpio-bcm-kona.o | ||||
| obj-$(CONFIG_GPIO_BCM_XGS_IPROC)	+= gpio-xgs-iproc.o | ||||
| obj-$(CONFIG_GPIO_BD70528)		+= gpio-bd70528.o | ||||
| obj-$(CONFIG_GPIO_BD71815)		+= gpio-bd71815.o | ||||
| obj-$(CONFIG_GPIO_BD71828)		+= gpio-bd71828.o | ||||
| obj-$(CONFIG_GPIO_BD9571MWV)		+= gpio-bd9571mwv.o | ||||
| obj-$(CONFIG_GPIO_BRCMSTB)		+= gpio-brcmstb.o | ||||
|  | ||||
							
								
								
									
										185
									
								
								drivers/gpio/gpio-bd71815.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								drivers/gpio/gpio-bd71815.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,185 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0
 | ||||
| /*
 | ||||
|  * Support to GPOs on ROHM BD71815 | ||||
|  * Copyright 2021 ROHM Semiconductors. | ||||
|  * Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | ||||
|  * | ||||
|  * Copyright 2014 Embest Technology Co. Ltd. Inc. | ||||
|  * Author: yanglsh@embest-tech.com | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/gpio/driver.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/platform_device.h> | ||||
| /* For the BD71815 register definitions */ | ||||
| #include <linux/mfd/rohm-bd71815.h> | ||||
| 
 | ||||
| struct bd71815_gpio { | ||||
| 	/* chip.parent points the MFD which provides DT node and regmap */ | ||||
| 	struct gpio_chip chip; | ||||
| 	/* dev points to the platform device for devm and prints */ | ||||
| 	struct device *dev; | ||||
| 	struct regmap *regmap; | ||||
| }; | ||||
| 
 | ||||
| static int bd71815gpo_get(struct gpio_chip *chip, unsigned int offset) | ||||
| { | ||||
| 	struct bd71815_gpio *bd71815 = gpiochip_get_data(chip); | ||||
| 	int ret, val; | ||||
| 
 | ||||
| 	ret = regmap_read(bd71815->regmap, BD71815_REG_GPO, &val); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return (val >> offset) & 1; | ||||
| } | ||||
| 
 | ||||
| static void bd71815gpo_set(struct gpio_chip *chip, unsigned int offset, | ||||
| 			   int value) | ||||
| { | ||||
| 	struct bd71815_gpio *bd71815 = gpiochip_get_data(chip); | ||||
| 	int ret, bit; | ||||
| 
 | ||||
| 	bit = BIT(offset); | ||||
| 
 | ||||
| 	if (value) | ||||
| 		ret = regmap_set_bits(bd71815->regmap, BD71815_REG_GPO, bit); | ||||
| 	else | ||||
| 		ret = regmap_clear_bits(bd71815->regmap, BD71815_REG_GPO, bit); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		dev_warn(bd71815->dev, "failed to toggle GPO\n"); | ||||
| } | ||||
| 
 | ||||
| static int bd71815_gpio_set_config(struct gpio_chip *chip, unsigned int offset, | ||||
| 				   unsigned long config) | ||||
| { | ||||
| 	struct bd71815_gpio *bdgpio = gpiochip_get_data(chip); | ||||
| 
 | ||||
| 	switch (pinconf_to_config_param(config)) { | ||||
| 	case PIN_CONFIG_DRIVE_OPEN_DRAIN: | ||||
| 		return regmap_update_bits(bdgpio->regmap, | ||||
| 					  BD71815_REG_GPO, | ||||
| 					  BD71815_GPIO_DRIVE_MASK << offset, | ||||
| 					  BD71815_GPIO_OPEN_DRAIN << offset); | ||||
| 	case PIN_CONFIG_DRIVE_PUSH_PULL: | ||||
| 		return regmap_update_bits(bdgpio->regmap, | ||||
| 					  BD71815_REG_GPO, | ||||
| 					  BD71815_GPIO_DRIVE_MASK << offset, | ||||
| 					  BD71815_GPIO_CMOS << offset); | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 	return -ENOTSUPP; | ||||
| } | ||||
| 
 | ||||
| /* BD71815 GPIO is actually GPO */ | ||||
| static int bd71815gpo_direction_get(struct gpio_chip *gc, unsigned int offset) | ||||
| { | ||||
| 	return GPIO_LINE_DIRECTION_OUT; | ||||
| } | ||||
| 
 | ||||
| /* Template for GPIO chip */ | ||||
| static const struct gpio_chip bd71815gpo_chip = { | ||||
| 	.label			= "bd71815", | ||||
| 	.owner			= THIS_MODULE, | ||||
| 	.get			= bd71815gpo_get, | ||||
| 	.get_direction		= bd71815gpo_direction_get, | ||||
| 	.set			= bd71815gpo_set, | ||||
| 	.set_config		= bd71815_gpio_set_config, | ||||
| 	.can_sleep		= true, | ||||
| }; | ||||
| 
 | ||||
| #define BD71815_TWO_GPIOS	GENMASK(1, 0) | ||||
| #define BD71815_ONE_GPIO	BIT(0) | ||||
| 
 | ||||
| /*
 | ||||
|  * Sigh. The BD71815 and BD71817 were originally designed to support two GPO | ||||
|  * pins. At some point it was noticed the second GPO pin which is the E5 pin | ||||
|  * located at the center of IC is hard to use on PCB (due to the location). It | ||||
|  * was decided to not promote this second GPO and the pin is marked as GND in | ||||
|  * the datasheet. The functionality is still there though! I guess driving a GPO | ||||
|  * connected to the ground is a bad idea. Thus we do not support it by default. | ||||
|  * OTOH - the original driver written by colleagues at Embest did support | ||||
|  * controlling this second GPO. It is thus possible this is used in some of the | ||||
|  * products. | ||||
|  * | ||||
|  * This driver does not by default support configuring this second GPO | ||||
|  * but allows using it by providing the DT property | ||||
|  * "rohm,enable-hidden-gpo". | ||||
|  */ | ||||
| static int bd71815_init_valid_mask(struct gpio_chip *gc, | ||||
| 				   unsigned long *valid_mask, | ||||
| 				   unsigned int ngpios) | ||||
| { | ||||
| 	if (ngpios != 2) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (gc->parent && device_property_present(gc->parent, | ||||
| 						  "rohm,enable-hidden-gpo")) | ||||
| 		*valid_mask = BD71815_TWO_GPIOS; | ||||
| 	else | ||||
| 		*valid_mask = BD71815_ONE_GPIO; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int gpo_bd71815_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct bd71815_gpio *g; | ||||
| 	struct device *parent, *dev; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Bind devm lifetime to this platform device => use dev for devm. | ||||
| 	 * also the prints should originate from this device. | ||||
| 	 */ | ||||
| 	dev = &pdev->dev; | ||||
| 	/* The device-tree and regmap come from MFD => use parent for that */ | ||||
| 	parent = dev->parent; | ||||
| 
 | ||||
| 	g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); | ||||
| 	if (!g) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	g->chip = bd71815gpo_chip; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * FIXME: As writing of this the sysfs interface for GPIO control does | ||||
| 	 * not respect the valid_mask. Do not trust it but rather set the ngpios | ||||
| 	 * to 1 if "rohm,enable-hidden-gpo" is not given. | ||||
| 	 * | ||||
| 	 * This check can be removed later if the sysfs export is fixed and | ||||
| 	 * if the fix is backported. | ||||
| 	 * | ||||
| 	 * For now it is safest to just set the ngpios though. | ||||
| 	 */ | ||||
| 	if (device_property_present(parent, "rohm,enable-hidden-gpo")) | ||||
| 		g->chip.ngpio = 2; | ||||
| 	else | ||||
| 		g->chip.ngpio = 1; | ||||
| 
 | ||||
| 	g->chip.init_valid_mask = bd71815_init_valid_mask; | ||||
| 	g->chip.base = -1; | ||||
| 	g->chip.parent = parent; | ||||
| 	g->regmap = dev_get_regmap(parent, NULL); | ||||
| 	g->dev = dev; | ||||
| 
 | ||||
| 	return devm_gpiochip_add_data(dev, &g->chip, g); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver gpo_bd71815_driver = { | ||||
| 	.driver = { | ||||
| 		.name	= "bd71815-gpo", | ||||
| 	}, | ||||
| 	.probe		= gpo_bd71815_probe, | ||||
| }; | ||||
| module_platform_driver(gpo_bd71815_driver); | ||||
| 
 | ||||
| MODULE_ALIAS("platform:bd71815-gpo"); | ||||
| MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | ||||
| MODULE_AUTHOR("Peter Yang <yanglsh@embest-tech.com>"); | ||||
| MODULE_DESCRIPTION("GPO interface for BD71815"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -22,7 +22,6 @@ | ||||
| #include <linux/mfd/syscon.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/platform_data/i2c-designware.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/pm.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| @ -206,7 +205,6 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { | ||||
| 
 | ||||
| static int dw_i2c_plat_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); | ||||
| 	struct i2c_adapter *adap; | ||||
| 	struct dw_i2c_dev *dev; | ||||
| 	struct i2c_timings *t; | ||||
| @ -236,10 +234,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | ||||
| 	reset_control_deassert(dev->rst); | ||||
| 
 | ||||
| 	t = &dev->timings; | ||||
| 	if (pdata) | ||||
| 		t->bus_freq_hz = pdata->i2c_scl_freq; | ||||
| 	else | ||||
| 		i2c_parse_fw_timings(&pdev->dev, t, false); | ||||
| 	i2c_parse_fw_timings(&pdev->dev, t, false); | ||||
| 
 | ||||
| 	i2c_dw_adjust_bus_speed(dev); | ||||
| 
 | ||||
|  | ||||
| @ -94,6 +94,17 @@ config INPUT_ARIZONA_HAPTICS | ||||
| 	  To compile this driver as a module, choose M here: the | ||||
| 	  module will be called arizona-haptics. | ||||
| 
 | ||||
| config INPUT_ATC260X_ONKEY | ||||
| 	tristate "Actions Semi ATC260x PMIC ONKEY" | ||||
| 	depends on MFD_ATC260X | ||||
| 	help | ||||
| 	  Support the ONKEY of ATC260x PMICs as an input device reporting | ||||
| 	  power button status. ONKEY can be used to wakeup from low power | ||||
| 	  modes and force a reset on long press. | ||||
| 
 | ||||
| 	  To compile this driver as a module, choose M here: the | ||||
| 	  module will be called atc260x-onkey. | ||||
| 
 | ||||
| config INPUT_ATMEL_CAPTOUCH | ||||
| 	tristate "Atmel Capacitive Touch Button Driver" | ||||
| 	depends on OF || COMPILE_TEST | ||||
|  | ||||
| @ -17,6 +17,7 @@ obj-$(CONFIG_INPUT_ADXL34X_SPI)		+= adxl34x-spi.o | ||||
| obj-$(CONFIG_INPUT_APANEL)		+= apanel.o | ||||
| obj-$(CONFIG_INPUT_ARIEL_PWRBUTTON)	+= ariel-pwrbutton.o | ||||
| obj-$(CONFIG_INPUT_ARIZONA_HAPTICS)	+= arizona-haptics.o | ||||
| obj-$(CONFIG_INPUT_ATC260X_ONKEY)	+= atc260x-onkey.o | ||||
| obj-$(CONFIG_INPUT_ATI_REMOTE2)		+= ati_remote2.o | ||||
| obj-$(CONFIG_INPUT_ATLAS_BTNS)		+= atlas_btns.o | ||||
| obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH)	+= atmel_captouch.o | ||||
| @ -86,4 +87,3 @@ obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o | ||||
| obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o | ||||
| obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o | ||||
| obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)	+= ideapad_slidebar.o | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										305
									
								
								drivers/input/misc/atc260x-onkey.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								drivers/input/misc/atc260x-onkey.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,305 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * Onkey driver for Actions Semi ATC260x PMICs. | ||||
|  * | ||||
|  * Copyright (c) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/bitfield.h> | ||||
| #include <linux/input.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/mfd/atc260x/core.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| /* <2s for short press, >2s for long press */ | ||||
| #define KEY_PRESS_TIME_SEC	2 | ||||
| 
 | ||||
| /* Driver internals */ | ||||
| enum atc260x_onkey_reset_status { | ||||
| 	KEY_RESET_HW_DEFAULT, | ||||
| 	KEY_RESET_DISABLED, | ||||
| 	KEY_RESET_USER_SEL, | ||||
| }; | ||||
| 
 | ||||
| struct atc260x_onkey_params { | ||||
| 	u32 reg_int_ctl; | ||||
| 	u32 kdwn_state_bm; | ||||
| 	u32 long_int_pnd_bm; | ||||
| 	u32 short_int_pnd_bm; | ||||
| 	u32 kdwn_int_pnd_bm; | ||||
| 	u32 press_int_en_bm; | ||||
| 	u32 kdwn_int_en_bm; | ||||
| 	u32 press_time_bm; | ||||
| 	u32 reset_en_bm; | ||||
| 	u32 reset_time_bm; | ||||
| }; | ||||
| 
 | ||||
| struct atc260x_onkey { | ||||
| 	struct atc260x *atc260x; | ||||
| 	const struct atc260x_onkey_params *params; | ||||
| 	struct input_dev *input_dev; | ||||
| 	struct delayed_work work; | ||||
| 	int irq; | ||||
| }; | ||||
| 
 | ||||
| static const struct atc260x_onkey_params atc2603c_onkey_params = { | ||||
| 	.reg_int_ctl		= ATC2603C_PMU_SYS_CTL2, | ||||
| 	.long_int_pnd_bm	= ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS, | ||||
| 	.short_int_pnd_bm	= ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS, | ||||
| 	.kdwn_int_pnd_bm	= ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD, | ||||
| 	.press_int_en_bm	= ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN, | ||||
| 	.kdwn_int_en_bm		= ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN, | ||||
| 	.kdwn_state_bm		= ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS, | ||||
| 	.press_time_bm		= ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME, | ||||
| 	.reset_en_bm		= ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN, | ||||
| 	.reset_time_bm		= ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL, | ||||
| }; | ||||
| 
 | ||||
| static const struct atc260x_onkey_params atc2609a_onkey_params = { | ||||
| 	.reg_int_ctl		= ATC2609A_PMU_SYS_CTL2, | ||||
| 	.long_int_pnd_bm	= ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS, | ||||
| 	.short_int_pnd_bm	= ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS, | ||||
| 	.kdwn_int_pnd_bm	= ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD, | ||||
| 	.press_int_en_bm	= ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN, | ||||
| 	.kdwn_int_en_bm		= ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN, | ||||
| 	.kdwn_state_bm		= ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS, | ||||
| 	.press_time_bm		= ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME, | ||||
| 	.reset_en_bm		= ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN, | ||||
| 	.reset_time_bm		= ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL, | ||||
| }; | ||||
| 
 | ||||
| static int atc2603x_onkey_hw_init(struct atc260x_onkey *onkey, | ||||
| 				  enum atc260x_onkey_reset_status reset_status, | ||||
| 				  u32 reset_time, u32 press_time) | ||||
| { | ||||
| 	u32 reg_bm, reg_val; | ||||
| 
 | ||||
| 	reg_bm = onkey->params->long_int_pnd_bm | | ||||
| 		 onkey->params->short_int_pnd_bm | | ||||
| 		 onkey->params->kdwn_int_pnd_bm | | ||||
| 		 onkey->params->press_int_en_bm | | ||||
| 		 onkey->params->kdwn_int_en_bm; | ||||
| 
 | ||||
| 	reg_val = reg_bm | press_time; | ||||
| 	reg_bm |= onkey->params->press_time_bm; | ||||
| 
 | ||||
| 	if (reset_status == KEY_RESET_DISABLED) { | ||||
| 		reg_bm |= onkey->params->reset_en_bm; | ||||
| 	} else if (reset_status == KEY_RESET_USER_SEL) { | ||||
| 		reg_bm |= onkey->params->reset_en_bm | | ||||
| 			  onkey->params->reset_time_bm; | ||||
| 		reg_val |= onkey->params->reset_en_bm | reset_time; | ||||
| 	} | ||||
| 
 | ||||
| 	return regmap_update_bits(onkey->atc260x->regmap, | ||||
| 				  onkey->params->reg_int_ctl, reg_bm, reg_val); | ||||
| } | ||||
| 
 | ||||
| static void atc260x_onkey_query(struct atc260x_onkey *onkey) | ||||
| { | ||||
| 	u32 reg_bits; | ||||
| 	int ret, key_down; | ||||
| 
 | ||||
| 	ret = regmap_read(onkey->atc260x->regmap, | ||||
| 			  onkey->params->reg_int_ctl, &key_down); | ||||
| 	if (ret) { | ||||
| 		key_down = 1; | ||||
| 		dev_err(onkey->atc260x->dev, | ||||
| 			"Failed to read onkey status: %d\n", ret); | ||||
| 	} else { | ||||
| 		key_down &= onkey->params->kdwn_state_bm; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The hardware generates interrupt only when the onkey pin is | ||||
| 	 * asserted. Hence, the deassertion of the pin is simulated through | ||||
| 	 * work queue. | ||||
| 	 */ | ||||
| 	if (key_down) { | ||||
| 		schedule_delayed_work(&onkey->work, msecs_to_jiffies(200)); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The key-down status bit is cleared when the On/Off button | ||||
| 	 * is released. | ||||
| 	 */ | ||||
| 	input_report_key(onkey->input_dev, KEY_POWER, 0); | ||||
| 	input_sync(onkey->input_dev); | ||||
| 
 | ||||
| 	reg_bits = onkey->params->long_int_pnd_bm | | ||||
| 		   onkey->params->short_int_pnd_bm | | ||||
| 		   onkey->params->kdwn_int_pnd_bm | | ||||
| 		   onkey->params->press_int_en_bm | | ||||
| 		   onkey->params->kdwn_int_en_bm; | ||||
| 
 | ||||
| 	/* Clear key press pending events and enable key press interrupts. */ | ||||
| 	regmap_update_bits(onkey->atc260x->regmap, onkey->params->reg_int_ctl, | ||||
| 			   reg_bits, reg_bits); | ||||
| } | ||||
| 
 | ||||
| static void atc260x_onkey_work(struct work_struct *work) | ||||
| { | ||||
| 	struct atc260x_onkey *onkey = container_of(work, struct atc260x_onkey, | ||||
| 						   work.work); | ||||
| 	atc260x_onkey_query(onkey); | ||||
| } | ||||
| 
 | ||||
| static irqreturn_t atc260x_onkey_irq(int irq, void *data) | ||||
| { | ||||
| 	struct atc260x_onkey *onkey = data; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* Disable key press interrupts. */ | ||||
| 	ret = regmap_update_bits(onkey->atc260x->regmap, | ||||
| 				 onkey->params->reg_int_ctl, | ||||
| 				 onkey->params->press_int_en_bm | | ||||
| 				 onkey->params->kdwn_int_en_bm, 0); | ||||
| 	if (ret) | ||||
| 		dev_err(onkey->atc260x->dev, | ||||
| 			"Failed to disable interrupts: %d\n", ret); | ||||
| 
 | ||||
| 	input_report_key(onkey->input_dev, KEY_POWER, 1); | ||||
| 	input_sync(onkey->input_dev); | ||||
| 
 | ||||
| 	atc260x_onkey_query(onkey); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| static int atc260x_onkey_open(struct input_dev *dev) | ||||
| { | ||||
| 	struct atc260x_onkey *onkey = input_get_drvdata(dev); | ||||
| 
 | ||||
| 	enable_irq(onkey->irq); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void atc260x_onkey_close(struct input_dev *dev) | ||||
| { | ||||
| 	struct atc260x_onkey *onkey = input_get_drvdata(dev); | ||||
| 
 | ||||
| 	disable_irq(onkey->irq); | ||||
| 	cancel_delayed_work_sync(&onkey->work); | ||||
| } | ||||
| 
 | ||||
| static int atc260x_onkey_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent); | ||||
| 	struct atc260x_onkey *onkey; | ||||
| 	struct input_dev *input_dev; | ||||
| 	enum atc260x_onkey_reset_status reset_status; | ||||
| 	u32 press_time = KEY_PRESS_TIME_SEC, reset_time = 0; | ||||
| 	int val, error; | ||||
| 
 | ||||
| 	onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); | ||||
| 	if (!onkey) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	error = device_property_read_u32(pdev->dev.parent, | ||||
| 					 "reset-time-sec", &val); | ||||
| 	if (error) { | ||||
| 		reset_status = KEY_RESET_HW_DEFAULT; | ||||
| 	} else if (val) { | ||||
| 		if (val < 6 || val > 12) { | ||||
| 			dev_err(&pdev->dev, "reset-time-sec out of range\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 
 | ||||
| 		reset_status = KEY_RESET_USER_SEL; | ||||
| 		reset_time = (val - 6) / 2; | ||||
| 	} else { | ||||
| 		reset_status = KEY_RESET_DISABLED; | ||||
| 		dev_dbg(&pdev->dev, "Disabled reset on long-press\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	switch (atc260x->ic_type) { | ||||
| 	case ATC2603C: | ||||
| 		onkey->params = &atc2603c_onkey_params; | ||||
| 		press_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME, | ||||
| 					press_time); | ||||
| 		reset_time = FIELD_PREP(ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL, | ||||
| 					reset_time); | ||||
| 		break; | ||||
| 	case ATC2609A: | ||||
| 		onkey->params = &atc2609a_onkey_params; | ||||
| 		press_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME, | ||||
| 					press_time); | ||||
| 		reset_time = FIELD_PREP(ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL, | ||||
| 					reset_time); | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(&pdev->dev, | ||||
| 			"OnKey not supported for ATC260x PMIC type: %u\n", | ||||
| 			atc260x->ic_type); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	input_dev = devm_input_allocate_device(&pdev->dev); | ||||
| 	if (!input_dev) { | ||||
| 		dev_err(&pdev->dev, "Failed to allocate input device\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	onkey->input_dev = input_dev; | ||||
| 	onkey->atc260x = atc260x; | ||||
| 
 | ||||
| 	input_dev->name = "atc260x-onkey"; | ||||
| 	input_dev->phys = "atc260x-onkey/input0"; | ||||
| 	input_dev->open = atc260x_onkey_open; | ||||
| 	input_dev->close = atc260x_onkey_close; | ||||
| 
 | ||||
| 	input_set_capability(input_dev, EV_KEY, KEY_POWER); | ||||
| 	input_set_drvdata(input_dev, onkey); | ||||
| 
 | ||||
| 	INIT_DELAYED_WORK(&onkey->work, atc260x_onkey_work); | ||||
| 
 | ||||
| 	onkey->irq = platform_get_irq(pdev, 0); | ||||
| 	if (onkey->irq < 0) | ||||
| 		return onkey->irq; | ||||
| 
 | ||||
| 	error = devm_request_threaded_irq(&pdev->dev, onkey->irq, NULL, | ||||
| 					  atc260x_onkey_irq, IRQF_ONESHOT, | ||||
| 					  dev_name(&pdev->dev), onkey); | ||||
| 	if (error) { | ||||
| 		dev_err(&pdev->dev, | ||||
| 			"Failed to register IRQ %d: %d\n", onkey->irq, error); | ||||
| 		return error; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Keep IRQ disabled until atc260x_onkey_open() is called. */ | ||||
| 	disable_irq(onkey->irq); | ||||
| 
 | ||||
| 	error = input_register_device(input_dev); | ||||
| 	if (error) { | ||||
| 		dev_err(&pdev->dev, | ||||
| 			"Failed to register input device: %d\n", error); | ||||
| 		return error; | ||||
| 	} | ||||
| 
 | ||||
| 	error = atc2603x_onkey_hw_init(onkey, reset_status, | ||||
| 				       reset_time, press_time); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	device_init_wakeup(&pdev->dev, true); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver atc260x_onkey_driver = { | ||||
| 	.probe	= atc260x_onkey_probe, | ||||
| 	.driver	= { | ||||
| 		.name = "atc260x-onkey", | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(atc260x_onkey_driver); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("Onkey driver for ATC260x PMICs"); | ||||
| MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -967,6 +967,17 @@ config MFD_VIPERBOARD | ||||
| 	  You need to select the mfd cell drivers separately. | ||||
| 	  The drivers do not support all features the board exposes. | ||||
| 
 | ||||
| config MFD_NTXEC | ||||
| 	tristate "Netronix embedded controller (EC)" | ||||
| 	depends on OF || COMPILE_TEST | ||||
| 	depends on I2C | ||||
| 	select REGMAP_I2C | ||||
| 	select MFD_CORE | ||||
| 	help | ||||
| 	  Say yes here if you want to support the embedded controller found in | ||||
| 	  certain e-book readers designed by the original design manufacturer | ||||
| 	  Netronix. | ||||
| 
 | ||||
| config MFD_RETU | ||||
| 	tristate "Nokia Retu and Tahvo multi-function device" | ||||
| 	select MFD_CORE | ||||
| @ -1224,7 +1235,8 @@ config MFD_SC27XX_PMIC | ||||
| 
 | ||||
| config ABX500_CORE | ||||
| 	bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | ||||
| 	default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST | ||||
| 	depends on ARCH_U8500 || COMPILE_TEST | ||||
| 	default y if ARCH_U8500 | ||||
| 	help | ||||
| 	  Say yes here if you have the ABX500 Mixed Signal IC family | ||||
| 	  chips. This core driver expose register access functions. | ||||
| @ -1232,30 +1244,6 @@ config ABX500_CORE | ||||
| 	  remain unchanged when IC changes. Binding of the functions to | ||||
| 	  actual register access is done by the IC core driver. | ||||
| 
 | ||||
| config AB3100_CORE | ||||
| 	bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | ||||
| 	depends on I2C=y && ABX500_CORE | ||||
| 	select MFD_CORE | ||||
| 	default y if ARCH_U300 | ||||
| 	help | ||||
| 	  Select this to enable the AB3100 Mixed Signal IC core | ||||
| 	  functionality. This connects to a AB3100 on the I2C bus | ||||
| 	  and expose a number of symbols needed for dependent devices | ||||
| 	  to read and write registers and subscribe to events from | ||||
| 	  this multi-functional IC. This is needed to use other features | ||||
| 	  of the AB3100 such as battery-backed RTC, charging control, | ||||
| 	  LEDs, vibrator, system power and temperature, power management | ||||
| 	  and ALSA sound. | ||||
| 
 | ||||
| config AB3100_OTP | ||||
| 	tristate "ST-Ericsson AB3100 OTP functions" | ||||
| 	depends on AB3100_CORE | ||||
| 	default y if AB3100_CORE | ||||
| 	help | ||||
| 	  Select this to enable the AB3100 Mixed Signal IC OTP (one-time | ||||
| 	  programmable memory) support. This exposes a sysfs file to read | ||||
| 	  out OTP values. | ||||
| 
 | ||||
| config AB8500_CORE | ||||
| 	bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | ||||
| 	depends on ABX500_CORE && MFD_DB8500_PRCMU | ||||
| @ -1975,19 +1963,31 @@ config MFD_ROHM_BD70528 | ||||
| 	  charger. | ||||
| 
 | ||||
| config MFD_ROHM_BD71828 | ||||
| 	tristate "ROHM BD71828 Power Management IC" | ||||
| 	tristate "ROHM BD71828 and BD71815 Power Management IC" | ||||
| 	depends on I2C=y | ||||
| 	depends on OF | ||||
| 	select REGMAP_I2C | ||||
| 	select REGMAP_IRQ | ||||
| 	select MFD_CORE | ||||
| 	help | ||||
| 	  Select this option to get support for the ROHM BD71828 Power | ||||
| 	  Management IC. BD71828GW is a single-chip power management IC for | ||||
| 	  battery-powered portable devices. The IC integrates 7 buck | ||||
| 	  converters, 7 LDOs, and a 1500 mA single-cell linear charger. | ||||
| 	  Also included is a Coulomb counter, a real-time clock (RTC), and | ||||
| 	  a 32.768 kHz clock gate. | ||||
| 	  Select this option to get support for the ROHM BD71828 and BD71815 | ||||
| 	  Power Management ICs. BD71828GW and BD71815AGW are single-chip power | ||||
| 	  management ICs mainly for battery-powered portable devices. | ||||
| 	  The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815 | ||||
| 	  has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide | ||||
| 	  also a single-cell linear charger, a Coulomb counter, a real-time | ||||
| 	  clock (RTC), GPIOs and a 32.768 kHz clock gate. | ||||
| 
 | ||||
| config MFD_ROHM_BD957XMUF | ||||
| 	tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs" | ||||
| 	depends on I2C=y | ||||
| 	depends on OF | ||||
| 	select REGMAP_I2C | ||||
| 	select MFD_CORE | ||||
| 	help | ||||
| 	  Select this option to get support for the ROHM BD9576MUF and | ||||
| 	  BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily | ||||
| 	  designed to be used to power R-Car series processors. | ||||
| 
 | ||||
| config MFD_STM32_LPTIMER | ||||
| 	tristate "Support for STM32 Low-Power Timer" | ||||
| @ -2055,6 +2055,24 @@ config MFD_WCD934X | ||||
| 	  This driver provides common support WCD934x audio codec and its | ||||
| 	  associated Pin Controller, Soundwire Controller and Audio codec. | ||||
| 
 | ||||
| config MFD_ATC260X | ||||
| 	tristate | ||||
| 	select MFD_CORE | ||||
| 	select REGMAP | ||||
| 	select REGMAP_IRQ | ||||
| 
 | ||||
| config MFD_ATC260X_I2C | ||||
| 	tristate "Actions Semi ATC260x PMICs with I2C" | ||||
| 	select MFD_ATC260X | ||||
| 	select REGMAP_I2C | ||||
| 	depends on I2C | ||||
| 	help | ||||
| 	  Support for the Actions Semi ATC260x PMICs controlled via I2C. | ||||
| 
 | ||||
| 	  This driver provides common support for accessing the ATC2603C | ||||
| 	  and ATC2609A chip variants, additional drivers must be enabled | ||||
| 	  in order to use the functionality of the device. | ||||
| 
 | ||||
| config MFD_KHADAS_MCU | ||||
| 	tristate "Support for Khadas System control Microcontroller" | ||||
| 	depends on I2C | ||||
|  | ||||
| @ -178,8 +178,6 @@ obj-$(CONFIG_MFD_PCF50633)	+= pcf50633.o | ||||
| obj-$(CONFIG_PCF50633_ADC)	+= pcf50633-adc.o | ||||
| obj-$(CONFIG_PCF50633_GPIO)	+= pcf50633-gpio.o | ||||
| obj-$(CONFIG_ABX500_CORE)	+= abx500-core.o | ||||
| obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o | ||||
| obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o | ||||
| obj-$(CONFIG_AB8500_DEBUG)	+= ab8500-debugfs.o | ||||
| obj-$(CONFIG_MFD_DB8500_PRCMU)	+= db8500-prcmu.o | ||||
| # ab8500-core need to come after db8500-prcmu (which provides the channel)
 | ||||
| @ -218,6 +216,7 @@ obj-$(CONFIG_MFD_INTEL_PMC_BXT)	+= intel_pmc_bxt.o | ||||
| obj-$(CONFIG_MFD_INTEL_PMT)	+= intel_pmt.o | ||||
| obj-$(CONFIG_MFD_PALMAS)	+= palmas.o | ||||
| obj-$(CONFIG_MFD_VIPERBOARD)    += viperboard.o | ||||
| obj-$(CONFIG_MFD_NTXEC)		+= ntxec.o | ||||
| obj-$(CONFIG_MFD_RC5T583)	+= rc5t583.o rc5t583-irq.o | ||||
| obj-$(CONFIG_MFD_RK808)		+= rk808.o | ||||
| obj-$(CONFIG_MFD_RN5T618)	+= rn5t618.o | ||||
| @ -261,6 +260,7 @@ obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o | ||||
| obj-$(CONFIG_MFD_ROHM_BD70528)	+= rohm-bd70528.o | ||||
| obj-$(CONFIG_MFD_ROHM_BD71828)	+= rohm-bd71828.o | ||||
| obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o | ||||
| obj-$(CONFIG_MFD_ROHM_BD957XMUF)	+= rohm-bd9576.o | ||||
| obj-$(CONFIG_MFD_STMFX) 	+= stmfx.o | ||||
| obj-$(CONFIG_MFD_KHADAS_MCU) 	+= khadas-mcu.o | ||||
| obj-$(CONFIG_MFD_ACER_A500_EC)	+= acer-ec-a500.o | ||||
| @ -268,3 +268,6 @@ obj-$(CONFIG_MFD_ACER_A500_EC)	+= acer-ec-a500.o | ||||
| obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o | ||||
| obj-$(CONFIG_MFD_SIMPLE_MFD_I2C)	+= simple-mfd-i2c.o | ||||
| obj-$(CONFIG_MFD_INTEL_M10_BMC)   += intel-m10-bmc.o | ||||
| 
 | ||||
| obj-$(CONFIG_MFD_ATC260X)	+= atc260x-core.o | ||||
| obj-$(CONFIG_MFD_ATC260X_I2C)	+= atc260x-i2c.o | ||||
|  | ||||
| @ -1,929 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| /*
 | ||||
|  * Copyright (C) 2007-2010 ST-Ericsson | ||||
|  * Low-level core for exclusive access to the AB3100 IC on the I2C bus | ||||
|  * and some basic chip-configuration. | ||||
|  * Author: Linus Walleij <linus.walleij@stericsson.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/mutex.h> | ||||
| #include <linux/list.h> | ||||
| #include <linux/notifier.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/device.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/random.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/seq_file.h> | ||||
| #include <linux/uaccess.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/mfd/ab3100.h> | ||||
| #include <linux/mfd/abx500.h> | ||||
| 
 | ||||
| /* These are the only registers inside AB3100 used in this main file */ | ||||
| 
 | ||||
| /* Interrupt event registers */ | ||||
| #define AB3100_EVENTA1		0x21 | ||||
| #define AB3100_EVENTA2		0x22 | ||||
| #define AB3100_EVENTA3		0x23 | ||||
| 
 | ||||
| /* AB3100 DAC converter registers */ | ||||
| #define AB3100_DIS		0x00 | ||||
| #define AB3100_D0C		0x01 | ||||
| #define AB3100_D1C		0x02 | ||||
| #define AB3100_D2C		0x03 | ||||
| #define AB3100_D3C		0x04 | ||||
| 
 | ||||
| /* Chip ID register */ | ||||
| #define AB3100_CID		0x20 | ||||
| 
 | ||||
| /* AB3100 interrupt registers */ | ||||
| #define AB3100_IMRA1		0x24 | ||||
| #define AB3100_IMRA2		0x25 | ||||
| #define AB3100_IMRA3		0x26 | ||||
| #define AB3100_IMRB1		0x2B | ||||
| #define AB3100_IMRB2		0x2C | ||||
| #define AB3100_IMRB3		0x2D | ||||
| 
 | ||||
| /* System Power Monitoring and control registers */ | ||||
| #define AB3100_MCA		0x2E | ||||
| #define AB3100_MCB		0x2F | ||||
| 
 | ||||
| /* SIM power up */ | ||||
| #define AB3100_SUP		0x50 | ||||
| 
 | ||||
| /*
 | ||||
|  * I2C communication | ||||
|  * | ||||
|  * The AB3100 is usually assigned address 0x48 (7-bit) | ||||
|  * The chip is defined in the platform i2c_board_data section. | ||||
|  */ | ||||
| static int ab3100_get_chip_id(struct device *dev) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return (int)ab3100->chip_id; | ||||
| } | ||||
| 
 | ||||
| static int ab3100_set_register_interruptible(struct ab3100 *ab3100, | ||||
| 	u8 reg, u8 regval) | ||||
| { | ||||
| 	u8 regandval[2] = {reg, regval}; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = mutex_lock_interruptible(&ab3100->access_mutex); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * A two-byte write message with the first byte containing the register | ||||
| 	 * number and the second byte containing the value to be written | ||||
| 	 * effectively sets a register in the AB3100. | ||||
| 	 */ | ||||
| 	err = i2c_master_send(ab3100->i2c_client, regandval, 2); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write register): %d\n", | ||||
| 			err); | ||||
| 	} else if (err != 2) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write register)\n" | ||||
| 			"  %d bytes transferred (expected 2)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 	} else { | ||||
| 		/* All is well */ | ||||
| 		err = 0; | ||||
| 	} | ||||
| 	mutex_unlock(&ab3100->access_mutex); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int set_register_interruptible(struct device *dev, | ||||
| 	u8 bank, u8 reg, u8 value) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return ab3100_set_register_interruptible(ab3100, reg, value); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * The test registers exist at an I2C bus address up one | ||||
|  * from the ordinary base. They are not supposed to be used | ||||
|  * in production code, but sometimes you have to do that | ||||
|  * anyway. It's currently only used from this file so declare | ||||
|  * it static and do not export. | ||||
|  */ | ||||
| static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, | ||||
| 				    u8 reg, u8 regval) | ||||
| { | ||||
| 	u8 regandval[2] = {reg, regval}; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = mutex_lock_interruptible(&ab3100->access_mutex); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	err = i2c_master_send(ab3100->testreg_client, regandval, 2); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write test register): %d\n", | ||||
| 			err); | ||||
| 	} else if (err != 2) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write test register)\n" | ||||
| 			"  %d bytes transferred (expected 2)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 	} else { | ||||
| 		/* All is well */ | ||||
| 		err = 0; | ||||
| 	} | ||||
| 	mutex_unlock(&ab3100->access_mutex); | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int ab3100_get_register_interruptible(struct ab3100 *ab3100, | ||||
| 					     u8 reg, u8 *regval) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = mutex_lock_interruptible(&ab3100->access_mutex); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * AB3100 require an I2C "stop" command between each message, else | ||||
| 	 * it will not work. The only way of achieveing this with the | ||||
| 	 * message transport layer is to send the read and write messages | ||||
| 	 * separately. | ||||
| 	 */ | ||||
| 	err = i2c_master_send(ab3100->i2c_client, ®, 1); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (send register address): %d\n", | ||||
| 			err); | ||||
| 		goto get_reg_out_unlock; | ||||
| 	} else if (err != 1) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (send register address)\n" | ||||
| 			"  %d bytes transferred (expected 1)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_reg_out_unlock; | ||||
| 	} else { | ||||
| 		/* All is well */ | ||||
| 		err = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	err = i2c_master_recv(ab3100->i2c_client, regval, 1); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (read register): %d\n", | ||||
| 			err); | ||||
| 		goto get_reg_out_unlock; | ||||
| 	} else if (err != 1) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (read register)\n" | ||||
| 			"  %d bytes transferred (expected 1)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_reg_out_unlock; | ||||
| 	} else { | ||||
| 		/* All is well */ | ||||
| 		err = 0; | ||||
| 	} | ||||
| 
 | ||||
|  get_reg_out_unlock: | ||||
| 	mutex_unlock(&ab3100->access_mutex); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, | ||||
| 				      u8 *value) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return ab3100_get_register_interruptible(ab3100, reg, value); | ||||
| } | ||||
| 
 | ||||
| static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100, | ||||
| 			     u8 first_reg, u8 *regvals, u8 numregs) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (ab3100->chip_id == 0xa0 || | ||||
| 	    ab3100->chip_id == 0xa1) | ||||
| 		/* These don't support paged reads */ | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	err = mutex_lock_interruptible(&ab3100->access_mutex); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Paged read also require an I2C "stop" command. | ||||
| 	 */ | ||||
| 	err = i2c_master_send(ab3100->i2c_client, &first_reg, 1); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (send first register address): %d\n", | ||||
| 			err); | ||||
| 		goto get_reg_page_out_unlock; | ||||
| 	} else if (err != 1) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (send first register address)\n" | ||||
| 			"  %d bytes transferred (expected 1)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_reg_page_out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	err = i2c_master_recv(ab3100->i2c_client, regvals, numregs); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (read register page): %d\n", | ||||
| 			err); | ||||
| 		goto get_reg_page_out_unlock; | ||||
| 	} else if (err != numregs) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (read register page)\n" | ||||
| 			"  %d bytes transferred (expected %d)\n", | ||||
| 			err, numregs); | ||||
| 		err = -EIO; | ||||
| 		goto get_reg_page_out_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	/* All is well */ | ||||
| 	err = 0; | ||||
| 
 | ||||
|  get_reg_page_out_unlock: | ||||
| 	mutex_unlock(&ab3100->access_mutex); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int get_register_page_interruptible(struct device *dev, u8 bank, | ||||
| 	u8 first_reg, u8 *regvals, u8 numregs) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return ab3100_get_register_page_interruptible(ab3100, | ||||
| 			first_reg, regvals, numregs); | ||||
| } | ||||
| 
 | ||||
| static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100, | ||||
| 				 u8 reg, u8 andmask, u8 ormask) | ||||
| { | ||||
| 	u8 regandval[2] = {reg, 0}; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = mutex_lock_interruptible(&ab3100->access_mutex); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/* First read out the target register */ | ||||
| 	err = i2c_master_send(ab3100->i2c_client, ®, 1); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (maskset send address): %d\n", | ||||
| 			err); | ||||
| 		goto get_maskset_unlock; | ||||
| 	} else if (err != 1) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (maskset send address)\n" | ||||
| 			"  %d bytes transferred (expected 1)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_maskset_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	err = i2c_master_recv(ab3100->i2c_client, ®andval[1], 1); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (maskset read register): %d\n", | ||||
| 			err); | ||||
| 		goto get_maskset_unlock; | ||||
| 	} else if (err != 1) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (maskset read register)\n" | ||||
| 			"  %d bytes transferred (expected 1)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_maskset_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Modify the register */ | ||||
| 	regandval[1] &= andmask; | ||||
| 	regandval[1] |= ormask; | ||||
| 
 | ||||
| 	/* Write the register */ | ||||
| 	err = i2c_master_send(ab3100->i2c_client, regandval, 2); | ||||
| 	if (err < 0) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write register): %d\n", | ||||
| 			err); | ||||
| 		goto get_maskset_unlock; | ||||
| 	} else if (err != 2) { | ||||
| 		dev_err(ab3100->dev, | ||||
| 			"write error (write register)\n" | ||||
| 			"  %d bytes transferred (expected 2)\n", | ||||
| 			err); | ||||
| 		err = -EIO; | ||||
| 		goto get_maskset_unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	/* All is well */ | ||||
| 	err = 0; | ||||
| 
 | ||||
|  get_maskset_unlock: | ||||
| 	mutex_unlock(&ab3100->access_mutex); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int mask_and_set_register_interruptible(struct device *dev, u8 bank, | ||||
| 	u8 reg, u8 bitmask, u8 bitvalues) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	return ab3100_mask_and_set_register_interruptible(ab3100, | ||||
| 			reg, bitmask, (bitmask & bitvalues)); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Register a simple callback for handling any AB3100 events. | ||||
|  */ | ||||
| int ab3100_event_register(struct ab3100 *ab3100, | ||||
| 			  struct notifier_block *nb) | ||||
| { | ||||
| 	return blocking_notifier_chain_register(&ab3100->event_subscribers, | ||||
| 					       nb); | ||||
| } | ||||
| EXPORT_SYMBOL(ab3100_event_register); | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove a previously registered callback. | ||||
|  */ | ||||
| int ab3100_event_unregister(struct ab3100 *ab3100, | ||||
| 			    struct notifier_block *nb) | ||||
| { | ||||
| 	return blocking_notifier_chain_unregister(&ab3100->event_subscribers, | ||||
| 					    nb); | ||||
| } | ||||
| EXPORT_SYMBOL(ab3100_event_unregister); | ||||
| 
 | ||||
| 
 | ||||
| static int ab3100_event_registers_startup_state_get(struct device *dev, | ||||
| 					     u8 *event) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); | ||||
| 
 | ||||
| 	if (!ab3100->startup_events_read) | ||||
| 		return -EAGAIN; /* Try again later */ | ||||
| 	memcpy(event, ab3100->startup_events, 3); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct abx500_ops ab3100_ops = { | ||||
| 	.get_chip_id = ab3100_get_chip_id, | ||||
| 	.set_register = set_register_interruptible, | ||||
| 	.get_register = get_register_interruptible, | ||||
| 	.get_register_page = get_register_page_interruptible, | ||||
| 	.set_register_page = NULL, | ||||
| 	.mask_and_set_register = mask_and_set_register_interruptible, | ||||
| 	.event_registers_startup_state_get = | ||||
| 		ab3100_event_registers_startup_state_get, | ||||
| 	.startup_irq_enabled = NULL, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * This is a threaded interrupt handler so we can make some | ||||
|  * I2C calls etc. | ||||
|  */ | ||||
| static irqreturn_t ab3100_irq_handler(int irq, void *data) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = data; | ||||
| 	u8 event_regs[3]; | ||||
| 	u32 fatevent; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, | ||||
| 				       event_regs, 3); | ||||
| 	if (err) | ||||
| 		goto err_event; | ||||
| 
 | ||||
| 	fatevent = (event_regs[0] << 16) | | ||||
| 		(event_regs[1] << 8) | | ||||
| 		event_regs[2]; | ||||
| 
 | ||||
| 	if (!ab3100->startup_events_read) { | ||||
| 		ab3100->startup_events[0] = event_regs[0]; | ||||
| 		ab3100->startup_events[1] = event_regs[1]; | ||||
| 		ab3100->startup_events[2] = event_regs[2]; | ||||
| 		ab3100->startup_events_read = true; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * The notified parties will have to mask out the events | ||||
| 	 * they're interested in and react to them. They will be | ||||
| 	 * notified on all events, then they use the fatevent value | ||||
| 	 * to determine if they're interested. | ||||
| 	 */ | ||||
| 	blocking_notifier_call_chain(&ab3100->event_subscribers, | ||||
| 				     fatevent, NULL); | ||||
| 
 | ||||
| 	dev_dbg(ab3100->dev, | ||||
| 		"IRQ Event: 0x%08x\n", fatevent); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| 
 | ||||
|  err_event: | ||||
| 	dev_dbg(ab3100->dev, | ||||
| 		"error reading event status\n"); | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| /*
 | ||||
|  * Some debugfs entries only exposed if we're using debug | ||||
|  */ | ||||
| static int ab3100_registers_print(struct seq_file *s, void *p) | ||||
| { | ||||
| 	struct ab3100 *ab3100 = s->private; | ||||
| 	u8 value; | ||||
| 	u8 reg; | ||||
| 
 | ||||
| 	seq_puts(s, "AB3100 registers:\n"); | ||||
| 
 | ||||
| 	for (reg = 0; reg < 0xff; reg++) { | ||||
| 		ab3100_get_register_interruptible(ab3100, reg, &value); | ||||
| 		seq_printf(s, "[0x%x]:  0x%x\n", reg, value); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ab3100_registers_open(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	return single_open(file, ab3100_registers_print, inode->i_private); | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations ab3100_registers_fops = { | ||||
| 	.open = ab3100_registers_open, | ||||
| 	.read = seq_read, | ||||
| 	.llseek = seq_lseek, | ||||
| 	.release = single_release, | ||||
| 	.owner = THIS_MODULE, | ||||
| }; | ||||
| 
 | ||||
| struct ab3100_get_set_reg_priv { | ||||
| 	struct ab3100 *ab3100; | ||||
| 	bool mode; | ||||
| }; | ||||
| 
 | ||||
| static ssize_t ab3100_get_set_reg(struct file *file, | ||||
| 				  const char __user *user_buf, | ||||
| 				  size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct ab3100_get_set_reg_priv *priv = file->private_data; | ||||
| 	struct ab3100 *ab3100 = priv->ab3100; | ||||
| 	char buf[32]; | ||||
| 	ssize_t buf_size; | ||||
| 	int regp; | ||||
| 	u8 user_reg; | ||||
| 	int err; | ||||
| 	int i = 0; | ||||
| 
 | ||||
| 	/* Get userspace string and assure termination */ | ||||
| 	buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1)); | ||||
| 	if (copy_from_user(buf, user_buf, buf_size)) | ||||
| 		return -EFAULT; | ||||
| 	buf[buf_size] = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The idea is here to parse a string which is either | ||||
| 	 * "0xnn" for reading a register, or "0xaa 0xbb" for | ||||
| 	 * writing 0xbb to the register 0xaa. First move past | ||||
| 	 * whitespace and then begin to parse the register. | ||||
| 	 */ | ||||
| 	while ((i < buf_size) && (buf[i] == ' ')) | ||||
| 		i++; | ||||
| 	regp = i; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Advance pointer to end of string then terminate | ||||
| 	 * the register string. This is needed to satisfy | ||||
| 	 * the kstrtou8() function. | ||||
| 	 */ | ||||
| 	while ((i < buf_size) && (buf[i] != ' ')) | ||||
| 		i++; | ||||
| 	buf[i] = '\0'; | ||||
| 
 | ||||
| 	err = kstrtou8(&buf[regp], 16, &user_reg); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/* Either we read or we write a register here */ | ||||
| 	if (!priv->mode) { | ||||
| 		/* Reading */ | ||||
| 		u8 regvalue; | ||||
| 
 | ||||
| 		ab3100_get_register_interruptible(ab3100, user_reg, ®value); | ||||
| 
 | ||||
| 		dev_info(ab3100->dev, | ||||
| 			 "debug read AB3100 reg[0x%02x]: 0x%02x\n", | ||||
| 			 user_reg, regvalue); | ||||
| 	} else { | ||||
| 		int valp; | ||||
| 		u8 user_value; | ||||
| 		u8 regvalue; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Writing, we need some value to write to | ||||
| 		 * the register so keep parsing the string | ||||
| 		 * from userspace. | ||||
| 		 */ | ||||
| 		i++; | ||||
| 		while ((i < buf_size) && (buf[i] == ' ')) | ||||
| 			i++; | ||||
| 		valp = i; | ||||
| 		while ((i < buf_size) && (buf[i] != ' ')) | ||||
| 			i++; | ||||
| 		buf[i] = '\0'; | ||||
| 
 | ||||
| 		err = kstrtou8(&buf[valp], 16, &user_value); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 
 | ||||
| 		ab3100_set_register_interruptible(ab3100, user_reg, user_value); | ||||
| 		ab3100_get_register_interruptible(ab3100, user_reg, ®value); | ||||
| 
 | ||||
| 		dev_info(ab3100->dev, | ||||
| 			 "debug write reg[0x%02x]\n" | ||||
| 			 "  with 0x%02x, after readback: 0x%02x\n", | ||||
| 			 user_reg, user_value, regvalue); | ||||
| 	} | ||||
| 	return buf_size; | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations ab3100_get_set_reg_fops = { | ||||
| 	.open = simple_open, | ||||
| 	.write = ab3100_get_set_reg, | ||||
| 	.llseek = noop_llseek, | ||||
| }; | ||||
| 
 | ||||
| static struct ab3100_get_set_reg_priv ab3100_get_priv; | ||||
| static struct ab3100_get_set_reg_priv ab3100_set_priv; | ||||
| 
 | ||||
| static void ab3100_setup_debugfs(struct ab3100 *ab3100) | ||||
| { | ||||
| 	struct dentry *ab3100_dir; | ||||
| 
 | ||||
| 	ab3100_dir = debugfs_create_dir("ab3100", NULL); | ||||
| 
 | ||||
| 	debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100, | ||||
| 			    &ab3100_registers_fops); | ||||
| 
 | ||||
| 	ab3100_get_priv.ab3100 = ab3100; | ||||
| 	ab3100_get_priv.mode = false; | ||||
| 	debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv, | ||||
| 			    &ab3100_get_set_reg_fops); | ||||
| 
 | ||||
| 	ab3100_set_priv.ab3100 = ab3100; | ||||
| 	ab3100_set_priv.mode = true; | ||||
| 	debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv, | ||||
| 			    &ab3100_get_set_reg_fops); | ||||
| } | ||||
| #else | ||||
| static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Basic set-up, datastructure creation/destruction and I2C interface. | ||||
|  * This sets up a default config in the AB3100 chip so that it | ||||
|  * will work as expected. | ||||
|  */ | ||||
| 
 | ||||
| struct ab3100_init_setting { | ||||
| 	u8 abreg; | ||||
| 	u8 setting; | ||||
| }; | ||||
| 
 | ||||
| static const struct ab3100_init_setting ab3100_init_settings[] = { | ||||
| 	{ | ||||
| 		.abreg = AB3100_MCA, | ||||
| 		.setting = 0x01 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_MCB, | ||||
| 		.setting = 0x30 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRA1, | ||||
| 		.setting = 0x00 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRA2, | ||||
| 		.setting = 0xFF | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRA3, | ||||
| 		.setting = 0x01 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRB1, | ||||
| 		.setting = 0xBF | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRB2, | ||||
| 		.setting = 0xFF | ||||
| 	}, { | ||||
| 		.abreg = AB3100_IMRB3, | ||||
| 		.setting = 0xFF | ||||
| 	}, { | ||||
| 		.abreg = AB3100_SUP, | ||||
| 		.setting = 0x00 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_DIS, | ||||
| 		.setting = 0xF0 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_D0C, | ||||
| 		.setting = 0x00 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_D1C, | ||||
| 		.setting = 0x00 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_D2C, | ||||
| 		.setting = 0x00 | ||||
| 	}, { | ||||
| 		.abreg = AB3100_D3C, | ||||
| 		.setting = 0x00 | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int ab3100_setup(struct ab3100 *ab3100) | ||||
| { | ||||
| 	int err = 0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) { | ||||
| 		err = ab3100_set_register_interruptible(ab3100, | ||||
| 					  ab3100_init_settings[i].abreg, | ||||
| 					  ab3100_init_settings[i].setting); | ||||
| 		if (err) | ||||
| 			goto exit_no_setup; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Special trick to make the AB3100 use the 32kHz clock (RTC) | ||||
| 	 * bit 3 in test register 0x02 is a special, undocumented test | ||||
| 	 * register bit that only exist in AB3100 P1E | ||||
| 	 */ | ||||
| 	if (ab3100->chip_id == 0xc4) { | ||||
| 		dev_warn(ab3100->dev, | ||||
| 			 "AB3100 P1E variant detected forcing chip to 32KHz\n"); | ||||
| 		err = ab3100_set_test_register_interruptible(ab3100, | ||||
| 			0x02, 0x08); | ||||
| 	} | ||||
| 
 | ||||
|  exit_no_setup: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /* The subdevices of the AB3100 */ | ||||
| static struct mfd_cell ab3100_devs[] = { | ||||
| 	{ | ||||
| 		.name = "ab3100-dac", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-leds", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-power", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-regulators", | ||||
| 		.of_compatible = "stericsson,ab3100-regulators", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-sim", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-uart", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-rtc", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-charger", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-boost", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-adc", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-fuelgauge", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-vibrator", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-otp", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "ab3100-codec", | ||||
| 		.id = -1, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| struct ab_family_id { | ||||
| 	u8	id; | ||||
| 	char	*name; | ||||
| }; | ||||
| 
 | ||||
| static const struct ab_family_id ids[] = { | ||||
| 	/* AB3100 */ | ||||
| 	{ | ||||
| 		.id = 0xc0, | ||||
| 		.name = "P1A" | ||||
| 	}, { | ||||
| 		.id = 0xc1, | ||||
| 		.name = "P1B" | ||||
| 	}, { | ||||
| 		.id = 0xc2, | ||||
| 		.name = "P1C" | ||||
| 	}, { | ||||
| 		.id = 0xc3, | ||||
| 		.name = "P1D" | ||||
| 	}, { | ||||
| 		.id = 0xc4, | ||||
| 		.name = "P1E" | ||||
| 	}, { | ||||
| 		.id = 0xc5, | ||||
| 		.name = "P1F/R1A" | ||||
| 	}, { | ||||
| 		.id = 0xc6, | ||||
| 		.name = "P1G/R1A" | ||||
| 	}, { | ||||
| 		.id = 0xc7, | ||||
| 		.name = "P2A/R2A" | ||||
| 	}, { | ||||
| 		.id = 0xc8, | ||||
| 		.name = "P2B/R2B" | ||||
| 	}, | ||||
| 	/* AB3000 variants, not supported */ | ||||
| 	{ | ||||
| 		.id = 0xa0 | ||||
| 	}, { | ||||
| 		.id = 0xa1 | ||||
| 	}, { | ||||
| 		.id = 0xa2 | ||||
| 	}, { | ||||
| 		.id = 0xa3 | ||||
| 	}, { | ||||
| 		.id = 0xa4 | ||||
| 	}, { | ||||
| 		.id = 0xa5 | ||||
| 	}, { | ||||
| 		.id = 0xa6 | ||||
| 	}, { | ||||
| 		.id = 0xa7 | ||||
| 	}, | ||||
| 	/* Terminator */ | ||||
| 	{ | ||||
| 		.id = 0x00, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int ab3100_probe(struct i2c_client *client, | ||||
| 				  const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct ab3100 *ab3100; | ||||
| 	struct ab3100_platform_data *ab3100_plf_data = | ||||
| 		dev_get_platdata(&client->dev); | ||||
| 	int err; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL); | ||||
| 	if (!ab3100) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	/* Initialize data structure */ | ||||
| 	mutex_init(&ab3100->access_mutex); | ||||
| 	BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers); | ||||
| 
 | ||||
| 	ab3100->i2c_client = client; | ||||
| 	ab3100->dev = &ab3100->i2c_client->dev; | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, ab3100); | ||||
| 
 | ||||
| 	/* Read chip ID register */ | ||||
| 	err = ab3100_get_register_interruptible(ab3100, AB3100_CID, | ||||
| 						&ab3100->chip_id); | ||||
| 	if (err) { | ||||
| 		dev_err(&client->dev, | ||||
| 			"failed to communicate with AB3100 chip\n"); | ||||
| 		goto exit_no_detect; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; ids[i].id != 0x0; i++) { | ||||
| 		if (ids[i].id == ab3100->chip_id) { | ||||
| 			if (ids[i].name) | ||||
| 				break; | ||||
| 
 | ||||
| 			dev_err(&client->dev, "AB3000 is not supported\n"); | ||||
| 			goto exit_no_detect; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	snprintf(&ab3100->chip_name[0], | ||||
| 		 sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name); | ||||
| 
 | ||||
| 	if (ids[i].id == 0x0) { | ||||
| 		dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n", | ||||
| 			ab3100->chip_id); | ||||
| 		dev_err(&client->dev, | ||||
| 			"accepting it anyway. Please update the driver.\n"); | ||||
| 		goto exit_no_detect; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&client->dev, "Detected chip: %s\n", | ||||
| 		 &ab3100->chip_name[0]); | ||||
| 
 | ||||
| 	/* Attach a second dummy i2c_client to the test register address */ | ||||
| 	ab3100->testreg_client = i2c_new_dummy_device(client->adapter, | ||||
| 					       client->addr + 1); | ||||
| 	if (IS_ERR(ab3100->testreg_client)) { | ||||
| 		err = PTR_ERR(ab3100->testreg_client); | ||||
| 		goto exit_no_testreg_client; | ||||
| 	} | ||||
| 
 | ||||
| 	err = ab3100_setup(ab3100); | ||||
| 	if (err) | ||||
| 		goto exit_no_setup; | ||||
| 
 | ||||
| 	err = devm_request_threaded_irq(&client->dev, | ||||
| 					client->irq, NULL, ab3100_irq_handler, | ||||
| 					IRQF_ONESHOT, "ab3100-core", ab3100); | ||||
| 	if (err) | ||||
| 		goto exit_no_irq; | ||||
| 
 | ||||
| 	err = abx500_register_ops(&client->dev, &ab3100_ops); | ||||
| 	if (err) | ||||
| 		goto exit_no_ops; | ||||
| 
 | ||||
| 	/* Set up and register the platform devices. */ | ||||
| 	for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { | ||||
| 		ab3100_devs[i].platform_data = ab3100_plf_data; | ||||
| 		ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data); | ||||
| 	} | ||||
| 
 | ||||
| 	err = mfd_add_devices(&client->dev, 0, ab3100_devs, | ||||
| 			      ARRAY_SIZE(ab3100_devs), NULL, 0, NULL); | ||||
| 
 | ||||
| 	ab3100_setup_debugfs(ab3100); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
|  exit_no_ops: | ||||
|  exit_no_irq: | ||||
|  exit_no_setup: | ||||
| 	i2c_unregister_device(ab3100->testreg_client); | ||||
|  exit_no_testreg_client: | ||||
|  exit_no_detect: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static const struct i2c_device_id ab3100_id[] = { | ||||
| 	{ "ab3100", 0 }, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| static struct i2c_driver ab3100_driver = { | ||||
| 	.driver = { | ||||
| 		.name			= "ab3100", | ||||
| 		.suppress_bind_attrs	= true, | ||||
| 	}, | ||||
| 	.id_table	= ab3100_id, | ||||
| 	.probe		= ab3100_probe, | ||||
| }; | ||||
| 
 | ||||
| static int __init ab3100_i2c_init(void) | ||||
| { | ||||
| 	return i2c_add_driver(&ab3100_driver); | ||||
| } | ||||
| subsys_initcall(ab3100_i2c_init); | ||||
| @ -1,240 +0,0 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| /*
 | ||||
|  * drivers/mfd/ab3100_otp.c | ||||
|  * | ||||
|  * Copyright (C) 2007-2009 ST-Ericsson AB | ||||
|  * Driver to read out OTP from the AB3100 Mixed-signal circuit | ||||
|  * Author: Linus Walleij <linus.walleij@stericsson.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/module.h> | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/mfd/abx500.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/seq_file.h> | ||||
| 
 | ||||
| /* The OTP registers */ | ||||
| #define AB3100_OTP0		0xb0 | ||||
| #define AB3100_OTP1		0xb1 | ||||
| #define AB3100_OTP2		0xb2 | ||||
| #define AB3100_OTP3		0xb3 | ||||
| #define AB3100_OTP4		0xb4 | ||||
| #define AB3100_OTP5		0xb5 | ||||
| #define AB3100_OTP6		0xb6 | ||||
| #define AB3100_OTP7		0xb7 | ||||
| #define AB3100_OTPP		0xbf | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ab3100_otp | ||||
|  * @dev: containing device | ||||
|  * @locked: whether the OTP is locked, after locking, no more bits | ||||
|  *       can be changed but before locking it is still possible | ||||
|  *       to change bits from 1->0. | ||||
|  * @freq: clocking frequency for the OTP, this frequency is either | ||||
|  *       32768Hz or 1MHz/30 | ||||
|  * @paf: product activation flag, indicates whether this is a real | ||||
|  *       product (paf true) or a lab board etc (paf false) | ||||
|  * @imeich: if this is set it is possible to override the | ||||
|  *       IMEI number found in the tac, fac and svn fields with | ||||
|  *       (secured) software | ||||
|  * @cid: customer ID | ||||
|  * @tac: type allocation code of the IMEI | ||||
|  * @fac: final assembly code of the IMEI | ||||
|  * @svn: software version number of the IMEI | ||||
|  * @debugfs: a debugfs file used when dumping to file | ||||
|  */ | ||||
| struct ab3100_otp { | ||||
| 	struct device *dev; | ||||
| 	bool locked; | ||||
| 	u32 freq; | ||||
| 	bool paf; | ||||
| 	bool imeich; | ||||
| 	u16 cid:14; | ||||
| 	u32 tac:20; | ||||
| 	u8 fac; | ||||
| 	u32 svn:20; | ||||
| 	struct dentry *debugfs; | ||||
| }; | ||||
| 
 | ||||
| static int __init ab3100_otp_read(struct ab3100_otp *otp) | ||||
| { | ||||
| 	u8 otpval[8]; | ||||
| 	u8 otpp; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = abx500_get_register_interruptible(otp->dev, 0, | ||||
| 		AB3100_OTPP, &otpp); | ||||
| 	if (err) { | ||||
| 		dev_err(otp->dev, "unable to read OTPP register\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	err = abx500_get_register_page_interruptible(otp->dev, 0, | ||||
| 		AB3100_OTP0, otpval, 8); | ||||
| 	if (err) { | ||||
| 		dev_err(otp->dev, "unable to read OTP register page\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Cache OTP properties, they never change by nature */ | ||||
| 	otp->locked = (otpp & 0x80); | ||||
| 	otp->freq = (otpp & 0x40) ? 32768 : 34100; | ||||
| 	otp->paf = (otpval[1] & 0x80); | ||||
| 	otp->imeich = (otpval[1] & 0x40); | ||||
| 	otp->cid = ((otpval[1] << 8) | otpval[0]) & 0x3fff; | ||||
| 	otp->tac = ((otpval[4] & 0x0f) << 16) | (otpval[3] << 8) | otpval[2]; | ||||
| 	otp->fac = ((otpval[5] & 0x0f) << 4) | (otpval[4] >> 4); | ||||
| 	otp->svn = (otpval[7] << 12) | (otpval[6] << 4) | (otpval[5] >> 4); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * This is a simple debugfs human-readable file that dumps out | ||||
|  * the contents of the OTP. | ||||
|  */ | ||||
| #ifdef CONFIG_DEBUG_FS | ||||
| static int ab3100_show_otp(struct seq_file *s, void *v) | ||||
| { | ||||
| 	struct ab3100_otp *otp = s->private; | ||||
| 
 | ||||
| 	seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED"); | ||||
| 	seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq); | ||||
| 	seq_printf(s, "PAF is %s\n", otp->paf ? "SET" : "NOT SET"); | ||||
| 	seq_printf(s, "IMEI is %s\n", otp->imeich ? | ||||
| 		   "CHANGEABLE" : "NOT CHANGEABLE"); | ||||
| 	seq_printf(s, "CID: 0x%04x (decimal: %d)\n", otp->cid, otp->cid); | ||||
| 	seq_printf(s, "IMEI: %u-%u-%u\n", otp->tac, otp->fac, otp->svn); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ab3100_otp_open(struct inode *inode, struct file *file) | ||||
| { | ||||
| 	return single_open(file, ab3100_show_otp, inode->i_private); | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations ab3100_otp_operations = { | ||||
| 	.open		= ab3100_otp_open, | ||||
| 	.read		= seq_read, | ||||
| 	.llseek		= seq_lseek, | ||||
| 	.release	= single_release, | ||||
| }; | ||||
| 
 | ||||
| static void __init ab3100_otp_init_debugfs(struct device *dev, | ||||
| 					   struct ab3100_otp *otp) | ||||
| { | ||||
| 	otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO, | ||||
| 					   NULL, otp, &ab3100_otp_operations); | ||||
| } | ||||
| 
 | ||||
| static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) | ||||
| { | ||||
| 	debugfs_remove(otp->debugfs); | ||||
| } | ||||
| #else | ||||
| /* Compile this out if debugfs not selected */ | ||||
| static inline void __init ab3100_otp_init_debugfs(struct device *dev, | ||||
| 						  struct ab3100_otp *otp) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #define SHOW_AB3100_ATTR(name) \ | ||||
| static ssize_t ab3100_otp_##name##_show(struct device *dev, \ | ||||
| 			       struct device_attribute *attr, \ | ||||
| 			       char *buf) \ | ||||
| {\ | ||||
| 	struct ab3100_otp *otp = dev_get_drvdata(dev); \ | ||||
| 	return sprintf(buf, "%u\n", otp->name); \ | ||||
| } | ||||
| 
 | ||||
| SHOW_AB3100_ATTR(locked) | ||||
| SHOW_AB3100_ATTR(freq) | ||||
| SHOW_AB3100_ATTR(paf) | ||||
| SHOW_AB3100_ATTR(imeich) | ||||
| SHOW_AB3100_ATTR(cid) | ||||
| SHOW_AB3100_ATTR(fac) | ||||
| SHOW_AB3100_ATTR(tac) | ||||
| SHOW_AB3100_ATTR(svn) | ||||
| 
 | ||||
| static struct device_attribute ab3100_otp_attrs[] = { | ||||
| 	__ATTR(locked, S_IRUGO, ab3100_otp_locked_show, NULL), | ||||
| 	__ATTR(freq, S_IRUGO, ab3100_otp_freq_show, NULL), | ||||
| 	__ATTR(paf, S_IRUGO, ab3100_otp_paf_show, NULL), | ||||
| 	__ATTR(imeich, S_IRUGO, ab3100_otp_imeich_show, NULL), | ||||
| 	__ATTR(cid, S_IRUGO, ab3100_otp_cid_show, NULL), | ||||
| 	__ATTR(fac, S_IRUGO, ab3100_otp_fac_show, NULL), | ||||
| 	__ATTR(tac, S_IRUGO, ab3100_otp_tac_show, NULL), | ||||
| 	__ATTR(svn, S_IRUGO, ab3100_otp_svn_show, NULL), | ||||
| }; | ||||
| 
 | ||||
| static int __init ab3100_otp_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct ab3100_otp *otp; | ||||
| 	int err = 0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL); | ||||
| 	if (!otp) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	otp->dev = &pdev->dev; | ||||
| 
 | ||||
| 	/* Replace platform data coming in with a local struct */ | ||||
| 	platform_set_drvdata(pdev, otp); | ||||
| 
 | ||||
| 	err = ab3100_otp_read(otp); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	dev_info(&pdev->dev, "AB3100 OTP readout registered\n"); | ||||
| 
 | ||||
| 	/* sysfs entries */ | ||||
| 	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) { | ||||
| 		err = device_create_file(&pdev->dev, | ||||
| 					 &ab3100_otp_attrs[i]); | ||||
| 		if (err) | ||||
| 			goto err; | ||||
| 	} | ||||
| 
 | ||||
| 	/* debugfs entries */ | ||||
| 	ab3100_otp_init_debugfs(&pdev->dev, otp); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err: | ||||
| 	while (--i >= 0) | ||||
| 		device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int __exit ab3100_otp_remove(struct platform_device *pdev) | ||||
| { | ||||
| 	struct ab3100_otp *otp = platform_get_drvdata(pdev); | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) | ||||
| 		device_remove_file(&pdev->dev, | ||||
| 				   &ab3100_otp_attrs[i]); | ||||
| 	ab3100_otp_exit_debugfs(otp); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver ab3100_otp_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "ab3100-otp", | ||||
| 	}, | ||||
| 	.remove	 = __exit_p(ab3100_otp_remove), | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe); | ||||
| 
 | ||||
| MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | ||||
| MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -120,12 +120,6 @@ | ||||
| static DEFINE_SPINLOCK(on_stat_lock); | ||||
| static u8 turn_on_stat_mask = 0xFF; | ||||
| static u8 turn_on_stat_set; | ||||
| static bool no_bm; /* No battery management */ | ||||
| /*
 | ||||
|  * not really modular, but the easiest way to keep compat with existing | ||||
|  * bootargs behaviour is to continue using module_param here. | ||||
|  */ | ||||
| module_param(no_bm, bool, S_IRUGO); | ||||
| 
 | ||||
| #define AB9540_MODEM_CTRL2_REG			0x23 | ||||
| #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT	BIT(2) | ||||
| @ -1254,14 +1248,12 @@ static int ab8500_probe(struct platform_device *pdev) | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	if (!no_bm) { | ||||
| 		/* Add battery management devices */ | ||||
| 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, | ||||
| 				      ARRAY_SIZE(ab8500_bm_devs), NULL, | ||||
| 				      0, ab8500->domain); | ||||
| 		if (ret) | ||||
| 			dev_err(ab8500->dev, "error adding bm devices\n"); | ||||
| 	} | ||||
| 	/* Add battery management devices */ | ||||
| 	ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, | ||||
| 			      ARRAY_SIZE(ab8500_bm_devs), NULL, | ||||
| 			      0, ab8500->domain); | ||||
| 	if (ret) | ||||
| 		dev_err(ab8500->dev, "error adding bm devices\n"); | ||||
| 
 | ||||
| 	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && | ||||
| 			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) | ||||
|  | ||||
| @ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = { | ||||
| static const struct mfd_cell wm5102_devs[] = { | ||||
| 	{ .name = "arizona-micsupp" }, | ||||
| 	{ .name = "arizona-gpio" }, | ||||
| 	{ | ||||
| 		.name = "arizona-extcon", | ||||
| 		.parent_supplies = wm5102_supplies, | ||||
| 		.num_parent_supplies = 1, /* We only need MICVDD */ | ||||
| 	}, | ||||
| 	{ .name = "arizona-haptics" }, | ||||
| 	{ .name = "arizona-pwm" }, | ||||
| 	{ | ||||
| @ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = { | ||||
| static const struct mfd_cell wm5110_devs[] = { | ||||
| 	{ .name = "arizona-micsupp" }, | ||||
| 	{ .name = "arizona-gpio" }, | ||||
| 	{ | ||||
| 		.name = "arizona-extcon", | ||||
| 		.parent_supplies = wm5102_supplies, | ||||
| 		.num_parent_supplies = 1, /* We only need MICVDD */ | ||||
| 	}, | ||||
| 	{ .name = "arizona-haptics" }, | ||||
| 	{ .name = "arizona-pwm" }, | ||||
| 	{ | ||||
| @ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = { | ||||
| static const struct mfd_cell wm8997_devs[] = { | ||||
| 	{ .name = "arizona-micsupp" }, | ||||
| 	{ .name = "arizona-gpio" }, | ||||
| 	{ | ||||
| 		.name = "arizona-extcon", | ||||
| 		.parent_supplies = wm8997_supplies, | ||||
| 		.num_parent_supplies = 1, /* We only need MICVDD */ | ||||
| 	}, | ||||
| 	{ .name = "arizona-haptics" }, | ||||
| 	{ .name = "arizona-pwm" }, | ||||
| 	{ | ||||
| @ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = { | ||||
| static const struct mfd_cell wm8998_devs[] = { | ||||
| 	{ .name = "arizona-micsupp" }, | ||||
| 	{ .name = "arizona-gpio" }, | ||||
| 	{ | ||||
| 		.name = "arizona-extcon", | ||||
| 		.parent_supplies = wm5102_supplies, | ||||
| 		.num_parent_supplies = 1, /* We only need MICVDD */ | ||||
| 	}, | ||||
| 	{ .name = "arizona-haptics" }, | ||||
| 	{ .name = "arizona-pwm" }, | ||||
| 	{ | ||||
|  | ||||
| @ -100,7 +100,7 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) | ||||
| 	unsigned int val; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = pm_runtime_get_sync(arizona->dev); | ||||
| 	ret = pm_runtime_resume_and_get(arizona->dev); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(arizona->dev, "Failed to resume device: %d\n", ret); | ||||
| 		return IRQ_NONE; | ||||
|  | ||||
| @ -25,8 +25,8 @@ | ||||
| #include "arizona.h" | ||||
| 
 | ||||
| #ifdef CONFIG_ACPI | ||||
| const struct acpi_gpio_params reset_gpios = { 1, 0, false }; | ||||
| const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; | ||||
| static const struct acpi_gpio_params reset_gpios = { 1, 0, false }; | ||||
| static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; | ||||
| 
 | ||||
| static const struct acpi_gpio_mapping arizona_acpi_gpios[] = { | ||||
| 	{ "reset-gpios", &reset_gpios, 1, }, | ||||
|  | ||||
							
								
								
									
										310
									
								
								drivers/mfd/atc260x-core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										310
									
								
								drivers/mfd/atc260x-core.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,310 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * Core support for ATC260x PMICs | ||||
|  * | ||||
|  * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
|  * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/mfd/atc260x/core.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| #define ATC260X_CHIP_REV_MAX	31 | ||||
| 
 | ||||
| struct atc260x_init_regs { | ||||
| 	unsigned int cmu_devrst; | ||||
| 	unsigned int cmu_devrst_ints; | ||||
| 	unsigned int ints_msk; | ||||
| 	unsigned int pad_en; | ||||
| 	unsigned int pad_en_extirq; | ||||
| }; | ||||
| 
 | ||||
| static void regmap_lock_mutex(void *__mutex) | ||||
| { | ||||
| 	struct mutex *mutex = __mutex; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Using regmap within an atomic context (e.g. accessing a PMIC when | ||||
| 	 * powering system down) is normally allowed only if the regmap type | ||||
| 	 * is MMIO and the regcache type is either REGCACHE_NONE or | ||||
| 	 * REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is | ||||
| 	 * internally protected by a mutex which is acquired non-atomically. | ||||
| 	 * | ||||
| 	 * Let's improve this by using a customized locking scheme inspired | ||||
| 	 * from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a | ||||
| 	 * starting point. | ||||
| 	 */ | ||||
| 	if (system_state > SYSTEM_RUNNING && irqs_disabled()) | ||||
| 		mutex_trylock(mutex); | ||||
| 	else | ||||
| 		mutex_lock(mutex); | ||||
| } | ||||
| 
 | ||||
| static void regmap_unlock_mutex(void *__mutex) | ||||
| { | ||||
| 	struct mutex *mutex = __mutex; | ||||
| 
 | ||||
| 	mutex_unlock(mutex); | ||||
| } | ||||
| 
 | ||||
| static const struct regmap_config atc2603c_regmap_config = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 16, | ||||
| 	.max_register = ATC2603C_SADDR, | ||||
| 	.cache_type = REGCACHE_NONE, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_config atc2609a_regmap_config = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 16, | ||||
| 	.max_register = ATC2609A_SADDR, | ||||
| 	.cache_type = REGCACHE_NONE, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_irq atc2603c_regmap_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO,	0, ATC2603C_INTS_MSK_AUDIO), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_OV,		0, ATC2603C_INTS_MSK_OV), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_OC,		0, ATC2603C_INTS_MSK_OC), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_OT,		0, ATC2603C_INTS_MSK_OT), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_UV,		0, ATC2603C_INTS_MSK_UV), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM,	0, ATC2603C_INTS_MSK_ALARM), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF,	0, ATC2603C_INTS_MSK_ONOFF), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO,	0, ATC2603C_INTS_MSK_SGPIO), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_IR,		0, ATC2603C_INTS_MSK_IR), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON,	0, ATC2603C_INTS_MSK_REMCON), | ||||
| 	REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN,	0, ATC2603C_INTS_MSK_POWERIN), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_irq atc2609a_regmap_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO,	0, ATC2609A_INTS_MSK_AUDIO), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_OV,		0, ATC2609A_INTS_MSK_OV), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_OC,		0, ATC2609A_INTS_MSK_OC), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_OT,		0, ATC2609A_INTS_MSK_OT), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_UV,		0, ATC2609A_INTS_MSK_UV), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM,	0, ATC2609A_INTS_MSK_ALARM), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF,	0, ATC2609A_INTS_MSK_ONOFF), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP,	0, ATC2609A_INTS_MSK_WKUP), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_IR,		0, ATC2609A_INTS_MSK_IR), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON,	0, ATC2609A_INTS_MSK_REMCON), | ||||
| 	REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN,	0, ATC2609A_INTS_MSK_POWERIN), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_irq_chip atc2603c_regmap_irq_chip = { | ||||
| 	.name = "atc2603c", | ||||
| 	.irqs = atc2603c_regmap_irqs, | ||||
| 	.num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs), | ||||
| 	.num_regs = 1, | ||||
| 	.status_base = ATC2603C_INTS_PD, | ||||
| 	.mask_base = ATC2603C_INTS_MSK, | ||||
| 	.mask_invert = true, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_irq_chip atc2609a_regmap_irq_chip = { | ||||
| 	.name = "atc2609a", | ||||
| 	.irqs = atc2609a_regmap_irqs, | ||||
| 	.num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs), | ||||
| 	.num_regs = 1, | ||||
| 	.status_base = ATC2609A_INTS_PD, | ||||
| 	.mask_base = ATC2609A_INTS_MSK, | ||||
| 	.mask_invert = true, | ||||
| }; | ||||
| 
 | ||||
| static const struct resource atc2603c_onkey_resources[] = { | ||||
| 	DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF), | ||||
| }; | ||||
| 
 | ||||
| static const struct resource atc2609a_onkey_resources[] = { | ||||
| 	DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF), | ||||
| }; | ||||
| 
 | ||||
| static const struct mfd_cell atc2603c_mfd_cells[] = { | ||||
| 	{ .name = "atc260x-regulator" }, | ||||
| 	{ .name = "atc260x-pwrc" }, | ||||
| 	{ | ||||
| 		.name = "atc260x-onkey", | ||||
| 		.num_resources = ARRAY_SIZE(atc2603c_onkey_resources), | ||||
| 		.resources = atc2603c_onkey_resources, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct mfd_cell atc2609a_mfd_cells[] = { | ||||
| 	{ .name = "atc260x-regulator" }, | ||||
| 	{ .name = "atc260x-pwrc" }, | ||||
| 	{ | ||||
| 		.name = "atc260x-onkey", | ||||
| 		.num_resources = ARRAY_SIZE(atc2609a_onkey_resources), | ||||
| 		.resources = atc2609a_onkey_resources, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct atc260x_init_regs atc2603c_init_regs = { | ||||
| 	.cmu_devrst = ATC2603C_CMU_DEVRST, | ||||
| 	.cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS, | ||||
| 	.ints_msk = ATC2603C_INTS_MSK, | ||||
| 	.pad_en = ATC2603C_PAD_EN, | ||||
| 	.pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ, | ||||
| }; | ||||
| 
 | ||||
| static const struct atc260x_init_regs atc2609a_init_regs = { | ||||
| 	.cmu_devrst = ATC2609A_CMU_DEVRST, | ||||
| 	.cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS, | ||||
| 	.ints_msk = ATC2609A_INTS_MSK, | ||||
| 	.pad_en = ATC2609A_PAD_EN, | ||||
| 	.pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ, | ||||
| }; | ||||
| 
 | ||||
| static void atc260x_cmu_reset(struct atc260x *atc260x) | ||||
| { | ||||
| 	const struct atc260x_init_regs *regs = atc260x->init_regs; | ||||
| 
 | ||||
| 	/* Assert reset */ | ||||
| 	regmap_update_bits(atc260x->regmap, regs->cmu_devrst, | ||||
| 			   regs->cmu_devrst_ints, ~regs->cmu_devrst_ints); | ||||
| 
 | ||||
| 	/* De-assert reset */ | ||||
| 	regmap_update_bits(atc260x->regmap, regs->cmu_devrst, | ||||
| 			   regs->cmu_devrst_ints, regs->cmu_devrst_ints); | ||||
| } | ||||
| 
 | ||||
| static void atc260x_dev_init(struct atc260x *atc260x) | ||||
| { | ||||
| 	const struct atc260x_init_regs *regs = atc260x->init_regs; | ||||
| 
 | ||||
| 	/* Initialize interrupt block */ | ||||
| 	atc260x_cmu_reset(atc260x); | ||||
| 
 | ||||
| 	/* Disable all interrupt sources */ | ||||
| 	regmap_write(atc260x->regmap, regs->ints_msk, 0); | ||||
| 
 | ||||
| 	/* Enable EXTIRQ pad */ | ||||
| 	regmap_update_bits(atc260x->regmap, regs->pad_en, | ||||
| 			   regs->pad_en_extirq, regs->pad_en_extirq); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * atc260x_match_device(): Setup ATC260x variant related fields | ||||
|  * | ||||
|  * @atc260x: ATC260x device to setup (.dev field must be set) | ||||
|  * @regmap_cfg: regmap config associated with this ATC260x device | ||||
|  * | ||||
|  * This lets the ATC260x core configure the MFD cells and register maps | ||||
|  * for later use. | ||||
|  */ | ||||
| int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg) | ||||
| { | ||||
| 	struct device *dev = atc260x->dev; | ||||
| 	const void *of_data; | ||||
| 
 | ||||
| 	of_data = of_device_get_match_data(dev); | ||||
| 	if (!of_data) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	atc260x->ic_type = (unsigned long)of_data; | ||||
| 
 | ||||
| 	switch (atc260x->ic_type) { | ||||
| 	case ATC2603C: | ||||
| 		*regmap_cfg = atc2603c_regmap_config; | ||||
| 		atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip; | ||||
| 		atc260x->cells = atc2603c_mfd_cells; | ||||
| 		atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells); | ||||
| 		atc260x->type_name = "atc2603c"; | ||||
| 		atc260x->rev_reg = ATC2603C_CHIP_VER; | ||||
| 		atc260x->init_regs = &atc2603c_init_regs; | ||||
| 		break; | ||||
| 	case ATC2609A: | ||||
| 		*regmap_cfg = atc2609a_regmap_config; | ||||
| 		atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip; | ||||
| 		atc260x->cells = atc2609a_mfd_cells; | ||||
| 		atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells); | ||||
| 		atc260x->type_name = "atc2609a"; | ||||
| 		atc260x->rev_reg = ATC2609A_CHIP_VER; | ||||
| 		atc260x->init_regs = &atc2609a_init_regs; | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(dev, "Unsupported ATC260x device type: %u\n", | ||||
| 			atc260x->ic_type); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex), | ||||
| 					     GFP_KERNEL); | ||||
| 	if (!atc260x->regmap_mutex) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	mutex_init(atc260x->regmap_mutex); | ||||
| 
 | ||||
| 	regmap_cfg->lock = regmap_lock_mutex, | ||||
| 	regmap_cfg->unlock = regmap_unlock_mutex, | ||||
| 	regmap_cfg->lock_arg = atc260x->regmap_mutex; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(atc260x_match_device); | ||||
| 
 | ||||
| /**
 | ||||
|  * atc260x_device_probe(): Probe a configured ATC260x device | ||||
|  * | ||||
|  * @atc260x: ATC260x device to probe (must be configured) | ||||
|  * | ||||
|  * This function lets the ATC260x core register the ATC260x MFD devices | ||||
|  * and IRQCHIP. The ATC260x device passed in must be fully configured | ||||
|  * with atc260x_match_device, its IRQ set, and regmap created. | ||||
|  */ | ||||
| int atc260x_device_probe(struct atc260x *atc260x) | ||||
| { | ||||
| 	struct device *dev = atc260x->dev; | ||||
| 	unsigned int chip_rev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!atc260x->irq) { | ||||
| 		dev_err(dev, "No interrupt support\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Initialize the hardware */ | ||||
| 	atc260x_dev_init(atc260x); | ||||
| 
 | ||||
| 	ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to get chip revision\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (chip_rev > ATC260X_CHIP_REV_MAX) { | ||||
| 		dev_err(dev, "Unknown chip revision: %u\n", chip_rev); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	atc260x->ic_ver = __ffs(chip_rev + 1U); | ||||
| 
 | ||||
| 	dev_info(dev, "Detected chip type %s rev.%c\n", | ||||
| 		 atc260x->type_name, 'A' + atc260x->ic_ver); | ||||
| 
 | ||||
| 	ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT, | ||||
| 				       -1, atc260x->regmap_irq_chip, &atc260x->irq_data); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to add IRQ chip: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | ||||
| 				   atc260x->cells, atc260x->nr_cells, NULL, 0, | ||||
| 				   regmap_irq_get_domain(atc260x->irq_data)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to add child devices: %d\n", ret); | ||||
| 		regmap_del_irq_chip(atc260x->irq, atc260x->irq_data); | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(atc260x_device_probe); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("ATC260x PMICs Core support"); | ||||
| MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); | ||||
| MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"); | ||||
| MODULE_LICENSE("GPL"); | ||||
							
								
								
									
										64
									
								
								drivers/mfd/atc260x-i2c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								drivers/mfd/atc260x-i2c.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,64 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * I2C bus interface for ATC260x PMICs | ||||
|  * | ||||
|  * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
|  * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/mfd/atc260x/core.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| static int atc260x_i2c_probe(struct i2c_client *client, | ||||
| 			     const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct atc260x *atc260x; | ||||
| 	struct regmap_config regmap_cfg; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	atc260x = devm_kzalloc(&client->dev, sizeof(*atc260x), GFP_KERNEL); | ||||
| 	if (!atc260x) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	atc260x->dev = &client->dev; | ||||
| 	atc260x->irq = client->irq; | ||||
| 
 | ||||
| 	ret = atc260x_match_device(atc260x, ®map_cfg); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, atc260x); | ||||
| 
 | ||||
| 	atc260x->regmap = devm_regmap_init_i2c(client, ®map_cfg); | ||||
| 	if (IS_ERR(atc260x->regmap)) { | ||||
| 		ret = PTR_ERR(atc260x->regmap); | ||||
| 		dev_err(&client->dev, "failed to init regmap: %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return atc260x_device_probe(atc260x); | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id atc260x_i2c_of_match[] = { | ||||
| 	{ .compatible = "actions,atc2603c", .data = (void *)ATC2603C }, | ||||
| 	{ .compatible = "actions,atc2609a", .data = (void *)ATC2609A }, | ||||
| 	{ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match); | ||||
| 
 | ||||
| static struct i2c_driver atc260x_i2c_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "atc260x", | ||||
| 		.of_match_table	= of_match_ptr(atc260x_i2c_of_match), | ||||
| 	}, | ||||
| 	.probe = atc260x_i2c_probe, | ||||
| }; | ||||
| module_i2c_driver(atc260x_i2c_driver); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("ATC260x PMICs I2C bus interface"); | ||||
| MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); | ||||
| MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -442,6 +442,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c, | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	/* If SMBus is not available and only I2C is possible, enter I2C mode */ | ||||
| 	if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { | ||||
| 		ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J, | ||||
| 					DA9063_TWOWIRE_TO); | ||||
| 		if (ret < 0) { | ||||
| 			dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n"); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return da9063_device_init(da9063, i2c->irq); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -33,7 +33,7 @@ struct kb3930 { | ||||
| 	struct gpio_descs *off_gpios; | ||||
| }; | ||||
| 
 | ||||
| struct kb3930 *kb3930_power_off; | ||||
| static struct kb3930 *kb3930_power_off; | ||||
| 
 | ||||
| #define EC_GPIO_WAVE		0 | ||||
| #define EC_GPIO_OFF_MODE	1 | ||||
|  | ||||
| @ -22,55 +22,71 @@ static const struct intel_lpss_platform_info spt_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry spt_i2c_properties[] = { | ||||
| static const struct property_entry spt_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info spt_i2c_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| static const struct software_node spt_i2c_node = { | ||||
| 	.properties = spt_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry uart_properties[] = { | ||||
| static const struct intel_lpss_platform_info spt_i2c_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| 	.swnode = &spt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry uart_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("reg-io-width", 4), | ||||
| 	PROPERTY_ENTRY_U32("reg-shift", 2), | ||||
| 	PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node uart_node = { | ||||
| 	.properties = uart_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info spt_uart_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| 	.clk_con_id = "baudclk", | ||||
| 	.properties = uart_properties, | ||||
| 	.swnode = &uart_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info bxt_info = { | ||||
| 	.clk_rate = 100000000, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry bxt_i2c_properties[] = { | ||||
| static const struct property_entry bxt_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42), | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), | ||||
| 	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info bxt_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| static const struct software_node bxt_i2c_node = { | ||||
| 	.properties = bxt_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry apl_i2c_properties[] = { | ||||
| static const struct intel_lpss_platform_info bxt_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| 	.swnode = &bxt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry apl_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207), | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), | ||||
| 	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node apl_i2c_node = { | ||||
| 	.properties = apl_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info apl_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| 	.properties = apl_i2c_properties, | ||||
| 	.swnode = &apl_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct acpi_device_id intel_lpss_acpi_ids[] = { | ||||
|  | ||||
| @ -65,27 +65,35 @@ static const struct intel_lpss_platform_info spt_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry spt_i2c_properties[] = { | ||||
| static const struct property_entry spt_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info spt_i2c_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| static const struct software_node spt_i2c_node = { | ||||
| 	.properties = spt_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry uart_properties[] = { | ||||
| static const struct intel_lpss_platform_info spt_i2c_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| 	.swnode = &spt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry uart_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("reg-io-width", 4), | ||||
| 	PROPERTY_ENTRY_U32("reg-shift", 2), | ||||
| 	PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node uart_node = { | ||||
| 	.properties = uart_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info spt_uart_info = { | ||||
| 	.clk_rate = 120000000, | ||||
| 	.clk_con_id = "baudclk", | ||||
| 	.properties = uart_properties, | ||||
| 	.swnode = &uart_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info bxt_info = { | ||||
| @ -95,53 +103,65 @@ static const struct intel_lpss_platform_info bxt_info = { | ||||
| static const struct intel_lpss_platform_info bxt_uart_info = { | ||||
| 	.clk_rate = 100000000, | ||||
| 	.clk_con_id = "baudclk", | ||||
| 	.properties = uart_properties, | ||||
| 	.swnode = &uart_node, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry bxt_i2c_properties[] = { | ||||
| static const struct property_entry bxt_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42), | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), | ||||
| 	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info bxt_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| static const struct software_node bxt_i2c_node = { | ||||
| 	.properties = bxt_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry apl_i2c_properties[] = { | ||||
| static const struct intel_lpss_platform_info bxt_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| 	.swnode = &bxt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry apl_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207), | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), | ||||
| 	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info apl_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| static const struct software_node apl_i2c_node = { | ||||
| 	.properties = apl_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static struct property_entry glk_i2c_properties[] = { | ||||
| static const struct intel_lpss_platform_info apl_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| 	.swnode = &apl_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry glk_i2c_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313), | ||||
| 	PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), | ||||
| 	PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290), | ||||
| 	{ }, | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node glk_i2c_node = { | ||||
| 	.properties = glk_i2c_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info glk_i2c_info = { | ||||
| 	.clk_rate = 133000000, | ||||
| 	.properties = glk_i2c_properties, | ||||
| 	.swnode = &glk_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info cnl_i2c_info = { | ||||
| 	.clk_rate = 216000000, | ||||
| 	.properties = spt_i2c_properties, | ||||
| 	.swnode = &spt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct intel_lpss_platform_info ehl_i2c_info = { | ||||
| 	.clk_rate = 100000000, | ||||
| 	.properties = bxt_i2c_properties, | ||||
| 	.swnode = &bxt_i2c_node, | ||||
| }; | ||||
| 
 | ||||
| static const struct pci_device_id intel_lpss_pci_ids[] = { | ||||
|  | ||||
| @ -399,7 +399,7 @@ int intel_lpss_probe(struct device *dev, | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	lpss->cell->properties = info->properties; | ||||
| 	lpss->cell->swnode = info->swnode; | ||||
| 
 | ||||
| 	intel_lpss_init_dev(lpss); | ||||
| 
 | ||||
|  | ||||
| @ -15,14 +15,14 @@ | ||||
| 
 | ||||
| struct device; | ||||
| struct resource; | ||||
| struct property_entry; | ||||
| struct software_node; | ||||
| 
 | ||||
| struct intel_lpss_platform_info { | ||||
| 	struct resource *mem; | ||||
| 	int irq; | ||||
| 	unsigned long clk_rate; | ||||
| 	const char *clk_con_id; | ||||
| 	struct property_entry *properties; | ||||
| 	const struct software_node *swnode; | ||||
| }; | ||||
| 
 | ||||
| int intel_lpss_probe(struct device *dev, | ||||
|  | ||||
| @ -28,10 +28,23 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = { | ||||
| 	{ .name = "n3000bmc-secure" }, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_range m10bmc_regmap_range[] = { | ||||
| 	regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), | ||||
| 	regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), | ||||
| 	regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_access_table m10bmc_access_table = { | ||||
| 	.yes_ranges	= m10bmc_regmap_range, | ||||
| 	.n_yes_ranges	= ARRAY_SIZE(m10bmc_regmap_range), | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_config intel_m10bmc_regmap_config = { | ||||
| 	.reg_bits = 32, | ||||
| 	.val_bits = 32, | ||||
| 	.reg_stride = 4, | ||||
| 	.wr_table = &m10bmc_access_table, | ||||
| 	.rd_table = &m10bmc_access_table, | ||||
| 	.max_register = M10BMC_MEM_END, | ||||
| }; | ||||
| 
 | ||||
| @ -121,17 +134,14 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata) | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This check is to filter out the very old legacy BMC versions, | ||||
| 	 * M10BMC_LEGACY_SYS_BASE is the offset to this old block of mmio | ||||
| 	 * registers. In the old BMC chips, the BMC version info is stored | ||||
| 	 * in this old version register (M10BMC_LEGACY_SYS_BASE + | ||||
| 	 * M10BMC_BUILD_VER), so its read out value would have not been | ||||
| 	 * LEGACY_INVALID (0xffffffff). But in new BMC chips that the | ||||
| 	 * driver supports, the value of this register should be | ||||
| 	 * LEGACY_INVALID. | ||||
| 	 * This check is to filter out the very old legacy BMC versions. In the | ||||
| 	 * old BMC chips, the BMC version info is stored in the old version | ||||
| 	 * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have | ||||
| 	 * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC | ||||
| 	 * chips that the driver supports, the value of this register should be | ||||
| 	 * M10BMC_VER_LEGACY_INVALID. | ||||
| 	 */ | ||||
| 	ret = m10bmc_raw_read(ddata, | ||||
| 			      M10BMC_LEGACY_SYS_BASE + M10BMC_BUILD_VER, &v); | ||||
| 	ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v); | ||||
| 	if (ret) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
|  | ||||
| @ -16,8 +16,9 @@ | ||||
| #include <linux/clkdev.h> | ||||
| #include <linux/clk-provider.h> | ||||
| #include <linux/dmi.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/platform_data/gpio-dwapb.h> | ||||
| #include <linux/platform_data/i2c-designware.h> | ||||
| #include <linux/property.h> | ||||
| 
 | ||||
| /* PCI BAR for register base address */ | ||||
| #define MFD_I2C_BAR		0 | ||||
| @ -45,29 +46,48 @@ | ||||
| #define INTEL_QUARK_I2C_CLK_HZ	33000000 | ||||
| 
 | ||||
| struct intel_quark_mfd { | ||||
| 	struct device		*dev; | ||||
| 	struct clk		*i2c_clk; | ||||
| 	struct clk_lookup	*i2c_clk_lookup; | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry intel_quark_i2c_controller_standard_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ), | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node intel_quark_i2c_controller_standard_node = { | ||||
| 	.name = "intel-quark-i2c-controller", | ||||
| 	.properties = intel_quark_i2c_controller_standard_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct property_entry intel_quark_i2c_controller_fast_properties[] = { | ||||
| 	PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ), | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| static const struct software_node intel_quark_i2c_controller_fast_node = { | ||||
| 	.name = "intel-quark-i2c-controller", | ||||
| 	.properties = intel_quark_i2c_controller_fast_properties, | ||||
| }; | ||||
| 
 | ||||
| static const struct dmi_system_id dmi_platform_info[] = { | ||||
| 	{ | ||||
| 		.matches = { | ||||
| 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), | ||||
| 		}, | ||||
| 		.driver_data = (void *)100000, | ||||
| 		.driver_data = (void *)&intel_quark_i2c_controller_standard_node, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.matches = { | ||||
| 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), | ||||
| 		}, | ||||
| 		.driver_data = (void *)400000, | ||||
| 		.driver_data = (void *)&intel_quark_i2c_controller_fast_node, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.matches = { | ||||
| 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), | ||||
| 		}, | ||||
| 		.driver_data = (void *)400000, | ||||
| 		.driver_data = (void *)&intel_quark_i2c_controller_fast_node, | ||||
| 	}, | ||||
| 	{} | ||||
| }; | ||||
| @ -98,15 +118,7 @@ static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { | ||||
| }; | ||||
| 
 | ||||
| static struct mfd_cell intel_quark_mfd_cells[] = { | ||||
| 	{ | ||||
| 		.id = MFD_GPIO_BAR, | ||||
| 		.name = "gpio-dwapb", | ||||
| 		.acpi_match = &intel_quark_acpi_match_gpio, | ||||
| 		.num_resources = ARRAY_SIZE(intel_quark_gpio_res), | ||||
| 		.resources = intel_quark_gpio_res, | ||||
| 		.ignore_resource_conflicts = true, | ||||
| 	}, | ||||
| 	{ | ||||
| 	[MFD_I2C_BAR] = { | ||||
| 		.id = MFD_I2C_BAR, | ||||
| 		.name = "i2c_designware", | ||||
| 		.acpi_match = &intel_quark_acpi_match_i2c, | ||||
| @ -114,6 +126,14 @@ static struct mfd_cell intel_quark_mfd_cells[] = { | ||||
| 		.resources = intel_quark_i2c_res, | ||||
| 		.ignore_resource_conflicts = true, | ||||
| 	}, | ||||
| 	[MFD_GPIO_BAR] = { | ||||
| 		.id = MFD_GPIO_BAR, | ||||
| 		.name = "gpio-dwapb", | ||||
| 		.acpi_match = &intel_quark_acpi_match_gpio, | ||||
| 		.num_resources = ARRAY_SIZE(intel_quark_gpio_res), | ||||
| 		.resources = intel_quark_gpio_res, | ||||
| 		.ignore_resource_conflicts = true, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct pci_device_id intel_quark_mfd_ids[] = { | ||||
| @ -157,48 +177,37 @@ static void intel_quark_unregister_i2c_clk(struct device *dev) | ||||
| 	clk_unregister(quark_mfd->i2c_clk); | ||||
| } | ||||
| 
 | ||||
| static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) | ||||
| static int intel_quark_i2c_setup(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR]; | ||||
| 	struct resource *res = intel_quark_i2c_res; | ||||
| 	const struct dmi_system_id *dmi_id; | ||||
| 	struct dw_i2c_platform_data *pdata; | ||||
| 	struct resource *res = (struct resource *)cell->resources; | ||||
| 	struct device *dev = &pdev->dev; | ||||
| 
 | ||||
| 	res[INTEL_QUARK_IORES_MEM].start = | ||||
| 		pci_resource_start(pdev, MFD_I2C_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].end = | ||||
| 		pci_resource_end(pdev, MFD_I2C_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); | ||||
| 
 | ||||
| 	res[INTEL_QUARK_IORES_IRQ].start = pdev->irq; | ||||
| 	res[INTEL_QUARK_IORES_IRQ].end = pdev->irq; | ||||
| 
 | ||||
| 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||||
| 	if (!pdata) | ||||
| 		return -ENOMEM; | ||||
| 	res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); | ||||
| 	res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); | ||||
| 
 | ||||
| 	/* Normal mode by default */ | ||||
| 	pdata->i2c_scl_freq = 100000; | ||||
| 	cell->swnode = &intel_quark_i2c_controller_standard_node; | ||||
| 
 | ||||
| 	dmi_id = dmi_first_match(dmi_platform_info); | ||||
| 	if (dmi_id) | ||||
| 		pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data; | ||||
| 
 | ||||
| 	cell->platform_data = pdata; | ||||
| 	cell->pdata_size = sizeof(*pdata); | ||||
| 		cell->swnode = (struct software_node *)dmi_id->driver_data; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) | ||||
| static int intel_quark_gpio_setup(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR]; | ||||
| 	struct resource *res = intel_quark_gpio_res; | ||||
| 	struct dwapb_platform_data *pdata; | ||||
| 	struct resource *res = (struct resource *)cell->resources; | ||||
| 	struct device *dev = &pdev->dev; | ||||
| 
 | ||||
| 	res[INTEL_QUARK_IORES_MEM].start = | ||||
| 		pci_resource_start(pdev, MFD_GPIO_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].end = | ||||
| 		pci_resource_end(pdev, MFD_GPIO_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR); | ||||
| 	res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR); | ||||
| 
 | ||||
| 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||||
| 	if (!pdata) | ||||
| @ -217,7 +226,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) | ||||
| 	pdata->properties->idx		= 0; | ||||
| 	pdata->properties->ngpio	= INTEL_QUARK_MFD_NGPIO; | ||||
| 	pdata->properties->gpio_base	= INTEL_QUARK_MFD_GPIO_BASE; | ||||
| 	pdata->properties->irq[0]	= pdev->irq; | ||||
| 	pdata->properties->irq[0]	= pci_irq_vector(pdev, 0); | ||||
| 	pdata->properties->irq_shared	= true; | ||||
| 
 | ||||
| 	cell->platform_data = pdata; | ||||
| @ -240,29 +249,37 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, | ||||
| 	if (!quark_mfd) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	quark_mfd->dev = &pdev->dev; | ||||
| 	dev_set_drvdata(&pdev->dev, quark_mfd); | ||||
| 
 | ||||
| 	ret = intel_quark_register_i2c_clk(&pdev->dev); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); | ||||
| 	if (ret) | ||||
| 	pci_set_master(pdev); | ||||
| 
 | ||||
| 	/* This driver only requires 1 IRQ vector */ | ||||
| 	ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); | ||||
| 	if (ret < 0) | ||||
| 		goto err_unregister_i2c_clk; | ||||
| 
 | ||||
| 	ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); | ||||
| 	ret = intel_quark_i2c_setup(pdev); | ||||
| 	if (ret) | ||||
| 		goto err_unregister_i2c_clk; | ||||
| 		goto err_free_irq_vectors; | ||||
| 
 | ||||
| 	ret = intel_quark_gpio_setup(pdev); | ||||
| 	if (ret) | ||||
| 		goto err_free_irq_vectors; | ||||
| 
 | ||||
| 	ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, | ||||
| 			      ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, | ||||
| 			      NULL); | ||||
| 	if (ret) | ||||
| 		goto err_unregister_i2c_clk; | ||||
| 		goto err_free_irq_vectors; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free_irq_vectors: | ||||
| 	pci_free_irq_vectors(pdev); | ||||
| err_unregister_i2c_clk: | ||||
| 	intel_quark_unregister_i2c_clk(&pdev->dev); | ||||
| 	return ret; | ||||
| @ -270,8 +287,9 @@ err_unregister_i2c_clk: | ||||
| 
 | ||||
| static void intel_quark_mfd_remove(struct pci_dev *pdev) | ||||
| { | ||||
| 	intel_quark_unregister_i2c_clk(&pdev->dev); | ||||
| 	mfd_remove_devices(&pdev->dev); | ||||
| 	pci_free_irq_vectors(pdev); | ||||
| 	intel_quark_unregister_i2c_clk(&pdev->dev); | ||||
| } | ||||
| 
 | ||||
| static struct pci_driver intel_quark_mfd_driver = { | ||||
|  | ||||
| @ -358,7 +358,7 @@ static struct attribute *lm3533_attributes[] = { | ||||
| static umode_t lm3533_attr_is_visible(struct kobject *kobj, | ||||
| 					     struct attribute *attr, int n) | ||||
| { | ||||
| 	struct device *dev = container_of(kobj, struct device, kobj); | ||||
| 	struct device *dev = kobj_to_dev(kobj); | ||||
| 	struct lm3533 *lm3533 = dev_get_drvdata(dev); | ||||
| 	struct device_attribute *dattr = to_dev_attr(attr); | ||||
| 	struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr); | ||||
|  | ||||
| @ -26,9 +26,6 @@ | ||||
| #define GPIO_IO_SIZE	64 | ||||
| #define GPIO_IO_SIZE_CENTERTON	128 | ||||
| 
 | ||||
| /* Intel Quark X1000 GPIO IRQ Number */ | ||||
| #define GPIO_IRQ_QUARK_X1000	9 | ||||
| 
 | ||||
| #define WDTBASE		0x84 | ||||
| #define WDT_IO_SIZE	64 | ||||
| 
 | ||||
| @ -43,30 +40,25 @@ struct lpc_sch_info { | ||||
| 	unsigned int io_size_smbus; | ||||
| 	unsigned int io_size_gpio; | ||||
| 	unsigned int io_size_wdt; | ||||
| 	int irq_gpio; | ||||
| }; | ||||
| 
 | ||||
| static struct lpc_sch_info sch_chipset_info[] = { | ||||
| 	[LPC_SCH] = { | ||||
| 		.io_size_smbus = SMBUS_IO_SIZE, | ||||
| 		.io_size_gpio = GPIO_IO_SIZE, | ||||
| 		.irq_gpio = -1, | ||||
| 	}, | ||||
| 	[LPC_ITC] = { | ||||
| 		.io_size_smbus = SMBUS_IO_SIZE, | ||||
| 		.io_size_gpio = GPIO_IO_SIZE, | ||||
| 		.io_size_wdt = WDT_IO_SIZE, | ||||
| 		.irq_gpio = -1, | ||||
| 	}, | ||||
| 	[LPC_CENTERTON] = { | ||||
| 		.io_size_smbus = SMBUS_IO_SIZE, | ||||
| 		.io_size_gpio = GPIO_IO_SIZE_CENTERTON, | ||||
| 		.io_size_wdt = WDT_IO_SIZE, | ||||
| 		.irq_gpio = -1, | ||||
| 	}, | ||||
| 	[LPC_QUARK_X1000] = { | ||||
| 		.io_size_gpio = GPIO_IO_SIZE, | ||||
| 		.irq_gpio = GPIO_IRQ_QUARK_X1000, | ||||
| 		.io_size_wdt = WDT_IO_SIZE, | ||||
| 	}, | ||||
| }; | ||||
| @ -113,13 +105,13 @@ static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name, | ||||
| } | ||||
| 
 | ||||
| static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, | ||||
| 				 const char *name, int size, int irq, | ||||
| 				 int id, struct mfd_cell *cell) | ||||
| 				 const char *name, int size, int id, | ||||
| 				 struct mfd_cell *cell) | ||||
| { | ||||
| 	struct resource *res; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL); | ||||
| 	res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL); | ||||
| 	if (!res) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| @ -135,18 +127,6 @@ static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, | ||||
| 	cell->ignore_resource_conflicts = true; | ||||
| 	cell->id = id; | ||||
| 
 | ||||
| 	/* Check if we need to add an IRQ resource */ | ||||
| 	if (irq < 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	res++; | ||||
| 
 | ||||
| 	res->start = irq; | ||||
| 	res->end = irq; | ||||
| 	res->flags = IORESOURCE_IRQ; | ||||
| 
 | ||||
| 	cell->num_resources++; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -158,7 +138,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus", | ||||
| 				    info->io_size_smbus, -1, | ||||
| 				    info->io_size_smbus, | ||||
| 				    id->device, &lpc_sch_cells[cells]); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| @ -166,7 +146,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||||
| 		cells++; | ||||
| 
 | ||||
| 	ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio", | ||||
| 				    info->io_size_gpio, info->irq_gpio, | ||||
| 				    info->io_size_gpio, | ||||
| 				    id->device, &lpc_sch_cells[cells]); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| @ -174,7 +154,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||||
| 		cells++; | ||||
| 
 | ||||
| 	ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt", | ||||
| 				    info->io_size_wdt, -1, | ||||
| 				    info->io_size_wdt, | ||||
| 				    id->device, &lpc_sch_cells[cells]); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
|  | ||||
| @ -29,9 +29,9 @@ | ||||
| static const struct mfd_cell max8997_devs[] = { | ||||
| 	{ .name = "max8997-pmic", }, | ||||
| 	{ .name = "max8997-rtc", }, | ||||
| 	{ .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", }, | ||||
| 	{ .name = "max8997-battery", }, | ||||
| 	{ .name = "max8997-haptic", }, | ||||
| 	{ .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", }, | ||||
| 	{ .name = "max8997-muic", }, | ||||
| 	{ .name = "max8997-led", .id = 1 }, | ||||
| 	{ .name = "max8997-led", .id = 2 }, | ||||
| }; | ||||
|  | ||||
| @ -65,7 +65,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, | ||||
| { | ||||
| 	const struct mfd_cell_acpi_match *match = cell->acpi_match; | ||||
| 	struct acpi_device *parent, *child; | ||||
| 	struct acpi_device *adev; | ||||
| 	struct acpi_device *adev = NULL; | ||||
| 
 | ||||
| 	parent = ACPI_COMPANION(pdev->dev.parent); | ||||
| 	if (!parent) | ||||
| @ -77,10 +77,9 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, | ||||
| 	 * _ADR or it will use the parent handle if is no ID is given. | ||||
| 	 * | ||||
| 	 * Note that use of _ADR is a grey area in the ACPI specification, | ||||
| 	 * though Intel Galileo Gen2 is using it to distinguish the children | ||||
| 	 * devices. | ||||
| 	 * though at least Intel Galileo Gen 2 is using it to distinguish | ||||
| 	 * the children devices. | ||||
| 	 */ | ||||
| 	adev = parent; | ||||
| 	if (match) { | ||||
| 		if (match->pnpid) { | ||||
| 			struct acpi_device_id ids[2] = {}; | ||||
| @ -93,22 +92,11 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| 			unsigned long long adr; | ||||
| 			acpi_status status; | ||||
| 
 | ||||
| 			list_for_each_entry(child, &parent->children, node) { | ||||
| 				status = acpi_evaluate_integer(child->handle, | ||||
| 							       "_ADR", NULL, | ||||
| 							       &adr); | ||||
| 				if (ACPI_SUCCESS(status) && match->adr == adr) { | ||||
| 					adev = child; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 			adev = acpi_find_child_device(parent, match->adr, false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ACPI_COMPANION_SET(&pdev->dev, adev); | ||||
| 	ACPI_COMPANION_SET(&pdev->dev, adev ?: parent); | ||||
| } | ||||
| #else | ||||
| static inline void mfd_acpi_add_device(const struct mfd_cell *cell, | ||||
| @ -238,8 +226,8 @@ static int mfd_add_device(struct device *parent, int id, | ||||
| 			goto fail_of_entry; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cell->properties) { | ||||
| 		ret = platform_device_add_properties(pdev, cell->properties); | ||||
| 	if (cell->swnode) { | ||||
| 		ret = device_add_software_node(&pdev->dev, cell->swnode); | ||||
| 		if (ret) | ||||
| 			goto fail_of_entry; | ||||
| 	} | ||||
| @ -304,6 +292,7 @@ fail_of_entry: | ||||
| 			list_del(&of_entry->list); | ||||
| 			kfree(of_entry); | ||||
| 		} | ||||
| 	device_remove_software_node(&pdev->dev); | ||||
| fail_alias: | ||||
| 	regulator_bulk_unregister_supply_alias(&pdev->dev, | ||||
| 					       cell->parent_supplies, | ||||
| @ -372,6 +361,8 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) | ||||
| 	regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, | ||||
| 					       cell->num_parent_supplies); | ||||
| 
 | ||||
| 	device_remove_software_node(&pdev->dev); | ||||
| 
 | ||||
| 	platform_device_unregister(pdev); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										271
									
								
								drivers/mfd/ntxec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								drivers/mfd/ntxec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,271 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| /*
 | ||||
|  * The Netronix embedded controller is a microcontroller found in some | ||||
|  * e-book readers designed by the original design manufacturer Netronix, Inc. | ||||
|  * It contains RTC, battery monitoring, system power management, and PWM | ||||
|  * functionality. | ||||
|  * | ||||
|  * This driver implements register access, version detection, and system | ||||
|  * power-off/reset. | ||||
|  * | ||||
|  * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/mfd/ntxec.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pm.h> | ||||
| #include <linux/reboot.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/types.h> | ||||
| #include <asm/unaligned.h> | ||||
| 
 | ||||
| #define NTXEC_REG_VERSION	0x00 | ||||
| #define NTXEC_REG_POWEROFF	0x50 | ||||
| #define NTXEC_REG_POWERKEEP	0x70 | ||||
| #define NTXEC_REG_RESET		0x90 | ||||
| 
 | ||||
| #define NTXEC_POWEROFF_VALUE	0x0100 | ||||
| #define NTXEC_POWERKEEP_VALUE	0x0800 | ||||
| #define NTXEC_RESET_VALUE	0xff00 | ||||
| 
 | ||||
| static struct i2c_client *poweroff_restart_client; | ||||
| 
 | ||||
| static void ntxec_poweroff(void) | ||||
| { | ||||
| 	int res; | ||||
| 	u8 buf[3] = { NTXEC_REG_POWEROFF }; | ||||
| 	struct i2c_msg msgs[] = { | ||||
| 		{ | ||||
| 			.addr = poweroff_restart_client->addr, | ||||
| 			.flags = 0, | ||||
| 			.len = sizeof(buf), | ||||
| 			.buf = buf, | ||||
| 		}, | ||||
| 	}; | ||||
| 
 | ||||
| 	put_unaligned_be16(NTXEC_POWEROFF_VALUE, buf + 1); | ||||
| 
 | ||||
| 	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs)); | ||||
| 	if (res < 0) | ||||
| 		dev_warn(&poweroff_restart_client->dev, | ||||
| 			 "Failed to power off (err = %d)\n", res); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The time from the register write until the host CPU is powered off | ||||
| 	 * has been observed to be about 2.5 to 3 seconds. Sleep long enough to | ||||
| 	 * safely avoid returning from the poweroff handler. | ||||
| 	 */ | ||||
| 	msleep(5000); | ||||
| } | ||||
| 
 | ||||
| static int ntxec_restart(struct notifier_block *nb, | ||||
| 			 unsigned long action, void *data) | ||||
| { | ||||
| 	int res; | ||||
| 	u8 buf[3] = { NTXEC_REG_RESET }; | ||||
| 	/*
 | ||||
| 	 * NOTE: The lower half of the reset value is not sent, because sending | ||||
| 	 * it causes an I2C error. (The reset handler in the downstream driver | ||||
| 	 * does send the full two-byte value, but doesn't check the result). | ||||
| 	 */ | ||||
| 	struct i2c_msg msgs[] = { | ||||
| 		{ | ||||
| 			.addr = poweroff_restart_client->addr, | ||||
| 			.flags = 0, | ||||
| 			.len = sizeof(buf) - 1, | ||||
| 			.buf = buf, | ||||
| 		}, | ||||
| 	}; | ||||
| 
 | ||||
| 	put_unaligned_be16(NTXEC_RESET_VALUE, buf + 1); | ||||
| 
 | ||||
| 	res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs)); | ||||
| 	if (res < 0) | ||||
| 		dev_warn(&poweroff_restart_client->dev, | ||||
| 			 "Failed to restart (err = %d)\n", res); | ||||
| 
 | ||||
| 	return NOTIFY_DONE; | ||||
| } | ||||
| 
 | ||||
| static struct notifier_block ntxec_restart_handler = { | ||||
| 	.notifier_call = ntxec_restart, | ||||
| 	.priority = 128, | ||||
| }; | ||||
| 
 | ||||
| static int regmap_ignore_write(void *context, | ||||
| 			       unsigned int reg, unsigned int val) | ||||
| 
 | ||||
| { | ||||
| 	struct regmap *regmap = context; | ||||
| 
 | ||||
| 	regmap_write(regmap, reg, val); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int regmap_wrap_read(void *context, unsigned int reg, | ||||
| 			    unsigned int *val) | ||||
| { | ||||
| 	struct regmap *regmap = context; | ||||
| 
 | ||||
| 	return regmap_read(regmap, reg, val); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Some firmware versions do not ack written data, add a wrapper. It | ||||
|  * is used to stack another regmap on top. | ||||
|  */ | ||||
| static const struct regmap_config regmap_config_noack = { | ||||
| 	.name = "ntxec_noack", | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 16, | ||||
| 	.cache_type = REGCACHE_NONE, | ||||
| 	.reg_write = regmap_ignore_write, | ||||
| 	.reg_read = regmap_wrap_read | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_config regmap_config = { | ||||
| 	.name = "ntxec", | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 16, | ||||
| 	.cache_type = REGCACHE_NONE, | ||||
| 	.val_format_endian = REGMAP_ENDIAN_BIG, | ||||
| }; | ||||
| 
 | ||||
| static const struct mfd_cell ntxec_subdev[] = { | ||||
| 	{ .name = "ntxec-rtc" }, | ||||
| 	{ .name = "ntxec-pwm" }, | ||||
| }; | ||||
| 
 | ||||
| static const struct mfd_cell ntxec_subdev_pwm[] = { | ||||
| 	{ .name = "ntxec-pwm" }, | ||||
| }; | ||||
| 
 | ||||
| static int ntxec_probe(struct i2c_client *client) | ||||
| { | ||||
| 	struct ntxec *ec; | ||||
| 	unsigned int version; | ||||
| 	int res; | ||||
| 	const struct mfd_cell *subdevs; | ||||
| 	size_t n_subdevs; | ||||
| 
 | ||||
| 	ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL); | ||||
| 	if (!ec) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	ec->dev = &client->dev; | ||||
| 
 | ||||
| 	ec->regmap = devm_regmap_init_i2c(client, ®map_config); | ||||
| 	if (IS_ERR(ec->regmap)) { | ||||
| 		dev_err(ec->dev, "Failed to set up regmap for device\n"); | ||||
| 		return PTR_ERR(ec->regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Determine the firmware version */ | ||||
| 	res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version); | ||||
| 	if (res < 0) { | ||||
| 		dev_err(ec->dev, "Failed to read firmware version number\n"); | ||||
| 		return res; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Bail out if we encounter an unknown firmware version */ | ||||
| 	switch (version) { | ||||
| 	case NTXEC_VERSION_KOBO_AURA: | ||||
| 		subdevs = ntxec_subdev; | ||||
| 		n_subdevs = ARRAY_SIZE(ntxec_subdev); | ||||
| 		break; | ||||
| 	case NTXEC_VERSION_TOLINO_SHINE2: | ||||
| 		subdevs = ntxec_subdev_pwm; | ||||
| 		n_subdevs = ARRAY_SIZE(ntxec_subdev_pwm); | ||||
| 		/* Another regmap stacked on top of the other */ | ||||
| 		ec->regmap = devm_regmap_init(ec->dev, NULL, | ||||
| 					      ec->regmap, | ||||
| 					      ®map_config_noack); | ||||
| 		if (IS_ERR(ec->regmap)) | ||||
| 			return PTR_ERR(ec->regmap); | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(ec->dev, | ||||
| 			"Netronix embedded controller version %04x is not supported.\n", | ||||
| 			version); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(ec->dev, | ||||
| 		 "Netronix embedded controller version %04x detected.\n", version); | ||||
| 
 | ||||
| 	if (of_device_is_system_power_controller(ec->dev->of_node)) { | ||||
| 		/*
 | ||||
| 		 * Set the 'powerkeep' bit. This is necessary on some boards | ||||
| 		 * in order to keep the system running. | ||||
| 		 */ | ||||
| 		res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP, | ||||
| 				   NTXEC_POWERKEEP_VALUE); | ||||
| 		if (res < 0) | ||||
| 			return res; | ||||
| 
 | ||||
| 		if (poweroff_restart_client) | ||||
| 			/*
 | ||||
| 			 * Another instance of the driver already took | ||||
| 			 * poweroff/restart duties. | ||||
| 			 */ | ||||
| 			dev_err(ec->dev, "poweroff_restart_client already assigned\n"); | ||||
| 		else | ||||
| 			poweroff_restart_client = client; | ||||
| 
 | ||||
| 		if (pm_power_off) | ||||
| 			/* Another driver already registered a poweroff handler. */ | ||||
| 			dev_err(ec->dev, "pm_power_off already assigned\n"); | ||||
| 		else | ||||
| 			pm_power_off = ntxec_poweroff; | ||||
| 
 | ||||
| 		res = register_restart_handler(&ntxec_restart_handler); | ||||
| 		if (res) | ||||
| 			dev_err(ec->dev, | ||||
| 				"Failed to register restart handler: %d\n", res); | ||||
| 	} | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, ec); | ||||
| 
 | ||||
| 	res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, | ||||
| 				   subdevs, n_subdevs, NULL, 0, NULL); | ||||
| 	if (res) | ||||
| 		dev_err(ec->dev, "Failed to add subdevices: %d\n", res); | ||||
| 
 | ||||
| 	return res; | ||||
| } | ||||
| 
 | ||||
| static int ntxec_remove(struct i2c_client *client) | ||||
| { | ||||
| 	if (client == poweroff_restart_client) { | ||||
| 		poweroff_restart_client = NULL; | ||||
| 		pm_power_off = NULL; | ||||
| 		unregister_restart_handler(&ntxec_restart_handler); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id of_ntxec_match_table[] = { | ||||
| 	{ .compatible = "netronix,ntxec", }, | ||||
| 	{} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, of_ntxec_match_table); | ||||
| 
 | ||||
| static struct i2c_driver ntxec_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "ntxec", | ||||
| 		.of_match_table = of_ntxec_match_table, | ||||
| 	}, | ||||
| 	.probe_new = ntxec_probe, | ||||
| 	.remove = ntxec_remove, | ||||
| }; | ||||
| module_i2c_driver(ntxec_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>"); | ||||
| MODULE_DESCRIPTION("Core driver for Netronix EC"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -45,8 +45,11 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) | ||||
| 	case RN5T618_INTMON: | ||||
| 	case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2: | ||||
| 	case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR: | ||||
| 	case RN5T618_CHGCTL1: | ||||
| 	case RN5T618_REGISET1 ... RN5T618_REGISET2: | ||||
| 	case RN5T618_CHGSTATE: | ||||
| 	case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI: | ||||
| 	case RN5T618_GCHGDET: | ||||
| 	case RN5T618_CONTROL ... RN5T618_CC_AVEREG0: | ||||
| 		return true; | ||||
| 	default: | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| //
 | ||||
| // Copyright (C) 2019 ROHM Semiconductors
 | ||||
| //
 | ||||
| // ROHM BD71828 PMIC driver
 | ||||
| // ROHM BD71828/BD71815 PMIC driver
 | ||||
| 
 | ||||
| #include <linux/gpio_keys.h> | ||||
| #include <linux/i2c.h> | ||||
| @ -11,7 +11,9 @@ | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/mfd/rohm-bd71815.h> | ||||
| #include <linux/mfd/rohm-bd71828.h> | ||||
| #include <linux/mfd/rohm-generic.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/regmap.h> | ||||
| @ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = { | ||||
| 	.name = "bd71828-pwrkey", | ||||
| }; | ||||
| 
 | ||||
| static const struct resource rtc_irqs[] = { | ||||
| static const struct resource bd71815_rtc_irqs[] = { | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"), | ||||
| }; | ||||
| 
 | ||||
| static const struct resource bd71828_rtc_irqs[] = { | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"), | ||||
| }; | ||||
| 
 | ||||
| static struct resource bd71815_power_irqs[] = { | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"), | ||||
| }; | ||||
| 
 | ||||
| static struct mfd_cell bd71815_mfd_cells[] = { | ||||
| 	{ .name = "bd71815-pmic", }, | ||||
| 	{ .name = "bd71815-clk", }, | ||||
| 	{ .name = "bd71815-gpo", }, | ||||
| 	{ | ||||
| 		.name = "bd71815-power", | ||||
| 		.num_resources = ARRAY_SIZE(bd71815_power_irqs), | ||||
| 		.resources = &bd71815_power_irqs[0], | ||||
| 	}, | ||||
| 	{ | ||||
| 		.name = "bd71815-rtc", | ||||
| 		.num_resources = ARRAY_SIZE(bd71815_rtc_irqs), | ||||
| 		.resources = &bd71815_rtc_irqs[0], | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static struct mfd_cell bd71828_mfd_cells[] = { | ||||
| 	{ .name = "bd71828-pmic", }, | ||||
| 	{ .name = "bd71828-gpio", }, | ||||
| @ -47,8 +121,8 @@ static struct mfd_cell bd71828_mfd_cells[] = { | ||||
| 	{ .name = "bd71827-power", }, | ||||
| 	{ | ||||
| 		.name = "bd71828-rtc", | ||||
| 		.resources = rtc_irqs, | ||||
| 		.num_resources = ARRAY_SIZE(rtc_irqs), | ||||
| 		.resources = bd71828_rtc_irqs, | ||||
| 		.num_resources = ARRAY_SIZE(bd71828_rtc_irqs), | ||||
| 	}, { | ||||
| 		.name = "gpio-keys", | ||||
| 		.platform_data = &bd71828_powerkey_data, | ||||
| @ -56,7 +130,35 @@ static struct mfd_cell bd71828_mfd_cells[] = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_range volatile_ranges[] = { | ||||
| static const struct regmap_range bd71815_volatile_ranges[] = { | ||||
| 	{ | ||||
| 		.range_min = BD71815_REG_SEC, | ||||
| 		.range_max = BD71815_REG_YEAR, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_CONF, | ||||
| 		.range_max = BD71815_REG_BAT_TEMP, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_VM_IBAT_U, | ||||
| 		.range_max = BD71815_REG_CC_CTRL, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_CC_STAT, | ||||
| 		.range_max = BD71815_REG_CC_CURCD_L, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_VM_BTMP_MON, | ||||
| 		.range_max = BD71815_REG_VM_BTMP_MON, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_INT_STAT, | ||||
| 		.range_max = BD71815_REG_INT_UPDATE, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_VM_VSYS_U, | ||||
| 		.range_max = BD71815_REG_REX_CTRL_1, | ||||
| 	}, { | ||||
| 		.range_min = BD71815_REG_FULL_CCNTD_3, | ||||
| 		.range_max = BD71815_REG_CCNTD_CHG_2, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_range bd71828_volatile_ranges[] = { | ||||
| 	{ | ||||
| 		.range_min = BD71828_REG_PS_CTRL_1, | ||||
| 		.range_max = BD71828_REG_PS_CTRL_1, | ||||
| @ -80,15 +182,28 @@ static const struct regmap_range volatile_ranges[] = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_access_table volatile_regs = { | ||||
| 	.yes_ranges = &volatile_ranges[0], | ||||
| 	.n_yes_ranges = ARRAY_SIZE(volatile_ranges), | ||||
| static const struct regmap_access_table bd71815_volatile_regs = { | ||||
| 	.yes_ranges = &bd71815_volatile_ranges[0], | ||||
| 	.n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges), | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_config bd71828_regmap = { | ||||
| static const struct regmap_access_table bd71828_volatile_regs = { | ||||
| 	.yes_ranges = &bd71828_volatile_ranges[0], | ||||
| 	.n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_config bd71815_regmap = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 8, | ||||
| 	.volatile_table = &volatile_regs, | ||||
| 	.volatile_table = &bd71815_volatile_regs, | ||||
| 	.max_register = BD71815_MAX_REGISTER - 1, | ||||
| 	.cache_type = REGCACHE_RBTREE, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_config bd71828_regmap = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 8, | ||||
| 	.volatile_table = &bd71828_volatile_regs, | ||||
| 	.max_register = BD71828_MAX_REGISTER, | ||||
| 	.cache_type = REGCACHE_RBTREE, | ||||
| }; | ||||
| @ -96,7 +211,7 @@ static struct regmap_config bd71828_regmap = { | ||||
| /*
 | ||||
|  * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can | ||||
|  * access corect sub-IRQ registers based on bits that are set in main IRQ | ||||
|  * register. | ||||
|  * register. BD71815 and BD71828 have same sub-register-block offests. | ||||
|  */ | ||||
| 
 | ||||
| static unsigned int bit0_offsets[] = {11};		/* RTC IRQ */ | ||||
| @ -108,7 +223,7 @@ static unsigned int bit5_offsets[] = {3};		/* VSYS IRQ */ | ||||
| static unsigned int bit6_offsets[] = {1, 2};		/* DCIN IRQ */ | ||||
| static unsigned int bit7_offsets[] = {0};		/* BUCK IRQ */ | ||||
| 
 | ||||
| static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = { | ||||
| static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = { | ||||
| 	REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), | ||||
| 	REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), | ||||
| 	REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), | ||||
| @ -119,6 +234,88 @@ static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = { | ||||
| 	REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_irq bd71815_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK), | ||||
| 	/* DCIN1 interrupts */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK), | ||||
| 	/* DCIN2 interrupts */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK), | ||||
| 	/* Vsys */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK), | ||||
| 	/* Charger */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4, | ||||
| 		       BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK), | ||||
| 	/* Battery */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK), | ||||
| 	/* Battery Mon 1 */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK), | ||||
| 	/* Battery Mon 2 */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK), | ||||
| 	/* Battery Mon 3 (Coulomb counter) */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK), | ||||
| 	/* Battery Mon 4 */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK), | ||||
| 	/* Temperature */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10, | ||||
| 		       BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10, | ||||
| 		       BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10, | ||||
| 		       BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10, | ||||
| 		       BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK), | ||||
| 	/* RTC Alarm */ | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK), | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_irq bd71828_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK), | ||||
| @ -134,10 +331,8 @@ static struct regmap_irq bd71828_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK), | ||||
| 	/* DCIN2 interrupts */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, | ||||
| 		       BD71828_INT_DCIN_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, | ||||
| 		       BD71828_INT_DCIN_MON_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK), | ||||
| @ -145,102 +340,59 @@ static struct regmap_irq bd71828_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK), | ||||
| 	/* Vsys */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, | ||||
| 		       BD71828_INT_VSYS_UV_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, | ||||
| 		       BD71828_INT_VSYS_UV_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, | ||||
| 		       BD71828_INT_VSYS_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, | ||||
| 		       BD71828_INT_VSYS_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, | ||||
| 		       BD71828_INT_VSYS_HALL_IN_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, | ||||
| 		       BD71828_INT_VSYS_HALL_TOGGLE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, | ||||
| 		       BD71828_INT_VSYS_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, | ||||
| 		       BD71828_INT_VSYS_MON_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK), | ||||
| 	/* Charger */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, | ||||
| 		       BD71828_INT_CHG_DCIN_ILIM_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, | ||||
| 		       BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, | ||||
| 		       BD71828_INT_CHG_WDG_TEMP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, | ||||
| 		       BD71828_INT_CHG_WDG_TIME_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, | ||||
| 		       BD71828_INT_CHG_RECHARGE_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, | ||||
| 		       BD71828_INT_CHG_RECHARGE_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4, | ||||
| 		       BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, | ||||
| 		       BD71828_INT_CHG_STATE_TRANSITION_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK), | ||||
| 	/* Battery */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, | ||||
| 		       BD71828_INT_BAT_TEMP_NORMAL_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, | ||||
| 		       BD71828_INT_BAT_TEMP_ERANGE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, | ||||
| 		       BD71828_INT_BAT_TEMP_WARN_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, | ||||
| 		       BD71828_INT_BAT_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, | ||||
| 		       BD71828_INT_BAT_DETECTED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, | ||||
| 		       BD71828_INT_THERM_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, | ||||
| 		       BD71828_INT_THERM_DETECTED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK), | ||||
| 	/* Battery Mon 1 */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, | ||||
| 		       BD71828_INT_BAT_SHORTC_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, | ||||
| 		       BD71828_INT_BAT_SHORTC_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, | ||||
| 		       BD71828_INT_BAT_LOW_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, | ||||
| 		       BD71828_INT_BAT_LOW_VOLT_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, | ||||
| 		       BD71828_INT_BAT_OVER_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, | ||||
| 		       BD71828_INT_BAT_OVER_VOLT_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK), | ||||
| 	/* Battery Mon 2 */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, | ||||
| 		       BD71828_INT_BAT_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, | ||||
| 		       BD71828_INT_BAT_MON_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK), | ||||
| 	/* Battery Mon 3 (Coulomb counter) */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, | ||||
| 		       BD71828_INT_BAT_CC_MON1_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, | ||||
| 		       BD71828_INT_BAT_CC_MON2_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, | ||||
| 		       BD71828_INT_BAT_CC_MON3_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK), | ||||
| 	/* Battery Mon 4 */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_1_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_1_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_2_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_2_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_3_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, | ||||
| 		       BD71828_INT_BAT_OVER_CURR_3_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK), | ||||
| 	/* Temperature */ | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, | ||||
| 		       BD71828_INT_TEMP_BAT_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, | ||||
| 		       BD71828_INT_TEMP_BAT_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, | ||||
| 		       BD71828_INT_TEMP_BAT_HI_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, | ||||
| 		       BD71828_INT_TEMP_BAT_HI_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10, | ||||
| 		       BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK), | ||||
| 	REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10, | ||||
| @ -267,57 +419,133 @@ static struct regmap_irq_chip bd71828_irq_chip = { | ||||
| 	.init_ack_masked = true, | ||||
| 	.num_regs = 12, | ||||
| 	.num_main_regs = 1, | ||||
| 	.sub_reg_offsets = &bd71828_sub_irq_offsets[0], | ||||
| 	.sub_reg_offsets = &bd718xx_sub_irq_offsets[0], | ||||
| 	.num_main_status_bits = 8, | ||||
| 	.irq_reg_stride = 1, | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_irq_chip bd71815_irq_chip = { | ||||
| 	.name = "bd71815_irq", | ||||
| 	.main_status = BD71815_REG_INT_STAT, | ||||
| 	.irqs = &bd71815_irqs[0], | ||||
| 	.num_irqs = ARRAY_SIZE(bd71815_irqs), | ||||
| 	.status_base = BD71815_REG_INT_STAT_01, | ||||
| 	.mask_base = BD71815_REG_INT_EN_01, | ||||
| 	.ack_base = BD71815_REG_INT_STAT_01, | ||||
| 	.mask_invert = true, | ||||
| 	.init_ack_masked = true, | ||||
| 	.num_regs = 12, | ||||
| 	.num_main_regs = 1, | ||||
| 	.sub_reg_offsets = &bd718xx_sub_irq_offsets[0], | ||||
| 	.num_main_status_bits = 8, | ||||
| 	.irq_reg_stride = 1, | ||||
| }; | ||||
| 
 | ||||
| static int set_clk_mode(struct device *dev, struct regmap *regmap, | ||||
| 			int clkmode_reg) | ||||
| { | ||||
| 	int ret; | ||||
| 	unsigned int open_drain; | ||||
| 
 | ||||
| 	ret = of_property_read_u32(dev->of_node, "rohm,clkout-open-drain", &open_drain); | ||||
| 	if (ret) { | ||||
| 		if (ret == -EINVAL) | ||||
| 			return 0; | ||||
| 		return ret; | ||||
| 	} | ||||
| 	if (open_drain > 1) { | ||||
| 		dev_err(dev, "bad clk32kout mode configuration"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (open_drain) | ||||
| 		return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE, | ||||
| 					  OUT32K_MODE_OPEN_DRAIN); | ||||
| 
 | ||||
| 	return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE, | ||||
| 				  OUT32K_MODE_CMOS); | ||||
| } | ||||
| 
 | ||||
| static int bd71828_i2c_probe(struct i2c_client *i2c) | ||||
| { | ||||
| 	struct rohm_regmap_dev *chip; | ||||
| 	struct regmap_irq_chip_data *irq_data; | ||||
| 	int ret; | ||||
| 	struct regmap *regmap; | ||||
| 	const struct regmap_config *regmap_config; | ||||
| 	struct regmap_irq_chip *irqchip; | ||||
| 	unsigned int chip_type; | ||||
| 	struct mfd_cell *mfd; | ||||
| 	int cells; | ||||
| 	int button_irq; | ||||
| 	int clkmode_reg; | ||||
| 
 | ||||
| 	if (!i2c->irq) { | ||||
| 		dev_err(&i2c->dev, "No IRQ configured\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL); | ||||
| 	if (!chip) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	dev_set_drvdata(&i2c->dev, chip); | ||||
| 
 | ||||
| 	chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap); | ||||
| 	if (IS_ERR(chip->regmap)) { | ||||
| 		dev_err(&i2c->dev, "Failed to initialize Regmap\n"); | ||||
| 		return PTR_ERR(chip->regmap); | ||||
| 	chip_type = (unsigned int)(uintptr_t) | ||||
| 		    of_device_get_match_data(&i2c->dev); | ||||
| 	switch (chip_type) { | ||||
| 	case ROHM_CHIP_TYPE_BD71828: | ||||
| 		mfd = bd71828_mfd_cells; | ||||
| 		cells = ARRAY_SIZE(bd71828_mfd_cells); | ||||
| 		regmap_config = &bd71828_regmap; | ||||
| 		irqchip = &bd71828_irq_chip; | ||||
| 		clkmode_reg = BD71828_REG_OUT32K; | ||||
| 		button_irq = BD71828_INT_SHORTPUSH; | ||||
| 		break; | ||||
| 	case ROHM_CHIP_TYPE_BD71815: | ||||
| 		mfd = bd71815_mfd_cells; | ||||
| 		cells = ARRAY_SIZE(bd71815_mfd_cells); | ||||
| 		regmap_config = &bd71815_regmap; | ||||
| 		irqchip = &bd71815_irq_chip; | ||||
| 		clkmode_reg = BD71815_REG_OUT32K; | ||||
| 		/*
 | ||||
| 		 * If BD71817 support is needed we should be able to handle it | ||||
| 		 * with proper DT configs + BD71815 drivers + power-button. | ||||
| 		 * BD71815 data-sheet does not list the power-button IRQ so we | ||||
| 		 * don't use it. | ||||
| 		 */ | ||||
| 		button_irq = 0; | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(&i2c->dev, "Unknown device type"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap, | ||||
| 				       i2c->irq, IRQF_ONESHOT, 0, | ||||
| 				       &bd71828_irq_chip, &irq_data); | ||||
| 	regmap = devm_regmap_init_i2c(i2c, regmap_config); | ||||
| 	if (IS_ERR(regmap)) { | ||||
| 		dev_err(&i2c->dev, "Failed to initialize Regmap\n"); | ||||
| 		return PTR_ERR(regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, | ||||
| 				       IRQF_ONESHOT, 0, irqchip, &irq_data); | ||||
| 	if (ret) { | ||||
| 		dev_err(&i2c->dev, "Failed to add IRQ chip\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n", | ||||
| 		bd71828_irq_chip.num_irqs); | ||||
| 		irqchip->num_irqs); | ||||
| 
 | ||||
| 	ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&i2c->dev, "Failed to get the power-key IRQ\n"); | ||||
| 		return ret; | ||||
| 	if (button_irq) { | ||||
| 		ret = regmap_irq_get_virq(irq_data, button_irq); | ||||
| 		if (ret < 0) { | ||||
| 			dev_err(&i2c->dev, "Failed to get the power-key IRQ\n"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		button.irq = ret; | ||||
| 	} | ||||
| 
 | ||||
| 	button.irq = ret; | ||||
| 	ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, | ||||
| 				   bd71828_mfd_cells, | ||||
| 				   ARRAY_SIZE(bd71828_mfd_cells), NULL, 0, | ||||
| 				   regmap_irq_get_domain(irq_data)); | ||||
| 	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells, | ||||
| 				   NULL, 0, regmap_irq_get_domain(irq_data)); | ||||
| 	if (ret) | ||||
| 		dev_err(&i2c->dev, "Failed to create subdevices\n"); | ||||
| 
 | ||||
| @ -325,7 +553,13 @@ static int bd71828_i2c_probe(struct i2c_client *i2c) | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id bd71828_of_match[] = { | ||||
| 	{ .compatible = "rohm,bd71828", }, | ||||
| 	{ | ||||
| 		.compatible = "rohm,bd71828", | ||||
| 		.data = (void *)ROHM_CHIP_TYPE_BD71828, | ||||
| 	}, { | ||||
| 		.compatible = "rohm,bd71815", | ||||
| 		.data = (void *)ROHM_CHIP_TYPE_BD71815, | ||||
| 	 }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, bd71828_of_match); | ||||
|  | ||||
| @ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = { | ||||
| 	.cache_type = REGCACHE_RBTREE, | ||||
| }; | ||||
| 
 | ||||
| static int bd718xx_init_press_duration(struct bd718xx *bd718xx) | ||||
| static int bd718xx_init_press_duration(struct regmap *regmap, | ||||
| 				       struct device *dev) | ||||
| { | ||||
| 	struct device* dev = bd718xx->chip.dev; | ||||
| 	u32 short_press_ms, long_press_ms; | ||||
| 	u32 short_press_value, long_press_value; | ||||
| 	int ret; | ||||
| @ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) | ||||
| 				   &short_press_ms); | ||||
| 	if (!ret) { | ||||
| 		short_press_value = min(15u, (short_press_ms + 250) / 500); | ||||
| 		ret = regmap_update_bits(bd718xx->chip.regmap, | ||||
| 					 BD718XX_REG_PWRONCONFIG0, | ||||
| 		ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0, | ||||
| 					 BD718XX_PWRBTN_PRESS_DURATION_MASK, | ||||
| 					 short_press_value); | ||||
| 		if (ret) { | ||||
| @ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) | ||||
| 				   &long_press_ms); | ||||
| 	if (!ret) { | ||||
| 		long_press_value = min(15u, (long_press_ms + 500) / 1000); | ||||
| 		ret = regmap_update_bits(bd718xx->chip.regmap, | ||||
| 					 BD718XX_REG_PWRONCONFIG1, | ||||
| 		ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1, | ||||
| 					 BD718XX_PWRBTN_PRESS_DURATION_MASK, | ||||
| 					 long_press_value); | ||||
| 		if (ret) { | ||||
| @ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) | ||||
| static int bd718xx_i2c_probe(struct i2c_client *i2c, | ||||
| 			    const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct bd718xx *bd718xx; | ||||
| 	struct regmap *regmap; | ||||
| 	struct regmap_irq_chip_data *irq_data; | ||||
| 	int ret; | ||||
| 	unsigned int chip_type; | ||||
| 	struct mfd_cell *mfd; | ||||
| @ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, | ||||
| 		dev_err(&i2c->dev, "No IRQ configured\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL); | ||||
| 
 | ||||
| 	if (!bd718xx) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	bd718xx->chip_irq = i2c->irq; | ||||
| 	chip_type = (unsigned int)(uintptr_t) | ||||
| 		    of_device_get_match_data(&i2c->dev); | ||||
| 	switch (chip_type) { | ||||
| @ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, | ||||
| 		dev_err(&i2c->dev, "Unknown device type"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	bd718xx->chip.dev = &i2c->dev; | ||||
| 	dev_set_drvdata(&i2c->dev, bd718xx); | ||||
| 
 | ||||
| 	bd718xx->chip.regmap = devm_regmap_init_i2c(i2c, | ||||
| 						    &bd718xx_regmap_config); | ||||
| 	if (IS_ERR(bd718xx->chip.regmap)) { | ||||
| 	regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config); | ||||
| 	if (IS_ERR(regmap)) { | ||||
| 		dev_err(&i2c->dev, "regmap initialization failed\n"); | ||||
| 		return PTR_ERR(bd718xx->chip.regmap); | ||||
| 		return PTR_ERR(regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap, | ||||
| 				       bd718xx->chip_irq, IRQF_ONESHOT, 0, | ||||
| 				       &bd718xx_irq_chip, &bd718xx->irq_data); | ||||
| 	ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, | ||||
| 				       IRQF_ONESHOT, 0, &bd718xx_irq_chip, | ||||
| 				       &irq_data); | ||||
| 	if (ret) { | ||||
| 		dev_err(&i2c->dev, "Failed to add irq_chip\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = bd718xx_init_press_duration(bd718xx); | ||||
| 	ret = bd718xx_init_press_duration(regmap, &i2c->dev); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S); | ||||
| 	ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S); | ||||
| 
 | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&i2c->dev, "Failed to get the IRQ\n"); | ||||
| @ -195,9 +184,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, | ||||
| 
 | ||||
| 	button.irq = ret; | ||||
| 
 | ||||
| 	ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO, | ||||
| 	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, | ||||
| 				   mfd, cells, NULL, 0, | ||||
| 				   regmap_irq_get_domain(bd718xx->irq_data)); | ||||
| 				   regmap_irq_get_domain(irq_data)); | ||||
| 	if (ret) | ||||
| 		dev_err(&i2c->dev, "Failed to create subdevices\n"); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										189
									
								
								drivers/mfd/rohm-bd9576.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								drivers/mfd/rohm-bd9576.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,189 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| /*
 | ||||
|  * Copyright (C) 2021 ROHM Semiconductors | ||||
|  * | ||||
|  * ROHM BD9576MUF and BD9573MUF PMIC driver | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/mfd/rohm-bd957x.h> | ||||
| #include <linux/mfd/rohm-generic.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| enum { | ||||
| 	BD957X_REGULATOR_CELL, | ||||
| 	BD957X_WDT_CELL, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs. | ||||
|  * These will be added to regulator resources only if IRQ information for the | ||||
|  * PMIC is populated in device-tree. | ||||
|  */ | ||||
| static const struct resource bd9576_regulator_irqs[] = { | ||||
| 	DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"), | ||||
| 	DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"), | ||||
| }; | ||||
| 
 | ||||
| static struct mfd_cell bd9573_mfd_cells[] = { | ||||
| 	[BD957X_REGULATOR_CELL]	= { .name = "bd9573-regulator", }, | ||||
| 	[BD957X_WDT_CELL]	= { .name = "bd9576-wdt", }, | ||||
| }; | ||||
| 
 | ||||
| static struct mfd_cell bd9576_mfd_cells[] = { | ||||
| 	[BD957X_REGULATOR_CELL]	= { .name = "bd9576-regulator", }, | ||||
| 	[BD957X_WDT_CELL]	= { .name = "bd9576-wdt", }, | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_range volatile_ranges[] = { | ||||
| 	regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT), | ||||
| 	regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT, | ||||
| 			 BD957X_REG_PMIC_INTERNAL_STAT), | ||||
| 	regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT), | ||||
| 	regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT), | ||||
| 	regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT), | ||||
| }; | ||||
| 
 | ||||
| static const struct regmap_access_table volatile_regs = { | ||||
| 	.yes_ranges = &volatile_ranges[0], | ||||
| 	.n_yes_ranges = ARRAY_SIZE(volatile_ranges), | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_config bd957x_regmap = { | ||||
| 	.reg_bits = 8, | ||||
| 	.val_bits = 8, | ||||
| 	.volatile_table = &volatile_regs, | ||||
| 	.max_register = BD957X_MAX_REGISTER, | ||||
| 	.cache_type = REGCACHE_RBTREE, | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_irq bd9576_irqs[] = { | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP), | ||||
| 	REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS), | ||||
| }; | ||||
| 
 | ||||
| static struct regmap_irq_chip bd9576_irq_chip = { | ||||
| 	.name = "bd9576_irq", | ||||
| 	.irqs = &bd9576_irqs[0], | ||||
| 	.num_irqs = ARRAY_SIZE(bd9576_irqs), | ||||
| 	.status_base = BD957X_REG_INT_MAIN_STAT, | ||||
| 	.mask_base = BD957X_REG_INT_MAIN_MASK, | ||||
| 	.ack_base = BD957X_REG_INT_MAIN_STAT, | ||||
| 	.init_ack_masked = true, | ||||
| 	.num_regs = 1, | ||||
| 	.irq_reg_stride = 1, | ||||
| }; | ||||
| 
 | ||||
| static int bd957x_i2c_probe(struct i2c_client *i2c, | ||||
| 			     const struct i2c_device_id *id) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct regmap *regmap; | ||||
| 	struct mfd_cell *cells; | ||||
| 	int num_cells; | ||||
| 	unsigned long chip_type; | ||||
| 	struct irq_domain *domain; | ||||
| 	bool usable_irqs; | ||||
| 
 | ||||
| 	chip_type = (unsigned long)of_device_get_match_data(&i2c->dev); | ||||
| 
 | ||||
| 	switch (chip_type) { | ||||
| 	case ROHM_CHIP_TYPE_BD9576: | ||||
| 		cells = bd9576_mfd_cells; | ||||
| 		num_cells = ARRAY_SIZE(bd9576_mfd_cells); | ||||
| 		usable_irqs = !!i2c->irq; | ||||
| 		break; | ||||
| 	case ROHM_CHIP_TYPE_BD9573: | ||||
| 		cells = bd9573_mfd_cells; | ||||
| 		num_cells = ARRAY_SIZE(bd9573_mfd_cells); | ||||
| 		/*
 | ||||
| 		 * BD9573 only supports fatal IRQs which we can not handle | ||||
| 		 * because SoC is going to lose the power. | ||||
| 		 */ | ||||
| 		usable_irqs = false; | ||||
| 		break; | ||||
| 	default: | ||||
| 		dev_err(&i2c->dev, "Unknown device type"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap); | ||||
| 	if (IS_ERR(regmap)) { | ||||
| 		dev_err(&i2c->dev, "Failed to initialize Regmap\n"); | ||||
| 		return PTR_ERR(regmap); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * BD9576 behaves badly. It kepts IRQ line asserted for the whole | ||||
| 	 * duration of detected HW condition (like over temperature). So we | ||||
| 	 * don't require IRQ to be populated. | ||||
| 	 * If IRQ information is not given, then we mask all IRQs and do not | ||||
| 	 * provide IRQ resources to regulator driver - which then just omits | ||||
| 	 * the notifiers. | ||||
| 	 */ | ||||
| 	if (usable_irqs) { | ||||
| 		struct regmap_irq_chip_data *irq_data; | ||||
| 		struct mfd_cell *regulators; | ||||
| 
 | ||||
| 		regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL]; | ||||
| 		regulators->resources = bd9576_regulator_irqs; | ||||
| 		regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs); | ||||
| 
 | ||||
| 		ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, | ||||
| 					       IRQF_ONESHOT, 0, | ||||
| 					       &bd9576_irq_chip, &irq_data); | ||||
| 		if (ret) { | ||||
| 			dev_err(&i2c->dev, "Failed to add IRQ chip\n"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 		domain = regmap_irq_get_domain(irq_data); | ||||
| 	} else { | ||||
| 		ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK, | ||||
| 					 BD957X_MASK_INT_ALL, | ||||
| 					 BD957X_MASK_INT_ALL); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		domain = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells, | ||||
| 				   num_cells, NULL, 0, domain); | ||||
| 	if (ret) | ||||
| 		dev_err(&i2c->dev, "Failed to create subdevices\n"); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct of_device_id bd957x_of_match[] = { | ||||
| 	{ .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, }, | ||||
| 	{ .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, bd957x_of_match); | ||||
| 
 | ||||
| static struct i2c_driver bd957x_drv = { | ||||
| 	.driver = { | ||||
| 		.name = "rohm-bd957x", | ||||
| 		.of_match_table = bd957x_of_match, | ||||
| 	}, | ||||
| 	.probe = &bd957x_i2c_probe, | ||||
| }; | ||||
| module_i2c_driver(bd957x_drv); | ||||
| 
 | ||||
| MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | ||||
| MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -549,19 +549,7 @@ static struct i2c_driver sec_pmic_driver = { | ||||
| 	.shutdown = sec_pmic_shutdown, | ||||
| 	.id_table = sec_pmic_id, | ||||
| }; | ||||
| 
 | ||||
| static int __init sec_pmic_init(void) | ||||
| { | ||||
| 	return i2c_add_driver(&sec_pmic_driver); | ||||
| } | ||||
| 
 | ||||
| subsys_initcall(sec_pmic_init); | ||||
| 
 | ||||
| static void __exit sec_pmic_exit(void) | ||||
| { | ||||
| 	i2c_del_driver(&sec_pmic_driver); | ||||
| } | ||||
| module_exit(sec_pmic_exit); | ||||
| module_i2c_driver(sec_pmic_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); | ||||
| MODULE_DESCRIPTION("Core support for the S5M MFD"); | ||||
|  | ||||
| @ -158,13 +158,18 @@ static const struct regmap_config stm32_timers_regmap_cfg = { | ||||
| 
 | ||||
| static void stm32_timers_get_arr_size(struct stm32_timers *ddata) | ||||
| { | ||||
| 	u32 arr; | ||||
| 
 | ||||
| 	/* Backup ARR to restore it after getting the maximum value */ | ||||
| 	regmap_read(ddata->regmap, TIM_ARR, &arr); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Only the available bits will be written so when readback | ||||
| 	 * we get the maximum value of auto reload register | ||||
| 	 */ | ||||
| 	regmap_write(ddata->regmap, TIM_ARR, ~0L); | ||||
| 	regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr); | ||||
| 	regmap_write(ddata->regmap, TIM_ARR, 0x0); | ||||
| 	regmap_write(ddata->regmap, TIM_ARR, arr); | ||||
| } | ||||
| 
 | ||||
| static int stm32_timers_dma_probe(struct device *dev, | ||||
|  | ||||
| @ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(stmpe_set_altfunc); | ||||
|  * GPIO (all variants) | ||||
|  */ | ||||
| 
 | ||||
| static const struct resource stmpe_gpio_resources[] = { | ||||
| static struct resource stmpe_gpio_resources[] = { | ||||
| 	/* Start and end filled dynamically */ | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| @ -336,7 +336,8 @@ static const struct mfd_cell stmpe_gpio_cell_noirq = { | ||||
|  * Keypad (1601, 2401, 2403) | ||||
|  */ | ||||
| 
 | ||||
| static const struct resource stmpe_keypad_resources[] = { | ||||
| static struct resource stmpe_keypad_resources[] = { | ||||
| 	/* Start and end filled dynamically */ | ||||
| 	{ | ||||
| 		.name	= "KEYPAD", | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| @ -357,7 +358,8 @@ static const struct mfd_cell stmpe_keypad_cell = { | ||||
| /*
 | ||||
|  * PWM (1601, 2401, 2403) | ||||
|  */ | ||||
| static const struct resource stmpe_pwm_resources[] = { | ||||
| static struct resource stmpe_pwm_resources[] = { | ||||
| 	/* Start and end filled dynamically */ | ||||
| 	{ | ||||
| 		.name	= "PWM0", | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| @ -445,7 +447,8 @@ static struct stmpe_variant_info stmpe801_noirq = { | ||||
|  * Touchscreen (STMPE811 or STMPE610) | ||||
|  */ | ||||
| 
 | ||||
| static const struct resource stmpe_ts_resources[] = { | ||||
| static struct resource stmpe_ts_resources[] = { | ||||
| 	/* Start and end filled dynamically */ | ||||
| 	{ | ||||
| 		.name	= "TOUCH_DET", | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| @ -467,7 +470,8 @@ static const struct mfd_cell stmpe_ts_cell = { | ||||
|  * ADC (STMPE811) | ||||
|  */ | ||||
| 
 | ||||
| static const struct resource stmpe_adc_resources[] = { | ||||
| static struct resource stmpe_adc_resources[] = { | ||||
| 	/* Start and end filled dynamically */ | ||||
| 	{ | ||||
| 		.name	= "STMPE_TEMP_SENS", | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
|  | ||||
| @ -393,6 +393,14 @@ config PWM_MXS | ||||
| 	  To compile this driver as a module, choose M here: the module | ||||
| 	  will be called pwm-mxs. | ||||
| 
 | ||||
| config PWM_NTXEC | ||||
| 	tristate "Netronix embedded controller PWM support" | ||||
| 	depends on MFD_NTXEC | ||||
| 	help | ||||
| 	  Say yes here if you want to support the PWM output of the embedded | ||||
| 	  controller found in certain e-book readers designed by the original | ||||
| 	  design manufacturer Netronix. | ||||
| 
 | ||||
| config PWM_OMAP_DMTIMER | ||||
| 	tristate "OMAP Dual-Mode Timer PWM support" | ||||
| 	depends on OF | ||||
|  | ||||
| @ -35,6 +35,7 @@ obj-$(CONFIG_PWM_MESON)		+= pwm-meson.o | ||||
| obj-$(CONFIG_PWM_MEDIATEK)	+= pwm-mediatek.o | ||||
| obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o | ||||
| obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o | ||||
| obj-$(CONFIG_PWM_NTXEC)		+= pwm-ntxec.o | ||||
| obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o | ||||
| obj-$(CONFIG_PWM_PCA9685)	+= pwm-pca9685.o | ||||
| obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o | ||||
|  | ||||
							
								
								
									
										184
									
								
								drivers/pwm/pwm-ntxec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								drivers/pwm/pwm-ntxec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,184 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| /*
 | ||||
|  * The Netronix embedded controller is a microcontroller found in some | ||||
|  * e-book readers designed by the original design manufacturer Netronix, Inc. | ||||
|  * It contains RTC, battery monitoring, system power management, and PWM | ||||
|  * functionality. | ||||
|  * | ||||
|  * This driver implements PWM output. | ||||
|  * | ||||
|  * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net> | ||||
|  * | ||||
|  * Limitations: | ||||
|  * - The get_state callback is not implemented, because the current state of | ||||
|  *   the PWM output can't be read back from the hardware. | ||||
|  * - The hardware can only generate normal polarity output. | ||||
|  * - The period and duty cycle can't be changed together in one atomic action. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/mfd/ntxec.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/pwm.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct ntxec_pwm { | ||||
| 	struct device *dev; | ||||
| 	struct ntxec *ec; | ||||
| 	struct pwm_chip chip; | ||||
| }; | ||||
| 
 | ||||
| static struct ntxec_pwm *ntxec_pwm_from_chip(struct pwm_chip *chip) | ||||
| { | ||||
| 	return container_of(chip, struct ntxec_pwm, chip); | ||||
| } | ||||
| 
 | ||||
| #define NTXEC_REG_AUTO_OFF_HI	0xa1 | ||||
| #define NTXEC_REG_AUTO_OFF_LO	0xa2 | ||||
| #define NTXEC_REG_ENABLE	0xa3 | ||||
| #define NTXEC_REG_PERIOD_LOW	0xa4 | ||||
| #define NTXEC_REG_PERIOD_HIGH	0xa5 | ||||
| #define NTXEC_REG_DUTY_LOW	0xa6 | ||||
| #define NTXEC_REG_DUTY_HIGH	0xa7 | ||||
| 
 | ||||
| /*
 | ||||
|  * The time base used in the EC is 8MHz, or 125ns. Period and duty cycle are | ||||
|  * measured in this unit. | ||||
|  */ | ||||
| #define TIME_BASE_NS 125 | ||||
| 
 | ||||
| /*
 | ||||
|  * The maximum input value (in nanoseconds) is determined by the time base and | ||||
|  * the range of the hardware registers that hold the converted value. | ||||
|  * It fits into 32 bits, so we can do our calculations in 32 bits as well. | ||||
|  */ | ||||
| #define MAX_PERIOD_NS (TIME_BASE_NS * 0xffff) | ||||
| 
 | ||||
| static int ntxec_pwm_set_raw_period_and_duty_cycle(struct pwm_chip *chip, | ||||
| 						   int period, int duty) | ||||
| { | ||||
| 	struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Changes to the period and duty cycle take effect as soon as the | ||||
| 	 * corresponding low byte is written, so the hardware may be configured | ||||
| 	 * to an inconsistent state after the period is written and before the | ||||
| 	 * duty cycle is fully written. If, in such a case, the old duty cycle | ||||
| 	 * is longer than the new period, the EC may output 100% for a moment. | ||||
| 	 * | ||||
| 	 * To minimize the time between the changes to period and duty cycle | ||||
| 	 * taking effect, the writes are interleaved. | ||||
| 	 */ | ||||
| 
 | ||||
| 	struct reg_sequence regs[] = { | ||||
| 		{ NTXEC_REG_PERIOD_HIGH, ntxec_reg8(period >> 8) }, | ||||
| 		{ NTXEC_REG_DUTY_HIGH, ntxec_reg8(duty >> 8) }, | ||||
| 		{ NTXEC_REG_PERIOD_LOW, ntxec_reg8(period) }, | ||||
| 		{ NTXEC_REG_DUTY_LOW, ntxec_reg8(duty) }, | ||||
| 	}; | ||||
| 
 | ||||
| 	return regmap_multi_reg_write(priv->ec->regmap, regs, ARRAY_SIZE(regs)); | ||||
| } | ||||
| 
 | ||||
| static int ntxec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm_dev, | ||||
| 			   const struct pwm_state *state) | ||||
| { | ||||
| 	struct ntxec_pwm *priv = ntxec_pwm_from_chip(chip); | ||||
| 	unsigned int period, duty; | ||||
| 	int res; | ||||
| 
 | ||||
| 	if (state->polarity != PWM_POLARITY_NORMAL) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	period = min_t(u64, state->period, MAX_PERIOD_NS); | ||||
| 	duty   = min_t(u64, state->duty_cycle, period); | ||||
| 
 | ||||
| 	period /= TIME_BASE_NS; | ||||
| 	duty   /= TIME_BASE_NS; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Writing a duty cycle of zero puts the device into a state where | ||||
| 	 * writing a higher duty cycle doesn't result in the brightness that it | ||||
| 	 * usually results in. This can be fixed by cycling the ENABLE register. | ||||
| 	 * | ||||
| 	 * As a workaround, write ENABLE=0 when the duty cycle is zero. | ||||
| 	 * The case that something has previously set the duty cycle to zero | ||||
| 	 * but ENABLE=1, is not handled. | ||||
| 	 */ | ||||
| 	if (state->enabled && duty != 0) { | ||||
| 		res = ntxec_pwm_set_raw_period_and_duty_cycle(chip, period, duty); | ||||
| 		if (res) | ||||
| 			return res; | ||||
| 
 | ||||
| 		res = regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(1)); | ||||
| 		if (res) | ||||
| 			return res; | ||||
| 
 | ||||
| 		/* Disable the auto-off timer */ | ||||
| 		res = regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_HI, ntxec_reg8(0xff)); | ||||
| 		if (res) | ||||
| 			return res; | ||||
| 
 | ||||
| 		return regmap_write(priv->ec->regmap, NTXEC_REG_AUTO_OFF_LO, ntxec_reg8(0xff)); | ||||
| 	} else { | ||||
| 		return regmap_write(priv->ec->regmap, NTXEC_REG_ENABLE, ntxec_reg8(0)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static const struct pwm_ops ntxec_pwm_ops = { | ||||
| 	.owner = THIS_MODULE, | ||||
| 	.apply = ntxec_pwm_apply, | ||||
| 	/*
 | ||||
| 	 * No .get_state callback, because the current state cannot be read | ||||
| 	 * back from the hardware. | ||||
| 	 */ | ||||
| }; | ||||
| 
 | ||||
| static int ntxec_pwm_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct ntxec *ec = dev_get_drvdata(pdev->dev.parent); | ||||
| 	struct ntxec_pwm *priv; | ||||
| 	struct pwm_chip *chip; | ||||
| 
 | ||||
| 	pdev->dev.of_node = pdev->dev.parent->of_node; | ||||
| 
 | ||||
| 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||||
| 	if (!priv) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	priv->ec = ec; | ||||
| 	priv->dev = &pdev->dev; | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, priv); | ||||
| 
 | ||||
| 	chip = &priv->chip; | ||||
| 	chip->dev = &pdev->dev; | ||||
| 	chip->ops = &ntxec_pwm_ops; | ||||
| 	chip->base = -1; | ||||
| 	chip->npwm = 1; | ||||
| 
 | ||||
| 	return pwmchip_add(chip); | ||||
| } | ||||
| 
 | ||||
| static int ntxec_pwm_remove(struct platform_device *pdev) | ||||
| { | ||||
| 	struct ntxec_pwm *priv = platform_get_drvdata(pdev); | ||||
| 	struct pwm_chip *chip = &priv->chip; | ||||
| 
 | ||||
| 	return pwmchip_remove(chip); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver ntxec_pwm_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "ntxec-pwm", | ||||
| 	}, | ||||
| 	.probe = ntxec_pwm_probe, | ||||
| 	.remove = ntxec_pwm_remove, | ||||
| }; | ||||
| module_platform_driver(ntxec_pwm_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>"); | ||||
| MODULE_DESCRIPTION("PWM driver for Netronix EC"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_ALIAS("platform:ntxec-pwm"); | ||||
| @ -204,6 +204,17 @@ config REGULATOR_BD70528 | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called bd70528-regulator. | ||||
| 
 | ||||
| config REGULATOR_BD71815 | ||||
| 	tristate "ROHM BD71815 Power Regulator" | ||||
| 	depends on MFD_ROHM_BD71828 | ||||
| 	help | ||||
| 	  This driver supports voltage regulators on ROHM BD71815 PMIC. | ||||
| 	  This will enable support for the software controllable buck | ||||
| 	  and LDO regulators and a current regulator for LEDs. | ||||
| 
 | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called bd71815-regulator. | ||||
| 
 | ||||
| config REGULATOR_BD71828 | ||||
| 	tristate "ROHM BD71828 Power Regulator" | ||||
| 	depends on MFD_ROHM_BD71828 | ||||
|  | ||||
| @ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_ATC260X) += atc260x-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BCM590XX) += bcm590xx-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BD70528) += bd70528-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BD71815)	+= bd71815-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BD71828) += bd71828-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o | ||||
| obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o | ||||
|  | ||||
							
								
								
									
										652
									
								
								drivers/regulator/bd71815-regulator.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										652
									
								
								drivers/regulator/bd71815-regulator.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,652 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-only
 | ||||
| //
 | ||||
| // Copyright 2014 Embest Technology Co. Ltd. Inc.
 | ||||
| // bd71815-regulator.c ROHM BD71815 regulator driver
 | ||||
| //
 | ||||
| // Author: Tony Luo <luofc@embedinfo.com>
 | ||||
| //
 | ||||
| // Partially rewritten at 2021 by
 | ||||
| // Matti Vaittinen <matti.vaitinen@fi.rohmeurope.com>
 | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/init.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/regulator/driver.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/mfd/rohm-generic.h> | ||||
| #include <linux/mfd/rohm-bd71815.h> | ||||
| #include <linux/regulator/of_regulator.h> | ||||
| 
 | ||||
| struct bd71815_regulator { | ||||
| 	struct regulator_desc desc; | ||||
| 	const struct rohm_dvs_config *dvs; | ||||
| }; | ||||
| 
 | ||||
| struct bd71815_pmic { | ||||
| 	struct bd71815_regulator descs[BD71815_REGULATOR_CNT]; | ||||
| 	struct regmap *regmap; | ||||
| 	struct device *dev; | ||||
| 	struct gpio_descs *gps; | ||||
| 	struct regulator_dev *rdev[BD71815_REGULATOR_CNT]; | ||||
| }; | ||||
| 
 | ||||
| static const int bd7181x_wled_currents[] = { | ||||
| 	10, 20, 30, 50, 70, 100, 200, 300, 500, 700, 1000, 2000, 3000, 4000, | ||||
| 	5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, | ||||
| 	16000, 17000, 18000, 19000, 20000, 21000, 22000, 23000, 24000, 25000, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config buck1_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_BUCK1_VOLT_H, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= BD71815_BUCK_RUN_ON, | ||||
| 	.snvs_on_mask		= BD71815_BUCK_SNVS_ON, | ||||
| 	.suspend_reg		= BD71815_REG_BUCK1_VOLT_L, | ||||
| 	.suspend_mask		= BD71815_VOLT_MASK, | ||||
| 	.suspend_on_mask	= BD71815_BUCK_SUSP_ON, | ||||
| 	.lpsr_reg		= BD71815_REG_BUCK1_VOLT_L, | ||||
| 	.lpsr_mask		= BD71815_VOLT_MASK, | ||||
| 	.lpsr_on_mask		= BD71815_BUCK_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config buck2_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_BUCK2_VOLT_H, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= BD71815_BUCK_RUN_ON, | ||||
| 	.snvs_on_mask		= BD71815_BUCK_SNVS_ON, | ||||
| 	.suspend_reg		= BD71815_REG_BUCK2_VOLT_L, | ||||
| 	.suspend_mask		= BD71815_VOLT_MASK, | ||||
| 	.suspend_on_mask	= BD71815_BUCK_SUSP_ON, | ||||
| 	.lpsr_reg		= BD71815_REG_BUCK2_VOLT_L, | ||||
| 	.lpsr_mask		= BD71815_VOLT_MASK, | ||||
| 	.lpsr_on_mask		= BD71815_BUCK_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config buck3_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_BUCK3_VOLT, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= BD71815_BUCK_RUN_ON, | ||||
| 	.snvs_on_mask		= BD71815_BUCK_SNVS_ON, | ||||
| 	.suspend_on_mask	= BD71815_BUCK_SUSP_ON, | ||||
| 	.lpsr_on_mask		= BD71815_BUCK_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config buck4_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_BUCK4_VOLT, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= BD71815_BUCK_RUN_ON, | ||||
| 	.snvs_on_mask		= BD71815_BUCK_SNVS_ON, | ||||
| 	.suspend_on_mask	= BD71815_BUCK_SUSP_ON, | ||||
| 	.lpsr_on_mask		= BD71815_BUCK_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldo1_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_LDO_MODE1, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= LDO1_RUN_ON, | ||||
| 	.snvs_on_mask		= LDO1_SNVS_ON, | ||||
| 	.suspend_on_mask	= LDO1_SUSP_ON, | ||||
| 	.lpsr_on_mask		= LDO1_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldo2_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_LDO_MODE2, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= LDO2_RUN_ON, | ||||
| 	.snvs_on_mask		= LDO2_SNVS_ON, | ||||
| 	.suspend_on_mask	= LDO2_SUSP_ON, | ||||
| 	.lpsr_on_mask		= LDO2_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldo3_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_LDO_MODE2, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= LDO3_RUN_ON, | ||||
| 	.snvs_on_mask		= LDO3_SNVS_ON, | ||||
| 	.suspend_on_mask	= LDO3_SUSP_ON, | ||||
| 	.lpsr_on_mask		= LDO3_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldo4_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_LDO_MODE3, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= LDO4_RUN_ON, | ||||
| 	.snvs_on_mask		= LDO4_SNVS_ON, | ||||
| 	.suspend_on_mask	= LDO4_SUSP_ON, | ||||
| 	.lpsr_on_mask		= LDO4_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldo5_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_LDO_MODE3, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= LDO5_RUN_ON, | ||||
| 	.snvs_on_mask		= LDO5_SNVS_ON, | ||||
| 	.suspend_on_mask	= LDO5_SUSP_ON, | ||||
| 	.lpsr_on_mask		= LDO5_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config dvref_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_on_mask		= DVREF_RUN_ON, | ||||
| 	.snvs_on_mask		= DVREF_SNVS_ON, | ||||
| 	.suspend_on_mask	= DVREF_SUSP_ON, | ||||
| 	.lpsr_on_mask		= DVREF_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config ldolpsr_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_on_mask		= DVREF_RUN_ON, | ||||
| 	.snvs_on_mask		= DVREF_SNVS_ON, | ||||
| 	.suspend_on_mask	= DVREF_SUSP_ON, | ||||
| 	.lpsr_on_mask		= DVREF_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static const struct rohm_dvs_config buck5_dvs = { | ||||
| 	.level_map		= ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_SNVS | | ||||
| 				  ROHM_DVS_LEVEL_SUSPEND | ROHM_DVS_LEVEL_LPSR, | ||||
| 	.run_reg		= BD71815_REG_BUCK5_VOLT, | ||||
| 	.run_mask		= BD71815_VOLT_MASK, | ||||
| 	.run_on_mask		= BD71815_BUCK_RUN_ON, | ||||
| 	.snvs_on_mask		= BD71815_BUCK_SNVS_ON, | ||||
| 	.suspend_on_mask	= BD71815_BUCK_SUSP_ON, | ||||
| 	.lpsr_on_mask		= BD71815_BUCK_LPSR_ON, | ||||
| }; | ||||
| 
 | ||||
| static int set_hw_dvs_levels(struct device_node *np, | ||||
| 			     const struct regulator_desc *desc, | ||||
| 			     struct regulator_config *cfg) | ||||
| { | ||||
| 	struct bd71815_regulator *data; | ||||
| 
 | ||||
| 	data = container_of(desc, struct bd71815_regulator, desc); | ||||
| 	return rohm_regulator_set_dvs_levels(data->dvs, np, desc, cfg->regmap); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Bucks 1 and 2 have two voltage selection registers where selected | ||||
|  * voltage can be set. Which of the registers is used can be either controlled | ||||
|  * by a control bit in register - or by HW state. If HW state specific voltages | ||||
|  * are given - then we assume HW state based control should be used. | ||||
|  * | ||||
|  * If volatge value is updated to currently selected register - then output | ||||
|  * voltage is immediately changed no matter what is set as ramp rate. Thus we | ||||
|  * default changing voltage by writing new value to inactive register and | ||||
|  * then updating the 'register selection' bit. This naturally only works when | ||||
|  * HW state machine is not used to select the voltage. | ||||
|  */ | ||||
| static int buck12_set_hw_dvs_levels(struct device_node *np, | ||||
| 				    const struct regulator_desc *desc, | ||||
| 				    struct regulator_config *cfg) | ||||
| { | ||||
| 	struct bd71815_regulator *data; | ||||
| 	int ret = 0, val; | ||||
| 
 | ||||
| 	data = container_of(desc, struct bd71815_regulator, desc); | ||||
| 
 | ||||
| 	if (of_find_property(np, "rohm,dvs-run-voltage", NULL) || | ||||
| 	    of_find_property(np, "rohm,dvs-suspend-voltage", NULL) || | ||||
| 	    of_find_property(np, "rohm,dvs-lpsr-voltage", NULL) || | ||||
| 	    of_find_property(np, "rohm,dvs-snvs-voltage", NULL)) { | ||||
| 		ret = regmap_read(cfg->regmap, desc->vsel_reg, &val); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 
 | ||||
| 		if (!(BD71815_BUCK_STBY_DVS & val) && | ||||
| 		    !(BD71815_BUCK_DVSSEL & val)) { | ||||
| 			int val2; | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * We are currently using voltage from _L. | ||||
| 			 * We'd better copy it to _H and switch to it to | ||||
| 			 * avoid shutting us down if LPSR or SUSPEND is set to | ||||
| 			 * disabled. _L value is at reg _H + 1 | ||||
| 			 */ | ||||
| 			ret = regmap_read(cfg->regmap, desc->vsel_reg + 1, | ||||
| 					  &val2); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 
 | ||||
| 			ret = regmap_update_bits(cfg->regmap, desc->vsel_reg, | ||||
| 						 BD71815_VOLT_MASK | | ||||
| 						 BD71815_BUCK_DVSSEL, | ||||
| 						 val2 | BD71815_BUCK_DVSSEL); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} | ||||
| 		ret = rohm_regulator_set_dvs_levels(data->dvs, np, desc, | ||||
| 						    cfg->regmap); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		/*
 | ||||
| 		 * DVS levels were given => use HW-state machine for voltage | ||||
| 		 * controls. NOTE: AFAIK, This means that if voltage is changed | ||||
| 		 * by SW the ramp-rate is not respected. Should we disable | ||||
| 		 * SW voltage control when the HW state machine is used? | ||||
| 		 */ | ||||
| 		ret = regmap_update_bits(cfg->regmap, desc->vsel_reg, | ||||
| 					 BD71815_BUCK_STBY_DVS, | ||||
| 					 BD71815_BUCK_STBY_DVS); | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * BUCK1/2 | ||||
|  * BUCK1RAMPRATE[1:0] BUCK1 DVS ramp rate setting | ||||
|  * 00: 10.00mV/usec	10mV 1uS | ||||
|  * 01: 5.00mV/usec	10mV 2uS | ||||
|  * 10: 2.50mV/usec	10mV 4uS | ||||
|  * 11: 1.25mV/usec	10mV 8uS | ||||
|  */ | ||||
| static const unsigned int bd7181x_ramp_table[] = { 1250, 2500, 5000, 10000 }; | ||||
| 
 | ||||
| static int bd7181x_led_set_current_limit(struct regulator_dev *rdev, | ||||
| 					int min_uA, int max_uA) | ||||
| { | ||||
| 	int ret; | ||||
| 	int onstatus; | ||||
| 
 | ||||
| 	onstatus = regulator_is_enabled_regmap(rdev); | ||||
| 
 | ||||
| 	ret = regulator_set_current_limit_regmap(rdev, min_uA, max_uA); | ||||
| 	if (!ret) { | ||||
| 		int newstatus; | ||||
| 
 | ||||
| 		newstatus = regulator_is_enabled_regmap(rdev); | ||||
| 		if (onstatus != newstatus) { | ||||
| 			/*
 | ||||
| 			 * HW FIX: spurious led status change detected. Toggle | ||||
| 			 * state as a workaround | ||||
| 			 */ | ||||
| 			if (onstatus) | ||||
| 				ret = regulator_enable_regmap(rdev); | ||||
| 			else | ||||
| 				ret = regulator_disable_regmap(rdev); | ||||
| 
 | ||||
| 			if (ret) | ||||
| 				dev_err(rdev_get_dev(rdev), | ||||
| 					"failed to revert the LED state (%d)\n", | ||||
| 					ret); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int bd7181x_buck12_get_voltage_sel(struct regulator_dev *rdev) | ||||
| { | ||||
| 	struct bd71815_pmic *pmic = rdev_get_drvdata(rdev); | ||||
| 	int rid = rdev_get_id(rdev); | ||||
| 	int ret, regh, regl, val; | ||||
| 
 | ||||
| 	regh = BD71815_REG_BUCK1_VOLT_H + rid * 0x2; | ||||
| 	regl = BD71815_REG_BUCK1_VOLT_L + rid * 0x2; | ||||
| 
 | ||||
| 	ret = regmap_read(pmic->regmap, regh, &val); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If we use HW state machine based voltage reg selection - then we | ||||
| 	 * return BD71815_REG_BUCK1_VOLT_H which is used at RUN. | ||||
| 	 * Else we do return the BD71815_REG_BUCK1_VOLT_H or | ||||
| 	 * BD71815_REG_BUCK1_VOLT_L depending on which is selected to be used | ||||
| 	 * by BD71815_BUCK_DVSSEL bit | ||||
| 	 */ | ||||
| 	if ((!(val & BD71815_BUCK_STBY_DVS)) && (!(val & BD71815_BUCK_DVSSEL))) | ||||
| 		ret = regmap_read(pmic->regmap, regl, &val); | ||||
| 
 | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	return val & BD71815_VOLT_MASK; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * For Buck 1/2. | ||||
|  */ | ||||
| static int bd7181x_buck12_set_voltage_sel(struct regulator_dev *rdev, | ||||
| 					  unsigned int sel) | ||||
| { | ||||
| 	struct bd71815_pmic *pmic = rdev_get_drvdata(rdev); | ||||
| 	int rid = rdev_get_id(rdev); | ||||
| 	int ret, val, reg, regh, regl; | ||||
| 
 | ||||
| 	regh = BD71815_REG_BUCK1_VOLT_H + rid*0x2; | ||||
| 	regl = BD71815_REG_BUCK1_VOLT_L + rid*0x2; | ||||
| 
 | ||||
| 	ret = regmap_read(pmic->regmap, regh, &val); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If bucks 1 & 2 are controlled by state machine - then the RUN state | ||||
| 	 * voltage is set to BD71815_REG_BUCK1_VOLT_H. Changing SUSPEND/LPSR | ||||
| 	 * voltages at runtime is not supported by this driver. | ||||
| 	 */ | ||||
| 	if (((val & BD71815_BUCK_STBY_DVS))) { | ||||
| 		return regmap_update_bits(pmic->regmap, regh, BD71815_VOLT_MASK, | ||||
| 					  sel); | ||||
| 	} | ||||
| 	/* Update new voltage to the register which is not selected now */ | ||||
| 	if (val & BD71815_BUCK_DVSSEL) | ||||
| 		reg = regl; | ||||
| 	else | ||||
| 		reg = regh; | ||||
| 
 | ||||
| 	ret = regmap_update_bits(pmic->regmap, reg, BD71815_VOLT_MASK, sel); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* Select the other DVS register to be used */ | ||||
| 	return regmap_update_bits(pmic->regmap, regh, BD71815_BUCK_DVSSEL, ~val); | ||||
| } | ||||
| 
 | ||||
| static const struct regulator_ops bd7181x_ldo_regulator_ops = { | ||||
| 	.enable = regulator_enable_regmap, | ||||
| 	.disable = regulator_disable_regmap, | ||||
| 	.is_enabled = regulator_is_enabled_regmap, | ||||
| 	.list_voltage = regulator_list_voltage_linear, | ||||
| 	.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||||
| 	.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||||
| }; | ||||
| 
 | ||||
| static const struct regulator_ops bd7181x_fixed_regulator_ops = { | ||||
| 	.enable = regulator_enable_regmap, | ||||
| 	.disable = regulator_disable_regmap, | ||||
| 	.is_enabled = regulator_is_enabled_regmap, | ||||
| 	.list_voltage = regulator_list_voltage_linear, | ||||
| }; | ||||
| 
 | ||||
| static const struct regulator_ops bd7181x_buck_regulator_ops = { | ||||
| 	.enable = regulator_enable_regmap, | ||||
| 	.disable = regulator_disable_regmap, | ||||
| 	.is_enabled = regulator_is_enabled_regmap, | ||||
| 	.list_voltage = regulator_list_voltage_linear, | ||||
| 	.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||||
| 	.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||||
| 	.set_voltage_time_sel = regulator_set_voltage_time_sel, | ||||
| }; | ||||
| 
 | ||||
| static const struct regulator_ops bd7181x_buck12_regulator_ops = { | ||||
| 	.enable = regulator_enable_regmap, | ||||
| 	.disable = regulator_disable_regmap, | ||||
| 	.is_enabled = regulator_is_enabled_regmap, | ||||
| 	.list_voltage = regulator_list_voltage_linear, | ||||
| 	.set_voltage_sel = bd7181x_buck12_set_voltage_sel, | ||||
| 	.get_voltage_sel = bd7181x_buck12_get_voltage_sel, | ||||
| 	.set_voltage_time_sel = regulator_set_voltage_time_sel, | ||||
| 	.set_ramp_delay = regulator_set_ramp_delay_regmap, | ||||
| }; | ||||
| 
 | ||||
| static const struct regulator_ops bd7181x_led_regulator_ops = { | ||||
| 	.enable = regulator_enable_regmap, | ||||
| 	.disable = regulator_disable_regmap, | ||||
| 	.is_enabled = regulator_is_enabled_regmap, | ||||
| 	.set_current_limit = bd7181x_led_set_current_limit, | ||||
| 	.get_current_limit = regulator_get_current_limit_regmap, | ||||
| }; | ||||
| 
 | ||||
| #define BD71815_FIXED_REG(_name, _id, ereg, emsk, voltage, _dvs)	\ | ||||
| 	[(_id)] = {							\ | ||||
| 		.desc = {						\ | ||||
| 			.name = #_name,					\ | ||||
| 			.of_match = of_match_ptr(#_name),		\ | ||||
| 			.regulators_node = of_match_ptr("regulators"),	\ | ||||
| 			.n_voltages = 1,				\ | ||||
| 			.ops = &bd7181x_fixed_regulator_ops,		\ | ||||
| 			.type = REGULATOR_VOLTAGE,			\ | ||||
| 			.id = (_id),					\ | ||||
| 			.owner = THIS_MODULE,				\ | ||||
| 			.min_uV = (voltage),				\ | ||||
| 			.enable_reg = (ereg),				\ | ||||
| 			.enable_mask = (emsk),				\ | ||||
| 			.of_parse_cb = set_hw_dvs_levels,		\ | ||||
| 		},							\ | ||||
| 		.dvs = (_dvs),						\ | ||||
| 	} | ||||
| 
 | ||||
| #define BD71815_BUCK_REG(_name, _id, vsel, ereg, min, max, step, _dvs)	\ | ||||
| 	[(_id)] = {							\ | ||||
| 		.desc = {						\ | ||||
| 			.name = #_name,					\ | ||||
| 			.of_match = of_match_ptr(#_name),		\ | ||||
| 			.regulators_node = of_match_ptr("regulators"),	\ | ||||
| 			.n_voltages = ((max) - (min)) / (step) + 1,	\ | ||||
| 			.ops = &bd7181x_buck_regulator_ops,		\ | ||||
| 			.type = REGULATOR_VOLTAGE,			\ | ||||
| 			.id = (_id),					\ | ||||
| 			.owner = THIS_MODULE,				\ | ||||
| 			.min_uV = (min),				\ | ||||
| 			.uV_step = (step),				\ | ||||
| 			.vsel_reg = (vsel),				\ | ||||
| 			.vsel_mask = BD71815_VOLT_MASK,			\ | ||||
| 			.enable_reg = (ereg),				\ | ||||
| 			.enable_mask = BD71815_BUCK_RUN_ON,		\ | ||||
| 			.of_parse_cb = set_hw_dvs_levels,		\ | ||||
| 		},							\ | ||||
| 		.dvs = (_dvs),						\ | ||||
| 	} | ||||
| 
 | ||||
| #define BD71815_BUCK12_REG(_name, _id, vsel, ereg, min, max, step,	\ | ||||
| 			   _dvs)					\ | ||||
| 	[(_id)] = {							\ | ||||
| 		.desc = {						\ | ||||
| 			.name = #_name,					\ | ||||
| 			.of_match = of_match_ptr(#_name),		\ | ||||
| 			.regulators_node = of_match_ptr("regulators"),	\ | ||||
| 			.n_voltages = ((max) - (min)) / (step) + 1,	\ | ||||
| 			.ops = &bd7181x_buck12_regulator_ops,		\ | ||||
| 			.type = REGULATOR_VOLTAGE,			\ | ||||
| 			.id = (_id),					\ | ||||
| 			.owner = THIS_MODULE,				\ | ||||
| 			.min_uV = (min),				\ | ||||
| 			.uV_step = (step),				\ | ||||
| 			.vsel_reg = (vsel),				\ | ||||
| 			.vsel_mask = 0x3f,				\ | ||||
| 			.enable_reg = (ereg),				\ | ||||
| 			.enable_mask = 0x04,				\ | ||||
| 			.ramp_reg = (ereg),				\ | ||||
| 			.ramp_mask = BD71815_BUCK_RAMPRATE_MASK,	\ | ||||
| 			.ramp_delay_table = bd7181x_ramp_table,		\ | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd7181x_ramp_table),\ | ||||
| 			.of_parse_cb = buck12_set_hw_dvs_levels,	\ | ||||
| 		},							\ | ||||
| 		.dvs = (_dvs),						\ | ||||
| 	} | ||||
| 
 | ||||
| #define BD71815_LED_REG(_name, _id, csel, mask, ereg, emsk, currents)	\ | ||||
| 	[(_id)] = {							\ | ||||
| 		.desc = {						\ | ||||
| 			.name = #_name,					\ | ||||
| 			.of_match = of_match_ptr(#_name),		\ | ||||
| 			.regulators_node = of_match_ptr("regulators"),	\ | ||||
| 			.n_current_limits = ARRAY_SIZE(currents),	\ | ||||
| 			.ops = &bd7181x_led_regulator_ops,		\ | ||||
| 			.type = REGULATOR_CURRENT,			\ | ||||
| 			.id = (_id),					\ | ||||
| 			.owner = THIS_MODULE,				\ | ||||
| 			.curr_table = currents,				\ | ||||
| 			.csel_reg = (csel),				\ | ||||
| 			.csel_mask = (mask),				\ | ||||
| 			.enable_reg = (ereg),				\ | ||||
| 			.enable_mask = (emsk),				\ | ||||
| 		},							\ | ||||
| 	} | ||||
| 
 | ||||
| #define BD71815_LDO_REG(_name, _id, vsel, ereg, emsk, min, max, step,	\ | ||||
| 			_dvs)						\ | ||||
| 	[(_id)] = {							\ | ||||
| 		.desc = {						\ | ||||
| 			.name = #_name,					\ | ||||
| 			.of_match = of_match_ptr(#_name),		\ | ||||
| 			.regulators_node = of_match_ptr("regulators"),	\ | ||||
| 			.n_voltages = ((max) - (min)) / (step) + 1,	\ | ||||
| 			.ops = &bd7181x_ldo_regulator_ops,		\ | ||||
| 			.type = REGULATOR_VOLTAGE,			\ | ||||
| 			.id = (_id),					\ | ||||
| 			.owner = THIS_MODULE,				\ | ||||
| 			.min_uV = (min),				\ | ||||
| 			.uV_step = (step),				\ | ||||
| 			.vsel_reg = (vsel),				\ | ||||
| 			.vsel_mask = BD71815_VOLT_MASK,			\ | ||||
| 			.enable_reg = (ereg),				\ | ||||
| 			.enable_mask = (emsk),				\ | ||||
| 			.of_parse_cb = set_hw_dvs_levels,		\ | ||||
| 		},							\ | ||||
| 		.dvs = (_dvs),						\ | ||||
| 	} | ||||
| 
 | ||||
| static struct bd71815_regulator bd71815_regulators[] = { | ||||
| 	BD71815_BUCK12_REG(buck1, BD71815_BUCK1, BD71815_REG_BUCK1_VOLT_H, | ||||
| 			   BD71815_REG_BUCK1_MODE, 800000, 2000000, 25000, | ||||
| 			   &buck1_dvs), | ||||
| 	BD71815_BUCK12_REG(buck2, BD71815_BUCK2, BD71815_REG_BUCK2_VOLT_H, | ||||
| 			   BD71815_REG_BUCK2_MODE, 800000, 2000000, 25000, | ||||
| 			   &buck2_dvs), | ||||
| 	BD71815_BUCK_REG(buck3, BD71815_BUCK3, BD71815_REG_BUCK3_VOLT, | ||||
| 			 BD71815_REG_BUCK3_MODE,  1200000, 2700000, 50000, | ||||
| 			 &buck3_dvs), | ||||
| 	BD71815_BUCK_REG(buck4, BD71815_BUCK4, BD71815_REG_BUCK4_VOLT, | ||||
| 			 BD71815_REG_BUCK4_MODE,  1100000, 1850000, 25000, | ||||
| 			 &buck4_dvs), | ||||
| 	BD71815_BUCK_REG(buck5, BD71815_BUCK5, BD71815_REG_BUCK5_VOLT, | ||||
| 			 BD71815_REG_BUCK5_MODE,  1800000, 3300000, 50000, | ||||
| 			 &buck5_dvs), | ||||
| 	BD71815_LDO_REG(ldo1, BD71815_LDO1, BD71815_REG_LDO1_VOLT, | ||||
| 			BD71815_REG_LDO_MODE1, LDO1_RUN_ON, 800000, 3300000, | ||||
| 			50000, &ldo1_dvs), | ||||
| 	BD71815_LDO_REG(ldo2, BD71815_LDO2, BD71815_REG_LDO2_VOLT, | ||||
| 			BD71815_REG_LDO_MODE2, LDO2_RUN_ON, 800000, 3300000, | ||||
| 			50000, &ldo2_dvs), | ||||
| 	/*
 | ||||
| 	 * Let's default LDO3 to be enabled by SW. We can override ops if DT | ||||
| 	 * says LDO3 should be enabled by HW when DCIN is connected. | ||||
| 	 */ | ||||
| 	BD71815_LDO_REG(ldo3, BD71815_LDO3, BD71815_REG_LDO3_VOLT, | ||||
| 			BD71815_REG_LDO_MODE2, LDO3_RUN_ON, 800000, 3300000, | ||||
| 			50000, &ldo3_dvs), | ||||
| 	BD71815_LDO_REG(ldo4, BD71815_LDO4, BD71815_REG_LDO4_VOLT, | ||||
| 			BD71815_REG_LDO_MODE3, LDO4_RUN_ON, 800000, 3300000, | ||||
| 			50000, &ldo4_dvs), | ||||
| 	BD71815_LDO_REG(ldo5, BD71815_LDO5, BD71815_REG_LDO5_VOLT_H, | ||||
| 			BD71815_REG_LDO_MODE3, LDO5_RUN_ON, 800000, 3300000, | ||||
| 			50000, &ldo5_dvs), | ||||
| 	BD71815_FIXED_REG(ldodvref, BD71815_LDODVREF, BD71815_REG_LDO_MODE4, | ||||
| 			  DVREF_RUN_ON, 3000000, &dvref_dvs), | ||||
| 	BD71815_FIXED_REG(ldolpsr, BD71815_LDOLPSR, BD71815_REG_LDO_MODE4, | ||||
| 			  LDO_LPSR_RUN_ON, 1800000, &ldolpsr_dvs), | ||||
| 	BD71815_LED_REG(wled, BD71815_WLED, BD71815_REG_LED_DIMM, LED_DIMM_MASK, | ||||
| 			BD71815_REG_LED_CTRL, LED_RUN_ON, | ||||
| 			bd7181x_wled_currents), | ||||
| }; | ||||
| 
 | ||||
| static int bd7181x_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct bd71815_pmic *pmic; | ||||
| 	struct regulator_config config = {}; | ||||
| 	int i, ret; | ||||
| 	struct gpio_desc *ldo4_en; | ||||
| 
 | ||||
| 	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); | ||||
| 	if (!pmic) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	memcpy(pmic->descs, bd71815_regulators,	sizeof(pmic->descs)); | ||||
| 
 | ||||
| 	pmic->dev = &pdev->dev; | ||||
| 	pmic->regmap = dev_get_regmap(pdev->dev.parent, NULL); | ||||
| 	if (!pmic->regmap) { | ||||
| 		dev_err(pmic->dev, "No parent regmap\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 	platform_set_drvdata(pdev, pmic); | ||||
| 	ldo4_en = devm_gpiod_get_from_of_node(&pdev->dev, | ||||
| 					      pdev->dev.parent->of_node, | ||||
| 						 "rohm,vsel-gpios", 0, | ||||
| 						 GPIOD_ASIS, "ldo4-en"); | ||||
| 
 | ||||
| 	if (IS_ERR(ldo4_en)) { | ||||
| 		ret = PTR_ERR(ldo4_en); | ||||
| 		if (ret != -ENOENT) | ||||
| 			return ret; | ||||
| 		ldo4_en = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Disable to go to ship-mode */ | ||||
| 	ret = regmap_update_bits(pmic->regmap, BD71815_REG_PWRCTRL, | ||||
| 				 RESTARTEN, 0); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	config.dev = pdev->dev.parent; | ||||
| 	config.regmap = pmic->regmap; | ||||
| 
 | ||||
| 	for (i = 0; i < BD71815_REGULATOR_CNT; i++) { | ||||
| 		struct regulator_desc *desc; | ||||
| 		struct regulator_dev *rdev; | ||||
| 
 | ||||
| 		desc = &pmic->descs[i].desc; | ||||
| 		if (i == BD71815_LDO4) | ||||
| 			config.ena_gpiod = ldo4_en; | ||||
| 
 | ||||
| 		config.driver_data = pmic; | ||||
| 
 | ||||
| 		rdev = devm_regulator_register(&pdev->dev, desc, &config); | ||||
| 		if (IS_ERR(rdev)) { | ||||
| 			dev_err(&pdev->dev, | ||||
| 				"failed to register %s regulator\n", | ||||
| 				desc->name); | ||||
| 			return PTR_ERR(rdev); | ||||
| 		} | ||||
| 		config.ena_gpiod = NULL; | ||||
| 		pmic->rdev[i] = rdev; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct platform_device_id bd7181x_pmic_id[] = { | ||||
| 	{ "bd71815-pmic", ROHM_CHIP_TYPE_BD71815 }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(platform, bd7181x_pmic_id); | ||||
| 
 | ||||
| static struct platform_driver bd7181x_regulator = { | ||||
| 	.driver = { | ||||
| 		.name = "bd7181x-pmic", | ||||
| 		.owner = THIS_MODULE, | ||||
| 	}, | ||||
| 	.probe = bd7181x_probe, | ||||
| 	.id_table = bd7181x_pmic_id, | ||||
| }; | ||||
| module_platform_driver(bd7181x_regulator); | ||||
| 
 | ||||
| MODULE_AUTHOR("Tony Luo <luofc@embedinfo.com>"); | ||||
| MODULE_DESCRIPTION("BD71815 voltage regulator driver"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| MODULE_ALIAS("platform:bd7181x-pmic"); | ||||
| @ -90,38 +90,7 @@ static const struct linear_range bd71828_ldo_volts[] = { | ||||
| 	REGULATOR_LINEAR_RANGE(3300000, 0x32, 0x3f, 0), | ||||
| }; | ||||
| 
 | ||||
| static int bd71828_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) | ||||
| { | ||||
| 	unsigned int val; | ||||
| 
 | ||||
| 	switch (ramp_delay) { | ||||
| 	case 1 ... 2500: | ||||
| 		val = 0; | ||||
| 		break; | ||||
| 	case 2501 ... 5000: | ||||
| 		val = 1; | ||||
| 		break; | ||||
| 	case 5001 ... 10000: | ||||
| 		val = 2; | ||||
| 		break; | ||||
| 	case 10001 ... 20000: | ||||
| 		val = 3; | ||||
| 		break; | ||||
| 	default: | ||||
| 		val = 3; | ||||
| 		dev_err(&rdev->dev, | ||||
| 			"ramp_delay: %d not supported, setting 20mV/uS", | ||||
| 			 ramp_delay); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * On BD71828 the ramp delay level control reg is at offset +2 to | ||||
| 	 * enable reg | ||||
| 	 */ | ||||
| 	return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg + 2, | ||||
| 				  BD71828_MASK_RAMP_DELAY, | ||||
| 				  val << (ffs(BD71828_MASK_RAMP_DELAY) - 1)); | ||||
| } | ||||
| static const unsigned int bd71828_ramp_delay[] = { 2500, 5000, 10000, 20000 }; | ||||
| 
 | ||||
| static int buck_set_hw_dvs_levels(struct device_node *np, | ||||
| 				  const struct regulator_desc *desc, | ||||
| @ -185,7 +154,7 @@ static const struct regulator_ops bd71828_dvs_buck_ops = { | ||||
| 	.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||||
| 	.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||||
| 	.set_voltage_time_sel = regulator_set_voltage_time_sel, | ||||
| 	.set_ramp_delay = bd71828_set_ramp_delay, | ||||
| 	.set_ramp_delay = regulator_set_ramp_delay_regmap, | ||||
| }; | ||||
| 
 | ||||
| static const struct regulator_ops bd71828_ldo_ops = { | ||||
| @ -219,6 +188,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { | ||||
| 			.enable_mask = BD71828_MASK_RUN_EN, | ||||
| 			.vsel_reg = BD71828_REG_BUCK1_VOLT, | ||||
| 			.vsel_mask = BD71828_MASK_BUCK1267_VOLT, | ||||
| 			.ramp_delay_table = bd71828_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), | ||||
| 			.ramp_reg = BD71828_REG_BUCK1_MODE, | ||||
| 			.ramp_mask = BD71828_MASK_RAMP_DELAY, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -261,6 +234,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { | ||||
| 			.enable_mask = BD71828_MASK_RUN_EN, | ||||
| 			.vsel_reg = BD71828_REG_BUCK2_VOLT, | ||||
| 			.vsel_mask = BD71828_MASK_BUCK1267_VOLT, | ||||
| 			.ramp_delay_table = bd71828_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), | ||||
| 			.ramp_reg = BD71828_REG_BUCK2_MODE, | ||||
| 			.ramp_mask = BD71828_MASK_RAMP_DELAY, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -421,6 +398,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { | ||||
| 			.enable_mask = BD71828_MASK_RUN_EN, | ||||
| 			.vsel_reg = BD71828_REG_BUCK6_VOLT, | ||||
| 			.vsel_mask = BD71828_MASK_BUCK1267_VOLT, | ||||
| 			.ramp_delay_table = bd71828_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), | ||||
| 			.ramp_reg = BD71828_REG_BUCK6_MODE, | ||||
| 			.ramp_mask = BD71828_MASK_RAMP_DELAY, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -458,6 +439,10 @@ static const struct bd71828_regulator_data bd71828_rdata[] = { | ||||
| 			.enable_mask = BD71828_MASK_RUN_EN, | ||||
| 			.vsel_reg = BD71828_REG_BUCK7_VOLT, | ||||
| 			.vsel_mask = BD71828_MASK_BUCK1267_VOLT, | ||||
| 			.ramp_delay_table = bd71828_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd71828_ramp_delay), | ||||
| 			.ramp_reg = BD71828_REG_BUCK7_MODE, | ||||
| 			.ramp_mask = BD71828_MASK_RAMP_DELAY, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
|  | ||||
| @ -86,37 +86,7 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = {	\ | ||||
|  * 10: 2.50mV/usec	10mV 4uS | ||||
|  * 11: 1.25mV/usec	10mV 8uS | ||||
|  */ | ||||
| static int bd718xx_buck1234_set_ramp_delay(struct regulator_dev *rdev, | ||||
| 					   int ramp_delay) | ||||
| { | ||||
| 	int id = rdev_get_id(rdev); | ||||
| 	unsigned int ramp_value; | ||||
| 
 | ||||
| 	dev_dbg(&rdev->dev, "Buck[%d] Set Ramp = %d\n", id + 1, | ||||
| 		ramp_delay); | ||||
| 	switch (ramp_delay) { | ||||
| 	case 1 ... 1250: | ||||
| 		ramp_value = BUCK_RAMPRATE_1P25MV; | ||||
| 		break; | ||||
| 	case 1251 ... 2500: | ||||
| 		ramp_value = BUCK_RAMPRATE_2P50MV; | ||||
| 		break; | ||||
| 	case 2501 ... 5000: | ||||
| 		ramp_value = BUCK_RAMPRATE_5P00MV; | ||||
| 		break; | ||||
| 	case 5001 ... 10000: | ||||
| 		ramp_value = BUCK_RAMPRATE_10P00MV; | ||||
| 		break; | ||||
| 	default: | ||||
| 		ramp_value = BUCK_RAMPRATE_10P00MV; | ||||
| 		dev_err(&rdev->dev, | ||||
| 			"%s: ramp_delay: %d not supported, setting 10000mV//us\n", | ||||
| 			rdev->desc->name, ramp_delay); | ||||
| 	} | ||||
| 
 | ||||
| 	return regmap_update_bits(rdev->regmap, BD718XX_REG_BUCK1_CTRL + id, | ||||
| 				  BUCK_RAMPRATE_MASK, ramp_value << 6); | ||||
| } | ||||
| static const unsigned int bd718xx_ramp_delay[] = { 10000, 5000, 2500, 1250 }; | ||||
| 
 | ||||
| /* These functions are used when regulators are under HW state machine control.
 | ||||
|  * We assume PMIC is in RUN state because SW running and able to query the | ||||
| @ -378,7 +348,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = { | ||||
| 	.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||||
| 	.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||||
| 	.set_voltage_time_sel = regulator_set_voltage_time_sel, | ||||
| 	.set_ramp_delay = bd718xx_buck1234_set_ramp_delay, | ||||
| 	.set_ramp_delay = regulator_set_ramp_delay_regmap, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
| @ -387,7 +357,7 @@ static const struct regulator_ops bd71837_buck34_ops_hwctrl = { | ||||
| BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range, | ||||
| 	    NULL, regulator_set_voltage_sel_regmap, | ||||
| 	    regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, | ||||
| 	    bd718xx_buck1234_set_ramp_delay); | ||||
| 	    /* bd718xx_buck1234_set_ramp_delay */ regulator_set_ramp_delay_regmap); | ||||
| 
 | ||||
| /*
 | ||||
|  * BD71837 BUCK1/2/3/4 | ||||
| @ -645,6 +615,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = { | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71847_BUCK1_STARTUP_TIME, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD718XX_REG_BUCK1_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| 		.dvs = { | ||||
| @ -678,6 +652,10 @@ static struct bd718xx_regulator_data bd71847_regulators[] = { | ||||
| 			.enable_reg = BD718XX_REG_BUCK2_CTRL, | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71847_BUCK2_STARTUP_TIME, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD718XX_REG_BUCK2_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -985,6 +963,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = { | ||||
| 			.enable_reg = BD718XX_REG_BUCK1_CTRL, | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71837_BUCK1_STARTUP_TIME, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD718XX_REG_BUCK1_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -1019,6 +1001,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = { | ||||
| 			.enable_reg = BD718XX_REG_BUCK2_CTRL, | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71837_BUCK2_STARTUP_TIME, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD718XX_REG_BUCK2_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -1050,6 +1036,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = { | ||||
| 			.enable_reg = BD71837_REG_BUCK3_CTRL, | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71837_BUCK3_STARTUP_TIME, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD71837_REG_BUCK3_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
| @ -1079,6 +1069,10 @@ static struct bd718xx_regulator_data bd71837_regulators[] = { | ||||
| 			.enable_reg = BD71837_REG_BUCK4_CTRL, | ||||
| 			.enable_mask = BD718XX_BUCK_EN, | ||||
| 			.enable_time = BD71837_BUCK4_STARTUP_TIME, | ||||
| 			.ramp_delay_table = bd718xx_ramp_delay, | ||||
| 			.n_ramp_values = ARRAY_SIZE(bd718xx_ramp_delay), | ||||
| 			.ramp_reg = BD71837_REG_BUCK4_CTRL, | ||||
| 			.ramp_mask = BUCK_RAMPRATE_MASK, | ||||
| 			.owner = THIS_MODULE, | ||||
| 			.of_parse_cb = buck_set_hw_dvs_levels, | ||||
| 		}, | ||||
|  | ||||
| @ -22,13 +22,26 @@ static int set_dvs_level(const struct regulator_desc *desc, | ||||
| 			return ret; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* If voltage is set to 0 => disable */ | ||||
| 	if (uv == 0) { | ||||
| 		if (omask) | ||||
| 			return regmap_update_bits(regmap, oreg, omask, 0); | ||||
| 	} | ||||
| 	/* Some setups don't allow setting own voltage but do allow enabling */ | ||||
| 	if (!mask) { | ||||
| 		if (omask) | ||||
| 			return regmap_update_bits(regmap, oreg, omask, omask); | ||||
| 
 | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	for (i = 0; i < desc->n_voltages; i++) { | ||||
| 		ret = regulator_desc_list_voltage_linear_range(desc, i); | ||||
| 		/* NOTE to next hacker - Does not support pickable ranges */ | ||||
| 		if (desc->linear_range_selectors) | ||||
| 			return -EINVAL; | ||||
| 		if (desc->n_linear_ranges) | ||||
| 			ret = regulator_desc_list_voltage_linear_range(desc, i); | ||||
| 		else | ||||
| 			ret = regulator_desc_list_voltage_linear(desc, i); | ||||
| 		if (ret < 0) | ||||
| 			continue; | ||||
| 		if (ret == uv) { | ||||
| @ -82,6 +95,12 @@ int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, | ||||
| 				mask = dvs->lpsr_mask; | ||||
| 				omask = dvs->lpsr_on_mask; | ||||
| 				break; | ||||
| 			case ROHM_DVS_LEVEL_SNVS: | ||||
| 				prop = "rohm,dvs-snvs-voltage"; | ||||
| 				reg = dvs->snvs_reg; | ||||
| 				mask = dvs->snvs_mask; | ||||
| 				omask = dvs->snvs_on_mask; | ||||
| 				break; | ||||
| 			default: | ||||
| 				return -EINVAL; | ||||
| 			} | ||||
|  | ||||
| @ -501,11 +501,11 @@ config RTC_DRV_M41T80_WDT | ||||
| 	  watchdog timer in the ST M41T60 and M41T80 RTC chips series. | ||||
| 
 | ||||
| config RTC_DRV_BD70528 | ||||
| 	tristate "ROHM BD70528 PMIC RTC" | ||||
| 	depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) | ||||
| 	tristate "ROHM BD70528, BD71815 and BD71828 PMIC RTC" | ||||
| 	depends on MFD_ROHM_BD71828 || MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) | ||||
| 	help | ||||
| 	  If you say Y here you will get support for the RTC | ||||
| 	  block on ROHM BD70528 and BD71828 Power Management IC. | ||||
| 	  block on ROHM BD70528, BD71815 and BD71828 Power Management IC. | ||||
| 
 | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called rtc-bd70528. | ||||
| @ -1296,6 +1296,14 @@ config RTC_DRV_CROS_EC | ||||
| 	  This driver can also be built as a module. If so, the module | ||||
| 	  will be called rtc-cros-ec. | ||||
| 
 | ||||
| config RTC_DRV_NTXEC | ||||
| 	tristate "Netronix embedded controller RTC" | ||||
| 	depends on MFD_NTXEC | ||||
| 	help | ||||
| 	  Say yes here if you want to support the RTC functionality of the | ||||
| 	  embedded controller found in certain e-book readers designed by the | ||||
| 	  original design manufacturer Netronix. | ||||
| 
 | ||||
| comment "on-CPU RTC drivers" | ||||
| 
 | ||||
| config RTC_DRV_ASM9260 | ||||
|  | ||||
| @ -108,6 +108,7 @@ obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o | ||||
| obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o | ||||
| obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o | ||||
| obj-$(CONFIG_RTC_DRV_MXC_V2)	+= rtc-mxc_v2.o | ||||
| obj-$(CONFIG_RTC_DRV_NTXEC)	+= rtc-ntxec.o | ||||
| obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o | ||||
| obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o | ||||
| obj-$(CONFIG_RTC_DRV_PALMAS)	+= rtc-palmas.o | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| 
 | ||||
| #include <linux/bcd.h> | ||||
| #include <linux/mfd/rohm-bd70528.h> | ||||
| #include <linux/mfd/rohm-bd71815.h> | ||||
| #include <linux/mfd/rohm-bd71828.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| @ -13,6 +14,12 @@ | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/rtc.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * On BD71828 and BD71815 the ALM0 MASK is 14 bytes after the ALM0 | ||||
|  * block start | ||||
|  */ | ||||
| #define BD718XX_ALM_EN_OFFSET 14 | ||||
| 
 | ||||
| /*
 | ||||
|  * We read regs RTC_SEC => RTC_YEAR | ||||
|  * this struct is ordered according to chip registers. | ||||
| @ -52,8 +59,10 @@ struct bd70528_rtc_alm { | ||||
| 
 | ||||
| struct bd70528_rtc { | ||||
| 	struct rohm_regmap_dev *parent; | ||||
| 	struct regmap *regmap; | ||||
| 	struct device *dev; | ||||
| 	u8 reg_time_start; | ||||
| 	u8 bd718xx_alm_block_start; | ||||
| 	bool has_rtc_timers; | ||||
| }; | ||||
| 
 | ||||
| @ -234,10 +243,9 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 	int ret; | ||||
| 	struct bd71828_rtc_alm alm; | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 
 | ||||
| 	ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START, | ||||
| 			       &alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm, | ||||
| 			       sizeof(alm)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read alarm regs\n"); | ||||
| 		return ret; | ||||
| @ -250,8 +258,8 @@ static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 	else | ||||
| 		alm.alm_mask |= BD70528_MASK_ALM_EN; | ||||
| 
 | ||||
| 	ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START, | ||||
| 				&alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_write(r->regmap, r->bd718xx_alm_block_start, &alm, | ||||
| 				sizeof(alm)); | ||||
| 	if (ret) | ||||
| 		dev_err(dev, "Failed to set alarm time\n"); | ||||
| 
 | ||||
| @ -265,17 +273,16 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 	struct bd70528_rtc_alm alm; | ||||
| 	int ret; | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 
 | ||||
| 	ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START, | ||||
| 			       &wake, sizeof(wake)); | ||||
| 	ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_WAKE_START, &wake, | ||||
| 			       sizeof(wake)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read wake regs\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START, | ||||
| 			       &alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm, | ||||
| 			       sizeof(alm)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read alarm regs\n"); | ||||
| 		return ret; | ||||
| @ -292,15 +299,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 		wake.ctrl &= ~BD70528_MASK_WAKE_EN; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = regmap_bulk_write(parent->regmap, | ||||
| 				BD70528_REG_RTC_WAKE_START, &wake, | ||||
| 	ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_WAKE_START, &wake, | ||||
| 				sizeof(wake)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to set wake time\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START, | ||||
| 				&alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_write(r->regmap, BD70528_REG_RTC_ALM_START, &alm, | ||||
| 				sizeof(alm)); | ||||
| 	if (ret) | ||||
| 		dev_err(dev, "Failed to set alarm time\n"); | ||||
| 
 | ||||
| @ -312,10 +318,9 @@ static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 	int ret; | ||||
| 	struct bd71828_rtc_alm alm; | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 
 | ||||
| 	ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START, | ||||
| 			       &alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_read(r->regmap, r->bd718xx_alm_block_start, &alm, | ||||
| 			       sizeof(alm)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read alarm regs\n"); | ||||
| 		return ret; | ||||
| @ -336,10 +341,9 @@ static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a) | ||||
| 	struct bd70528_rtc_alm alm; | ||||
| 	int ret; | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 
 | ||||
| 	ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START, | ||||
| 			       &alm, sizeof(alm)); | ||||
| 	ret = regmap_bulk_read(r->regmap, BD70528_REG_RTC_ALM_START, &alm, | ||||
| 			       sizeof(alm)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read alarm regs\n"); | ||||
| 		return ret; | ||||
| @ -360,14 +364,12 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) | ||||
| 	int ret, tmpret, old_states; | ||||
| 	struct bd70528_rtc_data rtc_data; | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 
 | ||||
| 	ret = bd70528_disable_rtc_based_timers(r, &old_states); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	tmpret = regmap_bulk_read(parent->regmap, | ||||
| 				  r->reg_time_start, &rtc_data, | ||||
| 	tmpret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data, | ||||
| 				  sizeof(rtc_data)); | ||||
| 	if (tmpret) { | ||||
| 		dev_err(dev, "Failed to read RTC time registers\n"); | ||||
| @ -375,8 +377,7 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) | ||||
| 	} | ||||
| 	tm2rtc(t, &rtc_data); | ||||
| 
 | ||||
| 	tmpret = regmap_bulk_write(parent->regmap, | ||||
| 				   r->reg_time_start, &rtc_data, | ||||
| 	tmpret = regmap_bulk_write(r->regmap, r->reg_time_start, &rtc_data, | ||||
| 				   sizeof(rtc_data)); | ||||
| 	if (tmpret) { | ||||
| 		dev_err(dev, "Failed to set RTC time\n"); | ||||
| @ -410,13 +411,11 @@ static int bd70528_set_time(struct device *dev, struct rtc_time *t) | ||||
| static int bd70528_get_time(struct device *dev, struct rtc_time *t) | ||||
| { | ||||
| 	struct bd70528_rtc *r = dev_get_drvdata(dev); | ||||
| 	struct rohm_regmap_dev *parent = r->parent; | ||||
| 	struct bd70528_rtc_data rtc_data; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* read the RTC date and time registers all at once */ | ||||
| 	ret = regmap_bulk_read(parent->regmap, | ||||
| 			       r->reg_time_start, &rtc_data, | ||||
| 	ret = regmap_bulk_read(r->regmap, r->reg_time_start, &rtc_data, | ||||
| 			       sizeof(rtc_data)); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "Failed to read RTC time (err %d)\n", ret); | ||||
| @ -443,7 +442,7 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled) | ||||
| 		dev_err(dev, "Failed to change wake state\n"); | ||||
| 		goto out_unlock; | ||||
| 	} | ||||
| 	ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK, | ||||
| 	ret = regmap_update_bits(r->regmap, BD70528_REG_RTC_ALM_MASK, | ||||
| 				 BD70528_MASK_ALM_EN, enableval); | ||||
| 	if (ret) | ||||
| 		dev_err(dev, "Failed to change alarm state\n"); | ||||
| @ -462,8 +461,9 @@ static int bd71828_alm_enable(struct device *dev, unsigned int enabled) | ||||
| 	if (!enabled) | ||||
| 		enableval = 0; | ||||
| 
 | ||||
| 	ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK, | ||||
| 				 BD70528_MASK_ALM_EN, enableval); | ||||
| 	ret = regmap_update_bits(r->regmap, r->bd718xx_alm_block_start + | ||||
| 				 BD718XX_ALM_EN_OFFSET, BD70528_MASK_ALM_EN, | ||||
| 				 enableval); | ||||
| 	if (ret) | ||||
| 		dev_err(dev, "Failed to change alarm state\n"); | ||||
| 
 | ||||
| @ -498,7 +498,6 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct bd70528_rtc *bd_rtc; | ||||
| 	const struct rtc_class_ops *rtc_ops; | ||||
| 	struct rohm_regmap_dev *parent; | ||||
| 	const char *irq_name; | ||||
| 	int ret; | ||||
| 	struct rtc_device *rtc; | ||||
| @ -508,20 +507,25 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| 	u8 hour_reg; | ||||
| 	enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; | ||||
| 
 | ||||
| 	parent = dev_get_drvdata(pdev->dev.parent); | ||||
| 	if (!parent) { | ||||
| 		dev_err(&pdev->dev, "No MFD driver data\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 	bd_rtc = devm_kzalloc(&pdev->dev, sizeof(*bd_rtc), GFP_KERNEL); | ||||
| 	if (!bd_rtc) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	bd_rtc->parent = parent; | ||||
| 	bd_rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL); | ||||
| 	if (!bd_rtc->regmap) { | ||||
| 		dev_err(&pdev->dev, "No regmap\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	bd_rtc->dev = &pdev->dev; | ||||
| 
 | ||||
| 	switch (chip) { | ||||
| 	case ROHM_CHIP_TYPE_BD70528: | ||||
| 		bd_rtc->parent = dev_get_drvdata(pdev->dev.parent); | ||||
| 		if (!bd_rtc->parent) { | ||||
| 			dev_err(&pdev->dev, "No MFD data\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		irq_name = "bd70528-rtc-alm"; | ||||
| 		bd_rtc->has_rtc_timers = true; | ||||
| 		bd_rtc->reg_time_start = BD70528_REG_RTC_START; | ||||
| @ -529,9 +533,28 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| 		enable_main_irq = true; | ||||
| 		rtc_ops = &bd70528_rtc_ops; | ||||
| 		break; | ||||
| 	case ROHM_CHIP_TYPE_BD71815: | ||||
| 		irq_name = "bd71815-rtc-alm-0"; | ||||
| 		bd_rtc->reg_time_start = BD71815_REG_RTC_START; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * See also BD718XX_ALM_EN_OFFSET: | ||||
| 		 * This works for BD71828 and BD71815 as they have same offset | ||||
| 		 * between ALM0 start and ALM0_MASK. If new ICs are to be | ||||
| 		 * added this requires proper check as ALM0_MASK is not located | ||||
| 		 * at the end of ALM0 block - but after all ALM blocks so if | ||||
| 		 * amount of ALMs differ the offset to enable/disable is likely | ||||
| 		 * to be incorrect and enable/disable must be given as own | ||||
| 		 * reg address here. | ||||
| 		 */ | ||||
| 		bd_rtc->bd718xx_alm_block_start = BD71815_REG_RTC_ALM_START; | ||||
| 		hour_reg = BD71815_REG_HOUR; | ||||
| 		rtc_ops = &bd71828_rtc_ops; | ||||
| 		break; | ||||
| 	case ROHM_CHIP_TYPE_BD71828: | ||||
| 		irq_name = "bd71828-rtc-alm-0"; | ||||
| 		bd_rtc->reg_time_start = BD71828_REG_RTC_START; | ||||
| 		bd_rtc->bd718xx_alm_block_start = BD71828_REG_RTC_ALM_START; | ||||
| 		hour_reg = BD71828_REG_RTC_HOUR; | ||||
| 		rtc_ops = &bd71828_rtc_ops; | ||||
| 		break; | ||||
| @ -547,7 +570,7 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, bd_rtc); | ||||
| 
 | ||||
| 	ret = regmap_read(parent->regmap, hour_reg, &hr); | ||||
| 	ret = regmap_read(bd_rtc->regmap, hour_reg, &hr); | ||||
| 
 | ||||
| 	if (ret) { | ||||
| 		dev_err(&pdev->dev, "Failed to reag RTC clock\n"); | ||||
| @ -595,7 +618,7 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| 	 *  from sub-registers when IRQ is disabled or freed. | ||||
| 	 */ | ||||
| 	if (enable_main_irq) { | ||||
| 		ret = regmap_update_bits(parent->regmap, | ||||
| 		ret = regmap_update_bits(bd_rtc->regmap, | ||||
| 				 BD70528_REG_INT_MAIN_MASK, | ||||
| 				 BD70528_INT_RTC_MASK, 0); | ||||
| 		if (ret) { | ||||
| @ -610,6 +633,7 @@ static int bd70528_probe(struct platform_device *pdev) | ||||
| static const struct platform_device_id bd718x7_rtc_id[] = { | ||||
| 	{ "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 }, | ||||
| 	{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 }, | ||||
| 	{ "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id); | ||||
|  | ||||
							
								
								
									
										145
									
								
								drivers/rtc/rtc-ntxec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								drivers/rtc/rtc-ntxec.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,145 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| /*
 | ||||
|  * The Netronix embedded controller is a microcontroller found in some | ||||
|  * e-book readers designed by the original design manufacturer Netronix, Inc. | ||||
|  * It contains RTC, battery monitoring, system power management, and PWM | ||||
|  * functionality. | ||||
|  * | ||||
|  * This driver implements access to the RTC time and date. | ||||
|  * | ||||
|  * Copyright 2020 Jonathan Neuschäfer <j.neuschaefer@gmx.net> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/mfd/ntxec.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/rtc.h> | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct ntxec_rtc { | ||||
| 	struct device *dev; | ||||
| 	struct ntxec *ec; | ||||
| }; | ||||
| 
 | ||||
| #define NTXEC_REG_WRITE_YEAR	0x10 | ||||
| #define NTXEC_REG_WRITE_MONTH	0x11 | ||||
| #define NTXEC_REG_WRITE_DAY	0x12 | ||||
| #define NTXEC_REG_WRITE_HOUR	0x13 | ||||
| #define NTXEC_REG_WRITE_MINUTE	0x14 | ||||
| #define NTXEC_REG_WRITE_SECOND	0x15 | ||||
| 
 | ||||
| #define NTXEC_REG_READ_YEAR_MONTH	0x20 | ||||
| #define NTXEC_REG_READ_MDAY_HOUR	0x21 | ||||
| #define NTXEC_REG_READ_MINUTE_SECOND	0x23 | ||||
| 
 | ||||
| static int ntxec_read_time(struct device *dev, struct rtc_time *tm) | ||||
| { | ||||
| 	struct ntxec_rtc *rtc = dev_get_drvdata(dev); | ||||
| 	unsigned int value; | ||||
| 	int res; | ||||
| 
 | ||||
| retry: | ||||
| 	res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value); | ||||
| 	if (res < 0) | ||||
| 		return res; | ||||
| 
 | ||||
| 	tm->tm_min = value >> 8; | ||||
| 	tm->tm_sec = value & 0xff; | ||||
| 
 | ||||
| 	res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MDAY_HOUR, &value); | ||||
| 	if (res < 0) | ||||
| 		return res; | ||||
| 
 | ||||
| 	tm->tm_mday = value >> 8; | ||||
| 	tm->tm_hour = value & 0xff; | ||||
| 
 | ||||
| 	res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_YEAR_MONTH, &value); | ||||
| 	if (res < 0) | ||||
| 		return res; | ||||
| 
 | ||||
| 	tm->tm_year = (value >> 8) + 100; | ||||
| 	tm->tm_mon = (value & 0xff) - 1; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Read the minutes/seconds field again. If it changed since the first | ||||
| 	 * read, we can't assume that the values read so far are consistent, | ||||
| 	 * and should start from the beginning. | ||||
| 	 */ | ||||
| 	res = regmap_read(rtc->ec->regmap, NTXEC_REG_READ_MINUTE_SECOND, &value); | ||||
| 	if (res < 0) | ||||
| 		return res; | ||||
| 
 | ||||
| 	if (tm->tm_min != value >> 8 || tm->tm_sec != (value & 0xff)) | ||||
| 		goto retry; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ntxec_set_time(struct device *dev, struct rtc_time *tm) | ||||
| { | ||||
| 	struct ntxec_rtc *rtc = dev_get_drvdata(dev); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * To avoid time overflows while we're writing the full date/time, | ||||
| 	 * set the seconds field to zero before doing anything else. For the | ||||
| 	 * next 59 seconds (plus however long it takes until the RTC's next | ||||
| 	 * update of the second field), the seconds field will not overflow | ||||
| 	 * into the other fields. | ||||
| 	 */ | ||||
| 	struct reg_sequence regs[] = { | ||||
| 		{ NTXEC_REG_WRITE_SECOND, ntxec_reg8(0) }, | ||||
| 		{ NTXEC_REG_WRITE_YEAR, ntxec_reg8(tm->tm_year - 100) }, | ||||
| 		{ NTXEC_REG_WRITE_MONTH, ntxec_reg8(tm->tm_mon + 1) }, | ||||
| 		{ NTXEC_REG_WRITE_DAY, ntxec_reg8(tm->tm_mday) }, | ||||
| 		{ NTXEC_REG_WRITE_HOUR, ntxec_reg8(tm->tm_hour) }, | ||||
| 		{ NTXEC_REG_WRITE_MINUTE, ntxec_reg8(tm->tm_min) }, | ||||
| 		{ NTXEC_REG_WRITE_SECOND, ntxec_reg8(tm->tm_sec) }, | ||||
| 	}; | ||||
| 
 | ||||
| 	return regmap_multi_reg_write(rtc->ec->regmap, regs, ARRAY_SIZE(regs)); | ||||
| } | ||||
| 
 | ||||
| static const struct rtc_class_ops ntxec_rtc_ops = { | ||||
| 	.read_time = ntxec_read_time, | ||||
| 	.set_time = ntxec_set_time, | ||||
| }; | ||||
| 
 | ||||
| static int ntxec_rtc_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct rtc_device *dev; | ||||
| 	struct ntxec_rtc *rtc; | ||||
| 
 | ||||
| 	pdev->dev.of_node = pdev->dev.parent->of_node; | ||||
| 
 | ||||
| 	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); | ||||
| 	if (!rtc) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	rtc->dev = &pdev->dev; | ||||
| 	rtc->ec = dev_get_drvdata(pdev->dev.parent); | ||||
| 	platform_set_drvdata(pdev, rtc); | ||||
| 
 | ||||
| 	dev = devm_rtc_allocate_device(&pdev->dev); | ||||
| 	if (IS_ERR(dev)) | ||||
| 		return PTR_ERR(dev); | ||||
| 
 | ||||
| 	dev->ops = &ntxec_rtc_ops; | ||||
| 	dev->range_min = RTC_TIMESTAMP_BEGIN_2000; | ||||
| 	dev->range_max = 9025257599LL; /* 2255-12-31 23:59:59 */ | ||||
| 
 | ||||
| 	return devm_rtc_register_device(dev); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver ntxec_rtc_driver = { | ||||
| 	.driver = { | ||||
| 		.name = "ntxec-rtc", | ||||
| 	}, | ||||
| 	.probe = ntxec_rtc_probe, | ||||
| }; | ||||
| module_platform_driver(ntxec_rtc_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Jonathan Neuschäfer <j.neuschaefer@gmx.net>"); | ||||
| MODULE_DESCRIPTION("RTC driver for Netronix EC"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_ALIAS("platform:ntxec-rtc"); | ||||
| @ -172,6 +172,19 @@ config BD70528_WATCHDOG | ||||
| 	  Alternatively say M to compile the driver as a module, | ||||
| 	  which will be called bd70528_wdt. | ||||
| 
 | ||||
| config BD957XMUF_WATCHDOG | ||||
| 	tristate "ROHM BD9576MUF and BD9573MUF PMIC Watchdog" | ||||
| 	depends on MFD_ROHM_BD957XMUF | ||||
| 	select WATCHDOG_CORE | ||||
| 	help | ||||
| 	  Support for the watchdog in the ROHM BD9576 and BD9573 PMICs. | ||||
| 	  These PMIC ICs contain watchdog block which can be configured | ||||
| 	  to toggle reset line if SoC fails to ping watchdog via GPIO. | ||||
| 
 | ||||
| 	  Say Y here to include support for the ROHM BD9576 or BD9573 | ||||
| 	  watchdog. Alternatively say M to compile the driver as a module, | ||||
| 	  which will be called bd9576_wdt. | ||||
| 
 | ||||
| config DA9052_WATCHDOG | ||||
| 	tristate "Dialog DA9052 Watchdog" | ||||
| 	depends on PMIC_DA9052 || COMPILE_TEST | ||||
|  | ||||
| @ -204,6 +204,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o | ||||
| 
 | ||||
| # Architecture Independent
 | ||||
| obj-$(CONFIG_BD70528_WATCHDOG) += bd70528_wdt.o | ||||
| obj-$(CONFIG_BD957XMUF_WATCHDOG) += bd9576_wdt.o | ||||
| obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o | ||||
| obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o | ||||
| obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o | ||||
|  | ||||
							
								
								
									
										291
									
								
								drivers/watchdog/bd9576_wdt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								drivers/watchdog/bd9576_wdt.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,291 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| /*
 | ||||
|  * Copyright (C) 2020 ROHM Semiconductors | ||||
|  * | ||||
|  * ROHM BD9576MUF and BD9573MUF Watchdog driver | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/err.h> | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/mfd/rohm-bd957x.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/regmap.h> | ||||
| #include <linux/watchdog.h> | ||||
| 
 | ||||
| static bool nowayout; | ||||
| module_param(nowayout, bool, 0); | ||||
| MODULE_PARM_DESC(nowayout, | ||||
| 		"Watchdog cannot be stopped once started (default=\"false\")"); | ||||
| 
 | ||||
| #define HW_MARGIN_MIN 2 | ||||
| #define HW_MARGIN_MAX 4416 | ||||
| #define BD957X_WDT_DEFAULT_MARGIN 4416 | ||||
| #define WATCHDOG_TIMEOUT 30 | ||||
| 
 | ||||
| struct bd9576_wdt_priv { | ||||
| 	struct gpio_desc	*gpiod_ping; | ||||
| 	struct gpio_desc	*gpiod_en; | ||||
| 	struct device		*dev; | ||||
| 	struct regmap		*regmap; | ||||
| 	bool			always_running; | ||||
| 	struct watchdog_device	wdd; | ||||
| }; | ||||
| 
 | ||||
| static void bd9576_wdt_disable(struct bd9576_wdt_priv *priv) | ||||
| { | ||||
| 	gpiod_set_value_cansleep(priv->gpiod_en, 0); | ||||
| } | ||||
| 
 | ||||
| static int bd9576_wdt_ping(struct watchdog_device *wdd) | ||||
| { | ||||
| 	struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||||
| 
 | ||||
| 	/* Pulse */ | ||||
| 	gpiod_set_value_cansleep(priv->gpiod_ping, 1); | ||||
| 	gpiod_set_value_cansleep(priv->gpiod_ping, 0); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int bd9576_wdt_start(struct watchdog_device *wdd) | ||||
| { | ||||
| 	struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||||
| 
 | ||||
| 	gpiod_set_value_cansleep(priv->gpiod_en, 1); | ||||
| 
 | ||||
| 	return bd9576_wdt_ping(wdd); | ||||
| } | ||||
| 
 | ||||
| static int bd9576_wdt_stop(struct watchdog_device *wdd) | ||||
| { | ||||
| 	struct bd9576_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||||
| 
 | ||||
| 	if (!priv->always_running) | ||||
| 		bd9576_wdt_disable(priv); | ||||
| 	else | ||||
| 		set_bit(WDOG_HW_RUNNING, &wdd->status); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct watchdog_info bd957x_wdt_ident = { | ||||
| 	.options	= WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | | ||||
| 			  WDIOF_SETTIMEOUT, | ||||
| 	.identity	= "BD957x Watchdog", | ||||
| }; | ||||
| 
 | ||||
| static const struct watchdog_ops bd957x_wdt_ops = { | ||||
| 	.owner		= THIS_MODULE, | ||||
| 	.start		= bd9576_wdt_start, | ||||
| 	.stop		= bd9576_wdt_stop, | ||||
| 	.ping		= bd9576_wdt_ping, | ||||
| }; | ||||
| 
 | ||||
| /* Unit is hundreds of uS */ | ||||
| #define FASTNG_MIN 23 | ||||
| 
 | ||||
| static int find_closest_fast(int target, int *sel, int *val) | ||||
| { | ||||
| 	int i; | ||||
| 	int window = FASTNG_MIN; | ||||
| 
 | ||||
| 	for (i = 0; i < 8 && window < target; i++) | ||||
| 		window <<= 1; | ||||
| 
 | ||||
| 	*val = window; | ||||
| 	*sel = i; | ||||
| 
 | ||||
| 	if (i == 8) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static int find_closest_slow_by_fast(int fast_val, int target, int *slowsel) | ||||
| { | ||||
| 	int sel; | ||||
| 	static const int multipliers[] = {2, 3, 7, 15}; | ||||
| 
 | ||||
| 	for (sel = 0; sel < ARRAY_SIZE(multipliers) && | ||||
| 	     multipliers[sel] * fast_val < target; sel++) | ||||
| 		; | ||||
| 
 | ||||
| 	if (sel == ARRAY_SIZE(multipliers)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	*slowsel = sel; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int find_closest_slow(int target, int *slow_sel, int *fast_sel) | ||||
| { | ||||
| 	static const int multipliers[] = {2, 3, 7, 15}; | ||||
| 	int i, j; | ||||
| 	int val = 0; | ||||
| 	int window = FASTNG_MIN; | ||||
| 
 | ||||
| 	for (i = 0; i < 8; i++) { | ||||
| 		for (j = 0; j < ARRAY_SIZE(multipliers); j++) { | ||||
| 			int slow; | ||||
| 
 | ||||
| 			slow = window * multipliers[j]; | ||||
| 			if (slow >= target && (!val || slow < val)) { | ||||
| 				val = slow; | ||||
| 				*fast_sel = i; | ||||
| 				*slow_sel = j; | ||||
| 			} | ||||
| 		} | ||||
| 		window <<= 1; | ||||
| 	} | ||||
| 	if (!val) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #define BD957X_WDG_TYPE_WINDOW BIT(5) | ||||
| #define BD957X_WDG_TYPE_SLOW 0 | ||||
| #define BD957X_WDG_TYPE_MASK BIT(5) | ||||
| #define BD957X_WDG_NG_RATIO_MASK 0x18 | ||||
| #define BD957X_WDG_FASTNG_MASK 0x7 | ||||
| 
 | ||||
| static int bd957x_set_wdt_mode(struct bd9576_wdt_priv *priv, int hw_margin, | ||||
| 			       int hw_margin_min) | ||||
| { | ||||
| 	int ret, fastng, slowng, type, reg, mask; | ||||
| 	struct device *dev = priv->dev; | ||||
| 
 | ||||
| 	/* convert to 100uS */ | ||||
| 	hw_margin *= 10; | ||||
| 	hw_margin_min *= 10; | ||||
| 	if (hw_margin_min) { | ||||
| 		int min; | ||||
| 
 | ||||
| 		type = BD957X_WDG_TYPE_WINDOW; | ||||
| 		dev_dbg(dev, "Setting type WINDOW 0x%x\n", type); | ||||
| 		ret = find_closest_fast(hw_margin_min, &fastng, &min); | ||||
| 		if (ret) { | ||||
| 			dev_err(dev, "bad WDT window for fast timeout\n"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = find_closest_slow_by_fast(min, hw_margin, &slowng); | ||||
| 		if (ret) { | ||||
| 			dev_err(dev, "bad WDT window\n"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 
 | ||||
| 	} else { | ||||
| 		type = BD957X_WDG_TYPE_SLOW; | ||||
| 		dev_dbg(dev, "Setting type SLOW 0x%x\n", type); | ||||
| 		ret = find_closest_slow(hw_margin, &slowng, &fastng); | ||||
| 		if (ret) { | ||||
| 			dev_err(dev, "bad WDT window\n"); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	slowng <<= ffs(BD957X_WDG_NG_RATIO_MASK) - 1; | ||||
| 	reg = type | slowng | fastng; | ||||
| 	mask = BD957X_WDG_TYPE_MASK | BD957X_WDG_NG_RATIO_MASK | | ||||
| 	       BD957X_WDG_FASTNG_MASK; | ||||
| 	ret = regmap_update_bits(priv->regmap, BD957X_REG_WDT_CONF, | ||||
| 				 mask, reg); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int bd9576_wdt_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct device *dev = &pdev->dev; | ||||
| 	struct device_node *np = dev->parent->of_node; | ||||
| 	struct bd9576_wdt_priv *priv; | ||||
| 	u32 hw_margin[2]; | ||||
| 	u32 hw_margin_max = BD957X_WDT_DEFAULT_MARGIN, hw_margin_min = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||||
| 	if (!priv) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, priv); | ||||
| 
 | ||||
| 	priv->dev = dev; | ||||
| 	priv->regmap = dev_get_regmap(dev->parent, NULL); | ||||
| 	if (!priv->regmap) { | ||||
| 		dev_err(dev, "No regmap found\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->gpiod_en = devm_gpiod_get_from_of_node(dev, dev->parent->of_node, | ||||
| 						     "rohm,watchdog-enable-gpios", | ||||
| 						     0, GPIOD_OUT_LOW, | ||||
| 						     "watchdog-enable"); | ||||
| 	if (IS_ERR(priv->gpiod_en)) | ||||
| 		return dev_err_probe(dev, PTR_ERR(priv->gpiod_en), | ||||
| 			      "getting watchdog-enable GPIO failed\n"); | ||||
| 
 | ||||
| 	priv->gpiod_ping = devm_gpiod_get_from_of_node(dev, dev->parent->of_node, | ||||
| 						     "rohm,watchdog-ping-gpios", | ||||
| 						     0, GPIOD_OUT_LOW, | ||||
| 						     "watchdog-ping"); | ||||
| 	if (IS_ERR(priv->gpiod_ping)) | ||||
| 		return dev_err_probe(dev, PTR_ERR(priv->gpiod_ping), | ||||
| 				     "getting watchdog-ping GPIO failed\n"); | ||||
| 
 | ||||
| 	ret = of_property_read_variable_u32_array(np, "rohm,hw-timeout-ms", | ||||
| 						  &hw_margin[0], 1, 2); | ||||
| 	if (ret < 0 && ret != -EINVAL) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	if (ret == 1) | ||||
| 		hw_margin_max = hw_margin[0]; | ||||
| 
 | ||||
| 	if (ret == 2) { | ||||
| 		hw_margin_max = hw_margin[1]; | ||||
| 		hw_margin_min = hw_margin[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = bd957x_set_wdt_mode(priv, hw_margin_max, hw_margin_min); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	priv->always_running = of_property_read_bool(np, "always-running"); | ||||
| 
 | ||||
| 	watchdog_set_drvdata(&priv->wdd, priv); | ||||
| 
 | ||||
| 	priv->wdd.info			= &bd957x_wdt_ident; | ||||
| 	priv->wdd.ops			= &bd957x_wdt_ops; | ||||
| 	priv->wdd.min_hw_heartbeat_ms	= hw_margin_min; | ||||
| 	priv->wdd.max_hw_heartbeat_ms	= hw_margin_max; | ||||
| 	priv->wdd.parent		= dev; | ||||
| 	priv->wdd.timeout		= WATCHDOG_TIMEOUT; | ||||
| 
 | ||||
| 	watchdog_init_timeout(&priv->wdd, 0, dev); | ||||
| 	watchdog_set_nowayout(&priv->wdd, nowayout); | ||||
| 
 | ||||
| 	watchdog_stop_on_reboot(&priv->wdd); | ||||
| 
 | ||||
| 	if (priv->always_running) | ||||
| 		bd9576_wdt_start(&priv->wdd); | ||||
| 
 | ||||
| 	return devm_watchdog_register_device(dev, &priv->wdd); | ||||
| } | ||||
| 
 | ||||
| static struct platform_driver bd9576_wdt_driver = { | ||||
| 	.driver	= { | ||||
| 		.name = "bd9576-wdt", | ||||
| 	}, | ||||
| 	.probe	= bd9576_wdt_probe, | ||||
| }; | ||||
| 
 | ||||
| module_platform_driver(bd9576_wdt_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | ||||
| MODULE_DESCRIPTION("ROHM BD9576/BD9573 Watchdog driver"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| MODULE_ALIAS("platform:bd9576-wdt"); | ||||
| @ -1,128 +0,0 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /*
 | ||||
|  * Copyright (C) 2007-2009 ST-Ericsson AB | ||||
|  * AB3100 core access functions | ||||
|  * Author: Linus Walleij <linus.walleij@stericsson.com> | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/regulator/machine.h> | ||||
| 
 | ||||
| struct device; | ||||
| 
 | ||||
| #ifndef MFD_AB3100_H | ||||
| #define MFD_AB3100_H | ||||
| 
 | ||||
| 
 | ||||
| #define AB3100_P1A	0xc0 | ||||
| #define AB3100_P1B	0xc1 | ||||
| #define AB3100_P1C	0xc2 | ||||
| #define AB3100_P1D	0xc3 | ||||
| #define AB3100_P1E	0xc4 | ||||
| #define AB3100_P1F	0xc5 | ||||
| #define AB3100_P1G	0xc6 | ||||
| #define AB3100_R2A	0xc7 | ||||
| #define AB3100_R2B	0xc8 | ||||
| 
 | ||||
| /*
 | ||||
|  * AB3100, EVENTA1, A2 and A3 event register flags | ||||
|  * these are catenated into a single 32-bit flag in the code | ||||
|  * for event notification broadcasts. | ||||
|  */ | ||||
| #define AB3100_EVENTA1_ONSWA				(0x01<<16) | ||||
| #define AB3100_EVENTA1_ONSWB				(0x02<<16) | ||||
| #define AB3100_EVENTA1_ONSWC				(0x04<<16) | ||||
| #define AB3100_EVENTA1_DCIO				(0x08<<16) | ||||
| #define AB3100_EVENTA1_OVER_TEMP			(0x10<<16) | ||||
| #define AB3100_EVENTA1_SIM_OFF				(0x20<<16) | ||||
| #define AB3100_EVENTA1_VBUS				(0x40<<16) | ||||
| #define AB3100_EVENTA1_VSET_USB				(0x80<<16) | ||||
| 
 | ||||
| #define AB3100_EVENTA2_READY_TX				(0x01<<8) | ||||
| #define AB3100_EVENTA2_READY_RX				(0x02<<8) | ||||
| #define AB3100_EVENTA2_OVERRUN_ERROR			(0x04<<8) | ||||
| #define AB3100_EVENTA2_FRAMING_ERROR			(0x08<<8) | ||||
| #define AB3100_EVENTA2_CHARG_OVERCURRENT		(0x10<<8) | ||||
| #define AB3100_EVENTA2_MIDR				(0x20<<8) | ||||
| #define AB3100_EVENTA2_BATTERY_REM			(0x40<<8) | ||||
| #define AB3100_EVENTA2_ALARM				(0x80<<8) | ||||
| 
 | ||||
| #define AB3100_EVENTA3_ADC_TRIG5			(0x01) | ||||
| #define AB3100_EVENTA3_ADC_TRIG4			(0x02) | ||||
| #define AB3100_EVENTA3_ADC_TRIG3			(0x04) | ||||
| #define AB3100_EVENTA3_ADC_TRIG2			(0x08) | ||||
| #define AB3100_EVENTA3_ADC_TRIGVBAT			(0x10) | ||||
| #define AB3100_EVENTA3_ADC_TRIGVTX			(0x20) | ||||
| #define AB3100_EVENTA3_ADC_TRIG1			(0x40) | ||||
| #define AB3100_EVENTA3_ADC_TRIG0			(0x80) | ||||
| 
 | ||||
| /* AB3100, STR register flags */ | ||||
| #define AB3100_STR_ONSWA				(0x01) | ||||
| #define AB3100_STR_ONSWB				(0x02) | ||||
| #define AB3100_STR_ONSWC				(0x04) | ||||
| #define AB3100_STR_DCIO					(0x08) | ||||
| #define AB3100_STR_BOOT_MODE				(0x10) | ||||
| #define AB3100_STR_SIM_OFF				(0x20) | ||||
| #define AB3100_STR_BATT_REMOVAL				(0x40) | ||||
| #define AB3100_STR_VBUS					(0x80) | ||||
| 
 | ||||
| /*
 | ||||
|  * AB3100 contains 8 regulators, one external regulator controller | ||||
|  * and a buck converter, further the LDO E and buck converter can | ||||
|  * have separate settings if they are in sleep mode, this is | ||||
|  * modeled as a separate regulator. | ||||
|  */ | ||||
| #define AB3100_NUM_REGULATORS				10 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ab3100 | ||||
|  * @access_mutex: lock out concurrent accesses to the AB3100 registers | ||||
|  * @dev: pointer to the containing device | ||||
|  * @i2c_client: I2C client for this chip | ||||
|  * @testreg_client: secondary client for test registers | ||||
|  * @chip_name: name of this chip variant | ||||
|  * @chip_id: 8 bit chip ID for this chip variant | ||||
|  * @event_subscribers: event subscribers are listed here | ||||
|  * @startup_events: a copy of the first reading of the event registers | ||||
|  * @startup_events_read: whether the first events have been read | ||||
|  * | ||||
|  * This struct is PRIVATE and devices using it should NOT | ||||
|  * access ANY fields. It is used as a token for calling the | ||||
|  * AB3100 functions. | ||||
|  */ | ||||
| struct ab3100 { | ||||
| 	struct mutex access_mutex; | ||||
| 	struct device *dev; | ||||
| 	struct i2c_client *i2c_client; | ||||
| 	struct i2c_client *testreg_client; | ||||
| 	char chip_name[32]; | ||||
| 	u8 chip_id; | ||||
| 	struct blocking_notifier_head event_subscribers; | ||||
| 	u8 startup_events[3]; | ||||
| 	bool startup_events_read; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ab3100_platform_data | ||||
|  * Data supplied to initialize board connections to the AB3100 | ||||
|  * @reg_constraints: regulator constraints for target board | ||||
|  *     the order of these constraints are: LDO A, C, D, E, | ||||
|  *     F, G, H, K, EXT and BUCK. | ||||
|  * @reg_initvals: initial values for the regulator registers | ||||
|  *     plus two sleep settings for LDO E and the BUCK converter. | ||||
|  *     exactly AB3100_NUM_REGULATORS+2 values must be sent in. | ||||
|  *     Order: LDO A, C, E, E sleep, F, G, H, K, EXT, BUCK, | ||||
|  *     BUCK sleep, LDO D. (LDO D need to be initialized last.) | ||||
|  * @external_voltage: voltage level of the external regulator. | ||||
|  */ | ||||
| struct ab3100_platform_data { | ||||
| 	struct regulator_init_data reg_constraints[AB3100_NUM_REGULATORS]; | ||||
| 	u8 reg_initvals[AB3100_NUM_REGULATORS+2]; | ||||
| 	int external_voltage; | ||||
| }; | ||||
| 
 | ||||
| int ab3100_event_register(struct ab3100 *ab3100, | ||||
| 			  struct notifier_block *nb); | ||||
| int ab3100_event_unregister(struct ab3100 *ab3100, | ||||
| 			    struct notifier_block *nb); | ||||
| 
 | ||||
| #endif /*  MFD_AB3100_H */ | ||||
							
								
								
									
										281
									
								
								include/linux/mfd/atc260x/atc2603c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										281
									
								
								include/linux/mfd/atc260x/atc2603c.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,281 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
| /*
 | ||||
|  * ATC2603C PMIC register definitions | ||||
|  * | ||||
|  * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __LINUX_MFD_ATC260X_ATC2603C_H | ||||
| #define __LINUX_MFD_ATC260X_ATC2603C_H | ||||
| 
 | ||||
| enum atc2603c_irq_def { | ||||
| 	ATC2603C_IRQ_AUDIO = 0, | ||||
| 	ATC2603C_IRQ_OV, | ||||
| 	ATC2603C_IRQ_OC, | ||||
| 	ATC2603C_IRQ_OT, | ||||
| 	ATC2603C_IRQ_UV, | ||||
| 	ATC2603C_IRQ_ALARM, | ||||
| 	ATC2603C_IRQ_ONOFF, | ||||
| 	ATC2603C_IRQ_SGPIO, | ||||
| 	ATC2603C_IRQ_IR, | ||||
| 	ATC2603C_IRQ_REMCON, | ||||
| 	ATC2603C_IRQ_POWER_IN, | ||||
| }; | ||||
| 
 | ||||
| /* PMU Registers */ | ||||
| #define ATC2603C_PMU_SYS_CTL0			0x00 | ||||
| #define ATC2603C_PMU_SYS_CTL1			0x01 | ||||
| #define ATC2603C_PMU_SYS_CTL2			0x02 | ||||
| #define ATC2603C_PMU_SYS_CTL3			0x03 | ||||
| #define ATC2603C_PMU_SYS_CTL4			0x04 | ||||
| #define ATC2603C_PMU_SYS_CTL5			0x05 | ||||
| #define ATC2603C_PMU_SYS_CTL6			0x06 | ||||
| #define ATC2603C_PMU_SYS_CTL7			0x07 | ||||
| #define ATC2603C_PMU_SYS_CTL8			0x08 | ||||
| #define ATC2603C_PMU_SYS_CTL9			0x09 | ||||
| #define ATC2603C_PMU_BAT_CTL0			0x0A | ||||
| #define ATC2603C_PMU_BAT_CTL1			0x0B | ||||
| #define ATC2603C_PMU_VBUS_CTL0			0x0C | ||||
| #define ATC2603C_PMU_VBUS_CTL1			0x0D | ||||
| #define ATC2603C_PMU_WALL_CTL0			0x0E | ||||
| #define ATC2603C_PMU_WALL_CTL1			0x0F | ||||
| #define ATC2603C_PMU_SYS_PENDING		0x10 | ||||
| #define ATC2603C_PMU_DC1_CTL0			0x11 | ||||
| #define ATC2603C_PMU_DC1_CTL1			0x12 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC1_CTL2			0x13 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC2_CTL0			0x14 | ||||
| #define ATC2603C_PMU_DC2_CTL1			0x15 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC2_CTL2			0x16 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC3_CTL0			0x17 | ||||
| #define ATC2603C_PMU_DC3_CTL1			0x18 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC3_CTL2			0x19 // Undocumented
 | ||||
| #define ATC2603C_PMU_DC4_CTL0			0x1A // Undocumented
 | ||||
| #define ATC2603C_PMU_DC4_CTL1			0x1B // Undocumented
 | ||||
| #define ATC2603C_PMU_DC5_CTL0			0x1C // Undocumented
 | ||||
| #define ATC2603C_PMU_DC5_CTL1			0x1D // Undocumented
 | ||||
| #define ATC2603C_PMU_LDO1_CTL			0x1E | ||||
| #define ATC2603C_PMU_LDO2_CTL			0x1F | ||||
| #define ATC2603C_PMU_LDO3_CTL			0x20 | ||||
| #define ATC2603C_PMU_LDO4_CTL			0x21 // Undocumented
 | ||||
| #define ATC2603C_PMU_LDO5_CTL			0x22 | ||||
| #define ATC2603C_PMU_LDO6_CTL			0x23 | ||||
| #define ATC2603C_PMU_LDO7_CTL			0x24 | ||||
| #define ATC2603C_PMU_LDO8_CTL			0x25 // Undocumented
 | ||||
| #define ATC2603C_PMU_LDO9_CTL			0x26 // Undocumented
 | ||||
| #define ATC2603C_PMU_LDO10_CTL			0x27 // Undocumented
 | ||||
| #define ATC2603C_PMU_LDO11_CTL			0x28 | ||||
| #define ATC2603C_PMU_SWITCH_CTL			0x29 | ||||
| #define ATC2603C_PMU_OV_CTL0			0x2A | ||||
| #define ATC2603C_PMU_OV_CTL1			0x2B | ||||
| #define ATC2603C_PMU_OV_STATUS			0x2C | ||||
| #define ATC2603C_PMU_OV_EN			0x2D | ||||
| #define ATC2603C_PMU_OV_INT_EN			0x2E | ||||
| #define ATC2603C_PMU_OC_CTL			0x2F | ||||
| #define ATC2603C_PMU_OC_STATUS			0x30 | ||||
| #define ATC2603C_PMU_OC_EN			0x31 | ||||
| #define ATC2603C_PMU_OC_INT_EN			0x32 | ||||
| #define ATC2603C_PMU_UV_CTL0			0x33 | ||||
| #define ATC2603C_PMU_UV_CTL1			0x34 | ||||
| #define ATC2603C_PMU_UV_STATUS			0x35 | ||||
| #define ATC2603C_PMU_UV_EN			0x36 | ||||
| #define ATC2603C_PMU_UV_INT_EN			0x37 | ||||
| #define ATC2603C_PMU_OT_CTL			0x38 | ||||
| #define ATC2603C_PMU_CHARGER_CTL0		0x39 | ||||
| #define ATC2603C_PMU_CHARGER_CTL1		0x3A | ||||
| #define ATC2603C_PMU_CHARGER_CTL2		0x3B | ||||
| #define ATC2603C_PMU_BAKCHARGER_CTL		0x3C // Undocumented
 | ||||
| #define ATC2603C_PMU_APDS_CTL			0x3D | ||||
| #define ATC2603C_PMU_AUXADC_CTL0		0x3E | ||||
| #define ATC2603C_PMU_AUXADC_CTL1		0x3F | ||||
| #define ATC2603C_PMU_BATVADC			0x40 | ||||
| #define ATC2603C_PMU_BATIADC			0x41 | ||||
| #define ATC2603C_PMU_WALLVADC			0x42 | ||||
| #define ATC2603C_PMU_WALLIADC			0x43 | ||||
| #define ATC2603C_PMU_VBUSVADC			0x44 | ||||
| #define ATC2603C_PMU_VBUSIADC			0x45 | ||||
| #define ATC2603C_PMU_SYSPWRADC			0x46 | ||||
| #define ATC2603C_PMU_REMCONADC			0x47 | ||||
| #define ATC2603C_PMU_SVCCADC			0x48 | ||||
| #define ATC2603C_PMU_CHGIADC			0x49 | ||||
| #define ATC2603C_PMU_IREFADC			0x4A | ||||
| #define ATC2603C_PMU_BAKBATADC			0x4B | ||||
| #define ATC2603C_PMU_ICTEMPADC			0x4C | ||||
| #define ATC2603C_PMU_AUXADC0			0x4D | ||||
| #define ATC2603C_PMU_AUXADC1			0x4E | ||||
| #define ATC2603C_PMU_AUXADC2			0x4F | ||||
| #define	ATC2603C_PMU_ICMADC			0x50 | ||||
| #define ATC2603C_PMU_BDG_CTL			0x51 // Undocumented
 | ||||
| #define ATC2603C_RTC_CTL			0x52 | ||||
| #define ATC2603C_RTC_MSALM			0x53 | ||||
| #define ATC2603C_RTC_HALM			0x54 | ||||
| #define ATC2603C_RTC_YMDALM			0x55 | ||||
| #define ATC2603C_RTC_MS				0x56 | ||||
| #define ATC2603C_RTC_H				0x57 | ||||
| #define ATC2603C_RTC_DC				0x58 | ||||
| #define ATC2603C_RTC_YMD			0x59 | ||||
| #define ATC2603C_EFUSE_DAT			0x5A // Undocumented
 | ||||
| #define ATC2603C_EFUSECRTL1			0x5B // Undocumented
 | ||||
| #define ATC2603C_EFUSECRTL2			0x5C // Undocumented
 | ||||
| #define ATC2603C_PMU_FW_USE0			0x5D // Undocumented
 | ||||
| #define ATC2603C_PMU_FW_USE1			0x5E // Undocumented
 | ||||
| #define ATC2603C_PMU_FW_USE2			0x5F // Undocumented
 | ||||
| #define ATC2603C_PMU_FW_USE3			0x60 // Undocumented
 | ||||
| #define ATC2603C_PMU_FW_USE4			0x61 // Undocumented
 | ||||
| #define ATC2603C_PMU_ABNORMAL_STATUS		0x62 | ||||
| #define ATC2603C_PMU_WALL_APDS_CTL		0x63 | ||||
| #define ATC2603C_PMU_REMCON_CTL0		0x64 | ||||
| #define ATC2603C_PMU_REMCON_CTL1		0x65 | ||||
| #define ATC2603C_PMU_MUX_CTL0			0x66 | ||||
| #define ATC2603C_PMU_SGPIO_CTL0			0x67 | ||||
| #define ATC2603C_PMU_SGPIO_CTL1			0x68 | ||||
| #define ATC2603C_PMU_SGPIO_CTL2			0x69 | ||||
| #define ATC2603C_PMU_SGPIO_CTL3			0x6A | ||||
| #define ATC2603C_PMU_SGPIO_CTL4			0x6B | ||||
| #define ATC2603C_PWMCLK_CTL			0x6C | ||||
| #define ATC2603C_PWM0_CTL			0x6D | ||||
| #define ATC2603C_PWM1_CTL			0x6E | ||||
| #define ATC2603C_PMU_ADC_DBG0			0x70 | ||||
| #define ATC2603C_PMU_ADC_DBG1			0x71 | ||||
| #define ATC2603C_PMU_ADC_DBG2			0x72 | ||||
| #define ATC2603C_PMU_ADC_DBG3			0x73 | ||||
| #define ATC2603C_PMU_ADC_DBG4			0x74 | ||||
| #define ATC2603C_IRC_CTL			0x80 | ||||
| #define ATC2603C_IRC_STAT			0x81 | ||||
| #define ATC2603C_IRC_CC				0x82 | ||||
| #define ATC2603C_IRC_KDC			0x83 | ||||
| #define ATC2603C_IRC_WK				0x84 | ||||
| #define ATC2603C_IRC_RCC			0x85 | ||||
| #define ATC2603C_IRC_FILTER			0x86 | ||||
| 
 | ||||
| /* AUDIO_OUT Registers */ | ||||
| #define ATC2603C_AUDIOINOUT_CTL			0xA0 | ||||
| #define ATC2603C_AUDIO_DEBUGOUTCTL		0xA1 | ||||
| #define ATC2603C_DAC_DIGITALCTL			0xA2 | ||||
| #define ATC2603C_DAC_VOLUMECTL0			0xA3 | ||||
| #define ATC2603C_DAC_ANALOG0			0xA4 | ||||
| #define ATC2603C_DAC_ANALOG1			0xA5 | ||||
| #define ATC2603C_DAC_ANALOG2			0xA6 | ||||
| #define ATC2603C_DAC_ANALOG3			0xA7 | ||||
| 
 | ||||
| /* AUDIO_IN Registers */ | ||||
| #define ATC2603C_ADC_DIGITALCTL			0xA8 | ||||
| #define ATC2603C_ADC_HPFCTL			0xA9 | ||||
| #define ATC2603C_ADC_CTL			0xAA | ||||
| #define ATC2603C_AGC_CTL0			0xAB | ||||
| #define ATC2603C_AGC_CTL1			0xAC // Undocumented
 | ||||
| #define ATC2603C_AGC_CTL2			0xAD | ||||
| #define ATC2603C_ADC_ANALOG0			0xAE | ||||
| #define ATC2603C_ADC_ANALOG1			0xAF | ||||
| 
 | ||||
| /* PCM_IF Registers */ | ||||
| #define ATC2603C_PCM0_CTL			0xB0 // Undocumented
 | ||||
| #define ATC2603C_PCM1_CTL			0xB1 // Undocumented
 | ||||
| #define ATC2603C_PCM2_CTL			0xB2 // Undocumented
 | ||||
| #define ATC2603C_PCMIF_CTL			0xB3 // Undocumented
 | ||||
| 
 | ||||
| /* CMU_CONTROL Registers */ | ||||
| #define ATC2603C_CMU_DEVRST			0xC1 // Undocumented
 | ||||
| 
 | ||||
| /* INTS Registers */ | ||||
| #define ATC2603C_INTS_PD			0xC8 | ||||
| #define ATC2603C_INTS_MSK			0xC9 | ||||
| 
 | ||||
| /* MFP Registers */ | ||||
| #define ATC2603C_MFP_CTL			0xD0 | ||||
| #define ATC2603C_PAD_VSEL			0xD1 // Undocumented
 | ||||
| #define ATC2603C_GPIO_OUTEN			0xD2 | ||||
| #define ATC2603C_GPIO_INEN			0xD3 | ||||
| #define ATC2603C_GPIO_DAT			0xD4 | ||||
| #define ATC2603C_PAD_DRV			0xD5 | ||||
| #define ATC2603C_PAD_EN				0xD6 | ||||
| #define ATC2603C_DEBUG_SEL			0xD7 // Undocumented
 | ||||
| #define ATC2603C_DEBUG_IE			0xD8 // Undocumented
 | ||||
| #define ATC2603C_DEBUG_OE			0xD9 // Undocumented
 | ||||
| #define ATC2603C_BIST_START			0x0A // Undocumented
 | ||||
| #define ATC2603C_BIST_RESULT			0x0B // Undocumented
 | ||||
| #define ATC2603C_CHIP_VER			0xDC | ||||
| 
 | ||||
| /* TWSI Registers */ | ||||
| #define ATC2603C_SADDR				0xFF | ||||
| 
 | ||||
| /* PMU_SYS_CTL0 Register Mask Bits */ | ||||
| #define ATC2603C_PMU_SYS_CTL0_IR_WK_EN			BIT(5) | ||||
| #define ATC2603C_PMU_SYS_CTL0_RESET_WK_EN		BIT(6) | ||||
| #define ATC2603C_PMU_SYS_CTL0_HDSW_WK_EN		BIT(7) | ||||
| #define ATC2603C_PMU_SYS_CTL0_ALARM_WK_EN		BIT(8) | ||||
| #define ATC2603C_PMU_SYS_CTL0_REM_CON_WK_EN		BIT(9) | ||||
| #define ATC2603C_PMU_SYS_CTL0_RESTART_EN		BIT(10) | ||||
| #define ATC2603C_PMU_SYS_CTL0_SGPIOIRQ_WK_EN		BIT(11) | ||||
| #define ATC2603C_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN		BIT(12) | ||||
| #define ATC2603C_PMU_SYS_CTL0_ONOFF_LONG_WK_EN		BIT(13) | ||||
| #define ATC2603C_PMU_SYS_CTL0_WALL_WK_EN		BIT(14) | ||||
| #define ATC2603C_PMU_SYS_CTL0_USB_WK_EN			BIT(15) | ||||
| #define ATC2603C_PMU_SYS_CTL0_WK_ALL			(GENMASK(15, 5) & (~BIT(10))) | ||||
| 
 | ||||
| /* PMU_SYS_CTL1 Register Mask Bits */ | ||||
| #define ATC2603C_PMU_SYS_CTL1_EN_S1			BIT(0) | ||||
| #define ATC2603C_PMU_SYS_CTL1_LB_S4_EN			BIT(2) | ||||
| #define ATC2603C_PMU_SYS_CTL1_LB_S4			GENMASK(4, 3) | ||||
| #define ATC2603C_PMU_SYS_CTL1_LB_S4_3_1V		BIT(4) | ||||
| #define ATC2603C_PMU_SYS_CTL1_IR_WK_FLAG		BIT(5) | ||||
| #define ATC2603C_PMU_SYS_CTL1_RESET_WK_FLAG		BIT(6) | ||||
| #define ATC2603C_PMU_SYS_CTL1_HDSW_WK_FLAG		BIT(7) | ||||
| #define ATC2603C_PMU_SYS_CTL1_ALARM_WK_FLAG		BIT(8) | ||||
| #define ATC2603C_PMU_SYS_CTL1_REM_CON_WK_FLAG		BIT(9) | ||||
| #define ATC2603C_PMU_SYS_CTL1_ONOFF_PRESS_RESET_IRQ_PD	BIT(10) | ||||
| #define ATC2603C_PMU_SYS_CTL1_SGPIOIRQ_WK_FLAG		BIT(11) | ||||
| #define ATC2603C_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG	BIT(12) | ||||
| #define ATC2603C_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG	BIT(13) | ||||
| #define ATC2603C_PMU_SYS_CTL1_WALL_WK_FLAG		BIT(14) | ||||
| #define ATC2603C_PMU_SYS_CTL1_USB_WK_FLAG		BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL2 Register Mask Bits */ | ||||
| #define ATC2603C_PMU_SYS_CTL2_PMU_A_EN			BIT(0) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN	BIT(1) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_PD		BIT(2) | ||||
| #define ATC2603C_PMU_SYS_CTL2_S2TIMER			GENMASK(5, 3) | ||||
| #define ATC2603C_PMU_SYS_CTL2_S2_TIMER_EN		BIT(6) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL	GENMASK(8, 7) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_RESET_EN	BIT(9) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS_TIME		GENMASK(11, 10) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_INT_EN		BIT(12) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_LONG_PRESS		BIT(13) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_SHORT_PRESS		BIT(14) | ||||
| #define ATC2603C_PMU_SYS_CTL2_ONOFF_PRESS		BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL3 Register Mask Bits */ | ||||
| #define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER		GENMASK(8, 7) | ||||
| #define ATC2603C_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN		BIT(9) | ||||
| #define ATC2603C_PMU_SYS_CTL3_S3_TIMER			GENMASK(12, 10) | ||||
| #define ATC2603C_PMU_SYS_CTL3_S3_TIMER_EN		BIT(13) | ||||
| #define ATC2603C_PMU_SYS_CTL3_EN_S3			BIT(14) | ||||
| #define ATC2603C_PMU_SYS_CTL3_EN_S2			BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL5 Register Mask Bits */ | ||||
| #define ATC2603C_PMU_SYS_CTL5_WALLWKDTEN		BIT(7) | ||||
| #define ATC2603C_PMU_SYS_CTL5_VBUSWKDTEN		BIT(8) | ||||
| #define ATC2603C_PMU_SYS_CTL5_REMCON_DECT_EN		BIT(9) | ||||
| #define ATC2603C_PMU_SYS_CTL5_ONOFF_8S_SEL		BIT(10) | ||||
| 
 | ||||
| /* INTS_MSK Register Mask Bits */ | ||||
| #define ATC2603C_INTS_MSK_AUDIO				BIT(0) | ||||
| #define ATC2603C_INTS_MSK_OV				BIT(1) | ||||
| #define ATC2603C_INTS_MSK_OC				BIT(2) | ||||
| #define ATC2603C_INTS_MSK_OT				BIT(3) | ||||
| #define ATC2603C_INTS_MSK_UV				BIT(4) | ||||
| #define ATC2603C_INTS_MSK_ALARM				BIT(5) | ||||
| #define ATC2603C_INTS_MSK_ONOFF				BIT(6) | ||||
| #define ATC2603C_INTS_MSK_SGPIO				BIT(7) | ||||
| #define ATC2603C_INTS_MSK_IR				BIT(8) | ||||
| #define ATC2603C_INTS_MSK_REMCON			BIT(9) | ||||
| #define ATC2603C_INTS_MSK_POWERIN			BIT(10) | ||||
| 
 | ||||
| /* CMU_DEVRST Register Mask Bits */ | ||||
| #define ATC2603C_CMU_DEVRST_MFP				BIT(1) | ||||
| #define ATC2603C_CMU_DEVRST_INTS			BIT(2) | ||||
| #define ATC2603C_CMU_DEVRST_AUDIO			BIT(4) | ||||
| 
 | ||||
| /* PAD_EN Register Mask Bits */ | ||||
| #define ATC2603C_PAD_EN_EXTIRQ				BIT(0) | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_ATC260X_ATC2603C_H */ | ||||
							
								
								
									
										308
									
								
								include/linux/mfd/atc260x/atc2609a.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								include/linux/mfd/atc260x/atc2609a.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,308 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
| /*
 | ||||
|  * ATC2609A PMIC register definitions | ||||
|  * | ||||
|  * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __LINUX_MFD_ATC260X_ATC2609A_H | ||||
| #define __LINUX_MFD_ATC260X_ATC2609A_H | ||||
| 
 | ||||
| enum atc2609a_irq_def { | ||||
| 	ATC2609A_IRQ_AUDIO = 0, | ||||
| 	ATC2609A_IRQ_OV, | ||||
| 	ATC2609A_IRQ_OC, | ||||
| 	ATC2609A_IRQ_OT, | ||||
| 	ATC2609A_IRQ_UV, | ||||
| 	ATC2609A_IRQ_ALARM, | ||||
| 	ATC2609A_IRQ_ONOFF, | ||||
| 	ATC2609A_IRQ_WKUP, | ||||
| 	ATC2609A_IRQ_IR, | ||||
| 	ATC2609A_IRQ_REMCON, | ||||
| 	ATC2609A_IRQ_POWER_IN, | ||||
| }; | ||||
| 
 | ||||
| /* PMU Registers */ | ||||
| #define ATC2609A_PMU_SYS_CTL0			0x00 | ||||
| #define ATC2609A_PMU_SYS_CTL1			0x01 | ||||
| #define ATC2609A_PMU_SYS_CTL2			0x02 | ||||
| #define ATC2609A_PMU_SYS_CTL3			0x03 | ||||
| #define ATC2609A_PMU_SYS_CTL4			0x04 | ||||
| #define ATC2609A_PMU_SYS_CTL5			0x05 | ||||
| #define ATC2609A_PMU_SYS_CTL6			0x06 | ||||
| #define ATC2609A_PMU_SYS_CTL7			0x07 | ||||
| #define ATC2609A_PMU_SYS_CTL8			0x08 | ||||
| #define ATC2609A_PMU_SYS_CTL9			0x09 | ||||
| #define ATC2609A_PMU_BAT_CTL0			0x0A | ||||
| #define ATC2609A_PMU_BAT_CTL1			0x0B | ||||
| #define ATC2609A_PMU_VBUS_CTL0			0x0C | ||||
| #define ATC2609A_PMU_VBUS_CTL1			0x0D | ||||
| #define ATC2609A_PMU_WALL_CTL0			0x0E | ||||
| #define ATC2609A_PMU_WALL_CTL1			0x0F | ||||
| #define ATC2609A_PMU_SYS_PENDING		0x10 | ||||
| #define ATC2609A_PMU_APDS_CTL0			0x11 | ||||
| #define ATC2609A_PMU_APDS_CTL1			0x12 | ||||
| #define ATC2609A_PMU_APDS_CTL2			0x13 | ||||
| #define ATC2609A_PMU_CHARGER_CTL		0x14 | ||||
| #define ATC2609A_PMU_BAKCHARGER_CTL		0x15 | ||||
| #define ATC2609A_PMU_SWCHG_CTL0			0x16 | ||||
| #define ATC2609A_PMU_SWCHG_CTL1			0x17 | ||||
| #define ATC2609A_PMU_SWCHG_CTL2			0x18 | ||||
| #define ATC2609A_PMU_SWCHG_CTL3			0x19 | ||||
| #define ATC2609A_PMU_SWCHG_CTL4			0x1A | ||||
| #define ATC2609A_PMU_DC_OSC			0x1B | ||||
| #define ATC2609A_PMU_DC0_CTL0			0x1C | ||||
| #define ATC2609A_PMU_DC0_CTL1			0x1D | ||||
| #define ATC2609A_PMU_DC0_CTL2			0x1E | ||||
| #define ATC2609A_PMU_DC0_CTL3			0x1F | ||||
| #define ATC2609A_PMU_DC0_CTL4			0x20 | ||||
| #define ATC2609A_PMU_DC0_CTL5			0x21 | ||||
| #define ATC2609A_PMU_DC0_CTL6			0x22 | ||||
| #define ATC2609A_PMU_DC1_CTL0			0x23 | ||||
| #define ATC2609A_PMU_DC1_CTL1			0x24 | ||||
| #define ATC2609A_PMU_DC1_CTL2			0x25 | ||||
| #define ATC2609A_PMU_DC1_CTL3			0x26 | ||||
| #define ATC2609A_PMU_DC1_CTL4			0x27 | ||||
| #define ATC2609A_PMU_DC1_CTL5			0x28 | ||||
| #define ATC2609A_PMU_DC1_CTL6			0x29 | ||||
| #define ATC2609A_PMU_DC2_CTL0			0x2A | ||||
| #define ATC2609A_PMU_DC2_CTL1			0x2B | ||||
| #define ATC2609A_PMU_DC2_CTL2			0x2C | ||||
| #define ATC2609A_PMU_DC2_CTL3			0x2D | ||||
| #define ATC2609A_PMU_DC2_CTL4			0x2E | ||||
| #define ATC2609A_PMU_DC2_CTL5			0x2F | ||||
| #define ATC2609A_PMU_DC2_CTL6			0x30 | ||||
| #define ATC2609A_PMU_DC3_CTL0			0x31 | ||||
| #define ATC2609A_PMU_DC3_CTL1			0x32 | ||||
| #define ATC2609A_PMU_DC3_CTL2			0x33 | ||||
| #define ATC2609A_PMU_DC3_CTL3			0x34 | ||||
| #define ATC2609A_PMU_DC3_CTL4			0x35 | ||||
| #define ATC2609A_PMU_DC3_CTL5			0x36 | ||||
| #define ATC2609A_PMU_DC3_CTL6			0x37 | ||||
| #define ATC2609A_PMU_DC_ZR			0x38 | ||||
| #define ATC2609A_PMU_LDO0_CTL0			0x39 | ||||
| #define ATC2609A_PMU_LDO0_CTL1			0x3A | ||||
| #define ATC2609A_PMU_LDO1_CTL0			0x3B | ||||
| #define ATC2609A_PMU_LDO1_CTL1			0x3C | ||||
| #define ATC2609A_PMU_LDO2_CTL0			0x3D | ||||
| #define ATC2609A_PMU_LDO2_CTL1			0x3E | ||||
| #define ATC2609A_PMU_LDO3_CTL0			0x3F | ||||
| #define ATC2609A_PMU_LDO3_CTL1			0x40 | ||||
| #define ATC2609A_PMU_LDO4_CTL0			0x41 | ||||
| #define ATC2609A_PMU_LDO4_CTL1			0x42 | ||||
| #define ATC2609A_PMU_LDO5_CTL0			0x43 | ||||
| #define ATC2609A_PMU_LDO5_CTL1			0x44 | ||||
| #define ATC2609A_PMU_LDO6_CTL0			0x45 | ||||
| #define ATC2609A_PMU_LDO6_CTL1			0x46 | ||||
| #define ATC2609A_PMU_LDO7_CTL0			0x47 | ||||
| #define ATC2609A_PMU_LDO7_CTL1			0x48 | ||||
| #define ATC2609A_PMU_LDO8_CTL0			0x49 | ||||
| #define ATC2609A_PMU_LDO8_CTL1			0x4A | ||||
| #define ATC2609A_PMU_LDO9_CTL			0x4B | ||||
| #define ATC2609A_PMU_OV_INT_EN			0x4C | ||||
| #define ATC2609A_PMU_OV_STATUS			0x4D | ||||
| #define ATC2609A_PMU_UV_INT_EN			0x4E | ||||
| #define ATC2609A_PMU_UV_STATUS			0x4F | ||||
| #define ATC2609A_PMU_OC_INT_EN			0x50 | ||||
| #define ATC2609A_PMU_OC_STATUS			0x51 | ||||
| #define ATC2609A_PMU_OT_CTL			0x52 | ||||
| #define ATC2609A_PMU_CM_CTL0			0x53 | ||||
| #define ATC2609A_PMU_FW_USE0			0x54 | ||||
| #define ATC2609A_PMU_FW_USE1			0x55 | ||||
| #define ATC2609A_PMU_ADC12B_I			0x56 | ||||
| #define ATC2609A_PMU_ADC12B_V			0x57 | ||||
| #define ATC2609A_PMU_ADC12B_DUMMY		0x58 | ||||
| #define ATC2609A_PMU_AUXADC_CTL0		0x59 | ||||
| #define ATC2609A_PMU_AUXADC_CTL1		0x5A | ||||
| #define ATC2609A_PMU_BATVADC			0x5B | ||||
| #define ATC2609A_PMU_BATIADC			0x5C | ||||
| #define ATC2609A_PMU_WALLVADC			0x5D | ||||
| #define ATC2609A_PMU_WALLIADC			0x5E | ||||
| #define ATC2609A_PMU_VBUSVADC			0x5F | ||||
| #define ATC2609A_PMU_VBUSIADC			0x60 | ||||
| #define ATC2609A_PMU_SYSPWRADC			0x61 | ||||
| #define ATC2609A_PMU_REMCONADC			0x62 | ||||
| #define ATC2609A_PMU_SVCCADC			0x63 | ||||
| #define ATC2609A_PMU_CHGIADC			0x64 | ||||
| #define ATC2609A_PMU_IREFADC			0x65 | ||||
| #define ATC2609A_PMU_BAKBATADC			0x66 | ||||
| #define ATC2609A_PMU_ICTEMPADC			0x67 | ||||
| #define ATC2609A_PMU_AUXADC0			0x68 | ||||
| #define ATC2609A_PMU_AUXADC1			0x69 | ||||
| #define ATC2609A_PMU_AUXADC2			0x6A | ||||
| #define ATC2609A_PMU_AUXADC3			0x6B | ||||
| #define ATC2609A_PMU_ICTEMPADC_ADJ		0x6C | ||||
| #define ATC2609A_PMU_BDG_CTL			0x6D | ||||
| #define ATC2609A_RTC_CTL			0x6E | ||||
| #define ATC2609A_RTC_MSALM			0x6F | ||||
| #define ATC2609A_RTC_HALM			0x70 | ||||
| #define ATC2609A_RTC_YMDALM			0x71 | ||||
| #define ATC2609A_RTC_MS				0x72 | ||||
| #define ATC2609A_RTC_H				0x73 | ||||
| #define ATC2609A_RTC_DC				0x74 | ||||
| #define ATC2609A_RTC_YMD			0x75 | ||||
| #define ATC2609A_EFUSE_DAT			0x76 | ||||
| #define ATC2609A_EFUSECRTL1			0x77 | ||||
| #define ATC2609A_EFUSECRTL2			0x78 | ||||
| #define ATC2609A_PMU_DC4_CTL0			0x79 | ||||
| #define ATC2609A_PMU_DC4_CTL1			0x7A | ||||
| #define ATC2609A_PMU_DC4_CTL2			0x7B | ||||
| #define ATC2609A_PMU_DC4_CTL3			0x7C | ||||
| #define ATC2609A_PMU_DC4_CTL4			0x7D | ||||
| #define ATC2609A_PMU_DC4_CTL5			0x7E | ||||
| #define ATC2609A_PMU_DC4_CTL6			0x7F | ||||
| #define ATC2609A_PMU_PWR_STATUS			0x80 | ||||
| #define ATC2609A_PMU_S2_PWR			0x81 | ||||
| #define ATC2609A_CLMT_CTL0			0x82 | ||||
| #define ATC2609A_CLMT_DATA0			0x83 | ||||
| #define ATC2609A_CLMT_DATA1			0x84 | ||||
| #define ATC2609A_CLMT_DATA2			0x85 | ||||
| #define ATC2609A_CLMT_DATA3			0x86 | ||||
| #define ATC2609A_CLMT_ADD0			0x87 | ||||
| #define ATC2609A_CLMT_ADD1			0x88 | ||||
| #define ATC2609A_CLMT_OCV_TABLE			0x89 | ||||
| #define ATC2609A_CLMT_R_TABLE			0x8A | ||||
| #define ATC2609A_PMU_PWRON_CTL0			0x8D | ||||
| #define ATC2609A_PMU_PWRON_CTL1			0x8E | ||||
| #define ATC2609A_PMU_PWRON_CTL2			0x8F | ||||
| #define ATC2609A_IRC_CTL			0x90 | ||||
| #define ATC2609A_IRC_STAT			0x91 | ||||
| #define ATC2609A_IRC_CC				0x92 | ||||
| #define ATC2609A_IRC_KDC			0x93 | ||||
| #define ATC2609A_IRC_WK				0x94 | ||||
| #define ATC2609A_IRC_RCC			0x95 | ||||
| 
 | ||||
| /* AUDIO_OUT Registers */ | ||||
| #define ATC2609A_AUDIOINOUT_CTL			0xA0 | ||||
| #define ATC2609A_AUDIO_DEBUGOUTCTL		0xA1 | ||||
| #define ATC2609A_DAC_DIGITALCTL			0xA2 | ||||
| #define ATC2609A_DAC_VOLUMECTL0			0xA3 | ||||
| #define ATC2609A_DAC_ANALOG0			0xA4 | ||||
| #define ATC2609A_DAC_ANALOG1			0xA5 | ||||
| #define ATC2609A_DAC_ANALOG2			0xA6 | ||||
| #define ATC2609A_DAC_ANALOG3			0xA7 | ||||
| 
 | ||||
| /* AUDIO_IN Registers */ | ||||
| #define ATC2609A_ADC_DIGITALCTL			0xA8 | ||||
| #define ATC2609A_ADC_HPFCTL			0xA9 | ||||
| #define ATC2609A_ADC_CTL			0xAA | ||||
| #define ATC2609A_AGC_CTL0			0xAB | ||||
| #define ATC2609A_AGC_CTL1			0xAC | ||||
| #define ATC2609A_AGC_CTL2			0xAD | ||||
| #define ATC2609A_ADC_ANALOG0			0xAE | ||||
| #define ATC2609A_ADC_ANALOG1			0xAF | ||||
| 
 | ||||
| /* PCM_IF Registers */ | ||||
| #define ATC2609A_PCM0_CTL			0xB0 | ||||
| #define ATC2609A_PCM1_CTL			0xB1 | ||||
| #define ATC2609A_PCM2_CTL			0xB2 | ||||
| #define ATC2609A_PCMIF_CTL			0xB3 | ||||
| 
 | ||||
| /* CMU_CONTROL Registers */ | ||||
| #define ATC2609A_CMU_DEVRST			0xC1 | ||||
| 
 | ||||
| /* INTS Registers */ | ||||
| #define ATC2609A_INTS_PD			0xC8 | ||||
| #define ATC2609A_INTS_MSK			0xC9 | ||||
| 
 | ||||
| /* MFP Registers */ | ||||
| #define ATC2609A_MFP_CTL			0xD0 | ||||
| #define ATC2609A_PAD_VSEL			0xD1 | ||||
| #define ATC2609A_GPIO_OUTEN			0xD2 | ||||
| #define ATC2609A_GPIO_INEN			0xD3 | ||||
| #define ATC2609A_GPIO_DAT			0xD4 | ||||
| #define ATC2609A_PAD_DRV			0xD5 | ||||
| #define ATC2609A_PAD_EN				0xD6 | ||||
| #define ATC2609A_DEBUG_SEL			0xD7 | ||||
| #define ATC2609A_DEBUG_IE			0xD8 | ||||
| #define ATC2609A_DEBUG_OE			0xD9 | ||||
| #define ATC2609A_CHIP_VER			0xDC | ||||
| 
 | ||||
| /* PWSI Registers */ | ||||
| #define ATC2609A_PWSI_CTL			0xF0 | ||||
| #define ATC2609A_PWSI_STATUS			0xF1 | ||||
| 
 | ||||
| /* TWSI Registers */ | ||||
| #define ATC2609A_SADDR				0xFF | ||||
| 
 | ||||
| /* PMU_SYS_CTL0 Register Mask Bits */ | ||||
| #define ATC2609A_PMU_SYS_CTL0_IR_WK_EN			BIT(5) | ||||
| #define ATC2609A_PMU_SYS_CTL0_RESET_WK_EN		BIT(6) | ||||
| #define ATC2609A_PMU_SYS_CTL0_HDSW_WK_EN		BIT(7) | ||||
| #define ATC2609A_PMU_SYS_CTL0_ALARM_WK_EN		BIT(8) | ||||
| #define ATC2609A_PMU_SYS_CTL0_REM_CON_WK_EN		BIT(9) | ||||
| #define ATC2609A_PMU_SYS_CTL0_RESTART_EN		BIT(10) | ||||
| #define ATC2609A_PMU_SYS_CTL0_WKIRQ_WK_EN		BIT(11) | ||||
| #define ATC2609A_PMU_SYS_CTL0_ONOFF_SHORT_WK_EN		BIT(12) | ||||
| #define ATC2609A_PMU_SYS_CTL0_ONOFF_LONG_WK_EN		BIT(13) | ||||
| #define ATC2609A_PMU_SYS_CTL0_WALL_WK_EN		BIT(14) | ||||
| #define ATC2609A_PMU_SYS_CTL0_USB_WK_EN			BIT(15) | ||||
| #define ATC2609A_PMU_SYS_CTL0_WK_ALL			(GENMASK(15, 5) & (~BIT(10))) | ||||
| 
 | ||||
| /* PMU_SYS_CTL1 Register Mask Bits */ | ||||
| #define ATC2609A_PMU_SYS_CTL1_EN_S1			BIT(0) | ||||
| #define ATC2609A_PMU_SYS_CTL1_LB_S4_EN			BIT(2) | ||||
| #define ATC2609A_PMU_SYS_CTL1_LB_S4			GENMASK(4, 3) | ||||
| #define ATC2609A_PMU_SYS_CTL1_LB_S4_3_1V		BIT(4) | ||||
| #define ATC2609A_PMU_SYS_CTL1_IR_WK_FLAG		BIT(5) | ||||
| #define ATC2609A_PMU_SYS_CTL1_RESET_WK_FLAG		BIT(6) | ||||
| #define ATC2609A_PMU_SYS_CTL1_HDSW_WK_FLAG		BIT(7) | ||||
| #define ATC2609A_PMU_SYS_CTL1_ALARM_WK_FLAG		BIT(8) | ||||
| #define ATC2609A_PMU_SYS_CTL1_REM_CON_WK_FLAG		BIT(9) | ||||
| #define ATC2609A_PMU_SYS_CTL1_RESTART_WK_FLAG		BIT(10) | ||||
| #define ATC2609A_PMU_SYS_CTL1_WKIRQ_WK_FLAG		BIT(11) | ||||
| #define ATC2609A_PMU_SYS_CTL1_ONOFF_SHORT_WK_FLAG	BIT(12) | ||||
| #define ATC2609A_PMU_SYS_CTL1_ONOFF_LONG_WK_FLAG	BIT(13) | ||||
| #define ATC2609A_PMU_SYS_CTL1_WALL_WK_FLAG		BIT(14) | ||||
| #define ATC2609A_PMU_SYS_CTL1_USB_WK_FLAG		BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL2 Register Mask Bits */ | ||||
| #define ATC2609A_PMU_SYS_CTL2_PMU_A_EN			BIT(0) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_INT_EN	BIT(1) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_PD		BIT(2) | ||||
| #define ATC2609A_PMU_SYS_CTL2_S2TIMER			GENMASK(5, 3) | ||||
| #define ATC2609A_PMU_SYS_CTL2_S2_TIMER_EN		BIT(6) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_TIME_SEL	GENMASK(8, 7) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_RESET_EN		BIT(9) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS_TIME		GENMASK(11, 10) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_LSP_INT_EN		BIT(12) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_LONG_PRESS		BIT(13) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_SHORT_PRESS		BIT(14) | ||||
| #define ATC2609A_PMU_SYS_CTL2_ONOFF_PRESS		BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL3 Register Mask Bits */ | ||||
| #define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER		GENMASK(8, 7) | ||||
| #define ATC2609A_PMU_SYS_CTL3_S2S3TOS1_TIMER_EN		BIT(9) | ||||
| #define ATC2609A_PMU_SYS_CTL3_S3_TIMER			GENMASK(12, 10) | ||||
| #define ATC2609A_PMU_SYS_CTL3_S3_TIMER_EN		BIT(13) | ||||
| #define ATC2609A_PMU_SYS_CTL3_EN_S3			BIT(14) | ||||
| #define ATC2609A_PMU_SYS_CTL3_EN_S2			BIT(15) | ||||
| 
 | ||||
| /* PMU_SYS_CTL5 Register Mask Bits */ | ||||
| #define ATC2609A_PMU_SYS_CTL5_WALLWKDTEN		BIT(7) | ||||
| #define ATC2609A_PMU_SYS_CTL5_VBUSWKDTEN		BIT(8) | ||||
| #define ATC2609A_PMU_SYS_CTL5_REMCON_DECT_EN		BIT(9) | ||||
| #define ATC2609A_PMU_SYS_CTL5_ONOFF_8S_SEL		BIT(10) | ||||
| 
 | ||||
| /* INTS_MSK Register Mask Bits */ | ||||
| #define ATC2609A_INTS_MSK_AUDIO				BIT(0) | ||||
| #define ATC2609A_INTS_MSK_OV				BIT(1) | ||||
| #define ATC2609A_INTS_MSK_OC				BIT(2) | ||||
| #define ATC2609A_INTS_MSK_OT				BIT(3) | ||||
| #define ATC2609A_INTS_MSK_UV				BIT(4) | ||||
| #define ATC2609A_INTS_MSK_ALARM				BIT(5) | ||||
| #define ATC2609A_INTS_MSK_ONOFF				BIT(6) | ||||
| #define ATC2609A_INTS_MSK_WKUP				BIT(7) | ||||
| #define ATC2609A_INTS_MSK_IR				BIT(8) | ||||
| #define ATC2609A_INTS_MSK_REMCON			BIT(9) | ||||
| #define ATC2609A_INTS_MSK_POWERIN			BIT(10) | ||||
| 
 | ||||
| /* CMU_DEVRST Register Mask Bits */ | ||||
| #define ATC2609A_CMU_DEVRST_AUDIO			BIT(0) | ||||
| #define ATC2609A_CMU_DEVRST_MFP				BIT(1) | ||||
| #define ATC2609A_CMU_DEVRST_INTS			BIT(2) | ||||
| 
 | ||||
| /* PAD_EN Register Mask Bits */ | ||||
| #define ATC2609A_PAD_EN_EXTIRQ				BIT(0) | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_ATC260X_ATC2609A_H */ | ||||
							
								
								
									
										58
									
								
								include/linux/mfd/atc260x/core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								include/linux/mfd/atc260x/core.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0+ */ | ||||
| /*
 | ||||
|  * Core MFD defines for ATC260x PMICs | ||||
|  * | ||||
|  * Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | ||||
|  * Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com> | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __LINUX_MFD_ATC260X_CORE_H | ||||
| #define __LINUX_MFD_ATC260X_CORE_H | ||||
| 
 | ||||
| #include <linux/mfd/atc260x/atc2603c.h> | ||||
| #include <linux/mfd/atc260x/atc2609a.h> | ||||
| 
 | ||||
| enum atc260x_type { | ||||
| 	ATC2603A = 0, | ||||
| 	ATC2603C, | ||||
| 	ATC2609A, | ||||
| }; | ||||
| 
 | ||||
| enum atc260x_ver { | ||||
| 	ATC260X_A = 0, | ||||
| 	ATC260X_B, | ||||
| 	ATC260X_C, | ||||
| 	ATC260X_D, | ||||
| 	ATC260X_E, | ||||
| 	ATC260X_F, | ||||
| 	ATC260X_G, | ||||
| 	ATC260X_H, | ||||
| }; | ||||
| 
 | ||||
| struct atc260x { | ||||
| 	struct device *dev; | ||||
| 
 | ||||
| 	struct regmap *regmap; | ||||
| 	const struct regmap_irq_chip *regmap_irq_chip; | ||||
| 	struct regmap_irq_chip_data *irq_data; | ||||
| 
 | ||||
| 	struct mutex *regmap_mutex;	/* mutex for custom regmap locking */ | ||||
| 
 | ||||
| 	const struct mfd_cell *cells; | ||||
| 	int nr_cells; | ||||
| 	int irq; | ||||
| 
 | ||||
| 	enum atc260x_type ic_type; | ||||
| 	enum atc260x_ver ic_ver; | ||||
| 	const char *type_name; | ||||
| 	unsigned int rev_reg; | ||||
| 
 | ||||
| 	const struct atc260x_init_regs *init_regs; /* regs for device init */ | ||||
| }; | ||||
| 
 | ||||
| struct regmap_config; | ||||
| 
 | ||||
| int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg); | ||||
| int atc260x_device_probe(struct atc260x *atc260x); | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_ATC260X_CORE_H */ | ||||
| @ -50,7 +50,7 @@ | ||||
| #define MFD_DEP_LEVEL_HIGH 1 | ||||
| 
 | ||||
| struct irq_domain; | ||||
| struct property_entry; | ||||
| struct software_node; | ||||
| 
 | ||||
| /* Matches ACPI PNP id, either _HID or _CID, or ACPI _ADR */ | ||||
| struct mfd_cell_acpi_match { | ||||
| @ -78,8 +78,8 @@ struct mfd_cell { | ||||
| 	void			*platform_data; | ||||
| 	size_t			pdata_size; | ||||
| 
 | ||||
| 	/* device properties passed to the sub devices drivers */ | ||||
| 	const struct property_entry *properties; | ||||
| 	/* Software node for the device. */ | ||||
| 	const struct software_node *swnode; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Device Tree compatible string | ||||
|  | ||||
| @ -1037,6 +1037,9 @@ | ||||
| #define		DA9063_NONKEY_PIN_AUTODOWN	0x02 | ||||
| #define		DA9063_NONKEY_PIN_AUTOFLPRT	0x03 | ||||
| 
 | ||||
| /* DA9063_REG_CONFIG_J (addr=0x10F) */ | ||||
| #define DA9063_TWOWIRE_TO			0x40 | ||||
| 
 | ||||
| /* DA9063_REG_MON_REG_5 (addr=0x116) */ | ||||
| #define DA9063_MON_A8_IDX_MASK			0x07 | ||||
| #define		DA9063_MON_A8_IDX_NONE		0x00 | ||||
|  | ||||
| @ -720,7 +720,7 @@ static inline int db8500_prcmu_load_a9wdog(u8 id, u32 val) | ||||
| 
 | ||||
| static inline bool db8500_prcmu_is_ac_wake_requested(void) | ||||
| { | ||||
| 	return 0; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static inline int db8500_prcmu_set_arm_opp(u8 opp) | ||||
|  | ||||
| @ -9,9 +9,15 @@ | ||||
| 
 | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| #define M10BMC_LEGACY_SYS_BASE		0x300400 | ||||
| #define M10BMC_LEGACY_BUILD_VER		0x300468 | ||||
| #define M10BMC_SYS_BASE			0x300800 | ||||
| #define M10BMC_MEM_END			0x200000fc | ||||
| #define M10BMC_SYS_END			0x300fff | ||||
| #define M10BMC_FLASH_BASE		0x10000000 | ||||
| #define M10BMC_FLASH_END		0x1fffffff | ||||
| #define M10BMC_MEM_END			M10BMC_FLASH_END | ||||
| 
 | ||||
| #define M10BMC_STAGING_BASE		0x18000000 | ||||
| #define M10BMC_STAGING_SIZE		0x3800000 | ||||
| 
 | ||||
| /* Register offset of system registers */ | ||||
| #define NIOS2_FW_VERSION		0x0 | ||||
| @ -30,6 +36,88 @@ | ||||
| #define M10BMC_VER_PCB_INFO_MSK		GENMASK(31, 24) | ||||
| #define M10BMC_VER_LEGACY_INVALID	0xffffffff | ||||
| 
 | ||||
| /* Secure update doorbell register, in system register region */ | ||||
| #define M10BMC_DOORBELL			0x400 | ||||
| 
 | ||||
| /* Authorization Result register, in system register region */ | ||||
| #define M10BMC_AUTH_RESULT		0x404 | ||||
| 
 | ||||
| /* Doorbell register fields */ | ||||
| #define DRBL_RSU_REQUEST		BIT(0) | ||||
| #define DRBL_RSU_PROGRESS		GENMASK(7, 4) | ||||
| #define DRBL_HOST_STATUS		GENMASK(11, 8) | ||||
| #define DRBL_RSU_STATUS			GENMASK(23, 16) | ||||
| #define DRBL_PKVL_EEPROM_LOAD_SEC	BIT(24) | ||||
| #define DRBL_PKVL1_POLL_EN		BIT(25) | ||||
| #define DRBL_PKVL2_POLL_EN		BIT(26) | ||||
| #define DRBL_CONFIG_SEL			BIT(28) | ||||
| #define DRBL_REBOOT_REQ			BIT(29) | ||||
| #define DRBL_REBOOT_DISABLED		BIT(30) | ||||
| 
 | ||||
| /* Progress states */ | ||||
| #define RSU_PROG_IDLE			0x0 | ||||
| #define RSU_PROG_PREPARE		0x1 | ||||
| #define RSU_PROG_READY			0x3 | ||||
| #define RSU_PROG_AUTHENTICATING		0x4 | ||||
| #define RSU_PROG_COPYING		0x5 | ||||
| #define RSU_PROG_UPDATE_CANCEL		0x6 | ||||
| #define RSU_PROG_PROGRAM_KEY_HASH	0x7 | ||||
| #define RSU_PROG_RSU_DONE		0x8 | ||||
| #define RSU_PROG_PKVL_PROM_DONE		0x9 | ||||
| 
 | ||||
| /* Device and error states */ | ||||
| #define RSU_STAT_NORMAL			0x0 | ||||
| #define RSU_STAT_TIMEOUT		0x1 | ||||
| #define RSU_STAT_AUTH_FAIL		0x2 | ||||
| #define RSU_STAT_COPY_FAIL		0x3 | ||||
| #define RSU_STAT_FATAL			0x4 | ||||
| #define RSU_STAT_PKVL_REJECT		0x5 | ||||
| #define RSU_STAT_NON_INC		0x6 | ||||
| #define RSU_STAT_ERASE_FAIL		0x7 | ||||
| #define RSU_STAT_WEAROUT		0x8 | ||||
| #define RSU_STAT_NIOS_OK		0x80 | ||||
| #define RSU_STAT_USER_OK		0x81 | ||||
| #define RSU_STAT_FACTORY_OK		0x82 | ||||
| #define RSU_STAT_USER_FAIL		0x83 | ||||
| #define RSU_STAT_FACTORY_FAIL		0x84 | ||||
| #define RSU_STAT_NIOS_FLASH_ERR		0x85 | ||||
| #define RSU_STAT_FPGA_FLASH_ERR		0x86 | ||||
| 
 | ||||
| #define HOST_STATUS_IDLE		0x0 | ||||
| #define HOST_STATUS_WRITE_DONE		0x1 | ||||
| #define HOST_STATUS_ABORT_RSU		0x2 | ||||
| 
 | ||||
| #define rsu_prog(doorbell)	FIELD_GET(DRBL_RSU_PROGRESS, doorbell) | ||||
| #define rsu_stat(doorbell)	FIELD_GET(DRBL_RSU_STATUS, doorbell) | ||||
| 
 | ||||
| /* interval 100ms and timeout 5s */ | ||||
| #define NIOS_HANDSHAKE_INTERVAL_US	(100 * 1000) | ||||
| #define NIOS_HANDSHAKE_TIMEOUT_US	(5 * 1000 * 1000) | ||||
| 
 | ||||
| /* RSU PREP Timeout (2 minutes) to erase flash staging area */ | ||||
| #define RSU_PREP_INTERVAL_MS		100 | ||||
| #define RSU_PREP_TIMEOUT_MS		(2 * 60 * 1000) | ||||
| 
 | ||||
| /* RSU Complete Timeout (40 minutes) for full flash update */ | ||||
| #define RSU_COMPLETE_INTERVAL_MS	1000 | ||||
| #define RSU_COMPLETE_TIMEOUT_MS		(40 * 60 * 1000) | ||||
| 
 | ||||
| /* Addresses for security related data in FLASH */ | ||||
| #define BMC_REH_ADDR	0x17ffc004 | ||||
| #define BMC_PROG_ADDR	0x17ffc000 | ||||
| #define BMC_PROG_MAGIC	0x5746 | ||||
| 
 | ||||
| #define SR_REH_ADDR	0x17ffd004 | ||||
| #define SR_PROG_ADDR	0x17ffd000 | ||||
| #define SR_PROG_MAGIC	0x5253 | ||||
| 
 | ||||
| #define PR_REH_ADDR	0x17ffe004 | ||||
| #define PR_PROG_ADDR	0x17ffe000 | ||||
| #define PR_PROG_MAGIC	0x5250 | ||||
| 
 | ||||
| /* Address of 4KB inverted bit vector containing staging area FLASH count */ | ||||
| #define STAGING_FLASH_COUNT	0x17ffb000 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct intel_m10bmc - Intel MAX 10 BMC parent driver data structure | ||||
|  * @dev: this device | ||||
|  | ||||
| @ -237,9 +237,6 @@ enum lp87565_device_type { | ||||
| #define LP87565_GOIO2_OUT			BIT(1) | ||||
| #define LP87565_GOIO1_OUT			BIT(0) | ||||
| 
 | ||||
| /* Number of step-down converters available */ | ||||
| #define LP87565_NUM_BUCK		6 | ||||
| 
 | ||||
| enum LP87565_regulator_id { | ||||
| 	/* BUCK's */ | ||||
| 	LP87565_BUCK_0, | ||||
|  | ||||
| @ -14,13 +14,13 @@ | ||||
|  * others and b) it can be enabled simply by using MAX17042 driver. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef __LINUX_MFD_MAX8998_H | ||||
| #define __LINUX_MFD_MAX8998_H | ||||
| #ifndef __LINUX_MFD_MAX8997_H | ||||
| #define __LINUX_MFD_MAX8997_H | ||||
| 
 | ||||
| #include <linux/regulator/consumer.h> | ||||
| 
 | ||||
| /* MAX8997/8966 regulator IDs */ | ||||
| enum max8998_regulators { | ||||
| enum max8997_regulators { | ||||
| 	MAX8997_LDO1 = 0, | ||||
| 	MAX8997_LDO2, | ||||
| 	MAX8997_LDO3, | ||||
| @ -207,4 +207,4 @@ struct max8997_platform_data { | ||||
| 	struct max8997_led_platform_data *led_pdata; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_MAX8998_H */ | ||||
| #endif /* __LINUX_MFD_MAX8997_H */ | ||||
|  | ||||
							
								
								
									
										38
									
								
								include/linux/mfd/ntxec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								include/linux/mfd/ntxec.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /*
 | ||||
|  * Copyright 2020 Jonathan Neuschäfer | ||||
|  * | ||||
|  * Register access and version information for the Netronix embedded | ||||
|  * controller. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef NTXEC_H | ||||
| #define NTXEC_H | ||||
| 
 | ||||
| #include <linux/types.h> | ||||
| 
 | ||||
| struct device; | ||||
| struct regmap; | ||||
| 
 | ||||
| struct ntxec { | ||||
| 	struct device *dev; | ||||
| 	struct regmap *regmap; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Some registers, such as the battery status register (0x41), are in | ||||
|  * big-endian, but others only have eight significant bits, which are in the | ||||
|  * first byte transmitted over I2C (the MSB of the big-endian value). | ||||
|  * This convenience function converts an 8-bit value to 16-bit for use in the | ||||
|  * second kind of register. | ||||
|  */ | ||||
| static inline __be16 ntxec_reg8(u8 value) | ||||
| { | ||||
| 	return value << 8; | ||||
| } | ||||
| 
 | ||||
| /* Known firmware versions */ | ||||
| #define NTXEC_VERSION_KOBO_AURA	0xd726	/* found in Kobo Aura */ | ||||
| #define NTXEC_VERSION_TOLINO_SHINE2 0xf110 /* found in Tolino Shine 2 HD */ | ||||
| 
 | ||||
| #endif | ||||
| @ -188,6 +188,7 @@ | ||||
| #define RN5T618_CHGOSCSCORESET3		0xd7 | ||||
| #define RN5T618_CHGOSCFREQSET1		0xd8 | ||||
| #define RN5T618_CHGOSCFREQSET2		0xd9 | ||||
| #define RN5T618_GCHGDET			0xda | ||||
| #define RN5T618_CONTROL			0xe0 | ||||
| #define RN5T618_SOC			0xe1 | ||||
| #define RN5T618_RE_CAP_H		0xe2 | ||||
|  | ||||
							
								
								
									
										562
									
								
								include/linux/mfd/rohm-bd71815.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										562
									
								
								include/linux/mfd/rohm-bd71815.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,562 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| /*
 | ||||
|  * Copyright 2021 ROHM Semiconductors. | ||||
|  * | ||||
|  * Author: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | ||||
|  * | ||||
|  * Copyright 2014 Embest Technology Co. Ltd. Inc. | ||||
|  * | ||||
|  * Author: yanglsh@embest-tech.com | ||||
|  */ | ||||
| 
 | ||||
| #ifndef _MFD_BD71815_H | ||||
| #define _MFD_BD71815_H | ||||
| 
 | ||||
| #include <linux/regmap.h> | ||||
| 
 | ||||
| enum { | ||||
| 	BD71815_BUCK1	=	0, | ||||
| 	BD71815_BUCK2, | ||||
| 	BD71815_BUCK3, | ||||
| 	BD71815_BUCK4, | ||||
| 	BD71815_BUCK5, | ||||
| 	/* General Purpose */ | ||||
| 	BD71815_LDO1, | ||||
| 	BD71815_LDO2, | ||||
| 	BD71815_LDO3, | ||||
| 	/* LDOs for SD Card and SD Card Interface */ | ||||
| 	BD71815_LDO4, | ||||
| 	BD71815_LDO5, | ||||
| 	/* LDO for DDR Reference Voltage */ | ||||
| 	BD71815_LDODVREF, | ||||
| 	/* LDO for Low-Power State Retention */ | ||||
| 	BD71815_LDOLPSR, | ||||
| 	BD71815_WLED, | ||||
| 	BD71815_REGULATOR_CNT, | ||||
| }; | ||||
| 
 | ||||
| #define BD71815_SUPPLY_STATE_ENABLED    0x1 | ||||
| 
 | ||||
| enum { | ||||
| 	BD71815_REG_DEVICE		= 0, | ||||
| 	BD71815_REG_PWRCTRL, | ||||
| 	BD71815_REG_BUCK1_MODE, | ||||
| 	BD71815_REG_BUCK2_MODE, | ||||
| 	BD71815_REG_BUCK3_MODE, | ||||
| 	BD71815_REG_BUCK4_MODE, | ||||
| 	BD71815_REG_BUCK5_MODE, | ||||
| 	BD71815_REG_BUCK1_VOLT_H, | ||||
| 	BD71815_REG_BUCK1_VOLT_L, | ||||
| 	BD71815_REG_BUCK2_VOLT_H, | ||||
| 	BD71815_REG_BUCK2_VOLT_L, | ||||
| 	BD71815_REG_BUCK3_VOLT, | ||||
| 	BD71815_REG_BUCK4_VOLT, | ||||
| 	BD71815_REG_BUCK5_VOLT, | ||||
| 	BD71815_REG_LED_CTRL, | ||||
| 	BD71815_REG_LED_DIMM, | ||||
| 	BD71815_REG_LDO_MODE1, | ||||
| 	BD71815_REG_LDO_MODE2, | ||||
| 	BD71815_REG_LDO_MODE3, | ||||
| 	BD71815_REG_LDO_MODE4, | ||||
| 	BD71815_REG_LDO1_VOLT, | ||||
| 	BD71815_REG_LDO2_VOLT, | ||||
| 	BD71815_REG_LDO3_VOLT, | ||||
| 	BD71815_REG_LDO4_VOLT, | ||||
| 	BD71815_REG_LDO5_VOLT_H, | ||||
| 	BD71815_REG_LDO5_VOLT_L, | ||||
| 	BD71815_REG_BUCK_PD_DIS, | ||||
| 	BD71815_REG_LDO_PD_DIS, | ||||
| 	BD71815_REG_GPO, | ||||
| 	BD71815_REG_OUT32K, | ||||
| 	BD71815_REG_SEC, | ||||
| 	BD71815_REG_MIN, | ||||
| 	BD71815_REG_HOUR, | ||||
| 	BD71815_REG_WEEK, | ||||
| 	BD71815_REG_DAY, | ||||
| 	BD71815_REG_MONTH, | ||||
| 	BD71815_REG_YEAR, | ||||
| 	BD71815_REG_ALM0_SEC, | ||||
| 
 | ||||
| 	BD71815_REG_ALM1_SEC		= 0x2C, | ||||
| 
 | ||||
| 	BD71815_REG_ALM0_MASK		= 0x33, | ||||
| 	BD71815_REG_ALM1_MASK, | ||||
| 	BD71815_REG_ALM2, | ||||
| 	BD71815_REG_TRIM, | ||||
| 	BD71815_REG_CONF, | ||||
| 	BD71815_REG_SYS_INIT, | ||||
| 	BD71815_REG_CHG_STATE, | ||||
| 	BD71815_REG_CHG_LAST_STATE, | ||||
| 	BD71815_REG_BAT_STAT, | ||||
| 	BD71815_REG_DCIN_STAT, | ||||
| 	BD71815_REG_VSYS_STAT, | ||||
| 	BD71815_REG_CHG_STAT, | ||||
| 	BD71815_REG_CHG_WDT_STAT, | ||||
| 	BD71815_REG_BAT_TEMP, | ||||
| 	BD71815_REG_IGNORE_0, | ||||
| 	BD71815_REG_INHIBIT_0, | ||||
| 	BD71815_REG_DCIN_CLPS, | ||||
| 	BD71815_REG_VSYS_REG, | ||||
| 	BD71815_REG_VSYS_MAX, | ||||
| 	BD71815_REG_VSYS_MIN, | ||||
| 	BD71815_REG_CHG_SET1, | ||||
| 	BD71815_REG_CHG_SET2, | ||||
| 	BD71815_REG_CHG_WDT_PRE, | ||||
| 	BD71815_REG_CHG_WDT_FST, | ||||
| 	BD71815_REG_CHG_IPRE, | ||||
| 	BD71815_REG_CHG_IFST, | ||||
| 	BD71815_REG_CHG_IFST_TERM, | ||||
| 	BD71815_REG_CHG_VPRE, | ||||
| 	BD71815_REG_CHG_VBAT_1, | ||||
| 	BD71815_REG_CHG_VBAT_2, | ||||
| 	BD71815_REG_CHG_VBAT_3, | ||||
| 	BD71815_REG_CHG_LED_1, | ||||
| 	BD71815_REG_VF_TH, | ||||
| 	BD71815_REG_BAT_SET_1, | ||||
| 	BD71815_REG_BAT_SET_2, | ||||
| 	BD71815_REG_BAT_SET_3, | ||||
| 	BD71815_REG_ALM_VBAT_TH_U, | ||||
| 	BD71815_REG_ALM_VBAT_TH_L, | ||||
| 	BD71815_REG_ALM_DCIN_TH, | ||||
| 	BD71815_REG_ALM_VSYS_TH, | ||||
| 	BD71815_REG_VM_IBAT_U, | ||||
| 	BD71815_REG_VM_IBAT_L, | ||||
| 	BD71815_REG_VM_VBAT_U, | ||||
| 	BD71815_REG_VM_VBAT_L, | ||||
| 	BD71815_REG_VM_BTMP, | ||||
| 	BD71815_REG_VM_VTH, | ||||
| 	BD71815_REG_VM_DCIN_U, | ||||
| 	BD71815_REG_VM_DCIN_L, | ||||
| 	BD71815_REG_VM_VSYS, | ||||
| 	BD71815_REG_VM_VF, | ||||
| 	BD71815_REG_VM_OCI_PRE_U, | ||||
| 	BD71815_REG_VM_OCI_PRE_L, | ||||
| 	BD71815_REG_VM_OCV_PRE_U, | ||||
| 	BD71815_REG_VM_OCV_PRE_L, | ||||
| 	BD71815_REG_VM_OCI_PST_U, | ||||
| 	BD71815_REG_VM_OCI_PST_L, | ||||
| 	BD71815_REG_VM_OCV_PST_U, | ||||
| 	BD71815_REG_VM_OCV_PST_L, | ||||
| 	BD71815_REG_VM_SA_VBAT_U, | ||||
| 	BD71815_REG_VM_SA_VBAT_L, | ||||
| 	BD71815_REG_VM_SA_IBAT_U, | ||||
| 	BD71815_REG_VM_SA_IBAT_L, | ||||
| 	BD71815_REG_CC_CTRL, | ||||
| 	BD71815_REG_CC_BATCAP1_TH_U, | ||||
| 	BD71815_REG_CC_BATCAP1_TH_L, | ||||
| 	BD71815_REG_CC_BATCAP2_TH_U, | ||||
| 	BD71815_REG_CC_BATCAP2_TH_L, | ||||
| 	BD71815_REG_CC_BATCAP3_TH_U, | ||||
| 	BD71815_REG_CC_BATCAP3_TH_L, | ||||
| 	BD71815_REG_CC_STAT, | ||||
| 	BD71815_REG_CC_CCNTD_3, | ||||
| 	BD71815_REG_CC_CCNTD_2, | ||||
| 	BD71815_REG_CC_CCNTD_1, | ||||
| 	BD71815_REG_CC_CCNTD_0, | ||||
| 	BD71815_REG_CC_CURCD_U, | ||||
| 	BD71815_REG_CC_CURCD_L, | ||||
| 	BD71815_REG_VM_OCUR_THR_1, | ||||
| 	BD71815_REG_VM_OCUR_DUR_1, | ||||
| 	BD71815_REG_VM_OCUR_THR_2, | ||||
| 	BD71815_REG_VM_OCUR_DUR_2, | ||||
| 	BD71815_REG_VM_OCUR_THR_3, | ||||
| 	BD71815_REG_VM_OCUR_DUR_3, | ||||
| 	BD71815_REG_VM_OCUR_MON, | ||||
| 	BD71815_REG_VM_BTMP_OV_THR, | ||||
| 	BD71815_REG_VM_BTMP_OV_DUR, | ||||
| 	BD71815_REG_VM_BTMP_LO_THR, | ||||
| 	BD71815_REG_VM_BTMP_LO_DUR, | ||||
| 	BD71815_REG_VM_BTMP_MON, | ||||
| 	BD71815_REG_INT_EN_01, | ||||
| 
 | ||||
| 	BD71815_REG_INT_EN_11		= 0x95, | ||||
| 	BD71815_REG_INT_EN_12, | ||||
| 	BD71815_REG_INT_STAT, | ||||
| 	BD71815_REG_INT_STAT_01, | ||||
| 	BD71815_REG_INT_STAT_02, | ||||
| 	BD71815_REG_INT_STAT_03, | ||||
| 	BD71815_REG_INT_STAT_04, | ||||
| 	BD71815_REG_INT_STAT_05, | ||||
| 	BD71815_REG_INT_STAT_06, | ||||
| 	BD71815_REG_INT_STAT_07, | ||||
| 	BD71815_REG_INT_STAT_08, | ||||
| 	BD71815_REG_INT_STAT_09, | ||||
| 	BD71815_REG_INT_STAT_10, | ||||
| 	BD71815_REG_INT_STAT_11, | ||||
| 	BD71815_REG_INT_STAT_12, | ||||
| 	BD71815_REG_INT_UPDATE, | ||||
| 
 | ||||
| 	BD71815_REG_VM_VSYS_U		= 0xC0, | ||||
| 	BD71815_REG_VM_VSYS_L, | ||||
| 	BD71815_REG_VM_SA_VSYS_U, | ||||
| 	BD71815_REG_VM_SA_VSYS_L, | ||||
| 
 | ||||
| 	BD71815_REG_VM_SA_IBAT_MIN_U	= 0xD0, | ||||
| 	BD71815_REG_VM_SA_IBAT_MIN_L, | ||||
| 	BD71815_REG_VM_SA_IBAT_MAX_U, | ||||
| 	BD71815_REG_VM_SA_IBAT_MAX_L, | ||||
| 	BD71815_REG_VM_SA_VBAT_MIN_U, | ||||
| 	BD71815_REG_VM_SA_VBAT_MIN_L, | ||||
| 	BD71815_REG_VM_SA_VBAT_MAX_U, | ||||
| 	BD71815_REG_VM_SA_VBAT_MAX_L, | ||||
| 	BD71815_REG_VM_SA_VSYS_MIN_U, | ||||
| 	BD71815_REG_VM_SA_VSYS_MIN_L, | ||||
| 	BD71815_REG_VM_SA_VSYS_MAX_U, | ||||
| 	BD71815_REG_VM_SA_VSYS_MAX_L, | ||||
| 	BD71815_REG_VM_SA_MINMAX_CLR, | ||||
| 
 | ||||
| 	BD71815_REG_REX_CCNTD_3		= 0xE0, | ||||
| 	BD71815_REG_REX_CCNTD_2, | ||||
| 	BD71815_REG_REX_CCNTD_1, | ||||
| 	BD71815_REG_REX_CCNTD_0, | ||||
| 	BD71815_REG_REX_SA_VBAT_U, | ||||
| 	BD71815_REG_REX_SA_VBAT_L, | ||||
| 	BD71815_REG_REX_CTRL_1, | ||||
| 	BD71815_REG_REX_CTRL_2, | ||||
| 	BD71815_REG_FULL_CCNTD_3, | ||||
| 	BD71815_REG_FULL_CCNTD_2, | ||||
| 	BD71815_REG_FULL_CCNTD_1, | ||||
| 	BD71815_REG_FULL_CCNTD_0, | ||||
| 	BD71815_REG_FULL_CTRL, | ||||
| 
 | ||||
| 	BD71815_REG_CCNTD_CHG_3		= 0xF0, | ||||
| 	BD71815_REG_CCNTD_CHG_2, | ||||
| 
 | ||||
| 	BD71815_REG_TEST_MODE		= 0xFE, | ||||
| 	BD71815_MAX_REGISTER, | ||||
| }; | ||||
| 
 | ||||
| /* BD71815_REG_BUCK1_MODE bits */ | ||||
| #define BD71815_BUCK_RAMPRATE_MASK		0xC0 | ||||
| #define BD71815_BUCK_RAMPRATE_10P00MV		0x0 | ||||
| #define BD71815_BUCK_RAMPRATE_5P00MV		0x01 | ||||
| #define BD71815_BUCK_RAMPRATE_2P50MV		0x02 | ||||
| #define BD71815_BUCK_RAMPRATE_1P25MV		0x03 | ||||
| 
 | ||||
| #define BD71815_BUCK_PWM_FIXED			BIT(4) | ||||
| #define BD71815_BUCK_SNVS_ON			BIT(3) | ||||
| #define BD71815_BUCK_RUN_ON			BIT(2) | ||||
| #define BD71815_BUCK_LPSR_ON			BIT(1) | ||||
| #define BD71815_BUCK_SUSP_ON			BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_BUCK1_VOLT_H bits */ | ||||
| #define BD71815_BUCK_DVSSEL			BIT(7) | ||||
| #define BD71815_BUCK_STBY_DVS			BIT(6) | ||||
| #define BD71815_VOLT_MASK			0x3F | ||||
| #define BD71815_BUCK1_H_DEFAULT			0x14 | ||||
| #define BD71815_BUCK1_L_DEFAULT			0x14 | ||||
| 
 | ||||
| /* BD71815_REG_BUCK2_VOLT_H bits */ | ||||
| #define BD71815_BUCK2_H_DEFAULT			0x14 | ||||
| #define BD71815_BUCK2_L_DEFAULT			0x14 | ||||
| 
 | ||||
| /* WLED output */ | ||||
| /* current register mask */ | ||||
| #define LED_DIMM_MASK				0x3f | ||||
| /* LED enable bits at LED_CTRL reg */ | ||||
| #define LED_CHGDONE_EN				BIT(4) | ||||
| #define LED_RUN_ON				BIT(2) | ||||
| #define LED_LPSR_ON				BIT(1) | ||||
| #define LED_SUSP_ON				BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_LDO1_CTRL bits */ | ||||
| #define LDO1_EN					BIT(0) | ||||
| #define LDO2_EN					BIT(1) | ||||
| #define LDO3_EN					BIT(2) | ||||
| #define DVREF_EN				BIT(3) | ||||
| #define VOSNVS_SW_EN				BIT(4) | ||||
| 
 | ||||
| /* LDO_MODE1_register */ | ||||
| #define LDO1_SNVS_ON				BIT(7) | ||||
| #define LDO1_RUN_ON				BIT(6) | ||||
| #define LDO1_LPSR_ON				BIT(5) | ||||
| #define LDO1_SUSP_ON				BIT(4) | ||||
| /* set => register control, unset => GPIO control */ | ||||
| #define LDO4_MODE_MASK				BIT(3) | ||||
| #define LDO4_MODE_I2C				BIT(3) | ||||
| #define LDO4_MODE_GPIO				0 | ||||
| /* set => register control, unset => start when DCIN connected */ | ||||
| #define LDO3_MODE_MASK				BIT(2) | ||||
| #define LDO3_MODE_I2C				BIT(2) | ||||
| #define LDO3_MODE_DCIN				0 | ||||
| 
 | ||||
| /* LDO_MODE2 register */ | ||||
| #define LDO3_SNVS_ON				BIT(7) | ||||
| #define LDO3_RUN_ON				BIT(6) | ||||
| #define LDO3_LPSR_ON				BIT(5) | ||||
| #define LDO3_SUSP_ON				BIT(4) | ||||
| #define LDO2_SNVS_ON				BIT(3) | ||||
| #define LDO2_RUN_ON				BIT(2) | ||||
| #define LDO2_LPSR_ON				BIT(1) | ||||
| #define LDO2_SUSP_ON				BIT(0) | ||||
| 
 | ||||
| 
 | ||||
| /* LDO_MODE3 register */ | ||||
| #define LDO5_SNVS_ON				BIT(7) | ||||
| #define LDO5_RUN_ON				BIT(6) | ||||
| #define LDO5_LPSR_ON				BIT(5) | ||||
| #define LDO5_SUSP_ON				BIT(4) | ||||
| #define LDO4_SNVS_ON				BIT(3) | ||||
| #define LDO4_RUN_ON				BIT(2) | ||||
| #define LDO4_LPSR_ON				BIT(1) | ||||
| #define LDO4_SUSP_ON				BIT(0) | ||||
| 
 | ||||
| /* LDO_MODE4 register */ | ||||
| #define DVREF_SNVS_ON				BIT(7) | ||||
| #define DVREF_RUN_ON				BIT(6) | ||||
| #define DVREF_LPSR_ON				BIT(5) | ||||
| #define DVREF_SUSP_ON				BIT(4) | ||||
| #define LDO_LPSR_SNVS_ON			BIT(3) | ||||
| #define LDO_LPSR_RUN_ON				BIT(2) | ||||
| #define LDO_LPSR_LPSR_ON			BIT(1) | ||||
| #define LDO_LPSR_SUSP_ON			BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_OUT32K bits */ | ||||
| #define OUT32K_EN				BIT(0) | ||||
| #define OUT32K_MODE				BIT(1) | ||||
| #define OUT32K_MODE_CMOS			BIT(1) | ||||
| #define OUT32K_MODE_OPEN_DRAIN			0 | ||||
| 
 | ||||
| /* BD71815_REG_BAT_STAT bits */ | ||||
| #define BAT_DET					BIT(5) | ||||
| #define BAT_DET_OFFSET				5 | ||||
| #define BAT_DET_DONE				BIT(4) | ||||
| #define VBAT_OV					BIT(3) | ||||
| #define DBAT_DET				BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_VBUS_STAT bits */ | ||||
| #define VBUS_DET				BIT(0) | ||||
| 
 | ||||
| #define BD71815_REG_RTC_START			BD71815_REG_SEC | ||||
| #define BD71815_REG_RTC_ALM_START		BD71815_REG_ALM0_SEC | ||||
| 
 | ||||
| /* BD71815_REG_ALM0_MASK bits */ | ||||
| #define A0_ONESEC				BIT(7) | ||||
| 
 | ||||
| /* BD71815_REG_INT_EN_00 bits */ | ||||
| #define ALMALE					BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_INT_STAT_03 bits */ | ||||
| #define DCIN_MON_DET				BIT(1) | ||||
| #define DCIN_MON_RES				BIT(0) | ||||
| #define POWERON_LONG				BIT(2) | ||||
| #define POWERON_MID				BIT(3) | ||||
| #define POWERON_SHORT				BIT(4) | ||||
| #define POWERON_PRESS				BIT(5) | ||||
| 
 | ||||
| /* BD71805_REG_INT_STAT_08 bits */ | ||||
| #define VBAT_MON_DET				BIT(1) | ||||
| #define VBAT_MON_RES				BIT(0) | ||||
| 
 | ||||
| /* BD71805_REG_INT_STAT_11 bits */ | ||||
| #define	INT_STAT_11_VF_DET			BIT(7) | ||||
| #define	INT_STAT_11_VF_RES			BIT(6) | ||||
| #define	INT_STAT_11_VF125_DET			BIT(5) | ||||
| #define	INT_STAT_11_VF125_RES			BIT(4) | ||||
| #define	INT_STAT_11_OVTMP_DET			BIT(3) | ||||
| #define	INT_STAT_11_OVTMP_RES			BIT(2) | ||||
| #define	INT_STAT_11_LOTMP_DET			BIT(1) | ||||
| #define	INT_STAT_11_LOTMP_RES			BIT(0) | ||||
| 
 | ||||
| #define VBAT_MON_DET				BIT(1) | ||||
| #define VBAT_MON_RES				BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_PWRCTRL bits */ | ||||
| #define RESTARTEN				BIT(0) | ||||
| 
 | ||||
| /* BD71815_REG_GPO bits */ | ||||
| #define READY_FORCE_LOW				BIT(2) | ||||
| #define BD71815_GPIO_DRIVE_MASK			BIT(4) | ||||
| #define BD71815_GPIO_OPEN_DRAIN			0 | ||||
| #define BD71815_GPIO_CMOS			BIT(4) | ||||
| 
 | ||||
| /* BD71815 interrupt masks */ | ||||
| enum { | ||||
| 	BD71815_INT_EN_01_BUCKAST_MASK	=	0x0F, | ||||
| 	BD71815_INT_EN_02_DCINAST_MASK	=	0x3E, | ||||
| 	BD71815_INT_EN_03_DCINAST_MASK	=	0x3F, | ||||
| 	BD71815_INT_EN_04_VSYSAST_MASK	=	0xCF, | ||||
| 	BD71815_INT_EN_05_CHGAST_MASK	=	0xFC, | ||||
| 	BD71815_INT_EN_06_BATAST_MASK	=	0xF3, | ||||
| 	BD71815_INT_EN_07_BMONAST_MASK	=	0xFE, | ||||
| 	BD71815_INT_EN_08_BMONAST_MASK	=	0x03, | ||||
| 	BD71815_INT_EN_09_BMONAST_MASK	=	0x07, | ||||
| 	BD71815_INT_EN_10_BMONAST_MASK	=	0x3F, | ||||
| 	BD71815_INT_EN_11_TMPAST_MASK	=	0xFF, | ||||
| 	BD71815_INT_EN_12_ALMAST_MASK	=	0x07, | ||||
| }; | ||||
| /* BD71815 interrupt irqs */ | ||||
| enum { | ||||
| 	/* BUCK reg interrupts */ | ||||
| 	BD71815_INT_BUCK1_OCP, | ||||
| 	BD71815_INT_BUCK2_OCP, | ||||
| 	BD71815_INT_BUCK3_OCP, | ||||
| 	BD71815_INT_BUCK4_OCP, | ||||
| 	BD71815_INT_BUCK5_OCP, | ||||
| 	BD71815_INT_LED_OVP, | ||||
| 	BD71815_INT_LED_OCP, | ||||
| 	BD71815_INT_LED_SCP, | ||||
| 	/* DCIN1 interrupts */ | ||||
| 	BD71815_INT_DCIN_RMV, | ||||
| 	BD71815_INT_CLPS_OUT, | ||||
| 	BD71815_INT_CLPS_IN, | ||||
| 	BD71815_INT_DCIN_OVP_RES, | ||||
| 	BD71815_INT_DCIN_OVP_DET, | ||||
| 	/* DCIN2 interrupts */ | ||||
| 	BD71815_INT_DCIN_MON_RES, | ||||
| 	BD71815_INT_DCIN_MON_DET, | ||||
| 	BD71815_INT_WDOG, | ||||
| 	/* Vsys INT_STAT_04 */ | ||||
| 	BD71815_INT_VSYS_UV_RES, | ||||
| 	BD71815_INT_VSYS_UV_DET, | ||||
| 	BD71815_INT_VSYS_LOW_RES, | ||||
| 	BD71815_INT_VSYS_LOW_DET, | ||||
| 	BD71815_INT_VSYS_MON_RES, | ||||
| 	BD71815_INT_VSYS_MON_DET, | ||||
| 	/* Charger INT_STAT_05 */ | ||||
| 	BD71815_INT_CHG_WDG_TEMP, | ||||
| 	BD71815_INT_CHG_WDG_TIME, | ||||
| 	BD71815_INT_CHG_RECHARGE_RES, | ||||
| 	BD71815_INT_CHG_RECHARGE_DET, | ||||
| 	BD71815_INT_CHG_RANGED_TEMP_TRANSITION, | ||||
| 	BD71815_INT_CHG_STATE_TRANSITION, | ||||
| 	/* Battery  INT_STAT_06 */ | ||||
| 	BD71815_INT_BAT_TEMP_NORMAL, | ||||
| 	BD71815_INT_BAT_TEMP_ERANGE, | ||||
| 	BD71815_INT_BAT_REMOVED, | ||||
| 	BD71815_INT_BAT_DETECTED, | ||||
| 	BD71815_INT_THERM_REMOVED, | ||||
| 	BD71815_INT_THERM_DETECTED, | ||||
| 	/* Battery Mon 1 INT_STAT_07 */ | ||||
| 	BD71815_INT_BAT_DEAD, | ||||
| 	BD71815_INT_BAT_SHORTC_RES, | ||||
| 	BD71815_INT_BAT_SHORTC_DET, | ||||
| 	BD71815_INT_BAT_LOW_VOLT_RES, | ||||
| 	BD71815_INT_BAT_LOW_VOLT_DET, | ||||
| 	BD71815_INT_BAT_OVER_VOLT_RES, | ||||
| 	BD71815_INT_BAT_OVER_VOLT_DET, | ||||
| 	/* Battery Mon 2 INT_STAT_08 */ | ||||
| 	BD71815_INT_BAT_MON_RES, | ||||
| 	BD71815_INT_BAT_MON_DET, | ||||
| 	/* Battery Mon 3 (Coulomb counter) INT_STAT_09 */ | ||||
| 	BD71815_INT_BAT_CC_MON1, | ||||
| 	BD71815_INT_BAT_CC_MON2, | ||||
| 	BD71815_INT_BAT_CC_MON3, | ||||
| 	/* Battery Mon 4 INT_STAT_10 */ | ||||
| 	BD71815_INT_BAT_OVER_CURR_1_RES, | ||||
| 	BD71815_INT_BAT_OVER_CURR_1_DET, | ||||
| 	BD71815_INT_BAT_OVER_CURR_2_RES, | ||||
| 	BD71815_INT_BAT_OVER_CURR_2_DET, | ||||
| 	BD71815_INT_BAT_OVER_CURR_3_RES, | ||||
| 	BD71815_INT_BAT_OVER_CURR_3_DET, | ||||
| 	/* Temperature INT_STAT_11 */ | ||||
| 	BD71815_INT_TEMP_BAT_LOW_RES, | ||||
| 	BD71815_INT_TEMP_BAT_LOW_DET, | ||||
| 	BD71815_INT_TEMP_BAT_HI_RES, | ||||
| 	BD71815_INT_TEMP_BAT_HI_DET, | ||||
| 	BD71815_INT_TEMP_CHIP_OVER_125_RES, | ||||
| 	BD71815_INT_TEMP_CHIP_OVER_125_DET, | ||||
| 	BD71815_INT_TEMP_CHIP_OVER_VF_RES, | ||||
| 	BD71815_INT_TEMP_CHIP_OVER_VF_DET, | ||||
| 	/* RTC Alarm INT_STAT_12 */ | ||||
| 	BD71815_INT_RTC0, | ||||
| 	BD71815_INT_RTC1, | ||||
| 	BD71815_INT_RTC2, | ||||
| }; | ||||
| 
 | ||||
| #define BD71815_INT_BUCK1_OCP_MASK			BIT(0) | ||||
| #define BD71815_INT_BUCK2_OCP_MASK			BIT(1) | ||||
| #define BD71815_INT_BUCK3_OCP_MASK			BIT(2) | ||||
| #define BD71815_INT_BUCK4_OCP_MASK			BIT(3) | ||||
| #define BD71815_INT_BUCK5_OCP_MASK			BIT(4) | ||||
| #define BD71815_INT_LED_OVP_MASK			BIT(5) | ||||
| #define BD71815_INT_LED_OCP_MASK			BIT(6) | ||||
| #define BD71815_INT_LED_SCP_MASK			BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_DCIN_RMV_MASK			BIT(1) | ||||
| #define BD71815_INT_CLPS_OUT_MASK			BIT(2) | ||||
| #define BD71815_INT_CLPS_IN_MASK			BIT(3) | ||||
| #define BD71815_INT_DCIN_OVP_RES_MASK			BIT(4) | ||||
| #define BD71815_INT_DCIN_OVP_DET_MASK			BIT(5) | ||||
| 
 | ||||
| #define BD71815_INT_DCIN_MON_RES_MASK			BIT(0) | ||||
| #define BD71815_INT_DCIN_MON_DET_MASK			BIT(1) | ||||
| #define BD71815_INT_WDOG_MASK				BIT(6) | ||||
| 
 | ||||
| #define BD71815_INT_VSYS_UV_RES_MASK			BIT(0) | ||||
| #define BD71815_INT_VSYS_UV_DET_MASK			BIT(1) | ||||
| #define BD71815_INT_VSYS_LOW_RES_MASK			BIT(2) | ||||
| #define BD71815_INT_VSYS_LOW_DET_MASK			BIT(3) | ||||
| #define BD71815_INT_VSYS_MON_RES_MASK			BIT(6) | ||||
| #define BD71815_INT_VSYS_MON_DET_MASK			BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_CHG_WDG_TEMP_MASK			BIT(2) | ||||
| #define BD71815_INT_CHG_WDG_TIME_MASK			BIT(3) | ||||
| #define BD71815_INT_CHG_RECHARGE_RES_MASK		BIT(4) | ||||
| #define BD71815_INT_CHG_RECHARGE_DET_MASK		BIT(5) | ||||
| #define BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK	BIT(6) | ||||
| #define BD71815_INT_CHG_STATE_TRANSITION_MASK		BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_BAT_TEMP_NORMAL_MASK		BIT(0) | ||||
| #define BD71815_INT_BAT_TEMP_ERANGE_MASK		BIT(1) | ||||
| #define BD71815_INT_BAT_REMOVED_MASK			BIT(4) | ||||
| #define BD71815_INT_BAT_DETECTED_MASK			BIT(5) | ||||
| #define BD71815_INT_THERM_REMOVED_MASK			BIT(6) | ||||
| #define BD71815_INT_THERM_DETECTED_MASK			BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_BAT_DEAD_MASK			BIT(1) | ||||
| #define BD71815_INT_BAT_SHORTC_RES_MASK			BIT(2) | ||||
| #define BD71815_INT_BAT_SHORTC_DET_MASK			BIT(3) | ||||
| #define BD71815_INT_BAT_LOW_VOLT_RES_MASK		BIT(4) | ||||
| #define BD71815_INT_BAT_LOW_VOLT_DET_MASK		BIT(5) | ||||
| #define BD71815_INT_BAT_OVER_VOLT_RES_MASK		BIT(6) | ||||
| #define BD71815_INT_BAT_OVER_VOLT_DET_MASK		BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_BAT_MON_RES_MASK			BIT(0) | ||||
| #define BD71815_INT_BAT_MON_DET_MASK			BIT(1) | ||||
| 
 | ||||
| #define BD71815_INT_BAT_CC_MON1_MASK			BIT(0) | ||||
| #define BD71815_INT_BAT_CC_MON2_MASK			BIT(1) | ||||
| #define BD71815_INT_BAT_CC_MON3_MASK			BIT(2) | ||||
| 
 | ||||
| #define BD71815_INT_BAT_OVER_CURR_1_RES_MASK		BIT(0) | ||||
| #define BD71815_INT_BAT_OVER_CURR_1_DET_MASK		BIT(1) | ||||
| #define BD71815_INT_BAT_OVER_CURR_2_RES_MASK		BIT(2) | ||||
| #define BD71815_INT_BAT_OVER_CURR_2_DET_MASK		BIT(3) | ||||
| #define BD71815_INT_BAT_OVER_CURR_3_RES_MASK		BIT(4) | ||||
| #define BD71815_INT_BAT_OVER_CURR_3_DET_MASK		BIT(5) | ||||
| 
 | ||||
| #define BD71815_INT_TEMP_BAT_LOW_RES_MASK		BIT(0) | ||||
| #define BD71815_INT_TEMP_BAT_LOW_DET_MASK		BIT(1) | ||||
| #define BD71815_INT_TEMP_BAT_HI_RES_MASK		BIT(2) | ||||
| #define BD71815_INT_TEMP_BAT_HI_DET_MASK		BIT(3) | ||||
| #define BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK		BIT(4) | ||||
| #define BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK		BIT(5) | ||||
| #define BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK		BIT(6) | ||||
| #define BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK		BIT(7) | ||||
| 
 | ||||
| #define BD71815_INT_RTC0_MASK				BIT(0) | ||||
| #define BD71815_INT_RTC1_MASK				BIT(1) | ||||
| #define BD71815_INT_RTC2_MASK				BIT(2) | ||||
| 
 | ||||
| /* BD71815_REG_CC_CTRL bits */ | ||||
| #define CCNTRST						0x80 | ||||
| #define CCNTENB						0x40 | ||||
| #define CCCALIB						0x20 | ||||
| 
 | ||||
| /* BD71815_REG_CC_CURCD */ | ||||
| #define CURDIR_Discharging				0x8000 | ||||
| 
 | ||||
| /* BD71815_REG_VM_SA_IBAT */ | ||||
| #define IBAT_SA_DIR_Discharging				0x8000 | ||||
| 
 | ||||
| /* BD71815_REG_REX_CTRL_1 bits */ | ||||
| #define REX_CLR						BIT(4) | ||||
| 
 | ||||
| /* BD71815_REG_REX_CTRL_1 bits */ | ||||
| #define REX_PMU_STATE_MASK				BIT(2) | ||||
| 
 | ||||
| /* BD71815_REG_LED_CTRL bits */ | ||||
| #define CHGDONE_LED_EN					BIT(4) | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_BD71815_H */ | ||||
| @ -151,6 +151,9 @@ enum { | ||||
| #define BD71828_REG_GPIO_CTRL3		0x49 | ||||
| #define BD71828_REG_IO_STAT		0xed | ||||
| 
 | ||||
| /* clk */ | ||||
| #define BD71828_REG_OUT32K		0x4b | ||||
| 
 | ||||
| /* RTC */ | ||||
| #define BD71828_REG_RTC_SEC		0x4c | ||||
| #define BD71828_REG_RTC_MINUTE		0x4d | ||||
|  | ||||
| @ -310,17 +310,4 @@ enum { | ||||
| 	BD718XX_PWRBTN_LONG_PRESS_15S | ||||
| }; | ||||
| 
 | ||||
| struct bd718xx { | ||||
| 	/*
 | ||||
| 	 * Please keep this as the first member here as some | ||||
| 	 * drivers (clk) supporting more than one chip may only know this | ||||
| 	 * generic struct 'struct rohm_regmap_dev' and assume it is | ||||
| 	 * the first chunk of parent device's private data. | ||||
| 	 */ | ||||
| 	struct rohm_regmap_dev chip; | ||||
| 
 | ||||
| 	int chip_irq; | ||||
| 	struct regmap_irq_chip_data *irq_data; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __LINUX_MFD_BD718XX_H__ */ | ||||
|  | ||||
							
								
								
									
										140
									
								
								include/linux/mfd/rohm-bd957x.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								include/linux/mfd/rohm-bd957x.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||||
| /* Copyright (C) 2021 ROHM Semiconductors */ | ||||
| 
 | ||||
| #ifndef __LINUX_MFD_BD957X_H__ | ||||
| #define __LINUX_MFD_BD957X_H__ | ||||
| 
 | ||||
| enum { | ||||
| 	BD957X_VD50, | ||||
| 	BD957X_VD18, | ||||
| 	BD957X_VDDDR, | ||||
| 	BD957X_VD10, | ||||
| 	BD957X_VOUTL1, | ||||
| 	BD957X_VOUTS1, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * The BD9576 has own IRQ 'blocks' for: | ||||
|  *  - I2C/thermal, | ||||
|  *  - Over voltage protection | ||||
|  *  - Short-circuit protection | ||||
|  *  - Over current protection | ||||
|  *  - Over voltage detection | ||||
|  *  - Under voltage detection | ||||
|  *  - Under voltage protection | ||||
|  *  - 'system interrupt'. | ||||
|  * | ||||
|  * Each of the blocks have a status register giving more accurate IRQ source | ||||
|  * information - for example which of the regulators have over-voltage. | ||||
|  * | ||||
|  * On top of this, there is "main IRQ" status register where each bit indicates | ||||
|  * which of sub-blocks have active IRQs. Fine. That would fit regmap-irq main | ||||
|  * status handling. Except that: | ||||
|  *  - Only some sub-IRQs can be masked. | ||||
|  *  - The IRQ informs us about fault-condition, not when fault state changes. | ||||
|  *    The IRQ line it is kept asserted until the detected condition is acked | ||||
|  *    AND cleared in HW. This is annoying for IRQs like the one informing high | ||||
|  *    temperature because if IRQ is not disabled it keeps the CPU in IRQ | ||||
|  *    handling loop. | ||||
|  * | ||||
|  * For now we do just use the main-IRQ register as source for our IRQ | ||||
|  * information and bind the regmap-irq to this. We leave fine-grained sub-IRQ | ||||
|  * register handling to handlers in sub-devices. The regulator driver shall | ||||
|  * read which regulators are source for problem - or if the detected error is | ||||
|  * regulator temperature error. The sub-drivers do also handle masking of "sub- | ||||
|  * IRQs" if this is supported/needed. | ||||
|  * | ||||
|  * To overcome the problem with HW keeping IRQ asserted we do call | ||||
|  * disable_irq_nosync() from sub-device handler and add a delayed work to | ||||
|  * re-enable IRQ roughly 1 second later. This should keep our CPU out of | ||||
|  * busy-loop. | ||||
|  */ | ||||
| #define IRQS_SILENT_MS			1000 | ||||
| 
 | ||||
| enum { | ||||
| 	BD9576_INT_THERM, | ||||
| 	BD9576_INT_OVP, | ||||
| 	BD9576_INT_SCP, | ||||
| 	BD9576_INT_OCP, | ||||
| 	BD9576_INT_OVD, | ||||
| 	BD9576_INT_UVD, | ||||
| 	BD9576_INT_UVP, | ||||
| 	BD9576_INT_SYS, | ||||
| }; | ||||
| 
 | ||||
| #define BD957X_REG_SMRB_ASSERT		0x15 | ||||
| #define BD957X_REG_PMIC_INTERNAL_STAT	0x20 | ||||
| #define BD957X_REG_INT_THERM_STAT	0x23 | ||||
| #define BD957X_REG_INT_THERM_MASK	0x24 | ||||
| #define BD957X_REG_INT_OVP_STAT		0x25 | ||||
| #define BD957X_REG_INT_SCP_STAT		0x26 | ||||
| #define BD957X_REG_INT_OCP_STAT		0x27 | ||||
| #define BD957X_REG_INT_OVD_STAT		0x28 | ||||
| #define BD957X_REG_INT_UVD_STAT		0x29 | ||||
| #define BD957X_REG_INT_UVP_STAT		0x2a | ||||
| #define BD957X_REG_INT_SYS_STAT		0x2b | ||||
| #define BD957X_REG_INT_SYS_MASK		0x2c | ||||
| #define BD957X_REG_INT_MAIN_STAT	0x30 | ||||
| #define BD957X_REG_INT_MAIN_MASK	0x31 | ||||
| 
 | ||||
| #define UVD_IRQ_VALID_MASK		0x6F | ||||
| #define OVD_IRQ_VALID_MASK		0x2F | ||||
| 
 | ||||
| #define BD957X_MASK_INT_MAIN_THERM	BIT(0) | ||||
| #define BD957X_MASK_INT_MAIN_OVP	BIT(1) | ||||
| #define BD957X_MASK_INT_MAIN_SCP	BIT(2) | ||||
| #define BD957X_MASK_INT_MAIN_OCP	BIT(3) | ||||
| #define BD957X_MASK_INT_MAIN_OVD	BIT(4) | ||||
| #define BD957X_MASK_INT_MAIN_UVD	BIT(5) | ||||
| #define BD957X_MASK_INT_MAIN_UVP	BIT(6) | ||||
| #define BD957X_MASK_INT_MAIN_SYS	BIT(7) | ||||
| #define BD957X_MASK_INT_ALL		0xff | ||||
| 
 | ||||
| #define BD957X_REG_WDT_CONF		0x16 | ||||
| 
 | ||||
| #define BD957X_REG_POW_TRIGGER1		0x41 | ||||
| #define BD957X_REG_POW_TRIGGER2		0x42 | ||||
| #define BD957X_REG_POW_TRIGGER3		0x43 | ||||
| #define BD957X_REG_POW_TRIGGER4		0x44 | ||||
| #define BD957X_REG_POW_TRIGGERL1	0x45 | ||||
| #define BD957X_REG_POW_TRIGGERS1	0x46 | ||||
| 
 | ||||
| #define BD957X_REGULATOR_EN_MASK	0xff | ||||
| #define BD957X_REGULATOR_DIS_VAL	0xff | ||||
| 
 | ||||
| #define BD957X_VSEL_REG_MASK		0xff | ||||
| 
 | ||||
| #define BD957X_MASK_VOUT1_TUNE		0x87 | ||||
| #define BD957X_MASK_VOUT2_TUNE		0x87 | ||||
| #define BD957X_MASK_VOUT3_TUNE		0x1f | ||||
| #define BD957X_MASK_VOUT4_TUNE		0x1f | ||||
| #define BD957X_MASK_VOUTL1_TUNE		0x87 | ||||
| 
 | ||||
| #define BD957X_REG_VOUT1_TUNE		0x50 | ||||
| #define BD957X_REG_VOUT2_TUNE		0x53 | ||||
| #define BD957X_REG_VOUT3_TUNE		0x56 | ||||
| #define BD957X_REG_VOUT4_TUNE		0x59 | ||||
| #define BD957X_REG_VOUTL1_TUNE		0x5c | ||||
| 
 | ||||
| #define BD9576_REG_VOUT1_OVD		0x51 | ||||
| #define BD9576_REG_VOUT1_UVD		0x52 | ||||
| #define BD9576_REG_VOUT2_OVD		0x54 | ||||
| #define BD9576_REG_VOUT2_UVD		0x55 | ||||
| #define BD9576_REG_VOUT3_OVD		0x57 | ||||
| #define BD9576_REG_VOUT3_UVD		0x58 | ||||
| #define BD9576_REG_VOUT4_OVD		0x5a | ||||
| #define BD9576_REG_VOUT4_UVD		0x5b | ||||
| #define BD9576_REG_VOUTL1_OVD		0x5d | ||||
| #define BD9576_REG_VOUTL1_UVD		0x5e | ||||
| 
 | ||||
| #define BD9576_MASK_XVD			0x7f | ||||
| 
 | ||||
| #define BD9576_REG_VOUT1S_OCW		0x5f | ||||
| #define BD9576_REG_VOUT1S_OCP		0x60 | ||||
| 
 | ||||
| #define BD9576_MASK_VOUT1S_OCW		0x3f | ||||
| #define BD9576_MASK_VOUT1S_OCP		0x3f | ||||
| 
 | ||||
| #define BD957X_MAX_REGISTER		0x61 | ||||
| 
 | ||||
| #endif | ||||
| @ -8,12 +8,15 @@ | ||||
| #include <linux/regulator/driver.h> | ||||
| 
 | ||||
| enum rohm_chip_type { | ||||
| 	ROHM_CHIP_TYPE_BD71837 = 0, | ||||
| 	ROHM_CHIP_TYPE_BD71847, | ||||
| 	ROHM_CHIP_TYPE_BD70528, | ||||
| 	ROHM_CHIP_TYPE_BD71828, | ||||
| 	ROHM_CHIP_TYPE_BD9571, | ||||
| 	ROHM_CHIP_TYPE_BD9573, | ||||
| 	ROHM_CHIP_TYPE_BD9574, | ||||
| 	ROHM_CHIP_TYPE_BD9576, | ||||
| 	ROHM_CHIP_TYPE_BD70528, | ||||
| 	ROHM_CHIP_TYPE_BD71815, | ||||
| 	ROHM_CHIP_TYPE_BD71828, | ||||
| 	ROHM_CHIP_TYPE_BD71837, | ||||
| 	ROHM_CHIP_TYPE_BD71847, | ||||
| 	ROHM_CHIP_TYPE_AMOUNT | ||||
| }; | ||||
| 
 | ||||
| @ -26,7 +29,8 @@ struct rohm_regmap_dev { | ||||
| #define ROHM_DVS_LEVEL_IDLE		BIT(1) | ||||
| #define ROHM_DVS_LEVEL_SUSPEND		BIT(2) | ||||
| #define ROHM_DVS_LEVEL_LPSR		BIT(3) | ||||
| #define ROHM_DVS_LEVEL_VALID_AMOUNT	4 | ||||
| #define ROHM_DVS_LEVEL_SNVS		BIT(4) | ||||
| #define ROHM_DVS_LEVEL_VALID_AMOUNT	5 | ||||
| #define ROHM_DVS_LEVEL_UNKNOWN		0 | ||||
| 
 | ||||
| /**
 | ||||
| @ -65,6 +69,9 @@ struct rohm_dvs_config { | ||||
| 	unsigned int lpsr_reg; | ||||
| 	unsigned int lpsr_mask; | ||||
| 	unsigned int lpsr_on_mask; | ||||
| 	unsigned int snvs_reg; | ||||
| 	unsigned int snvs_mask; | ||||
| 	unsigned int snvs_on_mask; | ||||
| }; | ||||
| 
 | ||||
| #if IS_ENABLED(CONFIG_REGULATOR_ROHM) | ||||
|  | ||||
| @ -781,8 +781,6 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base); | ||||
| #define TWL4030_VAUX3_DEV_GRP		0x1F | ||||
| #define TWL4030_VAUX3_DEDICATED		0x22 | ||||
| 
 | ||||
| static inline int twl4030charger_usb_en(int enable) { return 0; } | ||||
| 
 | ||||
| /*----------------------------------------------------------------------*/ | ||||
| 
 | ||||
| /* Linux-specific regulator identifiers ... for now, we only support
 | ||||
|  | ||||
| @ -1,13 +0,0 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0-only */ | ||||
| /*
 | ||||
|  * Copyright(c) 2014 Intel Corporation. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef I2C_DESIGNWARE_H | ||||
| #define I2C_DESIGNWARE_H | ||||
| 
 | ||||
| struct dw_i2c_platform_data { | ||||
| 	unsigned int i2c_scl_freq; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| @ -290,7 +290,7 @@ static void arizona_start_mic(struct arizona_extcon_info *info) | ||||
| 	unsigned int mode; | ||||
| 
 | ||||
| 	/* Microphone detection can't use idle mode */ | ||||
| 	pm_runtime_get(info->dev); | ||||
| 	pm_runtime_get_sync(info->dev); | ||||
| 
 | ||||
| 	if (info->detecting) { | ||||
| 		ret = regulator_allow_bypass(info->micvdd, false); | ||||
| @ -601,7 +601,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | ||||
| 	struct arizona *arizona = info->arizona; | ||||
| 	int id_gpio = arizona->pdata.hpdet_id_gpio; | ||||
| 	unsigned int report = EXTCON_JACK_HEADPHONE; | ||||
| 	int ret, reading; | ||||
| 	int ret, reading, state; | ||||
| 	bool mic = false; | ||||
| 
 | ||||
| 	mutex_lock(&info->lock); | ||||
| @ -614,12 +614,11 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | ||||
| 	} | ||||
| 
 | ||||
| 	/* If the cable was removed while measuring ignore the result */ | ||||
| 	ret = extcon_get_state(info->edev, EXTCON_MECHANICAL); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(arizona->dev, "Failed to check cable state: %d\n", | ||||
| 			ret); | ||||
| 	state = extcon_get_state(info->edev, EXTCON_MECHANICAL); | ||||
| 	if (state < 0) { | ||||
| 		dev_err(arizona->dev, "Failed to check cable state: %d\n", state); | ||||
| 		goto out; | ||||
| 	} else if (!ret) { | ||||
| 	} else if (!state) { | ||||
| 		dev_dbg(arizona->dev, "Ignoring HPDET for removed cable\n"); | ||||
| 		goto done; | ||||
| 	} | ||||
| @ -667,7 +666,7 @@ done: | ||||
| 		gpio_set_value_cansleep(id_gpio, 0); | ||||
| 
 | ||||
| 	/* If we have a mic then reenable MICDET */ | ||||
| 	if (mic || info->mic) | ||||
| 	if (state && (mic || info->mic)) | ||||
| 		arizona_start_mic(info); | ||||
| 
 | ||||
| 	if (info->hpdet_active) { | ||||
| @ -675,7 +674,9 @@ done: | ||||
| 		info->hpdet_active = false; | ||||
| 	} | ||||
| 
 | ||||
| 	info->hpdet_done = true; | ||||
| 	/* Do not set hp_det done when the cable has been unplugged */ | ||||
| 	if (state) | ||||
| 		info->hpdet_done = true; | ||||
| 
 | ||||
| out: | ||||
| 	mutex_unlock(&info->lock); | ||||
| @ -694,7 +695,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) | ||||
| 	dev_dbg(arizona->dev, "Starting HPDET\n"); | ||||
| 
 | ||||
| 	/* Make sure we keep the device enabled during the measurement */ | ||||
| 	pm_runtime_get(info->dev); | ||||
| 	pm_runtime_get_sync(info->dev); | ||||
| 
 | ||||
| 	info->hpdet_active = true; | ||||
| 
 | ||||
| @ -1509,7 +1510,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) | ||||
| 		 */ | ||||
| 		info->micd_pol_gpio = gpiod_get_optional(arizona->dev, | ||||
| 							 "wlf,micd-pol", | ||||
| 							 GPIOD_OUT_LOW); | ||||
| 							 mode); | ||||
| 		if (IS_ERR(info->micd_pol_gpio)) { | ||||
| 			ret = PTR_ERR(info->micd_pol_gpio); | ||||
| 			dev_err(arizona->dev, | ||||
| @ -1759,25 +1760,6 @@ static int arizona_extcon_remove(struct platform_device *pdev) | ||||
| 	bool change; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | ||||
| 				       ARIZONA_MICD_ENA, 0, | ||||
| 				       &change); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n", | ||||
| 			ret); | ||||
| 	} else if (change) { | ||||
| 		regulator_disable(info->micvdd); | ||||
| 		pm_runtime_put(info->dev); | ||||
| 	} | ||||
| 
 | ||||
| 	gpiod_put(info->micd_pol_gpio); | ||||
| 
 | ||||
| 	pm_runtime_disable(&pdev->dev); | ||||
| 
 | ||||
| 	regmap_update_bits(arizona->regmap, | ||||
| 			   ARIZONA_MICD_CLAMP_CONTROL, | ||||
| 			   ARIZONA_MICD_CLAMP_MODE_MASK, 0); | ||||
| 
 | ||||
| 	if (info->micd_clamp) { | ||||
| 		jack_irq_rise = ARIZONA_IRQ_MICD_CLAMP_RISE; | ||||
| 		jack_irq_fall = ARIZONA_IRQ_MICD_CLAMP_FALL; | ||||
| @ -1793,10 +1775,31 @@ static int arizona_extcon_remove(struct platform_device *pdev) | ||||
| 	arizona_free_irq(arizona, jack_irq_rise, info); | ||||
| 	arizona_free_irq(arizona, jack_irq_fall, info); | ||||
| 	cancel_delayed_work_sync(&info->hpdet_work); | ||||
| 	cancel_delayed_work_sync(&info->micd_detect_work); | ||||
| 	cancel_delayed_work_sync(&info->micd_timeout_work); | ||||
| 
 | ||||
| 	ret = regmap_update_bits_check(arizona->regmap, ARIZONA_MIC_DETECT_1, | ||||
| 				       ARIZONA_MICD_ENA, 0, | ||||
| 				       &change); | ||||
| 	if (ret < 0) { | ||||
| 		dev_err(&pdev->dev, "Failed to disable micd on remove: %d\n", | ||||
| 			ret); | ||||
| 	} else if (change) { | ||||
| 		regulator_disable(info->micvdd); | ||||
| 		pm_runtime_put(info->dev); | ||||
| 	} | ||||
| 
 | ||||
| 	regmap_update_bits(arizona->regmap, | ||||
| 			   ARIZONA_MICD_CLAMP_CONTROL, | ||||
| 			   ARIZONA_MICD_CLAMP_MODE_MASK, 0); | ||||
| 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, | ||||
| 			   ARIZONA_JD1_ENA, 0); | ||||
| 	arizona_clk32k_disable(arizona); | ||||
| 
 | ||||
| 	gpiod_put(info->micd_pol_gpio); | ||||
| 
 | ||||
| 	pm_runtime_disable(&pdev->dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user