diff options
88 files changed, 8956 insertions, 1317 deletions
diff --git a/Documentation/devicetree/bindings/input/cros-ec-keyb.txt b/Documentation/devicetree/bindings/input/cros-ec-keyb.txt new file mode 100644 index 000000000000..0f6355ce39b5 --- /dev/null +++ b/Documentation/devicetree/bindings/input/cros-ec-keyb.txt | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | ChromeOS EC Keyboard | ||
| 2 | |||
| 3 | Google's ChromeOS EC Keyboard is a simple matrix keyboard implemented on | ||
| 4 | a separate EC (Embedded Controller) device. It provides a message for reading | ||
| 5 | key scans from the EC. These are then converted into keycodes for processing | ||
| 6 | by the kernel. | ||
| 7 | |||
| 8 | This binding is based on matrix-keymap.txt and extends/modifies it as follows: | ||
| 9 | |||
| 10 | Required properties: | ||
| 11 | - compatible: "google,cros-ec-keyb" | ||
| 12 | |||
| 13 | Optional properties: | ||
| 14 | - google,needs-ghost-filter: True to enable a ghost filter for the matrix | ||
| 15 | keyboard. This is recommended if the EC does not have its own logic or | ||
| 16 | hardware for this. | ||
| 17 | |||
| 18 | |||
| 19 | Example: | ||
| 20 | |||
| 21 | cros-ec-keyb { | ||
| 22 | compatible = "google,cros-ec-keyb"; | ||
| 23 | keypad,num-rows = <8>; | ||
| 24 | keypad,num-columns = <13>; | ||
| 25 | google,needs-ghost-filter; | ||
| 26 | /* | ||
| 27 | * Keymap entries take the form of 0xRRCCKKKK where | ||
| 28 | * RR=Row CC=Column KKKK=Key Code | ||
| 29 | * The values below are for a US keyboard layout and | ||
| 30 | * are taken from the Linux driver. Note that the | ||
| 31 | * 102ND key is not used for US keyboards. | ||
| 32 | */ | ||
| 33 | linux,keymap = < | ||
| 34 | /* CAPSLCK F1 B F10 */ | ||
| 35 | 0x0001003a 0x0002003b 0x00030030 0x00040044 | ||
| 36 | /* N = R_ALT ESC */ | ||
| 37 | 0x00060031 0x0008000d 0x000a0064 0x01010001 | ||
| 38 | /* F4 G F7 H */ | ||
| 39 | 0x0102003e 0x01030022 0x01040041 0x01060023 | ||
| 40 | /* ' F9 BKSPACE L_CTRL */ | ||
| 41 | 0x01080028 0x01090043 0x010b000e 0x0200001d | ||
| 42 | /* TAB F3 T F6 */ | ||
| 43 | 0x0201000f 0x0202003d 0x02030014 0x02040040 | ||
| 44 | /* ] Y 102ND [ */ | ||
| 45 | 0x0205001b 0x02060015 0x02070056 0x0208001a | ||
| 46 | /* F8 GRAVE F2 5 */ | ||
| 47 | 0x02090042 0x03010029 0x0302003c 0x03030006 | ||
| 48 | /* F5 6 - \ */ | ||
| 49 | 0x0304003f 0x03060007 0x0308000c 0x030b002b | ||
| 50 | /* R_CTRL A D F */ | ||
| 51 | 0x04000061 0x0401001e 0x04020020 0x04030021 | ||
| 52 | /* S K J ; */ | ||
| 53 | 0x0404001f 0x04050025 0x04060024 0x04080027 | ||
| 54 | /* L ENTER Z C */ | ||
| 55 | 0x04090026 0x040b001c 0x0501002c 0x0502002e | ||
| 56 | /* V X , M */ | ||
| 57 | 0x0503002f 0x0504002d 0x05050033 0x05060032 | ||
| 58 | /* L_SHIFT / . SPACE */ | ||
| 59 | 0x0507002a 0x05080035 0x05090034 0x050B0039 | ||
| 60 | /* 1 3 4 2 */ | ||
| 61 | 0x06010002 0x06020004 0x06030005 0x06040003 | ||
| 62 | /* 8 7 0 9 */ | ||
| 63 | 0x06050009 0x06060008 0x0608000b 0x0609000a | ||
| 64 | /* L_ALT DOWN RIGHT Q */ | ||
| 65 | 0x060a0038 0x060b006c 0x060c006a 0x07010010 | ||
| 66 | /* E R W I */ | ||
| 67 | 0x07020012 0x07030013 0x07040011 0x07050017 | ||
| 68 | /* U R_SHIFT P O */ | ||
| 69 | 0x07060016 0x07070036 0x07080019 0x07090018 | ||
| 70 | /* UP LEFT */ | ||
| 71 | 0x070b0067 0x070c0069>; | ||
| 72 | }; | ||
diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt new file mode 100644 index 000000000000..d98cf18c721c --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/as3711.txt | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power | ||
| 2 | supplies, a battery charger and an RTC. So far only bindings for the two stepup | ||
| 3 | DCDC converters are defined. Other DCDC and LDO supplies are configured, using | ||
| 4 | standard regulator properties, they must belong to a sub-node, called | ||
| 5 | "regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter | ||
| 6 | configuration should be placed in a subnode, called "backlight." | ||
| 7 | |||
| 8 | Compulsory properties: | ||
| 9 | - compatible : must be "ams,as3711" | ||
| 10 | - reg : specifies the I2C address | ||
| 11 | |||
| 12 | To use the SU1 converter as a backlight source the following two properties must | ||
| 13 | be provided: | ||
| 14 | - su1-dev : framebuffer phandle | ||
| 15 | - su1-max-uA : maximum current | ||
| 16 | |||
| 17 | To use the SU2 converter as a backlight source the following two properties must | ||
| 18 | be provided: | ||
| 19 | - su2-dev : framebuffer phandle | ||
| 20 | - su1-max-uA : maximum current | ||
| 21 | |||
| 22 | Additionally one of these properties must be provided to select the type of | ||
| 23 | feedback used: | ||
| 24 | - su2-feedback-voltage : voltage feedback is used | ||
| 25 | - su2-feedback-curr1 : CURR1 input used for current feedback | ||
| 26 | - su2-feedback-curr2 : CURR2 input used for current feedback | ||
| 27 | - su2-feedback-curr3 : CURR3 input used for current feedback | ||
| 28 | - su2-feedback-curr-auto: automatic current feedback selection | ||
| 29 | |||
| 30 | and one of these to select the over-voltage protection pin | ||
| 31 | - su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection | ||
| 32 | - su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection | ||
| 33 | - su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection | ||
| 34 | - su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection | ||
| 35 | |||
| 36 | If "su2-feedback-curr-auto" is selected, one or more of the following properties | ||
| 37 | have to be specified: | ||
| 38 | - su2-auto-curr1 : use CURR1 input for current feedback | ||
| 39 | - su2-auto-curr2 : use CURR2 input for current feedback | ||
| 40 | - su2-auto-curr3 : use CURR3 input for current feedback | ||
| 41 | |||
| 42 | Example: | ||
| 43 | |||
| 44 | as3711@40 { | ||
| 45 | compatible = "ams,as3711"; | ||
| 46 | reg = <0x40>; | ||
| 47 | |||
| 48 | regulators { | ||
| 49 | sd4 { | ||
| 50 | regulator-name = "1.215V"; | ||
| 51 | regulator-min-microvolt = <1215000>; | ||
| 52 | regulator-max-microvolt = <1235000>; | ||
| 53 | }; | ||
| 54 | ldo2 { | ||
| 55 | regulator-name = "2.8V CPU"; | ||
| 56 | regulator-min-microvolt = <2800000>; | ||
| 57 | regulator-max-microvolt = <2800000>; | ||
| 58 | regulator-always-on; | ||
| 59 | regulator-boot-on; | ||
| 60 | }; | ||
| 61 | }; | ||
| 62 | |||
| 63 | backlight { | ||
| 64 | compatible = "ams,as3711-bl"; | ||
| 65 | su2-dev = <&lcdc>; | ||
| 66 | su2-max-uA = <36000>; | ||
| 67 | su2-feedback-curr-auto; | ||
| 68 | su2-fbprot-gpio4; | ||
| 69 | su2-auto-curr1; | ||
| 70 | su2-auto-curr2; | ||
| 71 | su2-auto-curr3; | ||
| 72 | }; | ||
| 73 | }; | ||
diff --git a/Documentation/devicetree/bindings/mfd/cros-ec.txt b/Documentation/devicetree/bindings/mfd/cros-ec.txt new file mode 100644 index 000000000000..e0e59c58a1f9 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/cros-ec.txt | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | ChromeOS Embedded Controller | ||
| 2 | |||
| 3 | Google's ChromeOS EC is a Cortex-M device which talks to the AP and | ||
| 4 | implements various function such as keyboard and battery charging. | ||
| 5 | |||
| 6 | The EC can be connect through various means (I2C, SPI, LPC) and the | ||
| 7 | compatible string used depends on the inteface. Each connection method has | ||
| 8 | its own driver which connects to the top level interface-agnostic EC driver. | ||
| 9 | Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to | ||
| 10 | the top-level driver. | ||
| 11 | |||
| 12 | Required properties (I2C): | ||
| 13 | - compatible: "google,cros-ec-i2c" | ||
| 14 | - reg: I2C slave address | ||
| 15 | |||
| 16 | Required properties (SPI): | ||
| 17 | - compatible: "google,cros-ec-spi" | ||
| 18 | - reg: SPI chip select | ||
| 19 | |||
| 20 | Required properties (LPC): | ||
| 21 | - compatible: "google,cros-ec-lpc" | ||
| 22 | - reg: List of (IO address, size) pairs defining the interface uses | ||
| 23 | |||
| 24 | |||
| 25 | Example for I2C: | ||
| 26 | |||
| 27 | i2c@12CA0000 { | ||
| 28 | cros-ec@1e { | ||
| 29 | reg = <0x1e>; | ||
| 30 | compatible = "google,cros-ec-i2c"; | ||
| 31 | interrupts = <14 0>; | ||
| 32 | interrupt-parent = <&wakeup_eint>; | ||
| 33 | wakeup-source; | ||
| 34 | }; | ||
| 35 | |||
| 36 | |||
| 37 | Example for SPI: | ||
| 38 | |||
| 39 | spi@131b0000 { | ||
| 40 | ec@0 { | ||
| 41 | compatible = "google,cros-ec-spi"; | ||
| 42 | reg = <0x0>; | ||
| 43 | interrupts = <14 0>; | ||
| 44 | interrupt-parent = <&wakeup_eint>; | ||
| 45 | wakeup-source; | ||
| 46 | spi-max-frequency = <5000000>; | ||
| 47 | controller-data { | ||
| 48 | cs-gpio = <&gpf0 3 4 3 0>; | ||
| 49 | samsung,spi-cs; | ||
| 50 | samsung,spi-feedback-delay = <2>; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | |||
| 55 | |||
| 56 | Example for LPC is not supplied as it is not yet implemented. | ||
diff --git a/Documentation/devicetree/bindings/mfd/omap-usb-host.txt b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt new file mode 100644 index 000000000000..b381fa696bf9 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/omap-usb-host.txt | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | OMAP HS USB Host | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible: should be "ti,usbhs-host" | ||
| 6 | - reg: should contain one register range i.e. start and length | ||
| 7 | - ti,hwmods: must contain "usb_host_hs" | ||
| 8 | |||
| 9 | Optional properties: | ||
| 10 | |||
| 11 | - num-ports: number of USB ports. Usually this is automatically detected | ||
| 12 | from the IP's revision register but can be overridden by specifying | ||
| 13 | this property. A maximum of 3 ports are supported at the moment. | ||
| 14 | |||
| 15 | - portN-mode: String specifying the port mode for port N, where N can be | ||
| 16 | from 1 to 3. If the port mode is not specified, that port is treated | ||
| 17 | as unused. When specified, it must be one of the following. | ||
| 18 | "ehci-phy", | ||
| 19 | "ehci-tll", | ||
| 20 | "ehci-hsic", | ||
| 21 | "ohci-phy-6pin-datse0", | ||
| 22 | "ohci-phy-6pin-dpdm", | ||
| 23 | "ohci-phy-3pin-datse0", | ||
| 24 | "ohci-phy-4pin-dpdm", | ||
| 25 | "ohci-tll-6pin-datse0", | ||
| 26 | "ohci-tll-6pin-dpdm", | ||
| 27 | "ohci-tll-3pin-datse0", | ||
| 28 | "ohci-tll-4pin-dpdm", | ||
| 29 | "ohci-tll-2pin-datse0", | ||
| 30 | "ohci-tll-2pin-dpdm", | ||
| 31 | |||
| 32 | - single-ulpi-bypass: Must be present if the controller contains a single | ||
| 33 | ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1 | ||
| 34 | |||
| 35 | Required properties if child node exists: | ||
| 36 | |||
| 37 | - #address-cells: Must be 1 | ||
| 38 | - #size-cells: Must be 1 | ||
| 39 | - ranges: must be present | ||
| 40 | |||
| 41 | Properties for children: | ||
| 42 | |||
| 43 | The OMAP HS USB Host subsystem contains EHCI and OHCI controllers. | ||
| 44 | See Documentation/devicetree/bindings/usb/omap-ehci.txt and | ||
| 45 | omap3-ohci.txt | ||
| 46 | |||
| 47 | Example for OMAP4: | ||
| 48 | |||
| 49 | usbhshost: usbhshost@4a064000 { | ||
| 50 | compatible = "ti,usbhs-host"; | ||
| 51 | reg = <0x4a064000 0x800>; | ||
| 52 | ti,hwmods = "usb_host_hs"; | ||
| 53 | #address-cells = <1>; | ||
| 54 | #size-cells = <1>; | ||
| 55 | ranges; | ||
| 56 | |||
| 57 | usbhsohci: ohci@4a064800 { | ||
| 58 | compatible = "ti,ohci-omap3", "usb-ohci"; | ||
| 59 | reg = <0x4a064800 0x400>; | ||
| 60 | interrupt-parent = <&gic>; | ||
| 61 | interrupts = <0 76 0x4>; | ||
| 62 | }; | ||
| 63 | |||
| 64 | usbhsehci: ehci@4a064c00 { | ||
| 65 | compatible = "ti,ehci-omap", "usb-ehci"; | ||
| 66 | reg = <0x4a064c00 0x400>; | ||
| 67 | interrupt-parent = <&gic>; | ||
| 68 | interrupts = <0 77 0x4>; | ||
| 69 | }; | ||
| 70 | }; | ||
| 71 | |||
| 72 | &usbhshost { | ||
| 73 | port1-mode = "ehci-phy"; | ||
| 74 | port2-mode = "ehci-tll"; | ||
| 75 | port3-mode = "ehci-phy"; | ||
| 76 | }; | ||
| 77 | |||
| 78 | &usbhsehci { | ||
| 79 | phys = <&hsusb1_phy 0 &hsusb3_phy>; | ||
| 80 | }; | ||
diff --git a/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt b/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt new file mode 100644 index 000000000000..62fe69724e3b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/omap-usb-tll.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | OMAP HS USB Host TLL (Transceiver-Less Interface) | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : should be "ti,usbhs-tll" | ||
| 6 | - reg : should contain one register range i.e. start and length | ||
| 7 | - interrupts : should contain the TLL module's interrupt | ||
| 8 | - ti,hwmod : must contain "usb_tll_hs" | ||
| 9 | |||
| 10 | Example: | ||
| 11 | |||
| 12 | usbhstll: usbhstll@4a062000 { | ||
| 13 | compatible = "ti,usbhs-tll"; | ||
| 14 | reg = <0x4a062000 0x1000>; | ||
| 15 | interrupts = <78>; | ||
| 16 | ti,hwmods = "usb_tll_hs"; | ||
| 17 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/wm8994.txt b/Documentation/devicetree/bindings/sound/wm8994.txt index 7a7eb1e7bda6..f2f3e80934d2 100644 --- a/Documentation/devicetree/bindings/sound/wm8994.txt +++ b/Documentation/devicetree/bindings/sound/wm8994.txt | |||
| @@ -5,14 +5,70 @@ on the board). | |||
| 5 | 5 | ||
| 6 | Required properties: | 6 | Required properties: |
| 7 | 7 | ||
| 8 | - compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958" | 8 | - compatible : One of "wlf,wm1811", "wlf,wm8994" or "wlf,wm8958". |
| 9 | 9 | ||
| 10 | - reg : the I2C address of the device for I2C, the chip select | 10 | - reg : the I2C address of the device for I2C, the chip select |
| 11 | number for SPI. | 11 | number for SPI. |
| 12 | 12 | ||
| 13 | - gpio-controller : Indicates this device is a GPIO controller. | ||
| 14 | - #gpio-cells : Must be 2. The first cell is the pin number and the | ||
| 15 | second cell is used to specify optional parameters (currently unused). | ||
| 16 | |||
| 17 | - AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply, | ||
| 18 | SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered | ||
| 19 | in Documentation/devicetree/bindings/regulator/regulator.txt | ||
| 20 | |||
| 21 | Optional properties: | ||
| 22 | |||
| 23 | - interrupts : The interrupt line the IRQ signal for the device is | ||
| 24 | connected to. This is optional, if it is not connected then none | ||
| 25 | of the interrupt related properties should be specified. | ||
| 26 | - interrupt-controller : These devices contain interrupt controllers | ||
| 27 | and may provide interrupt services to other devices if they have an | ||
| 28 | interrupt line connected. | ||
| 29 | - interrupt-parent : The parent interrupt controller. | ||
| 30 | - #interrupt-cells: the number of cells to describe an IRQ, this should be 2. | ||
| 31 | The first cell is the IRQ number. | ||
| 32 | The second cell is the flags, encoded as the trigger masks from | ||
| 33 | Documentation/devicetree/bindings/interrupts.txt | ||
| 34 | |||
| 35 | - wlf,gpio-cfg : A list of GPIO configuration register values. If absent, | ||
| 36 | no configuration of these registers is performed. If any value is | ||
| 37 | over 0xffff then the register will be left as default. If present 11 | ||
| 38 | values must be supplied. | ||
| 39 | |||
| 40 | - wlf,micbias-cfg : Two MICBIAS register values for WM1811 or | ||
| 41 | WM8958. If absent the register defaults will be used. | ||
| 42 | |||
| 43 | - wlf,ldo1ena : GPIO specifier for control of LDO1ENA input to device. | ||
| 44 | - wlf,ldo2ena : GPIO specifier for control of LDO2ENA input to device. | ||
| 45 | |||
| 46 | - wlf,lineout1-se : If present LINEOUT1 is in single ended mode. | ||
| 47 | - wlf,lineout2-se : If present LINEOUT2 is in single ended mode. | ||
| 48 | |||
| 49 | - wlf,lineout1-feedback : If present LINEOUT1 has common mode feedback | ||
| 50 | connected. | ||
| 51 | - wlf,lineout2-feedback : If present LINEOUT2 has common mode feedback | ||
| 52 | connected. | ||
| 53 | |||
| 54 | - wlf,ldoena-always-driven : If present LDOENA is always driven. | ||
| 55 | |||
| 13 | Example: | 56 | Example: |
| 14 | 57 | ||
| 15 | codec: wm8994@1a { | 58 | codec: wm8994@1a { |
| 16 | compatible = "wlf,wm8994"; | 59 | compatible = "wlf,wm8994"; |
| 17 | reg = <0x1a>; | 60 | reg = <0x1a>; |
| 61 | |||
| 62 | gpio-controller; | ||
| 63 | #gpio-cells = <2>; | ||
| 64 | |||
| 65 | lineout1-se; | ||
| 66 | |||
| 67 | AVDD2-supply = <®ulator>; | ||
| 68 | CPVDD-supply = <®ulator>; | ||
| 69 | DBVDD1-supply = <®ulator>; | ||
| 70 | DBVDD2-supply = <®ulator>; | ||
| 71 | DBVDD3-supply = <®ulator>; | ||
| 72 | SPKVDD1-supply = <®ulator>; | ||
| 73 | SPKVDD2-supply = <®ulator>; | ||
| 18 | }; | 74 | }; |
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index d58ad4ff8d34..2ebc97e16b91 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig | |||
| @@ -466,8 +466,6 @@ config MACH_MX31ADS_WM1133_EV1 | |||
| 466 | depends on MACH_MX31ADS | 466 | depends on MACH_MX31ADS |
| 467 | depends on MFD_WM8350_I2C | 467 | depends on MFD_WM8350_I2C |
| 468 | depends on REGULATOR_WM8350 = y | 468 | depends on REGULATOR_WM8350 = y |
| 469 | select MFD_WM8350_CONFIG_MODE_0 | ||
| 470 | select MFD_WM8352_CONFIG_MODE_0 | ||
| 471 | help | 469 | help |
| 472 | Include support for the Wolfson Microelectronics 1133-EV1 PMU | 470 | Include support for the Wolfson Microelectronics 1133-EV1 PMU |
| 473 | and audio module for the MX31ADS platform. | 471 | and audio module for the MX31ADS platform. |
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 283cb77d4721..20578536aec7 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig | |||
| @@ -200,10 +200,7 @@ endchoice | |||
| 200 | config SMDK6410_WM1190_EV1 | 200 | config SMDK6410_WM1190_EV1 |
| 201 | bool "Support Wolfson Microelectronics 1190-EV1 PMIC card" | 201 | bool "Support Wolfson Microelectronics 1190-EV1 PMIC card" |
| 202 | depends on MACH_SMDK6410 | 202 | depends on MACH_SMDK6410 |
| 203 | select MFD_WM8350_CONFIG_MODE_0 | ||
| 204 | select MFD_WM8350_CONFIG_MODE_3 | ||
| 205 | select MFD_WM8350_I2C | 203 | select MFD_WM8350_I2C |
| 206 | select MFD_WM8352_CONFIG_MODE_0 | ||
| 207 | select REGULATOR | 204 | select REGULATOR |
| 208 | select REGULATOR_WM8350 | 205 | select REGULATOR_WM8350 |
| 209 | select SAMSUNG_GPIO_EXTRA64 | 206 | select SAMSUNG_GPIO_EXTRA64 |
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410-module.c b/arch/arm/mach-s3c64xx/mach-crag6410-module.c index a946b759fabd..7ccfef227c77 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410-module.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410-module.c | |||
| @@ -208,7 +208,7 @@ static const struct i2c_board_info wm1277_devs[] = { | |||
| 208 | static struct arizona_pdata wm5102_reva_pdata = { | 208 | static struct arizona_pdata wm5102_reva_pdata = { |
| 209 | .ldoena = S3C64XX_GPN(7), | 209 | .ldoena = S3C64XX_GPN(7), |
| 210 | .gpio_base = CODEC_GPIO_BASE, | 210 | .gpio_base = CODEC_GPIO_BASE, |
| 211 | .irq_active_high = true, | 211 | .irq_flags = IRQF_TRIGGER_HIGH, |
| 212 | .micd_pol_gpio = CODEC_GPIO_BASE + 4, | 212 | .micd_pol_gpio = CODEC_GPIO_BASE + 4, |
| 213 | .micd_rate = 6, | 213 | .micd_rate = 6, |
| 214 | .gpio_defaults = { | 214 | .gpio_defaults = { |
| @@ -238,7 +238,7 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { | |||
| 238 | static struct arizona_pdata wm5102_pdata = { | 238 | static struct arizona_pdata wm5102_pdata = { |
| 239 | .ldoena = S3C64XX_GPN(7), | 239 | .ldoena = S3C64XX_GPN(7), |
| 240 | .gpio_base = CODEC_GPIO_BASE, | 240 | .gpio_base = CODEC_GPIO_BASE, |
| 241 | .irq_active_high = true, | 241 | .irq_flags = IRQF_TRIGGER_HIGH, |
| 242 | .micd_pol_gpio = CODEC_GPIO_BASE + 2, | 242 | .micd_pol_gpio = CODEC_GPIO_BASE + 2, |
| 243 | .gpio_defaults = { | 243 | .gpio_defaults = { |
| 244 | [2] = 0x10000, /* AIF3TXLRCLK */ | 244 | [2] = 0x10000, /* AIF3TXLRCLK */ |
diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 26405efe0f9f..6d0feb234d3c 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c | |||
| @@ -12,8 +12,6 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/ucb1400.h> | 13 | #include <linux/ucb1400.h> |
| 14 | 14 | ||
| 15 | struct ucb1400_gpio_data *ucbdata; | ||
| 16 | |||
| 17 | static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) | 15 | static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) |
| 18 | { | 16 | { |
| 19 | struct ucb1400_gpio *gpio; | 17 | struct ucb1400_gpio *gpio; |
| @@ -50,7 +48,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) | |||
| 50 | struct ucb1400_gpio *ucb = dev->dev.platform_data; | 48 | struct ucb1400_gpio *ucb = dev->dev.platform_data; |
| 51 | int err = 0; | 49 | int err = 0; |
| 52 | 50 | ||
| 53 | if (!(ucbdata && ucbdata->gpio_offset)) { | 51 | if (!(ucb && ucb->gpio_offset)) { |
| 54 | err = -EINVAL; | 52 | err = -EINVAL; |
| 55 | goto err; | 53 | goto err; |
| 56 | } | 54 | } |
| @@ -58,7 +56,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) | |||
| 58 | platform_set_drvdata(dev, ucb); | 56 | platform_set_drvdata(dev, ucb); |
| 59 | 57 | ||
| 60 | ucb->gc.label = "ucb1400_gpio"; | 58 | ucb->gc.label = "ucb1400_gpio"; |
| 61 | ucb->gc.base = ucbdata->gpio_offset; | 59 | ucb->gc.base = ucb->gpio_offset; |
| 62 | ucb->gc.ngpio = 10; | 60 | ucb->gc.ngpio = 10; |
| 63 | ucb->gc.owner = THIS_MODULE; | 61 | ucb->gc.owner = THIS_MODULE; |
| 64 | 62 | ||
| @@ -72,8 +70,8 @@ static int ucb1400_gpio_probe(struct platform_device *dev) | |||
| 72 | if (err) | 70 | if (err) |
| 73 | goto err; | 71 | goto err; |
| 74 | 72 | ||
| 75 | if (ucbdata && ucbdata->gpio_setup) | 73 | if (ucb && ucb->gpio_setup) |
| 76 | err = ucbdata->gpio_setup(&dev->dev, ucb->gc.ngpio); | 74 | err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio); |
| 77 | 75 | ||
| 78 | err: | 76 | err: |
| 79 | return err; | 77 | return err; |
| @@ -85,8 +83,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev) | |||
| 85 | int err = 0; | 83 | int err = 0; |
| 86 | struct ucb1400_gpio *ucb = platform_get_drvdata(dev); | 84 | struct ucb1400_gpio *ucb = platform_get_drvdata(dev); |
| 87 | 85 | ||
| 88 | if (ucbdata && ucbdata->gpio_teardown) { | 86 | if (ucb && ucb->gpio_teardown) { |
| 89 | err = ucbdata->gpio_teardown(&dev->dev, ucb->gc.ngpio); | 87 | err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio); |
| 90 | if (err) | 88 | if (err) |
| 91 | return err; | 89 | return err; |
| 92 | } | 90 | } |
| @@ -103,11 +101,6 @@ static struct platform_driver ucb1400_gpio_driver = { | |||
| 103 | }, | 101 | }, |
| 104 | }; | 102 | }; |
| 105 | 103 | ||
| 106 | void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data) | ||
| 107 | { | ||
| 108 | ucbdata = data; | ||
| 109 | } | ||
| 110 | |||
| 111 | module_platform_driver(ucb1400_gpio_driver); | 104 | module_platform_driver(ucb1400_gpio_driver); |
| 112 | 105 | ||
| 113 | MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); | 106 | MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ac0500667000..6a195d5e90ff 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -628,4 +628,16 @@ config KEYBOARD_W90P910 | |||
| 628 | To compile this driver as a module, choose M here: the | 628 | To compile this driver as a module, choose M here: the |
| 629 | module will be called w90p910_keypad. | 629 | module will be called w90p910_keypad. |
| 630 | 630 | ||
| 631 | config KEYBOARD_CROS_EC | ||
| 632 | tristate "ChromeOS EC keyboard" | ||
| 633 | select INPUT_MATRIXKMAP | ||
| 634 | depends on MFD_CROS_EC | ||
| 635 | help | ||
| 636 | Say Y here to enable the matrix keyboard used by ChromeOS devices | ||
| 637 | and implemented on the ChromeOS EC. You must enable one bus option | ||
| 638 | (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. | ||
| 639 | |||
| 640 | To compile this driver as a module, choose M here: the | ||
| 641 | module will be called cros_ec_keyb. | ||
| 642 | |||
| 631 | endif | 643 | endif |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 49b16453d00e..0c43e8cf8d0e 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o | |||
| 11 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o | 11 | obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o |
| 12 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o | 12 | obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o |
| 13 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o | 13 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o |
| 14 | obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o | ||
| 14 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o | 15 | obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o |
| 15 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o | 16 | obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o |
| 16 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o | 17 | obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c new file mode 100644 index 000000000000..49557f27bfa6 --- /dev/null +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC keyboard driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * This driver uses the Chrome OS EC byte-level message-based protocol for | ||
| 16 | * communicating the keyboard state (which keys are pressed) from a keyboard EC | ||
| 17 | * to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing, | ||
| 18 | * but everything else (including deghosting) is done here. The main | ||
| 19 | * motivation for this is to keep the EC firmware as simple as possible, since | ||
| 20 | * it cannot be easily upgraded and EC flash/IRAM space is relatively | ||
| 21 | * expensive. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/input.h> | ||
| 27 | #include <linux/kernel.h> | ||
| 28 | #include <linux/notifier.h> | ||
| 29 | #include <linux/platform_device.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/input/matrix_keypad.h> | ||
| 32 | #include <linux/mfd/cros_ec.h> | ||
| 33 | #include <linux/mfd/cros_ec_commands.h> | ||
| 34 | |||
| 35 | /* | ||
| 36 | * @rows: Number of rows in the keypad | ||
| 37 | * @cols: Number of columns in the keypad | ||
| 38 | * @row_shift: log2 or number of rows, rounded up | ||
| 39 | * @keymap_data: Matrix keymap data used to convert to keyscan values | ||
| 40 | * @ghost_filter: true to enable the matrix key-ghosting filter | ||
| 41 | * @dev: Device pointer | ||
| 42 | * @idev: Input device | ||
| 43 | * @ec: Top level ChromeOS device to use to talk to EC | ||
| 44 | * @event_notifier: interrupt event notifier for transport devices | ||
| 45 | */ | ||
| 46 | struct cros_ec_keyb { | ||
| 47 | unsigned int rows; | ||
| 48 | unsigned int cols; | ||
| 49 | int row_shift; | ||
| 50 | const struct matrix_keymap_data *keymap_data; | ||
| 51 | bool ghost_filter; | ||
| 52 | |||
| 53 | struct device *dev; | ||
| 54 | struct input_dev *idev; | ||
| 55 | struct cros_ec_device *ec; | ||
| 56 | struct notifier_block notifier; | ||
| 57 | }; | ||
| 58 | |||
| 59 | |||
| 60 | static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev, | ||
| 61 | uint8_t *buf, int row) | ||
| 62 | { | ||
| 63 | int pressed_in_row = 0; | ||
| 64 | int row_has_teeth = 0; | ||
| 65 | int col, mask; | ||
| 66 | |||
| 67 | mask = 1 << row; | ||
| 68 | for (col = 0; col < ckdev->cols; col++) { | ||
| 69 | if (buf[col] & mask) { | ||
| 70 | pressed_in_row++; | ||
| 71 | row_has_teeth |= buf[col] & ~mask; | ||
| 72 | if (pressed_in_row > 1 && row_has_teeth) { | ||
| 73 | /* ghosting */ | ||
| 74 | dev_dbg(ckdev->dev, | ||
| 75 | "ghost found at: r%d c%d, pressed %d, teeth 0x%x\n", | ||
| 76 | row, col, pressed_in_row, | ||
| 77 | row_has_teeth); | ||
| 78 | return true; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | return false; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Returns true when there is at least one combination of pressed keys that | ||
| 88 | * results in ghosting. | ||
| 89 | */ | ||
| 90 | static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) | ||
| 91 | { | ||
| 92 | int row; | ||
| 93 | |||
| 94 | /* | ||
| 95 | * Ghosting happens if for any pressed key X there are other keys | ||
| 96 | * pressed both in the same row and column of X as, for instance, | ||
| 97 | * in the following diagram: | ||
| 98 | * | ||
| 99 | * . . Y . g . | ||
| 100 | * . . . . . . | ||
| 101 | * . . . . . . | ||
| 102 | * . . X . Z . | ||
| 103 | * | ||
| 104 | * In this case only X, Y, and Z are pressed, but g appears to be | ||
| 105 | * pressed too (see Wikipedia). | ||
| 106 | * | ||
| 107 | * We can detect ghosting in a single pass (*) over the keyboard state | ||
| 108 | * by maintaining two arrays. pressed_in_row counts how many pressed | ||
| 109 | * keys we have found in a row. row_has_teeth is true if any of the | ||
| 110 | * pressed keys for this row has other pressed keys in its column. If | ||
| 111 | * at any point of the scan we find that a row has multiple pressed | ||
| 112 | * keys, and at least one of them is at the intersection with a column | ||
| 113 | * with multiple pressed keys, we're sure there is ghosting. | ||
| 114 | * Conversely, if there is ghosting, we will detect such situation for | ||
| 115 | * at least one key during the pass. | ||
| 116 | * | ||
| 117 | * (*) This looks linear in the number of keys, but it's not. We can | ||
| 118 | * cheat because the number of rows is small. | ||
| 119 | */ | ||
| 120 | for (row = 0; row < ckdev->rows; row++) | ||
| 121 | if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row)) | ||
| 122 | return true; | ||
| 123 | |||
| 124 | return false; | ||
| 125 | } | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Compares the new keyboard state to the old one and produces key | ||
| 129 | * press/release events accordingly. The keyboard state is 13 bytes (one byte | ||
| 130 | * per column) | ||
| 131 | */ | ||
| 132 | static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, | ||
| 133 | uint8_t *kb_state, int len) | ||
| 134 | { | ||
| 135 | struct input_dev *idev = ckdev->idev; | ||
| 136 | int col, row; | ||
| 137 | int new_state; | ||
| 138 | int num_cols; | ||
| 139 | |||
| 140 | num_cols = len; | ||
| 141 | |||
| 142 | if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { | ||
| 143 | /* | ||
| 144 | * Simple-minded solution: ignore this state. The obvious | ||
| 145 | * improvement is to only ignore changes to keys involved in | ||
| 146 | * the ghosting, but process the other changes. | ||
| 147 | */ | ||
| 148 | dev_dbg(ckdev->dev, "ghosting found\n"); | ||
| 149 | return; | ||
| 150 | } | ||
| 151 | |||
| 152 | for (col = 0; col < ckdev->cols; col++) { | ||
| 153 | for (row = 0; row < ckdev->rows; row++) { | ||
| 154 | int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); | ||
| 155 | const unsigned short *keycodes = idev->keycode; | ||
| 156 | int code; | ||
| 157 | |||
| 158 | code = keycodes[pos]; | ||
| 159 | new_state = kb_state[col] & (1 << row); | ||
| 160 | if (!!new_state != test_bit(code, idev->key)) { | ||
| 161 | dev_dbg(ckdev->dev, | ||
| 162 | "changed: [r%d c%d]: byte %02x\n", | ||
| 163 | row, col, new_state); | ||
| 164 | |||
| 165 | input_report_key(idev, code, new_state); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } | ||
| 169 | input_sync(ckdev->idev); | ||
| 170 | } | ||
| 171 | |||
| 172 | static int cros_ec_keyb_open(struct input_dev *dev) | ||
| 173 | { | ||
| 174 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | ||
| 175 | |||
| 176 | return blocking_notifier_chain_register(&ckdev->ec->event_notifier, | ||
| 177 | &ckdev->notifier); | ||
| 178 | } | ||
| 179 | |||
| 180 | static void cros_ec_keyb_close(struct input_dev *dev) | ||
| 181 | { | ||
| 182 | struct cros_ec_keyb *ckdev = input_get_drvdata(dev); | ||
| 183 | |||
| 184 | blocking_notifier_chain_unregister(&ckdev->ec->event_notifier, | ||
| 185 | &ckdev->notifier); | ||
| 186 | } | ||
| 187 | |||
| 188 | static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state) | ||
| 189 | { | ||
| 190 | return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE, | ||
| 191 | kb_state, ckdev->cols); | ||
| 192 | } | ||
| 193 | |||
| 194 | static int cros_ec_keyb_work(struct notifier_block *nb, | ||
| 195 | unsigned long state, void *_notify) | ||
| 196 | { | ||
| 197 | int ret; | ||
| 198 | struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, | ||
| 199 | notifier); | ||
| 200 | uint8_t kb_state[ckdev->cols]; | ||
| 201 | |||
| 202 | ret = cros_ec_keyb_get_state(ckdev, kb_state); | ||
| 203 | if (ret >= 0) | ||
| 204 | cros_ec_keyb_process(ckdev, kb_state, ret); | ||
| 205 | |||
| 206 | return NOTIFY_DONE; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Clear any keys in the buffer */ | ||
| 210 | static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev) | ||
| 211 | { | ||
| 212 | uint8_t old_state[ckdev->cols]; | ||
| 213 | uint8_t new_state[ckdev->cols]; | ||
| 214 | unsigned long duration; | ||
| 215 | int i, ret; | ||
| 216 | |||
| 217 | /* | ||
| 218 | * Keep reading until we see that the scan state does not change. | ||
| 219 | * That indicates that we are done. | ||
| 220 | * | ||
| 221 | * Assume that the EC keyscan buffer is at most 32 deep. | ||
| 222 | */ | ||
| 223 | duration = jiffies; | ||
| 224 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
| 225 | for (i = 1; !ret && i < 32; i++) { | ||
| 226 | memcpy(old_state, new_state, sizeof(old_state)); | ||
| 227 | ret = cros_ec_keyb_get_state(ckdev, new_state); | ||
| 228 | if (0 == memcmp(old_state, new_state, sizeof(old_state))) | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | duration = jiffies - duration; | ||
| 232 | dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i, | ||
| 233 | jiffies_to_usecs(duration)); | ||
| 234 | } | ||
| 235 | |||
| 236 | static int cros_ec_keyb_probe(struct platform_device *pdev) | ||
| 237 | { | ||
| 238 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
| 239 | struct device *dev = ec->dev; | ||
| 240 | struct cros_ec_keyb *ckdev; | ||
| 241 | struct input_dev *idev; | ||
| 242 | struct device_node *np; | ||
| 243 | int err; | ||
| 244 | |||
| 245 | np = pdev->dev.of_node; | ||
| 246 | if (!np) | ||
| 247 | return -ENODEV; | ||
| 248 | |||
| 249 | ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL); | ||
| 250 | if (!ckdev) | ||
| 251 | return -ENOMEM; | ||
| 252 | err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows, | ||
| 253 | &ckdev->cols); | ||
| 254 | if (err) | ||
| 255 | return err; | ||
| 256 | |||
| 257 | idev = devm_input_allocate_device(&pdev->dev); | ||
| 258 | if (!idev) | ||
| 259 | return -ENOMEM; | ||
| 260 | |||
| 261 | ckdev->ec = ec; | ||
| 262 | ckdev->notifier.notifier_call = cros_ec_keyb_work; | ||
| 263 | ckdev->dev = dev; | ||
| 264 | dev_set_drvdata(&pdev->dev, ckdev); | ||
| 265 | |||
| 266 | idev->name = ec->ec_name; | ||
| 267 | idev->phys = ec->phys_name; | ||
| 268 | __set_bit(EV_REP, idev->evbit); | ||
| 269 | |||
| 270 | idev->id.bustype = BUS_VIRTUAL; | ||
| 271 | idev->id.version = 1; | ||
| 272 | idev->id.product = 0; | ||
| 273 | idev->dev.parent = &pdev->dev; | ||
| 274 | idev->open = cros_ec_keyb_open; | ||
| 275 | idev->close = cros_ec_keyb_close; | ||
| 276 | |||
| 277 | ckdev->ghost_filter = of_property_read_bool(np, | ||
| 278 | "google,needs-ghost-filter"); | ||
| 279 | |||
| 280 | err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, | ||
| 281 | NULL, idev); | ||
| 282 | if (err) { | ||
| 283 | dev_err(dev, "cannot build key matrix\n"); | ||
| 284 | return err; | ||
| 285 | } | ||
| 286 | |||
| 287 | ckdev->row_shift = get_count_order(ckdev->cols); | ||
| 288 | |||
| 289 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
| 290 | input_set_drvdata(idev, ckdev); | ||
| 291 | ckdev->idev = idev; | ||
| 292 | err = input_register_device(ckdev->idev); | ||
| 293 | if (err) { | ||
| 294 | dev_err(dev, "cannot register input device\n"); | ||
| 295 | return err; | ||
| 296 | } | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | #ifdef CONFIG_PM_SLEEP | ||
| 302 | static int cros_ec_keyb_resume(struct device *dev) | ||
| 303 | { | ||
| 304 | struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); | ||
| 305 | |||
| 306 | /* | ||
| 307 | * When the EC is not a wake source, then it could not have caused the | ||
| 308 | * resume, so we clear the EC's key scan buffer. If the EC was a | ||
| 309 | * wake source (e.g. the lid is open and the user might press a key to | ||
| 310 | * wake) then the key scan buffer should be preserved. | ||
| 311 | */ | ||
| 312 | if (ckdev->ec->was_wake_device) | ||
| 313 | cros_ec_keyb_clear_keyboard(ckdev); | ||
| 314 | |||
| 315 | return 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | #endif | ||
| 319 | |||
| 320 | static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume); | ||
| 321 | |||
| 322 | static struct platform_driver cros_ec_keyb_driver = { | ||
| 323 | .probe = cros_ec_keyb_probe, | ||
| 324 | .driver = { | ||
| 325 | .name = "cros-ec-keyb", | ||
| 326 | .pm = &cros_ec_keyb_pm_ops, | ||
| 327 | }, | ||
| 328 | }; | ||
| 329 | |||
| 330 | module_platform_driver(cros_ec_keyb_driver); | ||
| 331 | |||
| 332 | MODULE_LICENSE("GPL"); | ||
| 333 | MODULE_DESCRIPTION("ChromeOS EC keyboard driver"); | ||
| 334 | MODULE_ALIAS("platform:cros-ec-keyb"); | ||
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 1b8add6cfb9d..42181435fe67 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c | |||
| @@ -144,12 +144,13 @@ static int lpc32xx_parse_dt(struct device *dev, | |||
| 144 | { | 144 | { |
| 145 | struct device_node *np = dev->of_node; | 145 | struct device_node *np = dev->of_node; |
| 146 | u32 rows = 0, columns = 0; | 146 | u32 rows = 0, columns = 0; |
| 147 | int err; | ||
| 147 | 148 | ||
| 148 | of_property_read_u32(np, "keypad,num-rows", &rows); | 149 | err = matrix_keypad_parse_of_params(dev, &rows, &columns); |
| 149 | of_property_read_u32(np, "keypad,num-columns", &columns); | 150 | if (err) |
| 150 | if (!rows || rows != columns) { | 151 | return err; |
| 151 | dev_err(dev, | 152 | if (rows != columns) { |
| 152 | "rows and columns must be specified and be equal!\n"); | 153 | dev_err(dev, "rows and columns must be equal!\n"); |
| 153 | return -EINVAL; | 154 | return -EINVAL; |
| 154 | } | 155 | } |
| 155 | 156 | ||
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index e25b022692cd..1b289092f4e3 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c | |||
| @@ -215,18 +215,12 @@ static int omap4_keypad_parse_dt(struct device *dev, | |||
| 215 | struct omap4_keypad *keypad_data) | 215 | struct omap4_keypad *keypad_data) |
| 216 | { | 216 | { |
| 217 | struct device_node *np = dev->of_node; | 217 | struct device_node *np = dev->of_node; |
| 218 | int err; | ||
| 218 | 219 | ||
| 219 | if (!np) { | 220 | err = matrix_keypad_parse_of_params(dev, &keypad_data->rows, |
| 220 | dev_err(dev, "missing DT data"); | 221 | &keypad_data->cols); |
| 221 | return -EINVAL; | 222 | if (err) |
| 222 | } | 223 | return err; |
| 223 | |||
| 224 | of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows); | ||
| 225 | of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols); | ||
| 226 | if (!keypad_data->rows || !keypad_data->cols) { | ||
| 227 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
| 228 | return -EINVAL; | ||
| 229 | } | ||
| 230 | 224 | ||
| 231 | if (of_get_property(np, "linux,input-no-autorepeat", NULL)) | 225 | if (of_get_property(np, "linux,input-no-autorepeat", NULL)) |
| 232 | keypad_data->no_autorepeat = true; | 226 | keypad_data->no_autorepeat = true; |
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index a34cc6714e5b..55c15304ddbc 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c | |||
| @@ -288,8 +288,11 @@ static int tca8418_keypad_probe(struct i2c_client *client, | |||
| 288 | irq_is_gpio = pdata->irq_is_gpio; | 288 | irq_is_gpio = pdata->irq_is_gpio; |
| 289 | } else { | 289 | } else { |
| 290 | struct device_node *np = dev->of_node; | 290 | struct device_node *np = dev->of_node; |
| 291 | of_property_read_u32(np, "keypad,num-rows", &rows); | 291 | int err; |
| 292 | of_property_read_u32(np, "keypad,num-columns", &cols); | 292 | |
| 293 | err = matrix_keypad_parse_of_params(dev, &rows, &cols); | ||
| 294 | if (err) | ||
| 295 | return err; | ||
| 293 | rep = of_property_read_bool(np, "keypad,autorepeat"); | 296 | rep = of_property_read_bool(np, "keypad,autorepeat"); |
| 294 | } | 297 | } |
| 295 | 298 | ||
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 3ae496ea5fe6..08b61f506db6 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c | |||
| @@ -50,6 +50,26 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev, | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | #ifdef CONFIG_OF | 52 | #ifdef CONFIG_OF |
| 53 | int matrix_keypad_parse_of_params(struct device *dev, | ||
| 54 | unsigned int *rows, unsigned int *cols) | ||
| 55 | { | ||
| 56 | struct device_node *np = dev->of_node; | ||
| 57 | |||
| 58 | if (!np) { | ||
| 59 | dev_err(dev, "missing DT data"); | ||
| 60 | return -EINVAL; | ||
| 61 | } | ||
| 62 | of_property_read_u32(np, "keypad,num-rows", rows); | ||
| 63 | of_property_read_u32(np, "keypad,num-columns", cols); | ||
| 64 | if (!*rows || !*cols) { | ||
| 65 | dev_err(dev, "number of keypad rows/columns not specified\n"); | ||
| 66 | return -EINVAL; | ||
| 67 | } | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params); | ||
| 72 | |||
| 53 | static int matrix_keypad_parse_of_keymap(const char *propname, | 73 | static int matrix_keypad_parse_of_keymap(const char *propname, |
| 54 | unsigned int rows, unsigned int cols, | 74 | unsigned int rows, unsigned int cols, |
| 55 | struct input_dev *input_dev) | 75 | struct input_dev *input_dev) |
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 893fc1ba6ead..31ca55548ef9 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c | |||
| @@ -1144,17 +1144,15 @@ static int pm860x_probe(struct i2c_client *client, | |||
| 1144 | return -ENOMEM; | 1144 | return -ENOMEM; |
| 1145 | ret = pm860x_dt_init(node, &client->dev, pdata); | 1145 | ret = pm860x_dt_init(node, &client->dev, pdata); |
| 1146 | if (ret) | 1146 | if (ret) |
| 1147 | goto err; | 1147 | return ret; |
| 1148 | } else if (!pdata) { | 1148 | } else if (!pdata) { |
| 1149 | pr_info("No platform data in %s!\n", __func__); | 1149 | pr_info("No platform data in %s!\n", __func__); |
| 1150 | return -EINVAL; | 1150 | return -EINVAL; |
| 1151 | } | 1151 | } |
| 1152 | 1152 | ||
| 1153 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); | 1153 | chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); |
| 1154 | if (chip == NULL) { | 1154 | if (chip == NULL) |
| 1155 | ret = -ENOMEM; | 1155 | return -ENOMEM; |
| 1156 | goto err; | ||
| 1157 | } | ||
| 1158 | 1156 | ||
| 1159 | chip->id = verify_addr(client); | 1157 | chip->id = verify_addr(client); |
| 1160 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); | 1158 | chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); |
| @@ -1194,10 +1192,6 @@ static int pm860x_probe(struct i2c_client *client, | |||
| 1194 | 1192 | ||
| 1195 | pm860x_device_init(chip, pdata); | 1193 | pm860x_device_init(chip, pdata); |
| 1196 | return 0; | 1194 | return 0; |
| 1197 | err: | ||
| 1198 | if (node) | ||
| 1199 | devm_kfree(&client->dev, pdata); | ||
| 1200 | return ret; | ||
| 1201 | } | 1195 | } |
| 1202 | 1196 | ||
| 1203 | static int pm860x_remove(struct i2c_client *client) | 1197 | static int pm860x_remove(struct i2c_client *client) |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ca86581d02ce..d9aed1593e5d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
| @@ -10,19 +10,240 @@ config MFD_CORE | |||
| 10 | select IRQ_DOMAIN | 10 | select IRQ_DOMAIN |
| 11 | default n | 11 | default n |
| 12 | 12 | ||
| 13 | config MFD_88PM860X | 13 | config MFD_CS5535 |
| 14 | bool "Support Marvell 88PM8606/88PM8607" | 14 | tristate "AMD CS5535 and CS5536 southbridge core functions" |
| 15 | select MFD_CORE | ||
| 16 | depends on PCI && X86 | ||
| 17 | ---help--- | ||
| 18 | This is the core driver for CS5535/CS5536 MFD functions. This is | ||
| 19 | necessary for using the board's GPIO and MFGPT functionality. | ||
| 20 | |||
| 21 | config MFD_AS3711 | ||
| 22 | bool "AMS AS3711" | ||
| 23 | select MFD_CORE | ||
| 24 | select REGMAP_I2C | ||
| 25 | select REGMAP_IRQ | ||
| 15 | depends on I2C=y && GENERIC_HARDIRQS | 26 | depends on I2C=y && GENERIC_HARDIRQS |
| 27 | help | ||
| 28 | Support for the AS3711 PMIC from AMS | ||
| 29 | |||
| 30 | config PMIC_ADP5520 | ||
| 31 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
| 32 | depends on I2C=y | ||
| 33 | help | ||
| 34 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
| 35 | Multifunction Power Management IC. This includes | ||
| 36 | the I2C driver and the core APIs _only_, you have to select | ||
| 37 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
| 38 | under the corresponding menus. | ||
| 39 | |||
| 40 | config MFD_AAT2870_CORE | ||
| 41 | bool "AnalogicTech AAT2870" | ||
| 42 | select MFD_CORE | ||
| 43 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | ||
| 44 | help | ||
| 45 | If you say yes here you get support for the AAT2870. | ||
| 46 | This driver provides common support for accessing the device, | ||
| 47 | additional drivers must be enabled in order to use the | ||
| 48 | functionality of the device. | ||
| 49 | |||
| 50 | config MFD_CROS_EC | ||
| 51 | tristate "ChromeOS Embedded Controller" | ||
| 52 | select MFD_CORE | ||
| 53 | help | ||
| 54 | If you say Y here you get support for the ChromeOS Embedded | ||
| 55 | Controller (EC) providing keyboard, battery and power services. | ||
| 56 | You also ned to enable the driver for the bus you are using. The | ||
| 57 | protocol for talking to the EC is defined by the bus driver. | ||
| 58 | |||
| 59 | config MFD_CROS_EC_I2C | ||
| 60 | tristate "ChromeOS Embedded Controller (I2C)" | ||
| 61 | depends on MFD_CROS_EC && I2C | ||
| 62 | |||
| 63 | help | ||
| 64 | If you say Y here, you get support for talking to the ChromeOS | ||
| 65 | EC through an I2C bus. This uses a simple byte-level protocol with | ||
| 66 | a checksum. Failing accesses will be retried three times to | ||
| 67 | improve reliability. | ||
| 68 | |||
| 69 | config MFD_CROS_EC_SPI | ||
| 70 | tristate "ChromeOS Embedded Controller (SPI)" | ||
| 71 | depends on MFD_CROS_EC && SPI | ||
| 72 | |||
| 73 | ---help--- | ||
| 74 | If you say Y here, you get support for talking to the ChromeOS EC | ||
| 75 | through a SPI bus, using a byte-level protocol. Since the EC's | ||
| 76 | response time cannot be guaranteed, we support ignoring | ||
| 77 | 'pre-amble' bytes before the response actually starts. | ||
| 78 | |||
| 79 | config MFD_ASIC3 | ||
| 80 | bool "Compaq ASIC3" | ||
| 81 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | ||
| 82 | select MFD_CORE | ||
| 83 | ---help--- | ||
| 84 | This driver supports the ASIC3 multifunction chip found on many | ||
| 85 | PDAs (mainly iPAQ and HTC based ones) | ||
| 86 | |||
| 87 | config PMIC_DA903X | ||
| 88 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" | ||
| 89 | depends on I2C=y | ||
| 90 | help | ||
| 91 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a | ||
| 92 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC | ||
| 93 | usually found on PXA processors-based platforms. This includes | ||
| 94 | the I2C driver and the core APIs _only_, you have to select | ||
| 95 | individual components like LCD backlight, voltage regulators, | ||
| 96 | LEDs and battery-charger under the corresponding menus. | ||
| 97 | |||
| 98 | config PMIC_DA9052 | ||
| 99 | bool | ||
| 100 | select MFD_CORE | ||
| 101 | |||
| 102 | config MFD_DA9052_SPI | ||
| 103 | bool "Dialog Semiconductor DA9052/53 PMIC variants with SPI" | ||
| 104 | select REGMAP_SPI | ||
| 105 | select REGMAP_IRQ | ||
| 106 | select PMIC_DA9052 | ||
| 107 | depends on SPI_MASTER=y && GENERIC_HARDIRQS | ||
| 108 | help | ||
| 109 | Support for the Dialog Semiconductor DA9052 PMIC | ||
| 110 | when controlled using SPI. This driver provides common support | ||
| 111 | for accessing the device, additional drivers must be enabled in | ||
| 112 | order to use the functionality of the device. | ||
| 113 | |||
| 114 | config MFD_DA9052_I2C | ||
| 115 | bool "Dialog Semiconductor DA9052/53 PMIC variants with I2C" | ||
| 16 | select REGMAP_I2C | 116 | select REGMAP_I2C |
| 117 | select REGMAP_IRQ | ||
| 118 | select PMIC_DA9052 | ||
| 119 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 120 | help | ||
| 121 | Support for the Dialog Semiconductor DA9052 PMIC | ||
| 122 | when controlled using I2C. This driver provides common support | ||
| 123 | for accessing the device, additional drivers must be enabled in | ||
| 124 | order to use the functionality of the device. | ||
| 125 | |||
| 126 | config MFD_DA9055 | ||
| 127 | bool "Dialog Semiconductor DA9055 PMIC Support" | ||
| 128 | select REGMAP_I2C | ||
| 129 | select REGMAP_IRQ | ||
| 17 | select MFD_CORE | 130 | select MFD_CORE |
| 131 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 18 | help | 132 | help |
| 19 | This supports for Marvell 88PM8606/88PM8607 Power Management IC. | 133 | Say yes here for support of Dialog Semiconductor DA9055. This is |
| 20 | This includes the I2C driver and the core APIs _only_, you have to | 134 | a Power Management IC. This driver provides common support for |
| 21 | select individual components like voltage regulators, RTC and | 135 | accessing the device as well as the I2C interface to the chip itself. |
| 22 | battery-charger under the corresponding menus. | 136 | Additional drivers must be enabled in order to use the functionality |
| 137 | of the device. | ||
| 138 | |||
| 139 | This driver can be built as a module. If built as a module it will be | ||
| 140 | called "da9055" | ||
| 141 | |||
| 142 | config MFD_MC13783 | ||
| 143 | tristate | ||
| 144 | |||
| 145 | config MFD_MC13XXX | ||
| 146 | tristate | ||
| 147 | depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS | ||
| 148 | select MFD_CORE | ||
| 149 | select MFD_MC13783 | ||
| 150 | help | ||
| 151 | Enable support for the Freescale MC13783 and MC13892 PMICs. | ||
| 152 | This driver provides common support for accessing the device, | ||
| 153 | additional drivers must be enabled in order to use the | ||
| 154 | functionality of the device. | ||
| 155 | |||
| 156 | config MFD_MC13XXX_SPI | ||
| 157 | tristate "Freescale MC13783 and MC13892 SPI interface" | ||
| 158 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
| 159 | select REGMAP_SPI | ||
| 160 | select MFD_MC13XXX | ||
| 161 | help | ||
| 162 | Select this if your MC13xxx is connected via an SPI bus. | ||
| 163 | |||
| 164 | config MFD_MC13XXX_I2C | ||
| 165 | tristate "Freescale MC13892 I2C interface" | ||
| 166 | depends on I2C && GENERIC_HARDIRQS | ||
| 167 | select REGMAP_I2C | ||
| 168 | select MFD_MC13XXX | ||
| 169 | help | ||
| 170 | Select this if your MC13xxx is connected via an I2C bus. | ||
| 171 | |||
| 172 | config HTC_EGPIO | ||
| 173 | bool "HTC EGPIO support" | ||
| 174 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | ||
| 175 | help | ||
| 176 | This driver supports the CPLD egpio chip present on | ||
| 177 | several HTC phones. It provides basic support for input | ||
| 178 | pins, output pins, and irqs. | ||
| 179 | |||
| 180 | config HTC_PASIC3 | ||
| 181 | tristate "HTC PASIC3 LED/DS1WM chip support" | ||
| 182 | select MFD_CORE | ||
| 183 | depends on GENERIC_HARDIRQS | ||
| 184 | help | ||
| 185 | This core driver provides register access for the LED/DS1WM | ||
| 186 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and | ||
| 187 | HTC Magician devices, respectively. Actual functionality is | ||
| 188 | handled by the leds-pasic3 and ds1wm drivers. | ||
| 189 | |||
| 190 | config HTC_I2CPLD | ||
| 191 | bool "HTC I2C PLD chip support" | ||
| 192 | depends on I2C=y && GPIOLIB | ||
| 193 | help | ||
| 194 | If you say yes here you get support for the supposed CPLD | ||
| 195 | found on omap850 HTC devices like the HTC Wizard and HTC Herald. | ||
| 196 | This device provides input and output GPIOs through an I2C | ||
| 197 | interface to one or more sub-chips. | ||
| 198 | |||
| 199 | config LPC_ICH | ||
| 200 | tristate "Intel ICH LPC" | ||
| 201 | depends on PCI && GENERIC_HARDIRQS | ||
| 202 | select MFD_CORE | ||
| 203 | help | ||
| 204 | The LPC bridge function of the Intel ICH provides support for | ||
| 205 | many functional units. This driver provides needed support for | ||
| 206 | other drivers to control these functions, currently GPIO and | ||
| 207 | watchdog. | ||
| 208 | |||
| 209 | config LPC_SCH | ||
| 210 | tristate "Intel SCH LPC" | ||
| 211 | depends on PCI && GENERIC_HARDIRQS | ||
| 212 | select MFD_CORE | ||
| 213 | help | ||
| 214 | LPC bridge function of the Intel SCH provides support for | ||
| 215 | System Management Bus and General Purpose I/O. | ||
| 216 | |||
| 217 | config MFD_INTEL_MSIC | ||
| 218 | bool "Intel MSIC" | ||
| 219 | depends on INTEL_SCU_IPC | ||
| 220 | select MFD_CORE | ||
| 221 | help | ||
| 222 | Select this option to enable access to Intel MSIC (Avatele | ||
| 223 | Passage) chip. This chip embeds audio, battery, GPIO, etc. | ||
| 224 | devices used in Intel Medfield platforms. | ||
| 225 | |||
| 226 | config MFD_JANZ_CMODIO | ||
| 227 | tristate "Janz CMOD-IO PCI MODULbus Carrier Board" | ||
| 228 | select MFD_CORE | ||
| 229 | depends on PCI && GENERIC_HARDIRQS | ||
| 230 | help | ||
| 231 | This is the core driver for the Janz CMOD-IO PCI MODULbus | ||
| 232 | carrier board. This device is a PCI to MODULbus bridge which may | ||
| 233 | host many different types of MODULbus daughterboards, including | ||
| 234 | CAN and GPIO controllers. | ||
| 235 | |||
| 236 | config MFD_JZ4740_ADC | ||
| 237 | bool "Janz JZ4740 ADC core" | ||
| 238 | select MFD_CORE | ||
| 239 | select GENERIC_IRQ_CHIP | ||
| 240 | depends on MACH_JZ4740 | ||
| 241 | help | ||
| 242 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. | ||
| 243 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | ||
| 23 | 244 | ||
| 24 | config MFD_88PM800 | 245 | config MFD_88PM800 |
| 25 | tristate "Support Marvell 88PM800" | 246 | tristate "Marvell 88PM800" |
| 26 | depends on I2C=y && GENERIC_HARDIRQS | 247 | depends on I2C=y && GENERIC_HARDIRQS |
| 27 | select REGMAP_I2C | 248 | select REGMAP_I2C |
| 28 | select REGMAP_IRQ | 249 | select REGMAP_IRQ |
| @@ -34,7 +255,7 @@ config MFD_88PM800 | |||
| 34 | battery-charger under the corresponding menus. | 255 | battery-charger under the corresponding menus. |
| 35 | 256 | ||
| 36 | config MFD_88PM805 | 257 | config MFD_88PM805 |
| 37 | tristate "Support Marvell 88PM805" | 258 | tristate "Marvell 88PM805" |
| 38 | depends on I2C=y && GENERIC_HARDIRQS | 259 | depends on I2C=y && GENERIC_HARDIRQS |
| 39 | select REGMAP_I2C | 260 | select REGMAP_I2C |
| 40 | select REGMAP_IRQ | 261 | select REGMAP_IRQ |
| @@ -45,8 +266,242 @@ config MFD_88PM805 | |||
| 45 | components like codec device, headset/Mic device under the | 266 | components like codec device, headset/Mic device under the |
| 46 | corresponding menus. | 267 | corresponding menus. |
| 47 | 268 | ||
| 269 | config MFD_88PM860X | ||
| 270 | bool "Marvell 88PM8606/88PM8607" | ||
| 271 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 272 | select REGMAP_I2C | ||
| 273 | select MFD_CORE | ||
| 274 | help | ||
| 275 | This supports for Marvell 88PM8606/88PM8607 Power Management IC. | ||
| 276 | This includes the I2C driver and the core APIs _only_, you have to | ||
| 277 | select individual components like voltage regulators, RTC and | ||
| 278 | battery-charger under the corresponding menus. | ||
| 279 | |||
| 280 | config MFD_MAX77686 | ||
| 281 | bool "Maxim Semiconductor MAX77686 PMIC Support" | ||
| 282 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 283 | select MFD_CORE | ||
| 284 | select REGMAP_I2C | ||
| 285 | select IRQ_DOMAIN | ||
| 286 | help | ||
| 287 | Say yes here to support for Maxim Semiconductor MAX77686. | ||
| 288 | This is a Power Management IC with RTC on chip. | ||
| 289 | This driver provides common support for accessing the device; | ||
| 290 | additional drivers must be enabled in order to use the functionality | ||
| 291 | of the device. | ||
| 292 | |||
| 293 | config MFD_MAX77693 | ||
| 294 | bool "Maxim Semiconductor MAX77693 PMIC Support" | ||
| 295 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 296 | select MFD_CORE | ||
| 297 | select REGMAP_I2C | ||
| 298 | help | ||
| 299 | Say yes here to support for Maxim Semiconductor MAX77693. | ||
| 300 | This is a companion Power Management IC with Flash, Haptic, Charger, | ||
| 301 | and MUIC(Micro USB Interface Controller) controls on chip. | ||
| 302 | This driver provides common support for accessing the device; | ||
| 303 | additional drivers must be enabled in order to use the functionality | ||
| 304 | of the device. | ||
| 305 | |||
| 306 | config MFD_MAX8907 | ||
| 307 | tristate "Maxim Semiconductor MAX8907 PMIC Support" | ||
| 308 | select MFD_CORE | ||
| 309 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 310 | select REGMAP_I2C | ||
| 311 | select REGMAP_IRQ | ||
| 312 | help | ||
| 313 | Say yes here to support for Maxim Semiconductor MAX8907. This is | ||
| 314 | a Power Management IC. This driver provides common support for | ||
| 315 | accessing the device; additional drivers must be enabled in order | ||
| 316 | to use the functionality of the device. | ||
| 317 | |||
| 318 | config MFD_MAX8925 | ||
| 319 | bool "Maxim Semiconductor MAX8925 PMIC Support" | ||
| 320 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 321 | select MFD_CORE | ||
| 322 | help | ||
| 323 | Say yes here to support for Maxim Semiconductor MAX8925. This is | ||
| 324 | a Power Management IC. This driver provides common support for | ||
| 325 | accessing the device, additional drivers must be enabled in order | ||
| 326 | to use the functionality of the device. | ||
| 327 | |||
| 328 | config MFD_MAX8997 | ||
| 329 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
| 330 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 331 | select MFD_CORE | ||
| 332 | select IRQ_DOMAIN | ||
| 333 | help | ||
| 334 | Say yes here to support for Maxim Semiconductor MAX8997/8966. | ||
| 335 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
| 336 | MUIC controls on chip. | ||
| 337 | This driver provides common support for accessing the device; | ||
| 338 | additional drivers must be enabled in order to use the functionality | ||
| 339 | of the device. | ||
| 340 | |||
| 341 | config MFD_MAX8998 | ||
| 342 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | ||
| 343 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 344 | select MFD_CORE | ||
| 345 | help | ||
| 346 | Say yes here to support for Maxim Semiconductor MAX8998 and | ||
| 347 | National Semiconductor LP3974. This is a Power Management IC. | ||
| 348 | This driver provides common support for accessing the device, | ||
| 349 | additional drivers must be enabled in order to use the functionality | ||
| 350 | of the device. | ||
| 351 | |||
| 352 | config EZX_PCAP | ||
| 353 | bool "Motorola EZXPCAP Support" | ||
| 354 | depends on GENERIC_HARDIRQS && SPI_MASTER | ||
| 355 | help | ||
| 356 | This enables the PCAP ASIC present on EZX Phones. This is | ||
| 357 | needed for MMC, TouchScreen, Sound, USB, etc.. | ||
| 358 | |||
| 359 | config MFD_VIPERBOARD | ||
| 360 | tristate "Nano River Technologies Viperboard" | ||
| 361 | select MFD_CORE | ||
| 362 | depends on USB && GENERIC_HARDIRQS | ||
| 363 | default n | ||
| 364 | help | ||
| 365 | Say yes here if you want support for Nano River Technologies | ||
| 366 | Viperboard. | ||
| 367 | There are mfd cell drivers available for i2c master, adc and | ||
| 368 | both gpios found on the board. The spi part does not yet | ||
| 369 | have a driver. | ||
| 370 | You need to select the mfd cell drivers separately. | ||
| 371 | The drivers do not support all features the board exposes. | ||
| 372 | |||
| 373 | config MFD_RETU | ||
| 374 | tristate "Nokia Retu and Tahvo multi-function device" | ||
| 375 | select MFD_CORE | ||
| 376 | depends on I2C && GENERIC_HARDIRQS | ||
| 377 | select REGMAP_IRQ | ||
| 378 | help | ||
| 379 | Retu and Tahvo are a multi-function devices found on Nokia | ||
| 380 | Internet Tablets (770, N800 and N810). | ||
| 381 | |||
| 382 | config MFD_PCF50633 | ||
| 383 | tristate "NXP PCF50633" | ||
| 384 | depends on I2C | ||
| 385 | select REGMAP_I2C | ||
| 386 | help | ||
| 387 | Say yes here if you have NXP PCF50633 chip on your board. | ||
| 388 | This core driver provides register access and IRQ handling | ||
| 389 | facilities, and registers devices for the various functions | ||
| 390 | so that function-specific drivers can bind to them. | ||
| 391 | |||
| 392 | config PCF50633_ADC | ||
| 393 | tristate "NXP PCF50633 ADC" | ||
| 394 | depends on MFD_PCF50633 | ||
| 395 | help | ||
| 396 | Say yes here if you want to include support for ADC in the | ||
| 397 | NXP PCF50633 chip. | ||
| 398 | |||
| 399 | config PCF50633_GPIO | ||
| 400 | tristate "NXP PCF50633 GPIO" | ||
| 401 | depends on MFD_PCF50633 | ||
| 402 | help | ||
| 403 | Say yes here if you want to include support GPIO for pins on | ||
| 404 | the PCF50633 chip. | ||
| 405 | |||
| 406 | config UCB1400_CORE | ||
| 407 | tristate "Philips UCB1400 Core driver" | ||
| 408 | depends on AC97_BUS | ||
| 409 | depends on GPIOLIB | ||
| 410 | help | ||
| 411 | This enables support for the Philips UCB1400 core functions. | ||
| 412 | The UCB1400 is an AC97 audio codec. | ||
| 413 | |||
| 414 | To compile this driver as a module, choose M here: the | ||
| 415 | module will be called ucb1400_core. | ||
| 416 | |||
| 417 | config MFD_PM8XXX | ||
| 418 | tristate | ||
| 419 | |||
| 420 | config MFD_PM8921_CORE | ||
| 421 | tristate "Qualcomm PM8921 PMIC chip" | ||
| 422 | depends on SSBI && BROKEN | ||
| 423 | select MFD_CORE | ||
| 424 | select MFD_PM8XXX | ||
| 425 | help | ||
| 426 | If you say yes to this option, support will be included for the | ||
| 427 | built-in PM8921 PMIC chip. | ||
| 428 | |||
| 429 | This is required if your board has a PM8921 and uses its features, | ||
| 430 | such as: MPPs, GPIOs, regulators, interrupts, and PWM. | ||
| 431 | |||
| 432 | Say M here if you want to include support for PM8921 chip as a module. | ||
| 433 | This will build a module called "pm8921-core". | ||
| 434 | |||
| 435 | config MFD_PM8XXX_IRQ | ||
| 436 | bool "Qualcomm PM8xxx IRQ features" | ||
| 437 | depends on MFD_PM8XXX | ||
| 438 | default y if MFD_PM8XXX | ||
| 439 | help | ||
| 440 | This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. | ||
| 441 | |||
| 442 | This is required to use certain other PM 8xxx features, such as GPIO | ||
| 443 | and MPP. | ||
| 444 | |||
| 445 | config MFD_RDC321X | ||
| 446 | tristate "RDC R-321x southbridge" | ||
| 447 | select MFD_CORE | ||
| 448 | depends on PCI && GENERIC_HARDIRQS | ||
| 449 | help | ||
| 450 | Say yes here if you want to have support for the RDC R-321x SoC | ||
| 451 | southbridge which provides access to GPIOs and Watchdog using the | ||
| 452 | southbridge PCI device configuration space. | ||
| 453 | |||
| 454 | config MFD_RTSX_PCI | ||
| 455 | tristate "Realtek PCI-E card reader" | ||
| 456 | depends on PCI && GENERIC_HARDIRQS | ||
| 457 | select MFD_CORE | ||
| 458 | help | ||
| 459 | This supports for Realtek PCI-Express card reader including rts5209, | ||
| 460 | rts5229, rtl8411, etc. Realtek card reader supports access to many | ||
| 461 | types of memory cards, such as Memory Stick, Memory Stick Pro, | ||
| 462 | Secure Digital and MultiMediaCard. | ||
| 463 | |||
| 464 | config MFD_RC5T583 | ||
| 465 | bool "Ricoh RC5T583 Power Management system device" | ||
| 466 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 467 | select MFD_CORE | ||
| 468 | select REGMAP_I2C | ||
| 469 | help | ||
| 470 | Select this option to get support for the RICOH583 Power | ||
| 471 | Management system device. | ||
| 472 | This driver provides common support for accessing the device | ||
| 473 | through i2c interface. The device supports multiple sub-devices | ||
| 474 | like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. | ||
| 475 | Additional drivers must be enabled in order to use the | ||
| 476 | different functionality of the device. | ||
| 477 | |||
| 478 | config MFD_SEC_CORE | ||
| 479 | bool "SAMSUNG Electronics PMIC Series Support" | ||
| 480 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 481 | select MFD_CORE | ||
| 482 | select REGMAP_I2C | ||
| 483 | select REGMAP_IRQ | ||
| 484 | help | ||
| 485 | Support for the Samsung Electronics MFD series. | ||
| 486 | This driver provides common support for accessing the device, | ||
| 487 | additional drivers must be enabled in order to use the functionality | ||
| 488 | of the device | ||
| 489 | |||
| 490 | config MFD_SI476X_CORE | ||
| 491 | tristate "Silicon Laboratories 4761/64/68 AM/FM radio." | ||
| 492 | depends on I2C | ||
| 493 | select MFD_CORE | ||
| 494 | select REGMAP_I2C | ||
| 495 | help | ||
| 496 | This is the core driver for the SI476x series of AM/FM | ||
| 497 | radio. This MFD driver connects the radio-si476x V4L2 module | ||
| 498 | and the si476x audio codec. | ||
| 499 | |||
| 500 | To compile this driver as a module, choose M here: the | ||
| 501 | module will be called si476x-core. | ||
| 502 | |||
| 48 | config MFD_SM501 | 503 | config MFD_SM501 |
| 49 | tristate "Support for Silicon Motion SM501" | 504 | tristate "Silicon Motion SM501" |
| 50 | ---help--- | 505 | ---help--- |
| 51 | This is the core driver for the Silicon Motion SM501 multimedia | 506 | This is the core driver for the Silicon Motion SM501 multimedia |
| 52 | companion chip. This device is a multifunction device which may | 507 | companion chip. This device is a multifunction device which may |
| @@ -63,46 +518,147 @@ config MFD_SM501_GPIO | |||
| 63 | lines on the SM501. The platform data is used to supply the | 518 | lines on the SM501. The platform data is used to supply the |
| 64 | base number for the first GPIO line to register. | 519 | base number for the first GPIO line to register. |
| 65 | 520 | ||
| 66 | config MFD_RTSX_PCI | 521 | config MFD_SMSC |
| 67 | tristate "Support for Realtek PCI-E card reader" | 522 | bool "SMSC ECE1099 series chips" |
| 68 | depends on PCI && GENERIC_HARDIRQS | 523 | depends on I2C=y && GENERIC_HARDIRQS |
| 524 | select MFD_CORE | ||
| 525 | select REGMAP_I2C | ||
| 526 | help | ||
| 527 | If you say yes here you get support for the | ||
| 528 | ece1099 chips from SMSC. | ||
| 529 | |||
| 530 | To compile this driver as a module, choose M here: the | ||
| 531 | module will be called smsc. | ||
| 532 | |||
| 533 | config ABX500_CORE | ||
| 534 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | ||
| 535 | default y if ARCH_U300 || ARCH_U8500 | ||
| 536 | help | ||
| 537 | Say yes here if you have the ABX500 Mixed Signal IC family | ||
| 538 | chips. This core driver expose register access functions. | ||
| 539 | Functionality specific drivers using these functions can | ||
| 540 | remain unchanged when IC changes. Binding of the functions to | ||
| 541 | actual register access is done by the IC core driver. | ||
| 542 | |||
| 543 | config AB3100_CORE | ||
| 544 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | ||
| 545 | depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS | ||
| 69 | select MFD_CORE | 546 | select MFD_CORE |
| 547 | default y if ARCH_U300 | ||
| 70 | help | 548 | help |
| 71 | This supports for Realtek PCI-Express card reader including rts5209, | 549 | Select this to enable the AB3100 Mixed Signal IC core |
| 72 | rts5229, rtl8411, etc. Realtek card reader supports access to many | 550 | functionality. This connects to a AB3100 on the I2C bus |
| 73 | types of memory cards, such as Memory Stick, Memory Stick Pro, | 551 | and expose a number of symbols needed for dependent devices |
| 74 | Secure Digital and MultiMediaCard. | 552 | to read and write registers and subscribe to events from |
| 553 | this multi-functional IC. This is needed to use other features | ||
| 554 | of the AB3100 such as battery-backed RTC, charging control, | ||
| 555 | LEDs, vibrator, system power and temperature, power management | ||
| 556 | and ALSA sound. | ||
| 75 | 557 | ||
| 76 | config MFD_ASIC3 | 558 | config AB3100_OTP |
| 77 | bool "Support for Compaq ASIC3" | 559 | tristate "ST-Ericsson AB3100 OTP functions" |
| 78 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 560 | depends on AB3100_CORE |
| 561 | default y if AB3100_CORE | ||
| 562 | help | ||
| 563 | Select this to enable the AB3100 Mixed Signal IC OTP (one-time | ||
| 564 | programmable memory) support. This exposes a sysfs file to read | ||
| 565 | out OTP values. | ||
| 566 | |||
| 567 | config AB8500_CORE | ||
| 568 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | ||
| 569 | depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU | ||
| 570 | select POWER_SUPPLY | ||
| 79 | select MFD_CORE | 571 | select MFD_CORE |
| 80 | ---help--- | 572 | select IRQ_DOMAIN |
| 81 | This driver supports the ASIC3 multifunction chip found on many | 573 | help |
| 82 | PDAs (mainly iPAQ and HTC based ones) | 574 | Select this option to enable access to AB8500 power management |
| 575 | chip. This connects to U8500 either on the SSP/SPI bus (deprecated | ||
| 576 | since hardware version v1.0) or the I2C bus via PRCMU. It also adds | ||
| 577 | the irq_chip parts for handling the Mixed Signal chip events. | ||
| 578 | This chip embeds various other multimedia funtionalities as well. | ||
| 83 | 579 | ||
| 84 | config MFD_DAVINCI_VOICECODEC | 580 | config AB8500_DEBUG |
| 85 | tristate | 581 | bool "Enable debug info via debugfs" |
| 582 | depends on AB8500_CORE && DEBUG_FS | ||
| 583 | default y if DEBUG_FS | ||
| 584 | help | ||
| 585 | Select this option if you want debug information using the debug | ||
| 586 | filesystem, debugfs. | ||
| 587 | |||
| 588 | config AB8500_GPADC | ||
| 589 | bool "ST-Ericsson AB8500 GPADC driver" | ||
| 590 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
| 591 | default y | ||
| 592 | help | ||
| 593 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
| 594 | |||
| 595 | config MFD_DB8500_PRCMU | ||
| 596 | bool "ST-Ericsson DB8500 Power Reset Control Management Unit" | ||
| 597 | depends on UX500_SOC_DB8500 | ||
| 86 | select MFD_CORE | 598 | select MFD_CORE |
| 599 | help | ||
| 600 | Select this option to enable support for the DB8500 Power Reset | ||
| 601 | and Control Management Unit. This is basically an autonomous | ||
| 602 | system controller running an XP70 microprocessor, which is accessed | ||
| 603 | through a register map. | ||
| 87 | 604 | ||
| 88 | config MFD_DM355EVM_MSP | 605 | config MFD_STMPE |
| 89 | bool "DaVinci DM355 EVM microcontroller" | 606 | bool "STMicroelectronics STMPE" |
| 90 | depends on I2C=y && MACH_DAVINCI_DM355_EVM | 607 | depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS |
| 608 | select MFD_CORE | ||
| 91 | help | 609 | help |
| 92 | This driver supports the MSP430 microcontroller used on these | 610 | Support for the STMPE family of I/O Expanders from |
| 93 | boards. MSP430 firmware manages resets and power sequencing, | 611 | STMicroelectronics. |
| 94 | inputs from buttons and the IR remote, LEDs, an RTC, and more. | ||
| 95 | 612 | ||
| 96 | config MFD_TI_SSP | 613 | Currently supported devices are: |
| 97 | tristate "TI Sequencer Serial Port support" | 614 | |
| 98 | depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS | 615 | STMPE811: GPIO, Touchscreen |
| 616 | STMPE1601: GPIO, Keypad | ||
| 617 | STMPE1801: GPIO, Keypad | ||
| 618 | STMPE2401: GPIO, Keypad | ||
| 619 | STMPE2403: GPIO, Keypad | ||
| 620 | |||
| 621 | This driver provides common support for accessing the device, | ||
| 622 | additional drivers must be enabled in order to use the functionality | ||
| 623 | of the device. Currently available sub drivers are: | ||
| 624 | |||
| 625 | GPIO: stmpe-gpio | ||
| 626 | Keypad: stmpe-keypad | ||
| 627 | Touchscreen: stmpe-ts | ||
| 628 | |||
| 629 | menu "STMicroelectronics STMPE Interface Drivers" | ||
| 630 | depends on MFD_STMPE | ||
| 631 | |||
| 632 | config STMPE_I2C | ||
| 633 | bool "STMicroelectronics STMPE I2C Inteface" | ||
| 634 | depends on I2C=y | ||
| 635 | default y | ||
| 636 | help | ||
| 637 | This is used to enable I2C interface of STMPE | ||
| 638 | |||
| 639 | config STMPE_SPI | ||
| 640 | bool "STMicroelectronics STMPE SPI Inteface" | ||
| 641 | depends on SPI_MASTER | ||
| 642 | help | ||
| 643 | This is used to enable SPI interface of STMPE | ||
| 644 | endmenu | ||
| 645 | |||
| 646 | config MFD_STA2X11 | ||
| 647 | bool "STMicroelectronics STA2X11" | ||
| 648 | depends on STA2X11 && GENERIC_HARDIRQS | ||
| 99 | select MFD_CORE | 649 | select MFD_CORE |
| 100 | ---help--- | 650 | select REGMAP_MMIO |
| 101 | Say Y here if you want support for the Sequencer Serial Port | ||
| 102 | in a Texas Instruments TNETV107X SoC. | ||
| 103 | 651 | ||
| 104 | To compile this driver as a module, choose M here: the | 652 | config MFD_SYSCON |
| 105 | module will be called ti-ssp. | 653 | bool "System Controller Register R/W Based on Regmap" |
| 654 | select REGMAP_MMIO | ||
| 655 | help | ||
| 656 | Select this option to enable accessing system control registers | ||
| 657 | via regmap. | ||
| 658 | |||
| 659 | config MFD_DAVINCI_VOICECODEC | ||
| 660 | tristate | ||
| 661 | select MFD_CORE | ||
| 106 | 662 | ||
| 107 | config MFD_TI_AM335X_TSCADC | 663 | config MFD_TI_AM335X_TSCADC |
| 108 | tristate "TI ADC / Touch Screen chip support" | 664 | tristate "TI ADC / Touch Screen chip support" |
| @@ -116,60 +672,56 @@ config MFD_TI_AM335X_TSCADC | |||
| 116 | To compile this driver as a module, choose M here: the | 672 | To compile this driver as a module, choose M here: the |
| 117 | module will be called ti_am335x_tscadc. | 673 | module will be called ti_am335x_tscadc. |
| 118 | 674 | ||
| 119 | config HTC_EGPIO | 675 | config MFD_DM355EVM_MSP |
| 120 | bool "HTC EGPIO support" | 676 | bool "TI DaVinci DM355 EVM microcontroller" |
| 121 | depends on GENERIC_HARDIRQS && GPIOLIB && ARM | 677 | depends on I2C=y && MACH_DAVINCI_DM355_EVM |
| 122 | help | 678 | help |
| 123 | This driver supports the CPLD egpio chip present on | 679 | This driver supports the MSP430 microcontroller used on these |
| 124 | several HTC phones. It provides basic support for input | 680 | boards. MSP430 firmware manages resets and power sequencing, |
| 125 | pins, output pins, and irqs. | 681 | inputs from buttons and the IR remote, LEDs, an RTC, and more. |
| 126 | 682 | ||
| 127 | config HTC_PASIC3 | 683 | config MFD_LP8788 |
| 128 | tristate "HTC PASIC3 LED/DS1WM chip support" | 684 | bool "TI LP8788 Power Management Unit Driver" |
| 685 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 129 | select MFD_CORE | 686 | select MFD_CORE |
| 130 | depends on GENERIC_HARDIRQS | 687 | select REGMAP_I2C |
| 131 | help | 688 | select IRQ_DOMAIN |
| 132 | This core driver provides register access for the LED/DS1WM | ||
| 133 | chips labeled "AIC2" and "AIC3", found on HTC Blueangel and | ||
| 134 | HTC Magician devices, respectively. Actual functionality is | ||
| 135 | handled by the leds-pasic3 and ds1wm drivers. | ||
| 136 | |||
| 137 | config HTC_I2CPLD | ||
| 138 | bool "HTC I2C PLD chip support" | ||
| 139 | depends on I2C=y && GPIOLIB | ||
| 140 | help | 689 | help |
| 141 | If you say yes here you get support for the supposed CPLD | 690 | TI LP8788 PMU supports regulators, battery charger, RTC, |
| 142 | found on omap850 HTC devices like the HTC Wizard and HTC Herald. | 691 | ADC, backlight driver and current sinks. |
| 143 | This device provides input and output GPIOs through an I2C | ||
| 144 | interface to one or more sub-chips. | ||
| 145 | 692 | ||
| 146 | config UCB1400_CORE | 693 | config MFD_OMAP_USB_HOST |
| 147 | tristate "Philips UCB1400 Core driver" | 694 | bool "TI OMAP USBHS core and TLL driver" |
| 148 | depends on AC97_BUS | 695 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 |
| 149 | depends on GPIOLIB | 696 | default y |
| 150 | help | 697 | help |
| 151 | This enables support for the Philips UCB1400 core functions. | 698 | This is the core driver for the OAMP EHCI and OHCI drivers. |
| 152 | The UCB1400 is an AC97 audio codec. | 699 | This MFD driver does the required setup functionalities for |
| 153 | 700 | OMAP USB Host drivers. | |
| 154 | To compile this driver as a module, choose M here: the | ||
| 155 | module will be called ucb1400_core. | ||
| 156 | 701 | ||
| 157 | config MFD_LM3533 | 702 | config MFD_PALMAS |
| 158 | tristate "LM3533 Lighting Power chip" | 703 | bool "TI Palmas series chips" |
| 159 | depends on I2C | ||
| 160 | select MFD_CORE | 704 | select MFD_CORE |
| 161 | select REGMAP_I2C | 705 | select REGMAP_I2C |
| 162 | depends on GENERIC_HARDIRQS | 706 | select REGMAP_IRQ |
| 707 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 163 | help | 708 | help |
| 164 | Say yes here to enable support for National Semiconductor / TI | 709 | If you say yes here you get support for the Palmas |
| 165 | LM3533 Lighting Power chips. | 710 | series of PMIC chips from Texas Instruments. |
| 166 | 711 | ||
| 167 | This driver provides common support for accessing the device; | 712 | config MFD_TI_SSP |
| 168 | additional drivers must be enabled in order to use the LED, | 713 | tristate "TI Sequencer Serial Port support" |
| 169 | backlight or ambient-light-sensor functionality of the device. | 714 | depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS |
| 715 | select MFD_CORE | ||
| 716 | ---help--- | ||
| 717 | Say Y here if you want support for the Sequencer Serial Port | ||
| 718 | in a Texas Instruments TNETV107X SoC. | ||
| 719 | |||
| 720 | To compile this driver as a module, choose M here: the | ||
| 721 | module will be called ti-ssp. | ||
| 170 | 722 | ||
| 171 | config TPS6105X | 723 | config TPS6105X |
| 172 | tristate "TPS61050/61052 Boost Converters" | 724 | tristate "TI TPS61050/61052 Boost Converters" |
| 173 | depends on I2C | 725 | depends on I2C |
| 174 | select REGULATOR | 726 | select REGULATOR |
| 175 | select MFD_CORE | 727 | select MFD_CORE |
| @@ -182,7 +734,7 @@ config TPS6105X | |||
| 182 | also contains a GPIO pin. | 734 | also contains a GPIO pin. |
| 183 | 735 | ||
| 184 | config TPS65010 | 736 | config TPS65010 |
| 185 | tristate "TPS6501x Power Management chips" | 737 | tristate "TI TPS6501x Power Management chips" |
| 186 | depends on I2C && GPIOLIB | 738 | depends on I2C && GPIOLIB |
| 187 | default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK | 739 | default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK |
| 188 | help | 740 | help |
| @@ -195,7 +747,7 @@ config TPS65010 | |||
| 195 | will be called tps65010. | 747 | will be called tps65010. |
| 196 | 748 | ||
| 197 | config TPS6507X | 749 | config TPS6507X |
| 198 | tristate "TPS6507x Power Management / Touch Screen chips" | 750 | tristate "TI TPS6507x Power Management / Touch Screen chips" |
| 199 | select MFD_CORE | 751 | select MFD_CORE |
| 200 | depends on I2C && GENERIC_HARDIRQS | 752 | depends on I2C && GENERIC_HARDIRQS |
| 201 | help | 753 | help |
| @@ -206,8 +758,24 @@ config TPS6507X | |||
| 206 | This driver can also be built as a module. If so, the module | 758 | This driver can also be built as a module. If so, the module |
| 207 | will be called tps6507x. | 759 | will be called tps6507x. |
| 208 | 760 | ||
| 761 | config TPS65911_COMPARATOR | ||
| 762 | tristate | ||
| 763 | |||
| 764 | config MFD_TPS65090 | ||
| 765 | bool "TI TPS65090 Power Management chips" | ||
| 766 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 767 | select MFD_CORE | ||
| 768 | select REGMAP_I2C | ||
| 769 | select REGMAP_IRQ | ||
| 770 | help | ||
| 771 | If you say yes here you get support for the TPS65090 series of | ||
| 772 | Power Management chips. | ||
| 773 | This driver provides common support for accessing the device, | ||
| 774 | additional drivers must be enabled in order to use the | ||
| 775 | functionality of the device. | ||
| 776 | |||
| 209 | config MFD_TPS65217 | 777 | config MFD_TPS65217 |
| 210 | tristate "TPS65217 Power Management / White LED chips" | 778 | tristate "TI TPS65217 Power Management / White LED chips" |
| 211 | depends on I2C && GENERIC_HARDIRQS | 779 | depends on I2C && GENERIC_HARDIRQS |
| 212 | select MFD_CORE | 780 | select MFD_CORE |
| 213 | select REGMAP_I2C | 781 | select REGMAP_I2C |
| @@ -222,7 +790,7 @@ config MFD_TPS65217 | |||
| 222 | will be called tps65217. | 790 | will be called tps65217. |
| 223 | 791 | ||
| 224 | config MFD_TPS6586X | 792 | config MFD_TPS6586X |
| 225 | bool "TPS6586x Power Management chips" | 793 | bool "TI TPS6586x Power Management chips" |
| 226 | depends on I2C=y && GENERIC_HARDIRQS | 794 | depends on I2C=y && GENERIC_HARDIRQS |
| 227 | select MFD_CORE | 795 | select MFD_CORE |
| 228 | select REGMAP_I2C | 796 | select REGMAP_I2C |
| @@ -237,7 +805,7 @@ config MFD_TPS6586X | |||
| 237 | will be called tps6586x. | 805 | will be called tps6586x. |
| 238 | 806 | ||
| 239 | config MFD_TPS65910 | 807 | config MFD_TPS65910 |
| 240 | bool "TPS65910 Power Management chip" | 808 | bool "TI TPS65910 Power Management chip" |
| 241 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | 809 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS |
| 242 | select MFD_CORE | 810 | select MFD_CORE |
| 243 | select REGMAP_I2C | 811 | select REGMAP_I2C |
| @@ -248,11 +816,14 @@ config MFD_TPS65910 | |||
| 248 | Power Management chips. | 816 | Power Management chips. |
| 249 | 817 | ||
| 250 | config MFD_TPS65912 | 818 | config MFD_TPS65912 |
| 251 | bool | 819 | bool "TI TPS65912 Power Management chip" |
| 252 | depends on GPIOLIB | 820 | depends on GPIOLIB |
| 821 | help | ||
| 822 | If you say yes here you get support for the TPS65912 series of | ||
| 823 | PM chips. | ||
| 253 | 824 | ||
| 254 | config MFD_TPS65912_I2C | 825 | config MFD_TPS65912_I2C |
| 255 | bool "TPS65912 Power Management chip with I2C" | 826 | bool "TI TPS65912 Power Management chip with I2C" |
| 256 | select MFD_CORE | 827 | select MFD_CORE |
| 257 | select MFD_TPS65912 | 828 | select MFD_TPS65912 |
| 258 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | 829 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS |
| @@ -261,7 +832,7 @@ config MFD_TPS65912_I2C | |||
| 261 | PM chips with I2C interface. | 832 | PM chips with I2C interface. |
| 262 | 833 | ||
| 263 | config MFD_TPS65912_SPI | 834 | config MFD_TPS65912_SPI |
| 264 | bool "TPS65912 Power Management chip with SPI" | 835 | bool "TI TPS65912 Power Management chip with SPI" |
| 265 | select MFD_CORE | 836 | select MFD_CORE |
| 266 | select MFD_TPS65912 | 837 | select MFD_TPS65912 |
| 267 | depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS | 838 | depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS |
| @@ -283,18 +854,8 @@ config MFD_TPS80031 | |||
| 283 | ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with | 854 | ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with |
| 284 | Power Path from USB, 32K clock generator. | 855 | Power Path from USB, 32K clock generator. |
| 285 | 856 | ||
| 286 | config MENELAUS | ||
| 287 | bool "Texas Instruments TWL92330/Menelaus PM chip" | ||
| 288 | depends on I2C=y && ARCH_OMAP2 | ||
| 289 | help | ||
| 290 | If you say yes here you get support for the Texas Instruments | ||
| 291 | TWL92330/Menelaus Power Management chip. This include voltage | ||
| 292 | regulators, Dual slot memory card transceivers, real-time clock | ||
| 293 | and other features that are often used in portable devices like | ||
| 294 | cell phones and PDAs. | ||
| 295 | |||
| 296 | config TWL4030_CORE | 857 | config TWL4030_CORE |
| 297 | bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" | 858 | bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" |
| 298 | depends on I2C=y && GENERIC_HARDIRQS | 859 | depends on I2C=y && GENERIC_HARDIRQS |
| 299 | select IRQ_DOMAIN | 860 | select IRQ_DOMAIN |
| 300 | select REGMAP_I2C | 861 | select REGMAP_I2C |
| @@ -310,7 +871,7 @@ config TWL4030_CORE | |||
| 310 | versions) and many other features. | 871 | versions) and many other features. |
| 311 | 872 | ||
| 312 | config TWL4030_MADC | 873 | config TWL4030_MADC |
| 313 | tristate "Texas Instruments TWL4030 MADC" | 874 | tristate "TI TWL4030 MADC" |
| 314 | depends on TWL4030_CORE | 875 | depends on TWL4030_CORE |
| 315 | help | 876 | help |
| 316 | This driver provides support for triton TWL4030-MADC. The | 877 | This driver provides support for triton TWL4030-MADC. The |
| @@ -320,7 +881,7 @@ config TWL4030_MADC | |||
| 320 | named twl4030-madc | 881 | named twl4030-madc |
| 321 | 882 | ||
| 322 | config TWL4030_POWER | 883 | config TWL4030_POWER |
| 323 | bool "Support power resources on TWL4030 family chips" | 884 | bool "TI TWL4030 power resources" |
| 324 | depends on TWL4030_CORE && ARM | 885 | depends on TWL4030_CORE && ARM |
| 325 | help | 886 | help |
| 326 | Say yes here if you want to use the power resources on the | 887 | Say yes here if you want to use the power resources on the |
| @@ -333,13 +894,13 @@ config TWL4030_POWER | |||
| 333 | or reset when a sleep, wakeup or warm reset event occurs. | 894 | or reset when a sleep, wakeup or warm reset event occurs. |
| 334 | 895 | ||
| 335 | config MFD_TWL4030_AUDIO | 896 | config MFD_TWL4030_AUDIO |
| 336 | bool | 897 | bool "TI TWL4030 Audio" |
| 337 | depends on TWL4030_CORE && GENERIC_HARDIRQS | 898 | depends on TWL4030_CORE && GENERIC_HARDIRQS |
| 338 | select MFD_CORE | 899 | select MFD_CORE |
| 339 | default n | 900 | default n |
| 340 | 901 | ||
| 341 | config TWL6040_CORE | 902 | config TWL6040_CORE |
| 342 | bool "Support for TWL6040 audio codec" | 903 | bool "TI TWL6040 audio codec" |
| 343 | depends on I2C=y && GENERIC_HARDIRQS | 904 | depends on I2C=y && GENERIC_HARDIRQS |
| 344 | select MFD_CORE | 905 | select MFD_CORE |
| 345 | select REGMAP_I2C | 906 | select REGMAP_I2C |
| @@ -352,48 +913,53 @@ config TWL6040_CORE | |||
| 352 | additional drivers must be enabled in order to use the | 913 | additional drivers must be enabled in order to use the |
| 353 | functionality of the device (audio, vibra). | 914 | functionality of the device (audio, vibra). |
| 354 | 915 | ||
| 355 | config MFD_STMPE | 916 | config MENELAUS |
| 356 | bool "Support STMicroelectronics STMPE" | 917 | bool "TI TWL92330/Menelaus PM chip" |
| 357 | depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS | 918 | depends on I2C=y && ARCH_OMAP2 |
| 358 | select MFD_CORE | ||
| 359 | help | 919 | help |
| 360 | Support for the STMPE family of I/O Expanders from | 920 | If you say yes here you get support for the Texas Instruments |
| 361 | STMicroelectronics. | 921 | TWL92330/Menelaus Power Management chip. This include voltage |
| 362 | 922 | regulators, Dual slot memory card transceivers, real-time clock | |
| 363 | Currently supported devices are: | 923 | and other features that are often used in portable devices like |
| 364 | 924 | cell phones and PDAs. | |
| 365 | STMPE811: GPIO, Touchscreen | ||
| 366 | STMPE1601: GPIO, Keypad | ||
| 367 | STMPE2401: GPIO, Keypad | ||
| 368 | STMPE2403: GPIO, Keypad | ||
| 369 | 925 | ||
| 370 | This driver provides common support for accessing the device, | 926 | config MFD_WL1273_CORE |
| 371 | additional drivers must be enabled in order to use the functionality | 927 | tristate "TI WL1273 FM radio" |
| 372 | of the device. Currently available sub drivers are: | 928 | depends on I2C && GENERIC_HARDIRQS |
| 929 | select MFD_CORE | ||
| 930 | default n | ||
| 931 | help | ||
| 932 | This is the core driver for the TI WL1273 FM radio. This MFD | ||
| 933 | driver connects the radio-wl1273 V4L2 module and the wl1273 | ||
| 934 | audio codec. | ||
| 373 | 935 | ||
| 374 | GPIO: stmpe-gpio | 936 | config MFD_LM3533 |
| 375 | Keypad: stmpe-keypad | 937 | tristate "TI/National Semiconductor LM3533 Lighting Power chip" |
| 376 | Touchscreen: stmpe-ts | 938 | depends on I2C |
| 939 | select MFD_CORE | ||
| 940 | select REGMAP_I2C | ||
| 941 | depends on GENERIC_HARDIRQS | ||
| 942 | help | ||
| 943 | Say yes here to enable support for National Semiconductor / TI | ||
| 944 | LM3533 Lighting Power chips. | ||
| 377 | 945 | ||
| 378 | menu "STMPE Interface Drivers" | 946 | This driver provides common support for accessing the device; |
| 379 | depends on MFD_STMPE | 947 | additional drivers must be enabled in order to use the LED, |
| 948 | backlight or ambient-light-sensor functionality of the device. | ||
| 380 | 949 | ||
| 381 | config STMPE_I2C | 950 | config MFD_TIMBERDALE |
| 382 | bool "STMPE I2C Inteface" | 951 | tristate "Timberdale FPGA" |
| 383 | depends on I2C=y | 952 | select MFD_CORE |
| 384 | default y | 953 | depends on PCI && GPIOLIB |
| 385 | help | 954 | ---help--- |
| 386 | This is used to enable I2C interface of STMPE | 955 | This is the core driver for the timberdale FPGA. This device is a |
| 956 | multifunction device which exposes numerous platform devices. | ||
| 387 | 957 | ||
| 388 | config STMPE_SPI | 958 | The timberdale FPGA can be found on the Intel Atom development board |
| 389 | bool "STMPE SPI Inteface" | 959 | for in-vehicle infontainment, called Russellville. |
| 390 | depends on SPI_MASTER | ||
| 391 | help | ||
| 392 | This is used to enable SPI interface of STMPE | ||
| 393 | endmenu | ||
| 394 | 960 | ||
| 395 | config MFD_TC3589X | 961 | config MFD_TC3589X |
| 396 | bool "Support Toshiba TC35892 and variants" | 962 | bool "Toshiba TC35892 and variants" |
| 397 | depends on I2C=y && GENERIC_HARDIRQS | 963 | depends on I2C=y && GENERIC_HARDIRQS |
| 398 | select MFD_CORE | 964 | select MFD_CORE |
| 399 | help | 965 | help |
| @@ -408,27 +974,15 @@ config MFD_TMIO | |||
| 408 | default n | 974 | default n |
| 409 | 975 | ||
| 410 | config MFD_T7L66XB | 976 | config MFD_T7L66XB |
| 411 | bool "Support Toshiba T7L66XB" | 977 | bool "Toshiba T7L66XB" |
| 412 | depends on ARM && HAVE_CLK && GENERIC_HARDIRQS | 978 | depends on ARM && HAVE_CLK && GENERIC_HARDIRQS |
| 413 | select MFD_CORE | 979 | select MFD_CORE |
| 414 | select MFD_TMIO | 980 | select MFD_TMIO |
| 415 | help | 981 | help |
| 416 | Support for Toshiba Mobile IO Controller T7L66XB | 982 | Support for Toshiba Mobile IO Controller T7L66XB |
| 417 | 983 | ||
| 418 | config MFD_SMSC | ||
| 419 | bool "Support for the SMSC ECE1099 series chips" | ||
| 420 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 421 | select MFD_CORE | ||
| 422 | select REGMAP_I2C | ||
| 423 | help | ||
| 424 | If you say yes here you get support for the | ||
| 425 | ece1099 chips from SMSC. | ||
| 426 | |||
| 427 | To compile this driver as a module, choose M here: the | ||
| 428 | module will be called smsc. | ||
| 429 | |||
| 430 | config MFD_TC6387XB | 984 | config MFD_TC6387XB |
| 431 | bool "Support Toshiba TC6387XB" | 985 | bool "Toshiba TC6387XB" |
| 432 | depends on ARM && HAVE_CLK | 986 | depends on ARM && HAVE_CLK |
| 433 | select MFD_CORE | 987 | select MFD_CORE |
| 434 | select MFD_TMIO | 988 | select MFD_TMIO |
| @@ -436,7 +990,7 @@ config MFD_TC6387XB | |||
| 436 | Support for Toshiba Mobile IO Controller TC6387XB | 990 | Support for Toshiba Mobile IO Controller TC6387XB |
| 437 | 991 | ||
| 438 | config MFD_TC6393XB | 992 | config MFD_TC6393XB |
| 439 | bool "Support Toshiba TC6393XB" | 993 | bool "Toshiba TC6393XB" |
| 440 | depends on ARM && HAVE_CLK | 994 | depends on ARM && HAVE_CLK |
| 441 | select GPIOLIB | 995 | select GPIOLIB |
| 442 | select MFD_CORE | 996 | select MFD_CORE |
| @@ -444,165 +998,14 @@ config MFD_TC6393XB | |||
| 444 | help | 998 | help |
| 445 | Support for Toshiba Mobile IO Controller TC6393XB | 999 | Support for Toshiba Mobile IO Controller TC6393XB |
| 446 | 1000 | ||
| 447 | config PMIC_DA903X | 1001 | config MFD_VX855 |
| 448 | bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" | 1002 | tristate "VIA VX855/VX875 integrated south bridge" |
| 449 | depends on I2C=y | 1003 | depends on PCI && GENERIC_HARDIRQS |
| 450 | help | ||
| 451 | Say yes here to support for Dialog Semiconductor DA9030 (a.k.a | ||
| 452 | ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC | ||
| 453 | usually found on PXA processors-based platforms. This includes | ||
| 454 | the I2C driver and the core APIs _only_, you have to select | ||
| 455 | individual components like LCD backlight, voltage regulators, | ||
| 456 | LEDs and battery-charger under the corresponding menus. | ||
| 457 | |||
| 458 | config PMIC_DA9052 | ||
| 459 | bool | ||
| 460 | select MFD_CORE | ||
| 461 | |||
| 462 | config MFD_DA9052_SPI | ||
| 463 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI" | ||
| 464 | select REGMAP_SPI | ||
| 465 | select REGMAP_IRQ | ||
| 466 | select PMIC_DA9052 | ||
| 467 | depends on SPI_MASTER=y && GENERIC_HARDIRQS | ||
| 468 | help | ||
| 469 | Support for the Dialog Semiconductor DA9052 PMIC | ||
| 470 | when controlled using SPI. This driver provides common support | ||
| 471 | for accessing the device, additional drivers must be enabled in | ||
| 472 | order to use the functionality of the device. | ||
| 473 | |||
| 474 | config MFD_DA9052_I2C | ||
| 475 | bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C" | ||
| 476 | select REGMAP_I2C | ||
| 477 | select REGMAP_IRQ | ||
| 478 | select PMIC_DA9052 | ||
| 479 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 480 | help | ||
| 481 | Support for the Dialog Semiconductor DA9052 PMIC | ||
| 482 | when controlled using I2C. This driver provides common support | ||
| 483 | for accessing the device, additional drivers must be enabled in | ||
| 484 | order to use the functionality of the device. | ||
| 485 | |||
| 486 | config MFD_DA9055 | ||
| 487 | bool "Dialog Semiconductor DA9055 PMIC Support" | ||
| 488 | select REGMAP_I2C | ||
| 489 | select REGMAP_IRQ | ||
| 490 | select PMIC_DA9055 | ||
| 491 | select MFD_CORE | ||
| 492 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 493 | help | ||
| 494 | Say yes here for support of Dialog Semiconductor DA9055. This is | ||
| 495 | a Power Management IC. This driver provides common support for | ||
| 496 | accessing the device as well as the I2C interface to the chip itself. | ||
| 497 | Additional drivers must be enabled in order to use the functionality | ||
| 498 | of the device. | ||
| 499 | |||
| 500 | This driver can be built as a module. If built as a module it will be | ||
| 501 | called "da9055" | ||
| 502 | |||
| 503 | config PMIC_ADP5520 | ||
| 504 | bool "Analog Devices ADP5520/01 MFD PMIC Core Support" | ||
| 505 | depends on I2C=y | ||
| 506 | help | ||
| 507 | Say yes here to add support for Analog Devices AD5520 and ADP5501, | ||
| 508 | Multifunction Power Management IC. This includes | ||
| 509 | the I2C driver and the core APIs _only_, you have to select | ||
| 510 | individual components like LCD backlight, LEDs, GPIOs and Kepad | ||
| 511 | under the corresponding menus. | ||
| 512 | |||
| 513 | config MFD_LP8788 | ||
| 514 | bool "Texas Instruments LP8788 Power Management Unit Driver" | ||
| 515 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 516 | select MFD_CORE | ||
| 517 | select REGMAP_I2C | ||
| 518 | select IRQ_DOMAIN | ||
| 519 | help | ||
| 520 | TI LP8788 PMU supports regulators, battery charger, RTC, | ||
| 521 | ADC, backlight driver and current sinks. | ||
| 522 | |||
| 523 | config MFD_MAX77686 | ||
| 524 | bool "Maxim Semiconductor MAX77686 PMIC Support" | ||
| 525 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 526 | select MFD_CORE | ||
| 527 | select REGMAP_I2C | ||
| 528 | select IRQ_DOMAIN | ||
| 529 | help | ||
| 530 | Say yes here to support for Maxim Semiconductor MAX77686. | ||
| 531 | This is a Power Management IC with RTC on chip. | ||
| 532 | This driver provides common support for accessing the device; | ||
| 533 | additional drivers must be enabled in order to use the functionality | ||
| 534 | of the device. | ||
| 535 | |||
| 536 | config MFD_MAX77693 | ||
| 537 | bool "Maxim Semiconductor MAX77693 PMIC Support" | ||
| 538 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 539 | select MFD_CORE | ||
| 540 | select REGMAP_I2C | ||
| 541 | help | ||
| 542 | Say yes here to support for Maxim Semiconductor MAX77693. | ||
| 543 | This is a companion Power Management IC with Flash, Haptic, Charger, | ||
| 544 | and MUIC(Micro USB Interface Controller) controls on chip. | ||
| 545 | This driver provides common support for accessing the device; | ||
| 546 | additional drivers must be enabled in order to use the functionality | ||
| 547 | of the device. | ||
| 548 | |||
| 549 | config MFD_MAX8907 | ||
| 550 | tristate "Maxim Semiconductor MAX8907 PMIC Support" | ||
| 551 | select MFD_CORE | ||
| 552 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 553 | select REGMAP_I2C | ||
| 554 | select REGMAP_IRQ | ||
| 555 | help | ||
| 556 | Say yes here to support for Maxim Semiconductor MAX8907. This is | ||
| 557 | a Power Management IC. This driver provides common support for | ||
| 558 | accessing the device; additional drivers must be enabled in order | ||
| 559 | to use the functionality of the device. | ||
| 560 | |||
| 561 | config MFD_MAX8925 | ||
| 562 | bool "Maxim Semiconductor MAX8925 PMIC Support" | ||
| 563 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 564 | select MFD_CORE | ||
| 565 | help | ||
| 566 | Say yes here to support for Maxim Semiconductor MAX8925. This is | ||
| 567 | a Power Management IC. This driver provides common support for | ||
| 568 | accessing the device, additional drivers must be enabled in order | ||
| 569 | to use the functionality of the device. | ||
| 570 | |||
| 571 | config MFD_MAX8997 | ||
| 572 | bool "Maxim Semiconductor MAX8997/8966 PMIC Support" | ||
| 573 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 574 | select MFD_CORE | ||
| 575 | select IRQ_DOMAIN | ||
| 576 | help | ||
| 577 | Say yes here to support for Maxim Semiconductor MAX8997/8966. | ||
| 578 | This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, | ||
| 579 | MUIC controls on chip. | ||
| 580 | This driver provides common support for accessing the device; | ||
| 581 | additional drivers must be enabled in order to use the functionality | ||
| 582 | of the device. | ||
| 583 | |||
| 584 | config MFD_MAX8998 | ||
| 585 | bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" | ||
| 586 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 587 | select MFD_CORE | ||
| 588 | help | ||
| 589 | Say yes here to support for Maxim Semiconductor MAX8998 and | ||
| 590 | National Semiconductor LP3974. This is a Power Management IC. | ||
| 591 | This driver provides common support for accessing the device, | ||
| 592 | additional drivers must be enabled in order to use the functionality | ||
| 593 | of the device. | ||
| 594 | |||
| 595 | config MFD_SEC_CORE | ||
| 596 | bool "SAMSUNG Electronics PMIC Series Support" | ||
| 597 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 598 | select MFD_CORE | 1004 | select MFD_CORE |
| 599 | select REGMAP_I2C | ||
| 600 | select REGMAP_IRQ | ||
| 601 | help | 1005 | help |
| 602 | Support for the Samsung Electronics MFD series. | 1006 | Say yes here to enable support for various functions of the |
| 603 | This driver provides common support for accessing the device, | 1007 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi |
| 604 | additional drivers must be enabled in order to use the functionality | 1008 | and/or vx855_gpio drivers for this to do anything useful. |
| 605 | of the device | ||
| 606 | 1009 | ||
| 607 | config MFD_ARIZONA | 1010 | config MFD_ARIZONA |
| 608 | select REGMAP | 1011 | select REGMAP |
| @@ -611,7 +1014,7 @@ config MFD_ARIZONA | |||
| 611 | bool | 1014 | bool |
| 612 | 1015 | ||
| 613 | config MFD_ARIZONA_I2C | 1016 | config MFD_ARIZONA_I2C |
| 614 | tristate "Support Wolfson Microelectronics Arizona platform with I2C" | 1017 | tristate "Wolfson Microelectronics Arizona platform with I2C" |
| 615 | select MFD_ARIZONA | 1018 | select MFD_ARIZONA |
| 616 | select MFD_CORE | 1019 | select MFD_CORE |
| 617 | select REGMAP_I2C | 1020 | select REGMAP_I2C |
| @@ -621,7 +1024,7 @@ config MFD_ARIZONA_I2C | |||
| 621 | core functionality controlled via I2C. | 1024 | core functionality controlled via I2C. |
| 622 | 1025 | ||
| 623 | config MFD_ARIZONA_SPI | 1026 | config MFD_ARIZONA_SPI |
| 624 | tristate "Support Wolfson Microelectronics Arizona platform with SPI" | 1027 | tristate "Wolfson Microelectronics Arizona platform with SPI" |
| 625 | select MFD_ARIZONA | 1028 | select MFD_ARIZONA |
| 626 | select MFD_CORE | 1029 | select MFD_CORE |
| 627 | select REGMAP_SPI | 1030 | select REGMAP_SPI |
| @@ -631,19 +1034,19 @@ config MFD_ARIZONA_SPI | |||
| 631 | core functionality controlled via I2C. | 1034 | core functionality controlled via I2C. |
| 632 | 1035 | ||
| 633 | config MFD_WM5102 | 1036 | config MFD_WM5102 |
| 634 | bool "Support Wolfson Microelectronics WM5102" | 1037 | bool "Wolfson Microelectronics WM5102" |
| 635 | depends on MFD_ARIZONA | 1038 | depends on MFD_ARIZONA |
| 636 | help | 1039 | help |
| 637 | Support for Wolfson Microelectronics WM5102 low power audio SoC | 1040 | Support for Wolfson Microelectronics WM5102 low power audio SoC |
| 638 | 1041 | ||
| 639 | config MFD_WM5110 | 1042 | config MFD_WM5110 |
| 640 | bool "Support Wolfson Microelectronics WM5110" | 1043 | bool "Wolfson Microelectronics WM5110" |
| 641 | depends on MFD_ARIZONA | 1044 | depends on MFD_ARIZONA |
| 642 | help | 1045 | help |
| 643 | Support for Wolfson Microelectronics WM5110 low power audio SoC | 1046 | Support for Wolfson Microelectronics WM5110 low power audio SoC |
| 644 | 1047 | ||
| 645 | config MFD_WM8400 | 1048 | config MFD_WM8400 |
| 646 | bool "Support Wolfson Microelectronics WM8400" | 1049 | bool "Wolfson Microelectronics WM8400" |
| 647 | select MFD_CORE | 1050 | select MFD_CORE |
| 648 | depends on I2C=y && GENERIC_HARDIRQS | 1051 | depends on I2C=y && GENERIC_HARDIRQS |
| 649 | select REGMAP_I2C | 1052 | select REGMAP_I2C |
| @@ -658,7 +1061,7 @@ config MFD_WM831X | |||
| 658 | depends on GENERIC_HARDIRQS | 1061 | depends on GENERIC_HARDIRQS |
| 659 | 1062 | ||
| 660 | config MFD_WM831X_I2C | 1063 | config MFD_WM831X_I2C |
| 661 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C" | 1064 | bool "Wolfson Microelectronics WM831x/2x PMICs with I2C" |
| 662 | select MFD_CORE | 1065 | select MFD_CORE |
| 663 | select MFD_WM831X | 1066 | select MFD_WM831X |
| 664 | select REGMAP_I2C | 1067 | select REGMAP_I2C |
| @@ -671,7 +1074,7 @@ config MFD_WM831X_I2C | |||
| 671 | order to use the functionality of the device. | 1074 | order to use the functionality of the device. |
| 672 | 1075 | ||
| 673 | config MFD_WM831X_SPI | 1076 | config MFD_WM831X_SPI |
| 674 | bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI" | 1077 | bool "Wolfson Microelectronics WM831x/2x PMICs with SPI" |
| 675 | select MFD_CORE | 1078 | select MFD_CORE |
| 676 | select MFD_WM831X | 1079 | select MFD_WM831X |
| 677 | select REGMAP_SPI | 1080 | select REGMAP_SPI |
| @@ -687,56 +1090,8 @@ config MFD_WM8350 | |||
| 687 | bool | 1090 | bool |
| 688 | depends on GENERIC_HARDIRQS | 1091 | depends on GENERIC_HARDIRQS |
| 689 | 1092 | ||
| 690 | config MFD_WM8350_CONFIG_MODE_0 | ||
| 691 | bool | ||
| 692 | depends on MFD_WM8350 | ||
| 693 | |||
| 694 | config MFD_WM8350_CONFIG_MODE_1 | ||
| 695 | bool | ||
| 696 | depends on MFD_WM8350 | ||
| 697 | |||
| 698 | config MFD_WM8350_CONFIG_MODE_2 | ||
| 699 | bool | ||
| 700 | depends on MFD_WM8350 | ||
| 701 | |||
| 702 | config MFD_WM8350_CONFIG_MODE_3 | ||
| 703 | bool | ||
| 704 | depends on MFD_WM8350 | ||
| 705 | |||
| 706 | config MFD_WM8351_CONFIG_MODE_0 | ||
| 707 | bool | ||
| 708 | depends on MFD_WM8350 | ||
| 709 | |||
| 710 | config MFD_WM8351_CONFIG_MODE_1 | ||
| 711 | bool | ||
| 712 | depends on MFD_WM8350 | ||
| 713 | |||
| 714 | config MFD_WM8351_CONFIG_MODE_2 | ||
| 715 | bool | ||
| 716 | depends on MFD_WM8350 | ||
| 717 | |||
| 718 | config MFD_WM8351_CONFIG_MODE_3 | ||
| 719 | bool | ||
| 720 | depends on MFD_WM8350 | ||
| 721 | |||
| 722 | config MFD_WM8352_CONFIG_MODE_0 | ||
| 723 | bool | ||
| 724 | depends on MFD_WM8350 | ||
| 725 | |||
| 726 | config MFD_WM8352_CONFIG_MODE_1 | ||
| 727 | bool | ||
| 728 | depends on MFD_WM8350 | ||
| 729 | |||
| 730 | config MFD_WM8352_CONFIG_MODE_2 | ||
| 731 | bool | ||
| 732 | depends on MFD_WM8350 | ||
| 733 | |||
| 734 | config MFD_WM8352_CONFIG_MODE_3 | ||
| 735 | bool | ||
| 736 | depends on MFD_WM8350 | ||
| 737 | |||
| 738 | config MFD_WM8350_I2C | 1093 | config MFD_WM8350_I2C |
| 739 | bool "Support Wolfson Microelectronics WM8350 with I2C" | 1094 | bool "Wolfson Microelectronics WM8350 with I2C" |
| 740 | select MFD_WM8350 | 1095 | select MFD_WM8350 |
| 741 | depends on I2C=y && GENERIC_HARDIRQS | 1096 | depends on I2C=y && GENERIC_HARDIRQS |
| 742 | help | 1097 | help |
| @@ -747,7 +1102,7 @@ config MFD_WM8350_I2C | |||
| 747 | selected to enable support for the functionality of the chip. | 1102 | selected to enable support for the functionality of the chip. |
| 748 | 1103 | ||
| 749 | config MFD_WM8994 | 1104 | config MFD_WM8994 |
| 750 | bool "Support Wolfson Microelectronics WM8994" | 1105 | bool "Wolfson Microelectronics WM8994" |
| 751 | select MFD_CORE | 1106 | select MFD_CORE |
| 752 | select REGMAP_I2C | 1107 | select REGMAP_I2C |
| 753 | select REGMAP_IRQ | 1108 | select REGMAP_IRQ |
| @@ -760,365 +1115,6 @@ config MFD_WM8994 | |||
| 760 | core support for the WM8994, in order to use the actual | 1115 | core support for the WM8994, in order to use the actual |
| 761 | functionaltiy of the device other drivers must be enabled. | 1116 | functionaltiy of the device other drivers must be enabled. |
| 762 | 1117 | ||
| 763 | config MFD_PCF50633 | ||
| 764 | tristate "Support for NXP PCF50633" | ||
| 765 | depends on I2C | ||
| 766 | select REGMAP_I2C | ||
| 767 | help | ||
| 768 | Say yes here if you have NXP PCF50633 chip on your board. | ||
| 769 | This core driver provides register access and IRQ handling | ||
| 770 | facilities, and registers devices for the various functions | ||
| 771 | so that function-specific drivers can bind to them. | ||
| 772 | |||
| 773 | config PCF50633_ADC | ||
| 774 | tristate "Support for NXP PCF50633 ADC" | ||
| 775 | depends on MFD_PCF50633 | ||
| 776 | help | ||
| 777 | Say yes here if you want to include support for ADC in the | ||
| 778 | NXP PCF50633 chip. | ||
| 779 | |||
| 780 | config PCF50633_GPIO | ||
| 781 | tristate "Support for NXP PCF50633 GPIO" | ||
| 782 | depends on MFD_PCF50633 | ||
| 783 | help | ||
| 784 | Say yes here if you want to include support GPIO for pins on | ||
| 785 | the PCF50633 chip. | ||
| 786 | |||
| 787 | config MFD_MC13783 | ||
| 788 | tristate | ||
| 789 | |||
| 790 | config MFD_MC13XXX | ||
| 791 | tristate | ||
| 792 | depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS | ||
| 793 | select MFD_CORE | ||
| 794 | select MFD_MC13783 | ||
| 795 | help | ||
| 796 | Enable support for the Freescale MC13783 and MC13892 PMICs. | ||
| 797 | This driver provides common support for accessing the device, | ||
| 798 | additional drivers must be enabled in order to use the | ||
| 799 | functionality of the device. | ||
| 800 | |||
| 801 | config MFD_MC13XXX_SPI | ||
| 802 | tristate "Freescale MC13783 and MC13892 SPI interface" | ||
| 803 | depends on SPI_MASTER && GENERIC_HARDIRQS | ||
| 804 | select REGMAP_SPI | ||
| 805 | select MFD_MC13XXX | ||
| 806 | help | ||
| 807 | Select this if your MC13xxx is connected via an SPI bus. | ||
| 808 | |||
| 809 | config MFD_MC13XXX_I2C | ||
| 810 | tristate "Freescale MC13892 I2C interface" | ||
| 811 | depends on I2C && GENERIC_HARDIRQS | ||
| 812 | select REGMAP_I2C | ||
| 813 | select MFD_MC13XXX | ||
| 814 | help | ||
| 815 | Select this if your MC13xxx is connected via an I2C bus. | ||
| 816 | |||
| 817 | config ABX500_CORE | ||
| 818 | bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" | ||
| 819 | default y if ARCH_U300 || ARCH_U8500 | ||
| 820 | help | ||
| 821 | Say yes here if you have the ABX500 Mixed Signal IC family | ||
| 822 | chips. This core driver expose register access functions. | ||
| 823 | Functionality specific drivers using these functions can | ||
| 824 | remain unchanged when IC changes. Binding of the functions to | ||
| 825 | actual register access is done by the IC core driver. | ||
| 826 | |||
| 827 | config AB3100_CORE | ||
| 828 | bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" | ||
| 829 | depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS | ||
| 830 | select MFD_CORE | ||
| 831 | default y if ARCH_U300 | ||
| 832 | help | ||
| 833 | Select this to enable the AB3100 Mixed Signal IC core | ||
| 834 | functionality. This connects to a AB3100 on the I2C bus | ||
| 835 | and expose a number of symbols needed for dependent devices | ||
| 836 | to read and write registers and subscribe to events from | ||
| 837 | this multi-functional IC. This is needed to use other features | ||
| 838 | of the AB3100 such as battery-backed RTC, charging control, | ||
| 839 | LEDs, vibrator, system power and temperature, power management | ||
| 840 | and ALSA sound. | ||
| 841 | |||
| 842 | config AB3100_OTP | ||
| 843 | tristate "ST-Ericsson AB3100 OTP functions" | ||
| 844 | depends on AB3100_CORE | ||
| 845 | default y if AB3100_CORE | ||
| 846 | help | ||
| 847 | Select this to enable the AB3100 Mixed Signal IC OTP (one-time | ||
| 848 | programmable memory) support. This exposes a sysfs file to read | ||
| 849 | out OTP values. | ||
| 850 | |||
| 851 | config EZX_PCAP | ||
| 852 | bool "PCAP Support" | ||
| 853 | depends on GENERIC_HARDIRQS && SPI_MASTER | ||
| 854 | help | ||
| 855 | This enables the PCAP ASIC present on EZX Phones. This is | ||
| 856 | needed for MMC, TouchScreen, Sound, USB, etc.. | ||
| 857 | |||
| 858 | config AB8500_CORE | ||
| 859 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | ||
| 860 | depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU | ||
| 861 | select POWER_SUPPLY | ||
| 862 | select MFD_CORE | ||
| 863 | select IRQ_DOMAIN | ||
| 864 | help | ||
| 865 | Select this option to enable access to AB8500 power management | ||
| 866 | chip. This connects to U8500 either on the SSP/SPI bus (deprecated | ||
| 867 | since hardware version v1.0) or the I2C bus via PRCMU. It also adds | ||
| 868 | the irq_chip parts for handling the Mixed Signal chip events. | ||
| 869 | This chip embeds various other multimedia funtionalities as well. | ||
| 870 | |||
| 871 | config AB8500_DEBUG | ||
| 872 | bool "Enable debug info via debugfs" | ||
| 873 | depends on AB8500_CORE && DEBUG_FS | ||
| 874 | default y if DEBUG_FS | ||
| 875 | help | ||
| 876 | Select this option if you want debug information using the debug | ||
| 877 | filesystem, debugfs. | ||
| 878 | |||
| 879 | config AB8500_GPADC | ||
| 880 | bool "AB8500 GPADC driver" | ||
| 881 | depends on AB8500_CORE && REGULATOR_AB8500 | ||
| 882 | default y | ||
| 883 | help | ||
| 884 | AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage | ||
| 885 | |||
| 886 | config MFD_DB8500_PRCMU | ||
| 887 | bool "ST-Ericsson DB8500 Power Reset Control Management Unit" | ||
| 888 | depends on UX500_SOC_DB8500 | ||
| 889 | select MFD_CORE | ||
| 890 | help | ||
| 891 | Select this option to enable support for the DB8500 Power Reset | ||
| 892 | and Control Management Unit. This is basically an autonomous | ||
| 893 | system controller running an XP70 microprocessor, which is accessed | ||
| 894 | through a register map. | ||
| 895 | |||
| 896 | config MFD_CS5535 | ||
| 897 | tristate "Support for CS5535 and CS5536 southbridge core functions" | ||
| 898 | select MFD_CORE | ||
| 899 | depends on PCI && X86 | ||
| 900 | ---help--- | ||
| 901 | This is the core driver for CS5535/CS5536 MFD functions. This is | ||
| 902 | necessary for using the board's GPIO and MFGPT functionality. | ||
| 903 | |||
| 904 | config MFD_TIMBERDALE | ||
| 905 | tristate "Support for the Timberdale FPGA" | ||
| 906 | select MFD_CORE | ||
| 907 | depends on PCI && GPIOLIB | ||
| 908 | ---help--- | ||
| 909 | This is the core driver for the timberdale FPGA. This device is a | ||
| 910 | multifunction device which exposes numerous platform devices. | ||
| 911 | |||
| 912 | The timberdale FPGA can be found on the Intel Atom development board | ||
| 913 | for in-vehicle infontainment, called Russellville. | ||
| 914 | |||
| 915 | config LPC_SCH | ||
| 916 | tristate "Intel SCH LPC" | ||
| 917 | depends on PCI && GENERIC_HARDIRQS | ||
| 918 | select MFD_CORE | ||
| 919 | help | ||
| 920 | LPC bridge function of the Intel SCH provides support for | ||
| 921 | System Management Bus and General Purpose I/O. | ||
| 922 | |||
| 923 | config LPC_ICH | ||
| 924 | tristate "Intel ICH LPC" | ||
| 925 | depends on PCI && GENERIC_HARDIRQS | ||
| 926 | select MFD_CORE | ||
| 927 | help | ||
| 928 | The LPC bridge function of the Intel ICH provides support for | ||
| 929 | many functional units. This driver provides needed support for | ||
| 930 | other drivers to control these functions, currently GPIO and | ||
| 931 | watchdog. | ||
| 932 | |||
| 933 | config MFD_RDC321X | ||
| 934 | tristate "Support for RDC-R321x southbridge" | ||
| 935 | select MFD_CORE | ||
| 936 | depends on PCI && GENERIC_HARDIRQS | ||
| 937 | help | ||
| 938 | Say yes here if you want to have support for the RDC R-321x SoC | ||
| 939 | southbridge which provides access to GPIOs and Watchdog using the | ||
| 940 | southbridge PCI device configuration space. | ||
| 941 | |||
| 942 | config MFD_JANZ_CMODIO | ||
| 943 | tristate "Support for Janz CMOD-IO PCI MODULbus Carrier Board" | ||
| 944 | select MFD_CORE | ||
| 945 | depends on PCI && GENERIC_HARDIRQS | ||
| 946 | help | ||
| 947 | This is the core driver for the Janz CMOD-IO PCI MODULbus | ||
| 948 | carrier board. This device is a PCI to MODULbus bridge which may | ||
| 949 | host many different types of MODULbus daughterboards, including | ||
| 950 | CAN and GPIO controllers. | ||
| 951 | |||
| 952 | config MFD_JZ4740_ADC | ||
| 953 | bool "Support for the JZ4740 SoC ADC core" | ||
| 954 | select MFD_CORE | ||
| 955 | select GENERIC_IRQ_CHIP | ||
| 956 | depends on MACH_JZ4740 | ||
| 957 | help | ||
| 958 | Say yes here if you want support for the ADC unit in the JZ4740 SoC. | ||
| 959 | This driver is necessary for jz4740-battery and jz4740-hwmon driver. | ||
| 960 | |||
| 961 | config MFD_VX855 | ||
| 962 | tristate "Support for VIA VX855/VX875 integrated south bridge" | ||
| 963 | depends on PCI && GENERIC_HARDIRQS | ||
| 964 | select MFD_CORE | ||
| 965 | help | ||
| 966 | Say yes here to enable support for various functions of the | ||
| 967 | VIA VX855/VX875 south bridge. You will need to enable the vx855_spi | ||
| 968 | and/or vx855_gpio drivers for this to do anything useful. | ||
| 969 | |||
| 970 | config MFD_WL1273_CORE | ||
| 971 | tristate "Support for TI WL1273 FM radio." | ||
| 972 | depends on I2C && GENERIC_HARDIRQS | ||
| 973 | select MFD_CORE | ||
| 974 | default n | ||
| 975 | help | ||
| 976 | This is the core driver for the TI WL1273 FM radio. This MFD | ||
| 977 | driver connects the radio-wl1273 V4L2 module and the wl1273 | ||
| 978 | audio codec. | ||
| 979 | |||
| 980 | config MFD_OMAP_USB_HOST | ||
| 981 | bool "Support OMAP USBHS core and TLL driver" | ||
| 982 | depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 | ||
| 983 | default y | ||
| 984 | help | ||
| 985 | This is the core driver for the OAMP EHCI and OHCI drivers. | ||
| 986 | This MFD driver does the required setup functionalities for | ||
| 987 | OMAP USB Host drivers. | ||
| 988 | |||
| 989 | config MFD_PM8XXX | ||
| 990 | tristate | ||
| 991 | |||
| 992 | config MFD_PM8921_CORE | ||
| 993 | tristate "Qualcomm PM8921 PMIC chip" | ||
| 994 | depends on SSBI && BROKEN | ||
| 995 | select MFD_CORE | ||
| 996 | select MFD_PM8XXX | ||
| 997 | help | ||
| 998 | If you say yes to this option, support will be included for the | ||
| 999 | built-in PM8921 PMIC chip. | ||
| 1000 | |||
| 1001 | This is required if your board has a PM8921 and uses its features, | ||
| 1002 | such as: MPPs, GPIOs, regulators, interrupts, and PWM. | ||
| 1003 | |||
| 1004 | Say M here if you want to include support for PM8921 chip as a module. | ||
| 1005 | This will build a module called "pm8921-core". | ||
| 1006 | |||
| 1007 | config MFD_PM8XXX_IRQ | ||
| 1008 | bool "Support for Qualcomm PM8xxx IRQ features" | ||
| 1009 | depends on MFD_PM8XXX | ||
| 1010 | default y if MFD_PM8XXX | ||
| 1011 | help | ||
| 1012 | This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. | ||
| 1013 | |||
| 1014 | This is required to use certain other PM 8xxx features, such as GPIO | ||
| 1015 | and MPP. | ||
| 1016 | |||
| 1017 | config TPS65911_COMPARATOR | ||
| 1018 | tristate | ||
| 1019 | |||
| 1020 | config MFD_TPS65090 | ||
| 1021 | bool "TPS65090 Power Management chips" | ||
| 1022 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 1023 | select MFD_CORE | ||
| 1024 | select REGMAP_I2C | ||
| 1025 | select REGMAP_IRQ | ||
| 1026 | help | ||
| 1027 | If you say yes here you get support for the TPS65090 series of | ||
| 1028 | Power Management chips. | ||
| 1029 | This driver provides common support for accessing the device, | ||
| 1030 | additional drivers must be enabled in order to use the | ||
| 1031 | functionality of the device. | ||
| 1032 | |||
| 1033 | config MFD_AAT2870_CORE | ||
| 1034 | bool "Support for the AnalogicTech AAT2870" | ||
| 1035 | select MFD_CORE | ||
| 1036 | depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS | ||
| 1037 | help | ||
| 1038 | If you say yes here you get support for the AAT2870. | ||
| 1039 | This driver provides common support for accessing the device, | ||
| 1040 | additional drivers must be enabled in order to use the | ||
| 1041 | functionality of the device. | ||
| 1042 | |||
| 1043 | config MFD_INTEL_MSIC | ||
| 1044 | bool "Support for Intel MSIC" | ||
| 1045 | depends on INTEL_SCU_IPC | ||
| 1046 | select MFD_CORE | ||
| 1047 | help | ||
| 1048 | Select this option to enable access to Intel MSIC (Avatele | ||
| 1049 | Passage) chip. This chip embeds audio, battery, GPIO, etc. | ||
| 1050 | devices used in Intel Medfield platforms. | ||
| 1051 | |||
| 1052 | config MFD_RC5T583 | ||
| 1053 | bool "Ricoh RC5T583 Power Management system device" | ||
| 1054 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 1055 | select MFD_CORE | ||
| 1056 | select REGMAP_I2C | ||
| 1057 | help | ||
| 1058 | Select this option to get support for the RICOH583 Power | ||
| 1059 | Management system device. | ||
| 1060 | This driver provides common support for accessing the device | ||
| 1061 | through i2c interface. The device supports multiple sub-devices | ||
| 1062 | like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. | ||
| 1063 | Additional drivers must be enabled in order to use the | ||
| 1064 | different functionality of the device. | ||
| 1065 | |||
| 1066 | config MFD_STA2X11 | ||
| 1067 | bool "STA2X11 multi function device support" | ||
| 1068 | depends on STA2X11 && GENERIC_HARDIRQS | ||
| 1069 | select MFD_CORE | ||
| 1070 | select REGMAP_MMIO | ||
| 1071 | |||
| 1072 | config MFD_SYSCON | ||
| 1073 | bool "System Controller Register R/W Based on Regmap" | ||
| 1074 | depends on OF | ||
| 1075 | select REGMAP_MMIO | ||
| 1076 | help | ||
| 1077 | Select this option to enable accessing system control registers | ||
| 1078 | via regmap. | ||
| 1079 | |||
| 1080 | config MFD_PALMAS | ||
| 1081 | bool "Support for the TI Palmas series chips" | ||
| 1082 | select MFD_CORE | ||
| 1083 | select REGMAP_I2C | ||
| 1084 | select REGMAP_IRQ | ||
| 1085 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 1086 | help | ||
| 1087 | If you say yes here you get support for the Palmas | ||
| 1088 | series of PMIC chips from Texas Instruments. | ||
| 1089 | |||
| 1090 | config MFD_VIPERBOARD | ||
| 1091 | tristate "Support for Nano River Technologies Viperboard" | ||
| 1092 | select MFD_CORE | ||
| 1093 | depends on USB && GENERIC_HARDIRQS | ||
| 1094 | default n | ||
| 1095 | help | ||
| 1096 | Say yes here if you want support for Nano River Technologies | ||
| 1097 | Viperboard. | ||
| 1098 | There are mfd cell drivers available for i2c master, adc and | ||
| 1099 | both gpios found on the board. The spi part does not yet | ||
| 1100 | have a driver. | ||
| 1101 | You need to select the mfd cell drivers separately. | ||
| 1102 | The drivers do not support all features the board exposes. | ||
| 1103 | |||
| 1104 | config MFD_RETU | ||
| 1105 | tristate "Support for Retu multi-function device" | ||
| 1106 | select MFD_CORE | ||
| 1107 | depends on I2C && GENERIC_HARDIRQS | ||
| 1108 | select REGMAP_IRQ | ||
| 1109 | help | ||
| 1110 | Retu is a multi-function device found on Nokia Internet Tablets | ||
| 1111 | (770, N800 and N810). | ||
| 1112 | |||
| 1113 | config MFD_AS3711 | ||
| 1114 | bool "Support for AS3711" | ||
| 1115 | select MFD_CORE | ||
| 1116 | select REGMAP_I2C | ||
| 1117 | select REGMAP_IRQ | ||
| 1118 | depends on I2C=y && GENERIC_HARDIRQS | ||
| 1119 | help | ||
| 1120 | Support for the AS3711 PMIC from AMS | ||
| 1121 | |||
| 1122 | endmenu | 1118 | endmenu |
| 1123 | endif | 1119 | endif |
| 1124 | 1120 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b90409c23664..718e94a2a9a7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
| @@ -8,8 +8,11 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o | |||
| 8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o | 8 | obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o |
| 9 | obj-$(CONFIG_MFD_SM501) += sm501.o | 9 | obj-$(CONFIG_MFD_SM501) += sm501.o |
| 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o | 10 | obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o |
| 11 | obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o | ||
| 12 | obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o | ||
| 13 | obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o | ||
| 11 | 14 | ||
| 12 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o | 15 | rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o |
| 13 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o | 16 | obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o |
| 14 | 17 | ||
| 15 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o | 18 | obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o |
| @@ -131,6 +134,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o | |||
| 131 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o | 134 | obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o |
| 132 | obj-$(CONFIG_MFD_VX855) += vx855.o | 135 | obj-$(CONFIG_MFD_VX855) += vx855.o |
| 133 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o | 136 | obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o |
| 137 | |||
| 138 | si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o | ||
| 139 | obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o | ||
| 140 | |||
| 134 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o | 141 | obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o |
| 135 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o | 142 | obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o |
| 136 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o | 143 | obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o |
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index f1beb4971f87..dfdb0a2b6835 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c | |||
| @@ -367,12 +367,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
| 367 | int i, j; | 367 | int i, j; |
| 368 | int ret = 0; | 368 | int ret = 0; |
| 369 | 369 | ||
| 370 | aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL); | 370 | aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data), |
| 371 | GFP_KERNEL); | ||
| 371 | if (!aat2870) { | 372 | if (!aat2870) { |
| 372 | dev_err(&client->dev, | 373 | dev_err(&client->dev, |
| 373 | "Failed to allocate memory for aat2870\n"); | 374 | "Failed to allocate memory for aat2870\n"); |
| 374 | ret = -ENOMEM; | 375 | return -ENOMEM; |
| 375 | goto out; | ||
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | aat2870->dev = &client->dev; | 378 | aat2870->dev = &client->dev; |
| @@ -400,12 +400,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
| 400 | aat2870->init(aat2870); | 400 | aat2870->init(aat2870); |
| 401 | 401 | ||
| 402 | if (aat2870->en_pin >= 0) { | 402 | if (aat2870->en_pin >= 0) { |
| 403 | ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, | 403 | ret = devm_gpio_request_one(&client->dev, aat2870->en_pin, |
| 404 | "aat2870-en"); | 404 | GPIOF_OUT_INIT_HIGH, "aat2870-en"); |
| 405 | if (ret < 0) { | 405 | if (ret < 0) { |
| 406 | dev_err(&client->dev, | 406 | dev_err(&client->dev, |
| 407 | "Failed to request GPIO %d\n", aat2870->en_pin); | 407 | "Failed to request GPIO %d\n", aat2870->en_pin); |
| 408 | goto out_kfree; | 408 | return ret; |
| 409 | } | 409 | } |
| 410 | } | 410 | } |
| 411 | 411 | ||
| @@ -436,11 +436,6 @@ static int aat2870_i2c_probe(struct i2c_client *client, | |||
| 436 | 436 | ||
| 437 | out_disable: | 437 | out_disable: |
| 438 | aat2870_disable(aat2870); | 438 | aat2870_disable(aat2870); |
| 439 | if (aat2870->en_pin >= 0) | ||
| 440 | gpio_free(aat2870->en_pin); | ||
| 441 | out_kfree: | ||
| 442 | kfree(aat2870); | ||
| 443 | out: | ||
| 444 | return ret; | 439 | return ret; |
| 445 | } | 440 | } |
| 446 | 441 | ||
| @@ -452,11 +447,8 @@ static int aat2870_i2c_remove(struct i2c_client *client) | |||
| 452 | 447 | ||
| 453 | mfd_remove_devices(aat2870->dev); | 448 | mfd_remove_devices(aat2870->dev); |
| 454 | aat2870_disable(aat2870); | 449 | aat2870_disable(aat2870); |
| 455 | if (aat2870->en_pin >= 0) | ||
| 456 | gpio_free(aat2870->en_pin); | ||
| 457 | if (aat2870->uninit) | 450 | if (aat2870->uninit) |
| 458 | aat2870->uninit(aat2870); | 451 | aat2870->uninit(aat2870); |
| 459 | kfree(aat2870); | ||
| 460 | 452 | ||
| 461 | return 0; | 453 | return 0; |
| 462 | } | 454 | } |
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c index 8440010eb2b8..d7ce016029fa 100644 --- a/drivers/mfd/ab3100-otp.c +++ b/drivers/mfd/ab3100-otp.c | |||
| @@ -248,19 +248,7 @@ static struct platform_driver ab3100_otp_driver = { | |||
| 248 | .remove = __exit_p(ab3100_otp_remove), | 248 | .remove = __exit_p(ab3100_otp_remove), |
| 249 | }; | 249 | }; |
| 250 | 250 | ||
| 251 | static int __init ab3100_otp_init(void) | 251 | module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe); |
| 252 | { | ||
| 253 | return platform_driver_probe(&ab3100_otp_driver, | ||
| 254 | ab3100_otp_probe); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void __exit ab3100_otp_exit(void) | ||
| 258 | { | ||
| 259 | platform_driver_unregister(&ab3100_otp_driver); | ||
| 260 | } | ||
| 261 | |||
| 262 | module_init(ab3100_otp_init); | ||
| 263 | module_exit(ab3100_otp_exit); | ||
| 264 | 252 | ||
| 265 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); | 253 | MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); |
| 266 | MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); | 254 | MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); |
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index f276352cc9ef..8e8a016effe9 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c | |||
| @@ -458,22 +458,23 @@ static void update_latch_offset(u8 *offset, int i) | |||
| 458 | static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, | 458 | static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, |
| 459 | int latch_offset, u8 latch_val) | 459 | int latch_offset, u8 latch_val) |
| 460 | { | 460 | { |
| 461 | int int_bit = __ffs(latch_val); | 461 | int int_bit, line, i; |
| 462 | int line, i; | ||
| 463 | 462 | ||
| 464 | do { | 463 | for (i = 0; i < ab8500->mask_size; i++) |
| 465 | int_bit = __ffs(latch_val); | 464 | if (ab8500->irq_reg_offset[i] == latch_offset) |
| 465 | break; | ||
| 466 | 466 | ||
| 467 | for (i = 0; i < ab8500->mask_size; i++) | 467 | if (i >= ab8500->mask_size) { |
| 468 | if (ab8500->irq_reg_offset[i] == latch_offset) | 468 | dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", |
| 469 | break; | 469 | latch_offset); |
| 470 | return -ENXIO; | ||
| 471 | } | ||
| 470 | 472 | ||
| 471 | if (i >= ab8500->mask_size) { | 473 | /* ignore masked out interrupts */ |
| 472 | dev_err(ab8500->dev, "Register offset 0x%2x not declared\n", | 474 | latch_val &= ~ab8500->mask[i]; |
| 473 | latch_offset); | ||
| 474 | return -ENXIO; | ||
| 475 | } | ||
| 476 | 475 | ||
| 476 | while (latch_val) { | ||
| 477 | int_bit = __ffs(latch_val); | ||
| 477 | line = (i << 3) + int_bit; | 478 | line = (i << 3) + int_bit; |
| 478 | latch_val &= ~(1 << int_bit); | 479 | latch_val &= ~(1 << int_bit); |
| 479 | 480 | ||
| @@ -491,7 +492,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, | |||
| 491 | line += 1; | 492 | line += 1; |
| 492 | 493 | ||
| 493 | handle_nested_irq(ab8500->irq_base + line); | 494 | handle_nested_irq(ab8500->irq_base + line); |
| 494 | } while (latch_val); | 495 | } |
| 495 | 496 | ||
| 496 | return 0; | 497 | return 0; |
| 497 | } | 498 | } |
| @@ -1107,6 +1108,7 @@ static struct mfd_cell ab8500_devs[] = { | |||
| 1107 | }, | 1108 | }, |
| 1108 | { | 1109 | { |
| 1109 | .name = "ab8500-usb", | 1110 | .name = "ab8500-usb", |
| 1111 | .of_compatible = "stericsson,ab8500-usb", | ||
| 1110 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), | 1112 | .num_resources = ARRAY_SIZE(ab8500_usb_resources), |
| 1111 | .resources = ab8500_usb_resources, | 1113 | .resources = ab8500_usb_resources, |
| 1112 | }, | 1114 | }, |
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 65f72284185d..5e65b28a5d09 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c | |||
| @@ -332,7 +332,7 @@ if (ad_value < 0) { | |||
| 332 | 332 | ||
| 333 | return voltage; | 333 | return voltage; |
| 334 | } | 334 | } |
| 335 | EXPORT_SYMBOL(ab8500_gpadc_convert); | 335 | EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert); |
| 336 | 336 | ||
| 337 | /** | 337 | /** |
| 338 | * ab8500_gpadc_read_raw() - gpadc read | 338 | * ab8500_gpadc_read_raw() - gpadc read |
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 272479cdb107..fbca1ced49fa 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c | |||
| @@ -242,7 +242,7 @@ static int __init ab8500_sysctrl_init(void) | |||
| 242 | { | 242 | { |
| 243 | return platform_driver_register(&ab8500_sysctrl_driver); | 243 | return platform_driver_register(&ab8500_sysctrl_driver); |
| 244 | } | 244 | } |
| 245 | subsys_initcall(ab8500_sysctrl_init); | 245 | arch_initcall(ab8500_sysctrl_init); |
| 246 | 246 | ||
| 247 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); | 247 | MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); |
| 248 | MODULE_DESCRIPTION("AB8500 system control driver"); | 248 | MODULE_DESCRIPTION("AB8500 system control driver"); |
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 210dd038bb5a..0d2eba023439 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c | |||
| @@ -36,6 +36,7 @@ struct adp5520_chip { | |||
| 36 | struct blocking_notifier_head notifier_list; | 36 | struct blocking_notifier_head notifier_list; |
| 37 | int irq; | 37 | int irq; |
| 38 | unsigned long id; | 38 | unsigned long id; |
| 39 | uint8_t mode; | ||
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 41 | static int __adp5520_read(struct i2c_client *client, | 42 | static int __adp5520_read(struct i2c_client *client, |
| @@ -326,7 +327,10 @@ static int adp5520_suspend(struct device *dev) | |||
| 326 | struct i2c_client *client = to_i2c_client(dev); | 327 | struct i2c_client *client = to_i2c_client(dev); |
| 327 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 328 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
| 328 | 329 | ||
| 329 | adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 330 | adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode); |
| 331 | /* All other bits are W1C */ | ||
| 332 | chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY; | ||
| 333 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); | ||
| 330 | return 0; | 334 | return 0; |
| 331 | } | 335 | } |
| 332 | 336 | ||
| @@ -335,7 +339,7 @@ static int adp5520_resume(struct device *dev) | |||
| 335 | struct i2c_client *client = to_i2c_client(dev); | 339 | struct i2c_client *client = to_i2c_client(dev); |
| 336 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); | 340 | struct adp5520_chip *chip = dev_get_drvdata(&client->dev); |
| 337 | 341 | ||
| 338 | adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); | 342 | adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode); |
| 339 | return 0; | 343 | return 0; |
| 340 | } | 344 | } |
| 341 | #endif | 345 | #endif |
| @@ -360,17 +364,7 @@ static struct i2c_driver adp5520_driver = { | |||
| 360 | .id_table = adp5520_id, | 364 | .id_table = adp5520_id, |
| 361 | }; | 365 | }; |
| 362 | 366 | ||
| 363 | static int __init adp5520_init(void) | 367 | module_i2c_driver(adp5520_driver); |
| 364 | { | ||
| 365 | return i2c_add_driver(&adp5520_driver); | ||
| 366 | } | ||
| 367 | module_init(adp5520_init); | ||
| 368 | |||
| 369 | static void __exit adp5520_exit(void) | ||
| 370 | { | ||
| 371 | i2c_del_driver(&adp5520_driver); | ||
| 372 | } | ||
| 373 | module_exit(adp5520_exit); | ||
| 374 | 368 | ||
| 375 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | 369 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); |
| 376 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); | 370 | MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); |
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index b562c7bf8a46..6ab03043fd60 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c | |||
| @@ -39,11 +39,21 @@ int arizona_clk32k_enable(struct arizona *arizona) | |||
| 39 | 39 | ||
| 40 | arizona->clk32k_ref++; | 40 | arizona->clk32k_ref++; |
| 41 | 41 | ||
| 42 | if (arizona->clk32k_ref == 1) | 42 | if (arizona->clk32k_ref == 1) { |
| 43 | switch (arizona->pdata.clk32k_src) { | ||
| 44 | case ARIZONA_32KZ_MCLK1: | ||
| 45 | ret = pm_runtime_get_sync(arizona->dev); | ||
| 46 | if (ret != 0) | ||
| 47 | goto out; | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | |||
| 43 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 51 | ret = regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
| 44 | ARIZONA_CLK_32K_ENA, | 52 | ARIZONA_CLK_32K_ENA, |
| 45 | ARIZONA_CLK_32K_ENA); | 53 | ARIZONA_CLK_32K_ENA); |
| 54 | } | ||
| 46 | 55 | ||
| 56 | out: | ||
| 47 | if (ret != 0) | 57 | if (ret != 0) |
| 48 | arizona->clk32k_ref--; | 58 | arizona->clk32k_ref--; |
| 49 | 59 | ||
| @@ -63,10 +73,17 @@ int arizona_clk32k_disable(struct arizona *arizona) | |||
| 63 | 73 | ||
| 64 | arizona->clk32k_ref--; | 74 | arizona->clk32k_ref--; |
| 65 | 75 | ||
| 66 | if (arizona->clk32k_ref == 0) | 76 | if (arizona->clk32k_ref == 0) { |
| 67 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 77 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
| 68 | ARIZONA_CLK_32K_ENA, 0); | 78 | ARIZONA_CLK_32K_ENA, 0); |
| 69 | 79 | ||
| 80 | switch (arizona->pdata.clk32k_src) { | ||
| 81 | case ARIZONA_32KZ_MCLK1: | ||
| 82 | pm_runtime_put_sync(arizona->dev); | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 70 | mutex_unlock(&arizona->clk_lock); | 87 | mutex_unlock(&arizona->clk_lock); |
| 71 | 88 | ||
| 72 | return ret; | 89 | return ret; |
| @@ -179,42 +196,134 @@ static irqreturn_t arizona_overclocked(int irq, void *data) | |||
| 179 | return IRQ_HANDLED; | 196 | return IRQ_HANDLED; |
| 180 | } | 197 | } |
| 181 | 198 | ||
| 182 | static int arizona_wait_for_boot(struct arizona *arizona) | 199 | static int arizona_poll_reg(struct arizona *arizona, |
| 200 | int timeout, unsigned int reg, | ||
| 201 | unsigned int mask, unsigned int target) | ||
| 183 | { | 202 | { |
| 184 | unsigned int reg; | 203 | unsigned int val = 0; |
| 185 | int ret, i; | 204 | int ret, i; |
| 186 | 205 | ||
| 206 | for (i = 0; i < timeout; i++) { | ||
| 207 | ret = regmap_read(arizona->regmap, reg, &val); | ||
| 208 | if (ret != 0) { | ||
| 209 | dev_err(arizona->dev, "Failed to read reg %u: %d\n", | ||
| 210 | reg, ret); | ||
| 211 | continue; | ||
| 212 | } | ||
| 213 | |||
| 214 | if ((val & mask) == target) | ||
| 215 | return 0; | ||
| 216 | |||
| 217 | msleep(1); | ||
| 218 | } | ||
| 219 | |||
| 220 | dev_err(arizona->dev, "Polling reg %u timed out: %x\n", reg, val); | ||
| 221 | return -ETIMEDOUT; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int arizona_wait_for_boot(struct arizona *arizona) | ||
| 225 | { | ||
| 226 | int ret; | ||
| 227 | |||
| 187 | /* | 228 | /* |
| 188 | * We can't use an interrupt as we need to runtime resume to do so, | 229 | * We can't use an interrupt as we need to runtime resume to do so, |
| 189 | * we won't race with the interrupt handler as it'll be blocked on | 230 | * we won't race with the interrupt handler as it'll be blocked on |
| 190 | * runtime resume. | 231 | * runtime resume. |
| 191 | */ | 232 | */ |
| 192 | for (i = 0; i < 5; i++) { | 233 | ret = arizona_poll_reg(arizona, 5, ARIZONA_INTERRUPT_RAW_STATUS_5, |
| 193 | msleep(1); | 234 | ARIZONA_BOOT_DONE_STS, ARIZONA_BOOT_DONE_STS); |
| 194 | 235 | ||
| 195 | ret = regmap_read(arizona->regmap, | 236 | if (!ret) |
| 196 | ARIZONA_INTERRUPT_RAW_STATUS_5, ®); | 237 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, |
| 197 | if (ret != 0) { | 238 | ARIZONA_BOOT_DONE_STS); |
| 198 | dev_err(arizona->dev, "Failed to read boot state: %d\n", | ||
| 199 | ret); | ||
| 200 | continue; | ||
| 201 | } | ||
| 202 | 239 | ||
| 203 | if (reg & ARIZONA_BOOT_DONE_STS) | 240 | pm_runtime_mark_last_busy(arizona->dev); |
| 204 | break; | 241 | |
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int arizona_apply_hardware_patch(struct arizona* arizona) | ||
| 246 | { | ||
| 247 | unsigned int fll, sysclk; | ||
| 248 | int ret, err; | ||
| 249 | |||
| 250 | regcache_cache_bypass(arizona->regmap, true); | ||
| 251 | |||
| 252 | /* Cache existing FLL and SYSCLK settings */ | ||
| 253 | ret = regmap_read(arizona->regmap, ARIZONA_FLL1_CONTROL_1, &fll); | ||
| 254 | if (ret != 0) { | ||
| 255 | dev_err(arizona->dev, "Failed to cache FLL settings: %d\n", | ||
| 256 | ret); | ||
| 257 | return ret; | ||
| 258 | } | ||
| 259 | ret = regmap_read(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, &sysclk); | ||
| 260 | if (ret != 0) { | ||
| 261 | dev_err(arizona->dev, "Failed to cache SYSCLK settings: %d\n", | ||
| 262 | ret); | ||
| 263 | return ret; | ||
| 205 | } | 264 | } |
| 206 | 265 | ||
| 207 | if (reg & ARIZONA_BOOT_DONE_STS) { | 266 | /* Start up SYSCLK using the FLL in free running mode */ |
| 208 | regmap_write(arizona->regmap, ARIZONA_INTERRUPT_STATUS_5, | 267 | ret = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, |
| 209 | ARIZONA_BOOT_DONE_STS); | 268 | ARIZONA_FLL1_ENA | ARIZONA_FLL1_FREERUN); |
| 210 | } else { | 269 | if (ret != 0) { |
| 211 | dev_err(arizona->dev, "Device boot timed out: %x\n", reg); | 270 | dev_err(arizona->dev, |
| 212 | return -ETIMEDOUT; | 271 | "Failed to start FLL in freerunning mode: %d\n", |
| 272 | ret); | ||
| 273 | return ret; | ||
| 274 | } | ||
| 275 | ret = arizona_poll_reg(arizona, 25, ARIZONA_INTERRUPT_RAW_STATUS_5, | ||
| 276 | ARIZONA_FLL1_CLOCK_OK_STS, | ||
| 277 | ARIZONA_FLL1_CLOCK_OK_STS); | ||
| 278 | if (ret != 0) { | ||
| 279 | ret = -ETIMEDOUT; | ||
| 280 | goto err_fll; | ||
| 213 | } | 281 | } |
| 214 | 282 | ||
| 215 | pm_runtime_mark_last_busy(arizona->dev); | 283 | ret = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, 0x0144); |
| 284 | if (ret != 0) { | ||
| 285 | dev_err(arizona->dev, "Failed to start SYSCLK: %d\n", ret); | ||
| 286 | goto err_fll; | ||
| 287 | } | ||
| 216 | 288 | ||
| 217 | return 0; | 289 | /* Start the write sequencer and wait for it to finish */ |
| 290 | ret = regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
| 291 | ARIZONA_WSEQ_ENA | ARIZONA_WSEQ_START | 160); | ||
| 292 | if (ret != 0) { | ||
| 293 | dev_err(arizona->dev, "Failed to start write sequencer: %d\n", | ||
| 294 | ret); | ||
| 295 | goto err_sysclk; | ||
| 296 | } | ||
| 297 | ret = arizona_poll_reg(arizona, 5, ARIZONA_WRITE_SEQUENCER_CTRL_1, | ||
| 298 | ARIZONA_WSEQ_BUSY, 0); | ||
| 299 | if (ret != 0) { | ||
| 300 | regmap_write(arizona->regmap, ARIZONA_WRITE_SEQUENCER_CTRL_0, | ||
| 301 | ARIZONA_WSEQ_ABORT); | ||
| 302 | ret = -ETIMEDOUT; | ||
| 303 | } | ||
| 304 | |||
| 305 | err_sysclk: | ||
| 306 | err = regmap_write(arizona->regmap, ARIZONA_SYSTEM_CLOCK_1, sysclk); | ||
| 307 | if (err != 0) { | ||
| 308 | dev_err(arizona->dev, | ||
| 309 | "Failed to re-apply old SYSCLK settings: %d\n", | ||
| 310 | err); | ||
| 311 | } | ||
| 312 | |||
| 313 | err_fll: | ||
| 314 | err = regmap_write(arizona->regmap, ARIZONA_FLL1_CONTROL_1, fll); | ||
| 315 | if (err != 0) { | ||
| 316 | dev_err(arizona->dev, | ||
| 317 | "Failed to re-apply old FLL settings: %d\n", | ||
| 318 | err); | ||
| 319 | } | ||
| 320 | |||
| 321 | regcache_cache_bypass(arizona->regmap, false); | ||
| 322 | |||
| 323 | if (ret != 0) | ||
| 324 | return ret; | ||
| 325 | else | ||
| 326 | return err; | ||
| 218 | } | 327 | } |
| 219 | 328 | ||
| 220 | #ifdef CONFIG_PM_RUNTIME | 329 | #ifdef CONFIG_PM_RUNTIME |
| @@ -233,20 +342,44 @@ static int arizona_runtime_resume(struct device *dev) | |||
| 233 | 342 | ||
| 234 | regcache_cache_only(arizona->regmap, false); | 343 | regcache_cache_only(arizona->regmap, false); |
| 235 | 344 | ||
| 236 | ret = arizona_wait_for_boot(arizona); | 345 | switch (arizona->type) { |
| 237 | if (ret != 0) { | 346 | case WM5102: |
| 238 | regulator_disable(arizona->dcvdd); | 347 | ret = wm5102_patch(arizona); |
| 239 | return ret; | 348 | if (ret != 0) { |
| 349 | dev_err(arizona->dev, "Failed to apply patch: %d\n", | ||
| 350 | ret); | ||
| 351 | goto err; | ||
| 352 | } | ||
| 353 | |||
| 354 | ret = arizona_apply_hardware_patch(arizona); | ||
| 355 | if (ret != 0) { | ||
| 356 | dev_err(arizona->dev, | ||
| 357 | "Failed to apply hardware patch: %d\n", | ||
| 358 | ret); | ||
| 359 | goto err; | ||
| 360 | } | ||
| 361 | break; | ||
| 362 | default: | ||
| 363 | ret = arizona_wait_for_boot(arizona); | ||
| 364 | if (ret != 0) { | ||
| 365 | goto err; | ||
| 366 | } | ||
| 367 | |||
| 368 | break; | ||
| 240 | } | 369 | } |
| 241 | 370 | ||
| 242 | ret = regcache_sync(arizona->regmap); | 371 | ret = regcache_sync(arizona->regmap); |
| 243 | if (ret != 0) { | 372 | if (ret != 0) { |
| 244 | dev_err(arizona->dev, "Failed to restore register cache\n"); | 373 | dev_err(arizona->dev, "Failed to restore register cache\n"); |
| 245 | regulator_disable(arizona->dcvdd); | 374 | goto err; |
| 246 | return ret; | ||
| 247 | } | 375 | } |
| 248 | 376 | ||
| 249 | return 0; | 377 | return 0; |
| 378 | |||
| 379 | err: | ||
| 380 | regcache_cache_only(arizona->regmap, true); | ||
| 381 | regulator_disable(arizona->dcvdd); | ||
| 382 | return ret; | ||
| 250 | } | 383 | } |
| 251 | 384 | ||
| 252 | static int arizona_runtime_suspend(struct device *dev) | 385 | static int arizona_runtime_suspend(struct device *dev) |
| @@ -371,6 +504,17 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 371 | goto err_early; | 504 | goto err_early; |
| 372 | } | 505 | } |
| 373 | 506 | ||
| 507 | if (arizona->pdata.reset) { | ||
| 508 | /* Start out with /RESET low to put the chip into reset */ | ||
| 509 | ret = gpio_request_one(arizona->pdata.reset, | ||
| 510 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
| 511 | "arizona /RESET"); | ||
| 512 | if (ret != 0) { | ||
| 513 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
| 514 | goto err_early; | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 374 | ret = regulator_bulk_enable(arizona->num_core_supplies, | 518 | ret = regulator_bulk_enable(arizona->num_core_supplies, |
| 375 | arizona->core_supplies); | 519 | arizona->core_supplies); |
| 376 | if (ret != 0) { | 520 | if (ret != 0) { |
| @@ -386,16 +530,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 386 | } | 530 | } |
| 387 | 531 | ||
| 388 | if (arizona->pdata.reset) { | 532 | if (arizona->pdata.reset) { |
| 389 | /* Start out with /RESET low to put the chip into reset */ | ||
| 390 | ret = gpio_request_one(arizona->pdata.reset, | ||
| 391 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | ||
| 392 | "arizona /RESET"); | ||
| 393 | if (ret != 0) { | ||
| 394 | dev_err(dev, "Failed to request /RESET: %d\n", ret); | ||
| 395 | goto err_dcvdd; | ||
| 396 | } | ||
| 397 | |||
| 398 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 533 | gpio_set_value_cansleep(arizona->pdata.reset, 1); |
| 534 | msleep(1); | ||
| 399 | } | 535 | } |
| 400 | 536 | ||
| 401 | regcache_cache_only(arizona->regmap, false); | 537 | regcache_cache_only(arizona->regmap, false); |
| @@ -424,6 +560,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 424 | arizona->type = WM5102; | 560 | arizona->type = WM5102; |
| 425 | } | 561 | } |
| 426 | apply_patch = wm5102_patch; | 562 | apply_patch = wm5102_patch; |
| 563 | arizona->rev &= 0x7; | ||
| 427 | break; | 564 | break; |
| 428 | #endif | 565 | #endif |
| 429 | #ifdef CONFIG_MFD_WM5110 | 566 | #ifdef CONFIG_MFD_WM5110 |
| @@ -454,6 +591,8 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 454 | goto err_reset; | 591 | goto err_reset; |
| 455 | } | 592 | } |
| 456 | 593 | ||
| 594 | msleep(1); | ||
| 595 | |||
| 457 | ret = regcache_sync(arizona->regmap); | 596 | ret = regcache_sync(arizona->regmap); |
| 458 | if (ret != 0) { | 597 | if (ret != 0) { |
| 459 | dev_err(dev, "Failed to sync device: %d\n", ret); | 598 | dev_err(dev, "Failed to sync device: %d\n", ret); |
| @@ -461,10 +600,24 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 461 | } | 600 | } |
| 462 | } | 601 | } |
| 463 | 602 | ||
| 464 | ret = arizona_wait_for_boot(arizona); | 603 | switch (arizona->type) { |
| 465 | if (ret != 0) { | 604 | case WM5102: |
| 466 | dev_err(arizona->dev, "Device failed initial boot: %d\n", ret); | 605 | ret = regmap_read(arizona->regmap, 0x19, &val); |
| 467 | goto err_reset; | 606 | if (ret != 0) |
| 607 | dev_err(dev, | ||
| 608 | "Failed to check write sequencer state: %d\n", | ||
| 609 | ret); | ||
| 610 | else if (val & 0x01) | ||
| 611 | break; | ||
| 612 | /* Fall through */ | ||
| 613 | default: | ||
| 614 | ret = arizona_wait_for_boot(arizona); | ||
| 615 | if (ret != 0) { | ||
| 616 | dev_err(arizona->dev, | ||
| 617 | "Device failed initial boot: %d\n", ret); | ||
| 618 | goto err_reset; | ||
| 619 | } | ||
| 620 | break; | ||
| 468 | } | 621 | } |
| 469 | 622 | ||
| 470 | if (apply_patch) { | 623 | if (apply_patch) { |
| @@ -474,6 +627,20 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 474 | ret); | 627 | ret); |
| 475 | goto err_reset; | 628 | goto err_reset; |
| 476 | } | 629 | } |
| 630 | |||
| 631 | switch (arizona->type) { | ||
| 632 | case WM5102: | ||
| 633 | ret = arizona_apply_hardware_patch(arizona); | ||
| 634 | if (ret != 0) { | ||
| 635 | dev_err(arizona->dev, | ||
| 636 | "Failed to apply hardware patch: %d\n", | ||
| 637 | ret); | ||
| 638 | goto err_reset; | ||
| 639 | } | ||
| 640 | break; | ||
| 641 | default: | ||
| 642 | break; | ||
| 643 | } | ||
| 477 | } | 644 | } |
| 478 | 645 | ||
| 479 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { | 646 | for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { |
| @@ -498,6 +665,7 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 498 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 665 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
| 499 | ARIZONA_CLK_32K_SRC_MASK, | 666 | ARIZONA_CLK_32K_SRC_MASK, |
| 500 | arizona->pdata.clk32k_src - 1); | 667 | arizona->pdata.clk32k_src - 1); |
| 668 | arizona_clk32k_enable(arizona); | ||
| 501 | break; | 669 | break; |
| 502 | case ARIZONA_32KZ_NONE: | 670 | case ARIZONA_32KZ_NONE: |
| 503 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, | 671 | regmap_update_bits(arizona->regmap, ARIZONA_CLOCK_32K_1, |
| @@ -511,10 +679,16 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 511 | } | 679 | } |
| 512 | 680 | ||
| 513 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { | 681 | for (i = 0; i < ARIZONA_MAX_MICBIAS; i++) { |
| 514 | if (!arizona->pdata.micbias[i].mV) | 682 | if (!arizona->pdata.micbias[i].mV && |
| 683 | !arizona->pdata.micbias[i].bypass) | ||
| 515 | continue; | 684 | continue; |
| 516 | 685 | ||
| 686 | /* Apply default for bypass mode */ | ||
| 687 | if (!arizona->pdata.micbias[i].mV) | ||
| 688 | arizona->pdata.micbias[i].mV = 2800; | ||
| 689 | |||
| 517 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; | 690 | val = (arizona->pdata.micbias[i].mV - 1500) / 100; |
| 691 | |||
| 518 | val <<= ARIZONA_MICB1_LVL_SHIFT; | 692 | val <<= ARIZONA_MICB1_LVL_SHIFT; |
| 519 | 693 | ||
| 520 | if (arizona->pdata.micbias[i].ext_cap) | 694 | if (arizona->pdata.micbias[i].ext_cap) |
| @@ -526,10 +700,14 @@ int arizona_dev_init(struct arizona *arizona) | |||
| 526 | if (arizona->pdata.micbias[i].fast_start) | 700 | if (arizona->pdata.micbias[i].fast_start) |
| 527 | val |= ARIZONA_MICB1_RATE; | 701 | val |= ARIZONA_MICB1_RATE; |
| 528 | 702 | ||
| 703 | if (arizona->pdata.micbias[i].bypass) | ||
| 704 | val |= ARIZONA_MICB1_BYPASS; | ||
| 705 | |||
| 529 | regmap_update_bits(arizona->regmap, | 706 | regmap_update_bits(arizona->regmap, |
| 530 | ARIZONA_MIC_BIAS_CTRL_1 + i, | 707 | ARIZONA_MIC_BIAS_CTRL_1 + i, |
| 531 | ARIZONA_MICB1_LVL_MASK | | 708 | ARIZONA_MICB1_LVL_MASK | |
| 532 | ARIZONA_MICB1_DISCH | | 709 | ARIZONA_MICB1_DISCH | |
| 710 | ARIZONA_MICB1_BYPASS | | ||
| 533 | ARIZONA_MICB1_RATE, val); | 711 | ARIZONA_MICB1_RATE, val); |
| 534 | } | 712 | } |
| 535 | 713 | ||
| @@ -610,10 +788,9 @@ err_irq: | |||
| 610 | arizona_irq_exit(arizona); | 788 | arizona_irq_exit(arizona); |
| 611 | err_reset: | 789 | err_reset: |
| 612 | if (arizona->pdata.reset) { | 790 | if (arizona->pdata.reset) { |
| 613 | gpio_set_value_cansleep(arizona->pdata.reset, 1); | 791 | gpio_set_value_cansleep(arizona->pdata.reset, 0); |
| 614 | gpio_free(arizona->pdata.reset); | 792 | gpio_free(arizona->pdata.reset); |
| 615 | } | 793 | } |
| 616 | err_dcvdd: | ||
| 617 | regulator_disable(arizona->dcvdd); | 794 | regulator_disable(arizona->dcvdd); |
| 618 | err_enable: | 795 | err_enable: |
| 619 | regulator_bulk_disable(arizona->num_core_supplies, | 796 | regulator_bulk_disable(arizona->num_core_supplies, |
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 2bec5f0db3ee..64cd9b6dac92 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c | |||
| @@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) | |||
| 94 | static irqreturn_t arizona_irq_thread(int irq, void *data) | 94 | static irqreturn_t arizona_irq_thread(int irq, void *data) |
| 95 | { | 95 | { |
| 96 | struct arizona *arizona = data; | 96 | struct arizona *arizona = data; |
| 97 | bool poll; | ||
| 97 | unsigned int val; | 98 | unsigned int val; |
| 98 | int ret; | 99 | int ret; |
| 99 | 100 | ||
| @@ -103,20 +104,39 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) | |||
| 103 | return IRQ_NONE; | 104 | return IRQ_NONE; |
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | /* Always handle the AoD domain */ | 107 | do { |
| 107 | handle_nested_irq(irq_find_mapping(arizona->virq, 0)); | 108 | poll = false; |
| 109 | |||
| 110 | /* Always handle the AoD domain */ | ||
| 111 | handle_nested_irq(irq_find_mapping(arizona->virq, 0)); | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Check if one of the main interrupts is asserted and only | ||
| 115 | * check that domain if it is. | ||
| 116 | */ | ||
| 117 | ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, | ||
| 118 | &val); | ||
| 119 | if (ret == 0 && val & ARIZONA_IRQ1_STS) { | ||
| 120 | handle_nested_irq(irq_find_mapping(arizona->virq, 1)); | ||
| 121 | } else if (ret != 0) { | ||
| 122 | dev_err(arizona->dev, | ||
| 123 | "Failed to read main IRQ status: %d\n", ret); | ||
| 124 | } | ||
| 108 | 125 | ||
| 109 | /* | 126 | /* |
| 110 | * Check if one of the main interrupts is asserted and only | 127 | * Poll the IRQ pin status to see if we're really done |
| 111 | * check that domain if it is. | 128 | * if the interrupt controller can't do it for us. |
| 112 | */ | 129 | */ |
| 113 | ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); | 130 | if (!arizona->pdata.irq_gpio) { |
| 114 | if (ret == 0 && val & ARIZONA_IRQ1_STS) { | 131 | break; |
| 115 | handle_nested_irq(irq_find_mapping(arizona->virq, 1)); | 132 | } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING && |
| 116 | } else if (ret != 0) { | 133 | gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { |
| 117 | dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", | 134 | poll = true; |
| 118 | ret); | 135 | } else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING && |
| 119 | } | 136 | !gpio_get_value_cansleep(arizona->pdata.irq_gpio)) { |
| 137 | poll = true; | ||
| 138 | } | ||
| 139 | } while (poll); | ||
| 120 | 140 | ||
| 121 | pm_runtime_mark_last_busy(arizona->dev); | 141 | pm_runtime_mark_last_busy(arizona->dev); |
| 122 | pm_runtime_put_autosuspend(arizona->dev); | 142 | pm_runtime_put_autosuspend(arizona->dev); |
| @@ -169,6 +189,7 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 169 | int ret, i; | 189 | int ret, i; |
| 170 | const struct regmap_irq_chip *aod, *irq; | 190 | const struct regmap_irq_chip *aod, *irq; |
| 171 | bool ctrlif_error = true; | 191 | bool ctrlif_error = true; |
| 192 | struct irq_data *irq_data; | ||
| 172 | 193 | ||
| 173 | switch (arizona->type) { | 194 | switch (arizona->type) { |
| 174 | #ifdef CONFIG_MFD_WM5102 | 195 | #ifdef CONFIG_MFD_WM5102 |
| @@ -192,7 +213,36 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 192 | return -EINVAL; | 213 | return -EINVAL; |
| 193 | } | 214 | } |
| 194 | 215 | ||
| 195 | if (arizona->pdata.irq_active_high) { | 216 | /* Disable all wake sources by default */ |
| 217 | regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0); | ||
| 218 | |||
| 219 | /* Read the flags from the interrupt controller if not specified */ | ||
| 220 | if (!arizona->pdata.irq_flags) { | ||
| 221 | irq_data = irq_get_irq_data(arizona->irq); | ||
| 222 | if (!irq_data) { | ||
| 223 | dev_err(arizona->dev, "Invalid IRQ: %d\n", | ||
| 224 | arizona->irq); | ||
| 225 | return -EINVAL; | ||
| 226 | } | ||
| 227 | |||
| 228 | arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data); | ||
| 229 | switch (arizona->pdata.irq_flags) { | ||
| 230 | case IRQF_TRIGGER_LOW: | ||
| 231 | case IRQF_TRIGGER_HIGH: | ||
| 232 | case IRQF_TRIGGER_RISING: | ||
| 233 | case IRQF_TRIGGER_FALLING: | ||
| 234 | break; | ||
| 235 | |||
| 236 | case IRQ_TYPE_NONE: | ||
| 237 | default: | ||
| 238 | /* Device default */ | ||
| 239 | arizona->pdata.irq_flags = IRQF_TRIGGER_LOW; | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | |||
| 244 | if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH | | ||
| 245 | IRQF_TRIGGER_RISING)) { | ||
| 196 | ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, | 246 | ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, |
| 197 | ARIZONA_IRQ_POL, 0); | 247 | ARIZONA_IRQ_POL, 0); |
| 198 | if (ret != 0) { | 248 | if (ret != 0) { |
| @@ -200,12 +250,10 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 200 | ret); | 250 | ret); |
| 201 | goto err; | 251 | goto err; |
| 202 | } | 252 | } |
| 203 | |||
| 204 | flags |= IRQF_TRIGGER_HIGH; | ||
| 205 | } else { | ||
| 206 | flags |= IRQF_TRIGGER_LOW; | ||
| 207 | } | 253 | } |
| 208 | 254 | ||
| 255 | flags |= arizona->pdata.irq_flags; | ||
| 256 | |||
| 209 | /* Allocate a virtual IRQ domain to distribute to the regmap domains */ | 257 | /* Allocate a virtual IRQ domain to distribute to the regmap domains */ |
| 210 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, | 258 | arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, |
| 211 | arizona); | 259 | arizona); |
| @@ -257,11 +305,31 @@ int arizona_irq_init(struct arizona *arizona) | |||
| 257 | } | 305 | } |
| 258 | } | 306 | } |
| 259 | 307 | ||
| 308 | /* Used to emulate edge trigger and to work around broken pinmux */ | ||
| 309 | if (arizona->pdata.irq_gpio) { | ||
| 310 | if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) { | ||
| 311 | dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n", | ||
| 312 | arizona->irq, arizona->pdata.irq_gpio, | ||
| 313 | gpio_to_irq(arizona->pdata.irq_gpio)); | ||
| 314 | arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio); | ||
| 315 | } | ||
| 316 | |||
| 317 | ret = devm_gpio_request_one(arizona->dev, | ||
| 318 | arizona->pdata.irq_gpio, | ||
| 319 | GPIOF_IN, "arizona IRQ"); | ||
| 320 | if (ret != 0) { | ||
| 321 | dev_err(arizona->dev, | ||
| 322 | "Failed to request IRQ GPIO %d:: %d\n", | ||
| 323 | arizona->pdata.irq_gpio, ret); | ||
| 324 | arizona->pdata.irq_gpio = 0; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 260 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, | 328 | ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, |
| 261 | flags, "arizona", arizona); | 329 | flags, "arizona", arizona); |
| 262 | 330 | ||
| 263 | if (ret != 0) { | 331 | if (ret != 0) { |
| 264 | dev_err(arizona->dev, "Failed to request IRQ %d: %d\n", | 332 | dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n", |
| 265 | arizona->irq, ret); | 333 | arizona->irq, ret); |
| 266 | goto err_main_irq; | 334 | goto err_main_irq; |
| 267 | } | 335 | } |
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 1b9fdd698b03..b57e642d2b4a 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c | |||
| @@ -67,7 +67,7 @@ static int arizona_spi_probe(struct spi_device *spi) | |||
| 67 | 67 | ||
| 68 | static int arizona_spi_remove(struct spi_device *spi) | 68 | static int arizona_spi_remove(struct spi_device *spi) |
| 69 | { | 69 | { |
| 70 | struct arizona *arizona = dev_get_drvdata(&spi->dev); | 70 | struct arizona *arizona = spi_get_drvdata(spi); |
| 71 | arizona_dev_exit(arizona); | 71 | arizona_dev_exit(arizona); |
| 72 | return 0; | 72 | return 0; |
| 73 | } | 73 | } |
diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index e994c9691124..01e414162702 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c | |||
| @@ -112,16 +112,34 @@ static const struct regmap_config as3711_regmap_config = { | |||
| 112 | .cache_type = REGCACHE_RBTREE, | 112 | .cache_type = REGCACHE_RBTREE, |
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | #ifdef CONFIG_OF | ||
| 116 | static struct of_device_id as3711_of_match[] = { | ||
| 117 | {.compatible = "ams,as3711",}, | ||
| 118 | {} | ||
| 119 | }; | ||
| 120 | MODULE_DEVICE_TABLE(of, as3711_of_match); | ||
| 121 | #endif | ||
| 122 | |||
| 115 | static int as3711_i2c_probe(struct i2c_client *client, | 123 | static int as3711_i2c_probe(struct i2c_client *client, |
| 116 | const struct i2c_device_id *id) | 124 | const struct i2c_device_id *id) |
| 117 | { | 125 | { |
| 118 | struct as3711 *as3711; | 126 | struct as3711 *as3711; |
| 119 | struct as3711_platform_data *pdata = client->dev.platform_data; | 127 | struct as3711_platform_data *pdata; |
| 120 | unsigned int id1, id2; | 128 | unsigned int id1, id2; |
| 121 | int ret; | 129 | int ret; |
| 122 | 130 | ||
| 123 | if (!pdata) | 131 | if (!client->dev.of_node) { |
| 124 | dev_dbg(&client->dev, "Platform data not found\n"); | 132 | pdata = client->dev.platform_data; |
| 133 | if (!pdata) | ||
| 134 | dev_dbg(&client->dev, "Platform data not found\n"); | ||
| 135 | } else { | ||
| 136 | pdata = devm_kzalloc(&client->dev, | ||
| 137 | sizeof(*pdata), GFP_KERNEL); | ||
| 138 | if (!pdata) { | ||
| 139 | dev_err(&client->dev, "Failed to allocate pdata\n"); | ||
| 140 | return -ENOMEM; | ||
| 141 | } | ||
| 142 | } | ||
| 125 | 143 | ||
| 126 | as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); | 144 | as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); |
| 127 | if (!as3711) { | 145 | if (!as3711) { |
| @@ -193,7 +211,8 @@ static struct i2c_driver as3711_i2c_driver = { | |||
| 193 | .driver = { | 211 | .driver = { |
| 194 | .name = "as3711", | 212 | .name = "as3711", |
| 195 | .owner = THIS_MODULE, | 213 | .owner = THIS_MODULE, |
| 196 | }, | 214 | .of_match_table = of_match_ptr(as3711_of_match), |
| 215 | }, | ||
| 197 | .probe = as3711_i2c_probe, | 216 | .probe = as3711_i2c_probe, |
| 198 | .remove = as3711_i2c_remove, | 217 | .remove = as3711_i2c_remove, |
| 199 | .id_table = as3711_i2c_id, | 218 | .id_table = as3711_i2c_id, |
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c new file mode 100644 index 000000000000..10cd14e35eb0 --- /dev/null +++ b/drivers/mfd/cros_ec.c | |||
| @@ -0,0 +1,196 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC multi-function device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * The ChromeOS EC multi function device is used to mux all the requests | ||
| 16 | * to the EC device for its multiple features: keyboard controller, | ||
| 17 | * battery charging and regulator control, firmware update. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/mfd/core.h> | ||
| 24 | #include <linux/mfd/cros_ec.h> | ||
| 25 | #include <linux/mfd/cros_ec_commands.h> | ||
| 26 | |||
| 27 | int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, | ||
| 28 | struct cros_ec_msg *msg) | ||
| 29 | { | ||
| 30 | uint8_t *out; | ||
| 31 | int csum, i; | ||
| 32 | |||
| 33 | BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE); | ||
| 34 | out = ec_dev->dout; | ||
| 35 | out[0] = EC_CMD_VERSION0 + msg->version; | ||
| 36 | out[1] = msg->cmd; | ||
| 37 | out[2] = msg->out_len; | ||
| 38 | csum = out[0] + out[1] + out[2]; | ||
| 39 | for (i = 0; i < msg->out_len; i++) | ||
| 40 | csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->out_buf[i]; | ||
| 41 | out[EC_MSG_TX_HEADER_BYTES + msg->out_len] = (uint8_t)(csum & 0xff); | ||
| 42 | |||
| 43 | return EC_MSG_TX_PROTO_BYTES + msg->out_len; | ||
| 44 | } | ||
| 45 | EXPORT_SYMBOL(cros_ec_prepare_tx); | ||
| 46 | |||
| 47 | static int cros_ec_command_sendrecv(struct cros_ec_device *ec_dev, | ||
| 48 | uint16_t cmd, void *out_buf, int out_len, | ||
| 49 | void *in_buf, int in_len) | ||
| 50 | { | ||
| 51 | struct cros_ec_msg msg; | ||
| 52 | |||
| 53 | msg.version = cmd >> 8; | ||
| 54 | msg.cmd = cmd & 0xff; | ||
| 55 | msg.out_buf = out_buf; | ||
| 56 | msg.out_len = out_len; | ||
| 57 | msg.in_buf = in_buf; | ||
| 58 | msg.in_len = in_len; | ||
| 59 | |||
| 60 | return ec_dev->command_xfer(ec_dev, &msg); | ||
| 61 | } | ||
| 62 | |||
| 63 | static int cros_ec_command_recv(struct cros_ec_device *ec_dev, | ||
| 64 | uint16_t cmd, void *buf, int buf_len) | ||
| 65 | { | ||
| 66 | return cros_ec_command_sendrecv(ec_dev, cmd, NULL, 0, buf, buf_len); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int cros_ec_command_send(struct cros_ec_device *ec_dev, | ||
| 70 | uint16_t cmd, void *buf, int buf_len) | ||
| 71 | { | ||
| 72 | return cros_ec_command_sendrecv(ec_dev, cmd, buf, buf_len, NULL, 0); | ||
| 73 | } | ||
| 74 | |||
| 75 | static irqreturn_t ec_irq_thread(int irq, void *data) | ||
| 76 | { | ||
| 77 | struct cros_ec_device *ec_dev = data; | ||
| 78 | |||
| 79 | if (device_may_wakeup(ec_dev->dev)) | ||
| 80 | pm_wakeup_event(ec_dev->dev, 0); | ||
| 81 | |||
| 82 | blocking_notifier_call_chain(&ec_dev->event_notifier, 1, ec_dev); | ||
| 83 | |||
| 84 | return IRQ_HANDLED; | ||
| 85 | } | ||
| 86 | |||
| 87 | static struct mfd_cell cros_devs[] = { | ||
| 88 | { | ||
| 89 | .name = "cros-ec-keyb", | ||
| 90 | .id = 1, | ||
| 91 | .of_compatible = "google,cros-ec-keyb", | ||
| 92 | }, | ||
| 93 | }; | ||
| 94 | |||
| 95 | int cros_ec_register(struct cros_ec_device *ec_dev) | ||
| 96 | { | ||
| 97 | struct device *dev = ec_dev->dev; | ||
| 98 | int err = 0; | ||
| 99 | |||
| 100 | BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier); | ||
| 101 | |||
| 102 | ec_dev->command_send = cros_ec_command_send; | ||
| 103 | ec_dev->command_recv = cros_ec_command_recv; | ||
| 104 | ec_dev->command_sendrecv = cros_ec_command_sendrecv; | ||
| 105 | |||
| 106 | if (ec_dev->din_size) { | ||
| 107 | ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL); | ||
| 108 | if (!ec_dev->din) { | ||
| 109 | err = -ENOMEM; | ||
| 110 | goto fail_din; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | if (ec_dev->dout_size) { | ||
| 114 | ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL); | ||
| 115 | if (!ec_dev->dout) { | ||
| 116 | err = -ENOMEM; | ||
| 117 | goto fail_dout; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | if (!ec_dev->irq) { | ||
| 122 | dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq); | ||
| 123 | goto fail_irq; | ||
| 124 | } | ||
| 125 | |||
| 126 | err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, | ||
| 127 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
| 128 | "chromeos-ec", ec_dev); | ||
| 129 | if (err) { | ||
| 130 | dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err); | ||
| 131 | goto fail_irq; | ||
| 132 | } | ||
| 133 | |||
| 134 | err = mfd_add_devices(dev, 0, cros_devs, | ||
| 135 | ARRAY_SIZE(cros_devs), | ||
| 136 | NULL, ec_dev->irq, NULL); | ||
| 137 | if (err) { | ||
| 138 | dev_err(dev, "failed to add mfd devices\n"); | ||
| 139 | goto fail_mfd; | ||
| 140 | } | ||
| 141 | |||
| 142 | dev_info(dev, "Chrome EC (%s)\n", ec_dev->name); | ||
| 143 | |||
| 144 | return 0; | ||
| 145 | |||
| 146 | fail_mfd: | ||
| 147 | free_irq(ec_dev->irq, ec_dev); | ||
| 148 | fail_irq: | ||
| 149 | kfree(ec_dev->dout); | ||
| 150 | fail_dout: | ||
| 151 | kfree(ec_dev->din); | ||
| 152 | fail_din: | ||
| 153 | return err; | ||
| 154 | } | ||
| 155 | EXPORT_SYMBOL(cros_ec_register); | ||
| 156 | |||
| 157 | int cros_ec_remove(struct cros_ec_device *ec_dev) | ||
| 158 | { | ||
| 159 | mfd_remove_devices(ec_dev->dev); | ||
| 160 | free_irq(ec_dev->irq, ec_dev); | ||
| 161 | kfree(ec_dev->dout); | ||
| 162 | kfree(ec_dev->din); | ||
| 163 | |||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | EXPORT_SYMBOL(cros_ec_remove); | ||
| 167 | |||
| 168 | #ifdef CONFIG_PM_SLEEP | ||
| 169 | int cros_ec_suspend(struct cros_ec_device *ec_dev) | ||
| 170 | { | ||
| 171 | struct device *dev = ec_dev->dev; | ||
| 172 | |||
| 173 | if (device_may_wakeup(dev)) | ||
| 174 | ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq); | ||
| 175 | |||
| 176 | disable_irq(ec_dev->irq); | ||
| 177 | ec_dev->was_wake_device = ec_dev->wake_enabled; | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | EXPORT_SYMBOL(cros_ec_suspend); | ||
| 182 | |||
| 183 | int cros_ec_resume(struct cros_ec_device *ec_dev) | ||
| 184 | { | ||
| 185 | enable_irq(ec_dev->irq); | ||
| 186 | |||
| 187 | if (ec_dev->wake_enabled) { | ||
| 188 | disable_irq_wake(ec_dev->irq); | ||
| 189 | ec_dev->wake_enabled = 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | EXPORT_SYMBOL(cros_ec_resume); | ||
| 195 | |||
| 196 | #endif | ||
diff --git a/drivers/mfd/cros_ec_i2c.c b/drivers/mfd/cros_ec_i2c.c new file mode 100644 index 000000000000..123044608b63 --- /dev/null +++ b/drivers/mfd/cros_ec_i2c.c | |||
| @@ -0,0 +1,201 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC multi-function device (I2C) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/i2c.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/mfd/cros_ec.h> | ||
| 21 | #include <linux/mfd/cros_ec_commands.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | |||
| 25 | static inline struct cros_ec_device *to_ec_dev(struct device *dev) | ||
| 26 | { | ||
| 27 | struct i2c_client *client = to_i2c_client(dev); | ||
| 28 | |||
| 29 | return i2c_get_clientdata(client); | ||
| 30 | } | ||
| 31 | |||
| 32 | static int cros_ec_command_xfer(struct cros_ec_device *ec_dev, | ||
| 33 | struct cros_ec_msg *msg) | ||
| 34 | { | ||
| 35 | struct i2c_client *client = ec_dev->priv; | ||
| 36 | int ret = -ENOMEM; | ||
| 37 | int i; | ||
| 38 | int packet_len; | ||
| 39 | u8 *out_buf = NULL; | ||
| 40 | u8 *in_buf = NULL; | ||
| 41 | u8 sum; | ||
| 42 | struct i2c_msg i2c_msg[2]; | ||
| 43 | |||
| 44 | i2c_msg[0].addr = client->addr; | ||
| 45 | i2c_msg[0].flags = 0; | ||
| 46 | i2c_msg[1].addr = client->addr; | ||
| 47 | i2c_msg[1].flags = I2C_M_RD; | ||
| 48 | |||
| 49 | /* | ||
| 50 | * allocate larger packet (one byte for checksum, one byte for | ||
| 51 | * length, and one for result code) | ||
| 52 | */ | ||
| 53 | packet_len = msg->in_len + 3; | ||
| 54 | in_buf = kzalloc(packet_len, GFP_KERNEL); | ||
| 55 | if (!in_buf) | ||
| 56 | goto done; | ||
| 57 | i2c_msg[1].len = packet_len; | ||
| 58 | i2c_msg[1].buf = (char *)in_buf; | ||
| 59 | |||
| 60 | /* | ||
| 61 | * allocate larger packet (one byte for checksum, one for | ||
| 62 | * command code, one for length, and one for command version) | ||
| 63 | */ | ||
| 64 | packet_len = msg->out_len + 4; | ||
| 65 | out_buf = kzalloc(packet_len, GFP_KERNEL); | ||
| 66 | if (!out_buf) | ||
| 67 | goto done; | ||
| 68 | i2c_msg[0].len = packet_len; | ||
| 69 | i2c_msg[0].buf = (char *)out_buf; | ||
| 70 | |||
| 71 | out_buf[0] = EC_CMD_VERSION0 + msg->version; | ||
| 72 | out_buf[1] = msg->cmd; | ||
| 73 | out_buf[2] = msg->out_len; | ||
| 74 | |||
| 75 | /* copy message payload and compute checksum */ | ||
| 76 | sum = out_buf[0] + out_buf[1] + out_buf[2]; | ||
| 77 | for (i = 0; i < msg->out_len; i++) { | ||
| 78 | out_buf[3 + i] = msg->out_buf[i]; | ||
| 79 | sum += out_buf[3 + i]; | ||
| 80 | } | ||
| 81 | out_buf[3 + msg->out_len] = sum; | ||
| 82 | |||
| 83 | /* send command to EC and read answer */ | ||
| 84 | ret = i2c_transfer(client->adapter, i2c_msg, 2); | ||
| 85 | if (ret < 0) { | ||
| 86 | dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret); | ||
| 87 | goto done; | ||
| 88 | } else if (ret != 2) { | ||
| 89 | dev_err(ec_dev->dev, "failed to get response: %d\n", ret); | ||
| 90 | ret = -EIO; | ||
| 91 | goto done; | ||
| 92 | } | ||
| 93 | |||
| 94 | /* check response error code */ | ||
| 95 | if (i2c_msg[1].buf[0]) { | ||
| 96 | dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", | ||
| 97 | msg->cmd, i2c_msg[1].buf[0]); | ||
| 98 | ret = -EINVAL; | ||
| 99 | goto done; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* copy response packet payload and compute checksum */ | ||
| 103 | sum = in_buf[0] + in_buf[1]; | ||
| 104 | for (i = 0; i < msg->in_len; i++) { | ||
| 105 | msg->in_buf[i] = in_buf[2 + i]; | ||
| 106 | sum += in_buf[2 + i]; | ||
| 107 | } | ||
| 108 | dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", | ||
| 109 | i2c_msg[1].len, in_buf, sum); | ||
| 110 | if (sum != in_buf[2 + msg->in_len]) { | ||
| 111 | dev_err(ec_dev->dev, "bad packet checksum\n"); | ||
| 112 | ret = -EBADMSG; | ||
| 113 | goto done; | ||
| 114 | } | ||
| 115 | |||
| 116 | ret = 0; | ||
| 117 | done: | ||
| 118 | kfree(in_buf); | ||
| 119 | kfree(out_buf); | ||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int cros_ec_probe_i2c(struct i2c_client *client, | ||
| 124 | const struct i2c_device_id *dev_id) | ||
| 125 | { | ||
| 126 | struct device *dev = &client->dev; | ||
| 127 | struct cros_ec_device *ec_dev = NULL; | ||
| 128 | int err; | ||
| 129 | |||
| 130 | ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); | ||
| 131 | if (!ec_dev) | ||
| 132 | return -ENOMEM; | ||
| 133 | |||
| 134 | i2c_set_clientdata(client, ec_dev); | ||
| 135 | ec_dev->name = "I2C"; | ||
| 136 | ec_dev->dev = dev; | ||
| 137 | ec_dev->priv = client; | ||
| 138 | ec_dev->irq = client->irq; | ||
| 139 | ec_dev->command_xfer = cros_ec_command_xfer; | ||
| 140 | ec_dev->ec_name = client->name; | ||
| 141 | ec_dev->phys_name = client->adapter->name; | ||
| 142 | ec_dev->parent = &client->dev; | ||
| 143 | |||
| 144 | err = cros_ec_register(ec_dev); | ||
| 145 | if (err) { | ||
| 146 | dev_err(dev, "cannot register EC\n"); | ||
| 147 | return err; | ||
| 148 | } | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int cros_ec_remove_i2c(struct i2c_client *client) | ||
| 154 | { | ||
| 155 | struct cros_ec_device *ec_dev = i2c_get_clientdata(client); | ||
| 156 | |||
| 157 | cros_ec_remove(ec_dev); | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | #ifdef CONFIG_PM_SLEEP | ||
| 163 | static int cros_ec_i2c_suspend(struct device *dev) | ||
| 164 | { | ||
| 165 | struct cros_ec_device *ec_dev = to_ec_dev(dev); | ||
| 166 | |||
| 167 | return cros_ec_suspend(ec_dev); | ||
| 168 | } | ||
| 169 | |||
| 170 | static int cros_ec_i2c_resume(struct device *dev) | ||
| 171 | { | ||
| 172 | struct cros_ec_device *ec_dev = to_ec_dev(dev); | ||
| 173 | |||
| 174 | return cros_ec_resume(ec_dev); | ||
| 175 | } | ||
| 176 | #endif | ||
| 177 | |||
| 178 | static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend, | ||
| 179 | cros_ec_i2c_resume); | ||
| 180 | |||
| 181 | static const struct i2c_device_id cros_ec_i2c_id[] = { | ||
| 182 | { "cros-ec-i2c", 0 }, | ||
| 183 | { } | ||
| 184 | }; | ||
| 185 | MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); | ||
| 186 | |||
| 187 | static struct i2c_driver cros_ec_driver = { | ||
| 188 | .driver = { | ||
| 189 | .name = "cros-ec-i2c", | ||
| 190 | .owner = THIS_MODULE, | ||
| 191 | .pm = &cros_ec_i2c_pm_ops, | ||
| 192 | }, | ||
| 193 | .probe = cros_ec_probe_i2c, | ||
| 194 | .remove = cros_ec_remove_i2c, | ||
| 195 | .id_table = cros_ec_i2c_id, | ||
| 196 | }; | ||
| 197 | |||
| 198 | module_i2c_driver(cros_ec_driver); | ||
| 199 | |||
| 200 | MODULE_LICENSE("GPL"); | ||
| 201 | MODULE_DESCRIPTION("ChromeOS EC multi function device"); | ||
diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c new file mode 100644 index 000000000000..19193cf1e7a1 --- /dev/null +++ b/drivers/mfd/cros_ec_spi.c | |||
| @@ -0,0 +1,375 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC multi-function device (SPI) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/delay.h> | ||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/mfd/cros_ec.h> | ||
| 20 | #include <linux/mfd/cros_ec_commands.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/spi/spi.h> | ||
| 24 | |||
| 25 | |||
| 26 | /* The header byte, which follows the preamble */ | ||
| 27 | #define EC_MSG_HEADER 0xec | ||
| 28 | |||
| 29 | /* | ||
| 30 | * Number of EC preamble bytes we read at a time. Since it takes | ||
| 31 | * about 400-500us for the EC to respond there is not a lot of | ||
| 32 | * point in tuning this. If the EC could respond faster then | ||
| 33 | * we could increase this so that might expect the preamble and | ||
| 34 | * message to occur in a single transaction. However, the maximum | ||
| 35 | * SPI transfer size is 256 bytes, so at 5MHz we need a response | ||
| 36 | * time of perhaps <320us (200 bytes / 1600 bits). | ||
| 37 | */ | ||
| 38 | #define EC_MSG_PREAMBLE_COUNT 32 | ||
| 39 | |||
| 40 | /* | ||
| 41 | * We must get a response from the EC in 5ms. This is a very long | ||
| 42 | * time, but the flash write command can take 2-3ms. The EC command | ||
| 43 | * processing is currently not very fast (about 500us). We could | ||
| 44 | * look at speeding this up and making the flash write command a | ||
| 45 | * 'slow' command, requiring a GET_STATUS wait loop, like flash | ||
| 46 | * erase. | ||
| 47 | */ | ||
| 48 | #define EC_MSG_DEADLINE_MS 5 | ||
| 49 | |||
| 50 | /* | ||
| 51 | * Time between raising the SPI chip select (for the end of a | ||
| 52 | * transaction) and dropping it again (for the next transaction). | ||
| 53 | * If we go too fast, the EC will miss the transaction. It seems | ||
| 54 | * that 50us is enough with the 16MHz STM32 EC. | ||
| 55 | */ | ||
| 56 | #define EC_SPI_RECOVERY_TIME_NS (50 * 1000) | ||
| 57 | |||
| 58 | /** | ||
| 59 | * struct cros_ec_spi - information about a SPI-connected EC | ||
| 60 | * | ||
| 61 | * @spi: SPI device we are connected to | ||
| 62 | * @last_transfer_ns: time that we last finished a transfer, or 0 if there | ||
| 63 | * if no record | ||
| 64 | */ | ||
| 65 | struct cros_ec_spi { | ||
| 66 | struct spi_device *spi; | ||
| 67 | s64 last_transfer_ns; | ||
| 68 | }; | ||
| 69 | |||
| 70 | static void debug_packet(struct device *dev, const char *name, u8 *ptr, | ||
| 71 | int len) | ||
| 72 | { | ||
| 73 | #ifdef DEBUG | ||
| 74 | int i; | ||
| 75 | |||
| 76 | dev_dbg(dev, "%s: ", name); | ||
| 77 | for (i = 0; i < len; i++) | ||
| 78 | dev_cont(dev, " %02x", ptr[i]); | ||
| 79 | #endif | ||
| 80 | } | ||
| 81 | |||
| 82 | /** | ||
| 83 | * cros_ec_spi_receive_response - Receive a response from the EC. | ||
| 84 | * | ||
| 85 | * This function has two phases: reading the preamble bytes (since if we read | ||
| 86 | * data from the EC before it is ready to send, we just get preamble) and | ||
| 87 | * reading the actual message. | ||
| 88 | * | ||
| 89 | * The received data is placed into ec_dev->din. | ||
| 90 | * | ||
| 91 | * @ec_dev: ChromeOS EC device | ||
| 92 | * @need_len: Number of message bytes we need to read | ||
| 93 | */ | ||
| 94 | static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, | ||
| 95 | int need_len) | ||
| 96 | { | ||
| 97 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
| 98 | struct spi_transfer trans; | ||
| 99 | struct spi_message msg; | ||
| 100 | u8 *ptr, *end; | ||
| 101 | int ret; | ||
| 102 | unsigned long deadline; | ||
| 103 | int todo; | ||
| 104 | |||
| 105 | /* Receive data until we see the header byte */ | ||
| 106 | deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); | ||
| 107 | do { | ||
| 108 | memset(&trans, '\0', sizeof(trans)); | ||
| 109 | trans.cs_change = 1; | ||
| 110 | trans.rx_buf = ptr = ec_dev->din; | ||
| 111 | trans.len = EC_MSG_PREAMBLE_COUNT; | ||
| 112 | |||
| 113 | spi_message_init(&msg); | ||
| 114 | spi_message_add_tail(&trans, &msg); | ||
| 115 | ret = spi_sync(ec_spi->spi, &msg); | ||
| 116 | if (ret < 0) { | ||
| 117 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
| 118 | return ret; | ||
| 119 | } | ||
| 120 | |||
| 121 | for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) { | ||
| 122 | if (*ptr == EC_MSG_HEADER) { | ||
| 123 | dev_dbg(ec_dev->dev, "msg found at %ld\n", | ||
| 124 | ptr - ec_dev->din); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | if (time_after(jiffies, deadline)) { | ||
| 130 | dev_warn(ec_dev->dev, "EC failed to respond in time\n"); | ||
| 131 | return -ETIMEDOUT; | ||
| 132 | } | ||
| 133 | } while (ptr == end); | ||
| 134 | |||
| 135 | /* | ||
| 136 | * ptr now points to the header byte. Copy any valid data to the | ||
| 137 | * start of our buffer | ||
| 138 | */ | ||
| 139 | todo = end - ++ptr; | ||
| 140 | BUG_ON(todo < 0 || todo > ec_dev->din_size); | ||
| 141 | todo = min(todo, need_len); | ||
| 142 | memmove(ec_dev->din, ptr, todo); | ||
| 143 | ptr = ec_dev->din + todo; | ||
| 144 | dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n", | ||
| 145 | need_len, todo); | ||
| 146 | need_len -= todo; | ||
| 147 | |||
| 148 | /* Receive data until we have it all */ | ||
| 149 | while (need_len > 0) { | ||
| 150 | /* | ||
| 151 | * We can't support transfers larger than the SPI FIFO size | ||
| 152 | * unless we have DMA. We don't have DMA on the ISP SPI ports | ||
| 153 | * for Exynos. We need a way of asking SPI driver for | ||
| 154 | * maximum-supported transfer size. | ||
| 155 | */ | ||
| 156 | todo = min(need_len, 256); | ||
| 157 | dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n", | ||
| 158 | todo, need_len, ptr - ec_dev->din); | ||
| 159 | |||
| 160 | memset(&trans, '\0', sizeof(trans)); | ||
| 161 | trans.cs_change = 1; | ||
| 162 | trans.rx_buf = ptr; | ||
| 163 | trans.len = todo; | ||
| 164 | spi_message_init(&msg); | ||
| 165 | spi_message_add_tail(&trans, &msg); | ||
| 166 | |||
| 167 | /* send command to EC and read answer */ | ||
| 168 | BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo > | ||
| 169 | ec_dev->din_size); | ||
| 170 | ret = spi_sync(ec_spi->spi, &msg); | ||
| 171 | if (ret < 0) { | ||
| 172 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
| 173 | return ret; | ||
| 174 | } | ||
| 175 | |||
| 176 | debug_packet(ec_dev->dev, "interim", ptr, todo); | ||
| 177 | ptr += todo; | ||
| 178 | need_len -= todo; | ||
| 179 | } | ||
| 180 | |||
| 181 | dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * cros_ec_command_spi_xfer - Transfer a message over SPI and receive the reply | ||
| 188 | * | ||
| 189 | * @ec_dev: ChromeOS EC device | ||
| 190 | * @ec_msg: Message to transfer | ||
| 191 | */ | ||
| 192 | static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, | ||
| 193 | struct cros_ec_msg *ec_msg) | ||
| 194 | { | ||
| 195 | struct cros_ec_spi *ec_spi = ec_dev->priv; | ||
| 196 | struct spi_transfer trans; | ||
| 197 | struct spi_message msg; | ||
| 198 | int i, len; | ||
| 199 | u8 *ptr; | ||
| 200 | int sum; | ||
| 201 | int ret = 0, final_ret; | ||
| 202 | struct timespec ts; | ||
| 203 | |||
| 204 | len = cros_ec_prepare_tx(ec_dev, ec_msg); | ||
| 205 | dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); | ||
| 206 | |||
| 207 | /* If it's too soon to do another transaction, wait */ | ||
| 208 | if (ec_spi->last_transfer_ns) { | ||
| 209 | struct timespec ts; | ||
| 210 | unsigned long delay; /* The delay completed so far */ | ||
| 211 | |||
| 212 | ktime_get_ts(&ts); | ||
| 213 | delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; | ||
| 214 | if (delay < EC_SPI_RECOVERY_TIME_NS) | ||
| 215 | ndelay(delay); | ||
| 216 | } | ||
| 217 | |||
| 218 | /* Transmit phase - send our message */ | ||
| 219 | debug_packet(ec_dev->dev, "out", ec_dev->dout, len); | ||
| 220 | memset(&trans, '\0', sizeof(trans)); | ||
| 221 | trans.tx_buf = ec_dev->dout; | ||
| 222 | trans.len = len; | ||
| 223 | trans.cs_change = 1; | ||
| 224 | spi_message_init(&msg); | ||
| 225 | spi_message_add_tail(&trans, &msg); | ||
| 226 | ret = spi_sync(ec_spi->spi, &msg); | ||
| 227 | |||
| 228 | /* Get the response */ | ||
| 229 | if (!ret) { | ||
| 230 | ret = cros_ec_spi_receive_response(ec_dev, | ||
| 231 | ec_msg->in_len + EC_MSG_TX_PROTO_BYTES); | ||
| 232 | } else { | ||
| 233 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
| 234 | } | ||
| 235 | |||
| 236 | /* turn off CS */ | ||
| 237 | spi_message_init(&msg); | ||
| 238 | final_ret = spi_sync(ec_spi->spi, &msg); | ||
| 239 | ktime_get_ts(&ts); | ||
| 240 | ec_spi->last_transfer_ns = timespec_to_ns(&ts); | ||
| 241 | if (!ret) | ||
| 242 | ret = final_ret; | ||
| 243 | if (ret < 0) { | ||
| 244 | dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); | ||
| 245 | return ret; | ||
| 246 | } | ||
| 247 | |||
| 248 | /* check response error code */ | ||
| 249 | ptr = ec_dev->din; | ||
| 250 | if (ptr[0]) { | ||
| 251 | dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", | ||
| 252 | ec_msg->cmd, ptr[0]); | ||
| 253 | debug_packet(ec_dev->dev, "in_err", ptr, len); | ||
| 254 | return -EINVAL; | ||
| 255 | } | ||
| 256 | len = ptr[1]; | ||
| 257 | sum = ptr[0] + ptr[1]; | ||
| 258 | if (len > ec_msg->in_len) { | ||
| 259 | dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", | ||
| 260 | len, ec_msg->in_len); | ||
| 261 | return -ENOSPC; | ||
| 262 | } | ||
| 263 | |||
| 264 | /* copy response packet payload and compute checksum */ | ||
| 265 | for (i = 0; i < len; i++) { | ||
| 266 | sum += ptr[i + 2]; | ||
| 267 | if (ec_msg->in_len) | ||
| 268 | ec_msg->in_buf[i] = ptr[i + 2]; | ||
| 269 | } | ||
| 270 | sum &= 0xff; | ||
| 271 | |||
| 272 | debug_packet(ec_dev->dev, "in", ptr, len + 3); | ||
| 273 | |||
| 274 | if (sum != ptr[len + 2]) { | ||
| 275 | dev_err(ec_dev->dev, | ||
| 276 | "bad packet checksum, expected %02x, got %02x\n", | ||
| 277 | sum, ptr[len + 2]); | ||
| 278 | return -EBADMSG; | ||
| 279 | } | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | static int cros_ec_probe_spi(struct spi_device *spi) | ||
| 285 | { | ||
| 286 | struct device *dev = &spi->dev; | ||
| 287 | struct cros_ec_device *ec_dev; | ||
| 288 | struct cros_ec_spi *ec_spi; | ||
| 289 | int err; | ||
| 290 | |||
| 291 | spi->bits_per_word = 8; | ||
| 292 | spi->mode = SPI_MODE_0; | ||
| 293 | err = spi_setup(spi); | ||
| 294 | if (err < 0) | ||
| 295 | return err; | ||
| 296 | |||
| 297 | ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL); | ||
| 298 | if (ec_spi == NULL) | ||
| 299 | return -ENOMEM; | ||
| 300 | ec_spi->spi = spi; | ||
| 301 | ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); | ||
| 302 | if (!ec_dev) | ||
| 303 | return -ENOMEM; | ||
| 304 | |||
| 305 | spi_set_drvdata(spi, ec_dev); | ||
| 306 | ec_dev->name = "SPI"; | ||
| 307 | ec_dev->dev = dev; | ||
| 308 | ec_dev->priv = ec_spi; | ||
| 309 | ec_dev->irq = spi->irq; | ||
| 310 | ec_dev->command_xfer = cros_ec_command_spi_xfer; | ||
| 311 | ec_dev->ec_name = ec_spi->spi->modalias; | ||
| 312 | ec_dev->phys_name = dev_name(&ec_spi->spi->dev); | ||
| 313 | ec_dev->parent = &ec_spi->spi->dev; | ||
| 314 | ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT; | ||
| 315 | ec_dev->dout_size = EC_MSG_BYTES; | ||
| 316 | |||
| 317 | err = cros_ec_register(ec_dev); | ||
| 318 | if (err) { | ||
| 319 | dev_err(dev, "cannot register EC\n"); | ||
| 320 | return err; | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int cros_ec_remove_spi(struct spi_device *spi) | ||
| 327 | { | ||
| 328 | struct cros_ec_device *ec_dev; | ||
| 329 | |||
| 330 | ec_dev = spi_get_drvdata(spi); | ||
| 331 | cros_ec_remove(ec_dev); | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | #ifdef CONFIG_PM_SLEEP | ||
| 337 | static int cros_ec_spi_suspend(struct device *dev) | ||
| 338 | { | ||
| 339 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
| 340 | |||
| 341 | return cros_ec_suspend(ec_dev); | ||
| 342 | } | ||
| 343 | |||
| 344 | static int cros_ec_spi_resume(struct device *dev) | ||
| 345 | { | ||
| 346 | struct cros_ec_device *ec_dev = dev_get_drvdata(dev); | ||
| 347 | |||
| 348 | return cros_ec_resume(ec_dev); | ||
| 349 | } | ||
| 350 | #endif | ||
| 351 | |||
| 352 | static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, | ||
| 353 | cros_ec_spi_resume); | ||
| 354 | |||
| 355 | static const struct spi_device_id cros_ec_spi_id[] = { | ||
| 356 | { "cros-ec-spi", 0 }, | ||
| 357 | { } | ||
| 358 | }; | ||
| 359 | MODULE_DEVICE_TABLE(spi, cros_ec_spi_id); | ||
| 360 | |||
| 361 | static struct spi_driver cros_ec_driver_spi = { | ||
| 362 | .driver = { | ||
| 363 | .name = "cros-ec-spi", | ||
| 364 | .owner = THIS_MODULE, | ||
| 365 | .pm = &cros_ec_spi_pm_ops, | ||
| 366 | }, | ||
| 367 | .probe = cros_ec_probe_spi, | ||
| 368 | .remove = cros_ec_remove_spi, | ||
| 369 | .id_table = cros_ec_spi_id, | ||
| 370 | }; | ||
| 371 | |||
| 372 | module_spi_driver(cros_ec_driver_spi); | ||
| 373 | |||
| 374 | MODULE_LICENSE("GPL"); | ||
| 375 | MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)"); | ||
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 05176cd2862b..f1a316e0d6a6 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c | |||
| @@ -499,7 +499,8 @@ static int da903x_probe(struct i2c_client *client, | |||
| 499 | unsigned int tmp; | 499 | unsigned int tmp; |
| 500 | int ret; | 500 | int ret; |
| 501 | 501 | ||
| 502 | chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); | 502 | chip = devm_kzalloc(&client->dev, sizeof(struct da903x_chip), |
| 503 | GFP_KERNEL); | ||
| 503 | if (chip == NULL) | 504 | if (chip == NULL) |
| 504 | return -ENOMEM; | 505 | return -ENOMEM; |
| 505 | 506 | ||
| @@ -515,33 +516,27 @@ static int da903x_probe(struct i2c_client *client, | |||
| 515 | 516 | ||
| 516 | ret = chip->ops->init_chip(chip); | 517 | ret = chip->ops->init_chip(chip); |
| 517 | if (ret) | 518 | if (ret) |
| 518 | goto out_free_chip; | 519 | return ret; |
| 519 | 520 | ||
| 520 | /* mask and clear all IRQs */ | 521 | /* mask and clear all IRQs */ |
| 521 | chip->events_mask = 0xffffffff; | 522 | chip->events_mask = 0xffffffff; |
| 522 | chip->ops->mask_events(chip, chip->events_mask); | 523 | chip->ops->mask_events(chip, chip->events_mask); |
| 523 | chip->ops->read_events(chip, &tmp); | 524 | chip->ops->read_events(chip, &tmp); |
| 524 | 525 | ||
| 525 | ret = request_irq(client->irq, da903x_irq_handler, | 526 | ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler, |
| 526 | IRQF_TRIGGER_FALLING, | 527 | IRQF_TRIGGER_FALLING, |
| 527 | "da903x", chip); | 528 | "da903x", chip); |
| 528 | if (ret) { | 529 | if (ret) { |
| 529 | dev_err(&client->dev, "failed to request irq %d\n", | 530 | dev_err(&client->dev, "failed to request irq %d\n", |
| 530 | client->irq); | 531 | client->irq); |
| 531 | goto out_free_chip; | 532 | return ret; |
| 532 | } | 533 | } |
| 533 | 534 | ||
| 534 | ret = da903x_add_subdevs(chip, pdata); | 535 | ret = da903x_add_subdevs(chip, pdata); |
| 535 | if (ret) | 536 | if (ret) |
| 536 | goto out_free_irq; | 537 | return ret; |
| 537 | 538 | ||
| 538 | return 0; | 539 | return 0; |
| 539 | |||
| 540 | out_free_irq: | ||
| 541 | free_irq(client->irq, chip); | ||
| 542 | out_free_chip: | ||
| 543 | kfree(chip); | ||
| 544 | return ret; | ||
| 545 | } | 540 | } |
| 546 | 541 | ||
| 547 | static int da903x_remove(struct i2c_client *client) | 542 | static int da903x_remove(struct i2c_client *client) |
| @@ -549,8 +544,6 @@ static int da903x_remove(struct i2c_client *client) | |||
| 549 | struct da903x_chip *chip = i2c_get_clientdata(client); | 544 | struct da903x_chip *chip = i2c_get_clientdata(client); |
| 550 | 545 | ||
| 551 | da903x_remove_subdevs(chip); | 546 | da903x_remove_subdevs(chip); |
| 552 | free_irq(client->irq, chip); | ||
| 553 | kfree(chip); | ||
| 554 | return 0; | 547 | return 0; |
| 555 | } | 548 | } |
| 556 | 549 | ||
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index 61d63b93576c..0680bcbc53de 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c | |||
| @@ -38,7 +38,7 @@ static int da9052_spi_probe(struct spi_device *spi) | |||
| 38 | da9052->dev = &spi->dev; | 38 | da9052->dev = &spi->dev; |
| 39 | da9052->chip_irq = spi->irq; | 39 | da9052->chip_irq = spi->irq; |
| 40 | 40 | ||
| 41 | dev_set_drvdata(&spi->dev, da9052); | 41 | spi_set_drvdata(spi, da9052); |
| 42 | 42 | ||
| 43 | da9052_regmap_config.read_flag_mask = 1; | 43 | da9052_regmap_config.read_flag_mask = 1; |
| 44 | da9052_regmap_config.write_flag_mask = 0; | 44 | da9052_regmap_config.write_flag_mask = 0; |
| @@ -60,7 +60,7 @@ static int da9052_spi_probe(struct spi_device *spi) | |||
| 60 | 60 | ||
| 61 | static int da9052_spi_remove(struct spi_device *spi) | 61 | static int da9052_spi_remove(struct spi_device *spi) |
| 62 | { | 62 | { |
| 63 | struct da9052 *da9052 = dev_get_drvdata(&spi->dev); | 63 | struct da9052 *da9052 = spi_get_drvdata(spi); |
| 64 | 64 | ||
| 65 | da9052_device_exit(da9052); | 65 | da9052_device_exit(da9052); |
| 66 | return 0; | 66 | return 0; |
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index f56a1a9f7777..49cb23d37469 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c | |||
| @@ -391,7 +391,7 @@ int da9055_device_init(struct da9055 *da9055) | |||
| 391 | da9055->irq_base = pdata->irq_base; | 391 | da9055->irq_base = pdata->irq_base; |
| 392 | 392 | ||
| 393 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, | 393 | ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, |
| 394 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | 394 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
| 395 | da9055->irq_base, &da9055_regmap_irq_chip, | 395 | da9055->irq_base, &da9055_regmap_irq_chip, |
| 396 | &da9055->irq_data); | 396 | &da9055->irq_data); |
| 397 | if (ret < 0) | 397 | if (ret < 0) |
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index c0bcc872af4e..c60ab0c3c4db 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c | |||
| @@ -177,17 +177,7 @@ static struct platform_driver davinci_vc_driver = { | |||
| 177 | .remove = davinci_vc_remove, | 177 | .remove = davinci_vc_remove, |
| 178 | }; | 178 | }; |
| 179 | 179 | ||
| 180 | static int __init davinci_vc_init(void) | 180 | module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe); |
| 181 | { | ||
| 182 | return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe); | ||
| 183 | } | ||
| 184 | module_init(davinci_vc_init); | ||
| 185 | |||
| 186 | static void __exit davinci_vc_exit(void) | ||
| 187 | { | ||
| 188 | platform_driver_unregister(&davinci_vc_driver); | ||
| 189 | } | ||
| 190 | module_exit(davinci_vc_exit); | ||
| 191 | 181 | ||
| 192 | MODULE_AUTHOR("Miguel Aguilar"); | 182 | MODULE_AUTHOR("Miguel Aguilar"); |
| 193 | MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); | 183 | MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); |
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 21434beb420a..319b8abe742b 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/jiffies.h> | 24 | #include <linux/jiffies.h> |
| 25 | #include <linux/bitops.h> | 25 | #include <linux/bitops.h> |
| 26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
| 27 | #include <linux/of.h> | ||
| 27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
| 28 | #include <linux/uaccess.h> | 29 | #include <linux/uaccess.h> |
| 29 | #include <linux/mfd/core.h> | 30 | #include <linux/mfd/core.h> |
| @@ -2704,6 +2705,7 @@ static void dbx500_fw_version_init(struct platform_device *pdev, | |||
| 2704 | { | 2705 | { |
| 2705 | struct resource *res; | 2706 | struct resource *res; |
| 2706 | void __iomem *tcpm_base; | 2707 | void __iomem *tcpm_base; |
| 2708 | u32 version; | ||
| 2707 | 2709 | ||
| 2708 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 2710 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 2709 | "prcmu-tcpm"); | 2711 | "prcmu-tcpm"); |
| @@ -2713,26 +2715,27 @@ static void dbx500_fw_version_init(struct platform_device *pdev, | |||
| 2713 | return; | 2715 | return; |
| 2714 | } | 2716 | } |
| 2715 | tcpm_base = ioremap(res->start, resource_size(res)); | 2717 | tcpm_base = ioremap(res->start, resource_size(res)); |
| 2716 | if (tcpm_base != NULL) { | 2718 | if (!tcpm_base) { |
| 2717 | u32 version; | 2719 | dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n"); |
| 2718 | 2720 | return; | |
| 2719 | version = readl(tcpm_base + version_offset); | ||
| 2720 | fw_info.version.project = (version & 0xFF); | ||
| 2721 | fw_info.version.api_version = (version >> 8) & 0xFF; | ||
| 2722 | fw_info.version.func_version = (version >> 16) & 0xFF; | ||
| 2723 | fw_info.version.errata = (version >> 24) & 0xFF; | ||
| 2724 | strncpy(fw_info.version.project_name, | ||
| 2725 | fw_project_name(fw_info.version.project), | ||
| 2726 | PRCMU_FW_PROJECT_NAME_LEN); | ||
| 2727 | fw_info.valid = true; | ||
| 2728 | pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", | ||
| 2729 | fw_info.version.project_name, | ||
| 2730 | fw_info.version.project, | ||
| 2731 | fw_info.version.api_version, | ||
| 2732 | fw_info.version.func_version, | ||
| 2733 | fw_info.version.errata); | ||
| 2734 | iounmap(tcpm_base); | ||
| 2735 | } | 2721 | } |
| 2722 | |||
| 2723 | version = readl(tcpm_base + version_offset); | ||
| 2724 | fw_info.version.project = (version & 0xFF); | ||
| 2725 | fw_info.version.api_version = (version >> 8) & 0xFF; | ||
| 2726 | fw_info.version.func_version = (version >> 16) & 0xFF; | ||
| 2727 | fw_info.version.errata = (version >> 24) & 0xFF; | ||
| 2728 | strncpy(fw_info.version.project_name, | ||
| 2729 | fw_project_name(fw_info.version.project), | ||
| 2730 | PRCMU_FW_PROJECT_NAME_LEN); | ||
| 2731 | fw_info.valid = true; | ||
| 2732 | pr_info("PRCMU firmware: %s(%d), version %d.%d.%d\n", | ||
| 2733 | fw_info.version.project_name, | ||
| 2734 | fw_info.version.project, | ||
| 2735 | fw_info.version.api_version, | ||
| 2736 | fw_info.version.func_version, | ||
| 2737 | fw_info.version.errata); | ||
| 2738 | iounmap(tcpm_base); | ||
| 2736 | } | 2739 | } |
| 2737 | 2740 | ||
| 2738 | void __init db8500_prcmu_early_init(u32 phy_base, u32 size) | 2741 | void __init db8500_prcmu_early_init(u32 phy_base, u32 size) |
| @@ -3065,6 +3068,15 @@ static struct db8500_thsens_platform_data db8500_thsens_data = { | |||
| 3065 | .num_trips = 4, | 3068 | .num_trips = 4, |
| 3066 | }; | 3069 | }; |
| 3067 | 3070 | ||
| 3071 | static struct mfd_cell common_prcmu_devs[] = { | ||
| 3072 | { | ||
| 3073 | .name = "ux500_wdt", | ||
| 3074 | .platform_data = &db8500_wdt_pdata, | ||
| 3075 | .pdata_size = sizeof(db8500_wdt_pdata), | ||
| 3076 | .id = -1, | ||
| 3077 | }, | ||
| 3078 | }; | ||
| 3079 | |||
| 3068 | static struct mfd_cell db8500_prcmu_devs[] = { | 3080 | static struct mfd_cell db8500_prcmu_devs[] = { |
| 3069 | { | 3081 | { |
| 3070 | .name = "db8500-prcmu-regulators", | 3082 | .name = "db8500-prcmu-regulators", |
| @@ -3079,12 +3091,6 @@ static struct mfd_cell db8500_prcmu_devs[] = { | |||
| 3079 | .pdata_size = sizeof(db8500_cpufreq_table), | 3091 | .pdata_size = sizeof(db8500_cpufreq_table), |
| 3080 | }, | 3092 | }, |
| 3081 | { | 3093 | { |
| 3082 | .name = "ux500_wdt", | ||
| 3083 | .platform_data = &db8500_wdt_pdata, | ||
| 3084 | .pdata_size = sizeof(db8500_wdt_pdata), | ||
| 3085 | .id = -1, | ||
| 3086 | }, | ||
| 3087 | { | ||
| 3088 | .name = "db8500-thermal", | 3094 | .name = "db8500-thermal", |
| 3089 | .num_resources = ARRAY_SIZE(db8500_thsens_resources), | 3095 | .num_resources = ARRAY_SIZE(db8500_thsens_resources), |
| 3090 | .resources = db8500_thsens_resources, | 3096 | .resources = db8500_thsens_resources, |
| @@ -3173,13 +3179,25 @@ static int db8500_prcmu_probe(struct platform_device *pdev) | |||
| 3173 | 3179 | ||
| 3174 | db8500_prcmu_update_cpufreq(); | 3180 | db8500_prcmu_update_cpufreq(); |
| 3175 | 3181 | ||
| 3176 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | 3182 | err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs, |
| 3177 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, db8500_irq_domain); | 3183 | ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain); |
| 3178 | if (err) { | 3184 | if (err) { |
| 3179 | pr_err("prcmu: Failed to add subdevices\n"); | 3185 | pr_err("prcmu: Failed to add subdevices\n"); |
| 3180 | return err; | 3186 | return err; |
| 3181 | } | 3187 | } |
| 3182 | 3188 | ||
| 3189 | /* TODO: Remove restriction when clk definitions are available. */ | ||
| 3190 | if (!of_machine_is_compatible("st-ericsson,u8540")) { | ||
| 3191 | err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, | ||
| 3192 | ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, | ||
| 3193 | db8500_irq_domain); | ||
| 3194 | if (err) { | ||
| 3195 | mfd_remove_devices(&pdev->dev); | ||
| 3196 | pr_err("prcmu: Failed to add subdevices\n"); | ||
| 3197 | goto no_irq_return; | ||
| 3198 | } | ||
| 3199 | } | ||
| 3200 | |||
| 3183 | err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, | 3201 | err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, |
| 3184 | pdata->ab_irq); | 3202 | pdata->ab_irq); |
| 3185 | if (err) { | 3203 | if (err) { |
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index b7a61f0f27a4..5502106ad515 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
| @@ -393,7 +393,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, | |||
| 393 | 393 | ||
| 394 | static int ezx_pcap_remove(struct spi_device *spi) | 394 | static int ezx_pcap_remove(struct spi_device *spi) |
| 395 | { | 395 | { |
| 396 | struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); | 396 | struct pcap_chip *pcap = spi_get_drvdata(spi); |
| 397 | struct pcap_platform_data *pdata = spi->dev.platform_data; | 397 | struct pcap_platform_data *pdata = spi->dev.platform_data; |
| 398 | int i, adc_irq; | 398 | int i, adc_irq; |
| 399 | 399 | ||
| @@ -403,7 +403,7 @@ static int ezx_pcap_remove(struct spi_device *spi) | |||
| 403 | /* cleanup ADC */ | 403 | /* cleanup ADC */ |
| 404 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 404 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
| 405 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); | 405 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); |
| 406 | free_irq(adc_irq, pcap); | 406 | devm_free_irq(&spi->dev, adc_irq, pcap); |
| 407 | mutex_lock(&pcap->adc_mutex); | 407 | mutex_lock(&pcap->adc_mutex); |
| 408 | for (i = 0; i < PCAP_ADC_MAXQ; i++) | 408 | for (i = 0; i < PCAP_ADC_MAXQ; i++) |
| 409 | kfree(pcap->adc_queue[i]); | 409 | kfree(pcap->adc_queue[i]); |
| @@ -415,8 +415,6 @@ static int ezx_pcap_remove(struct spi_device *spi) | |||
| 415 | 415 | ||
| 416 | destroy_workqueue(pcap->workqueue); | 416 | destroy_workqueue(pcap->workqueue); |
| 417 | 417 | ||
| 418 | kfree(pcap); | ||
| 419 | |||
| 420 | return 0; | 418 | return 0; |
| 421 | } | 419 | } |
| 422 | 420 | ||
| @@ -431,7 +429,7 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
| 431 | if (!pdata) | 429 | if (!pdata) |
| 432 | goto ret; | 430 | goto ret; |
| 433 | 431 | ||
| 434 | pcap = kzalloc(sizeof(*pcap), GFP_KERNEL); | 432 | pcap = devm_kzalloc(&spi->dev, sizeof(*pcap), GFP_KERNEL); |
| 435 | if (!pcap) { | 433 | if (!pcap) { |
| 436 | ret = -ENOMEM; | 434 | ret = -ENOMEM; |
| 437 | goto ret; | 435 | goto ret; |
| @@ -441,14 +439,14 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
| 441 | mutex_init(&pcap->adc_mutex); | 439 | mutex_init(&pcap->adc_mutex); |
| 442 | INIT_WORK(&pcap->isr_work, pcap_isr_work); | 440 | INIT_WORK(&pcap->isr_work, pcap_isr_work); |
| 443 | INIT_WORK(&pcap->msr_work, pcap_msr_work); | 441 | INIT_WORK(&pcap->msr_work, pcap_msr_work); |
| 444 | dev_set_drvdata(&spi->dev, pcap); | 442 | spi_set_drvdata(spi, pcap); |
| 445 | 443 | ||
| 446 | /* setup spi */ | 444 | /* setup spi */ |
| 447 | spi->bits_per_word = 32; | 445 | spi->bits_per_word = 32; |
| 448 | spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); | 446 | spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); |
| 449 | ret = spi_setup(spi); | 447 | ret = spi_setup(spi); |
| 450 | if (ret) | 448 | if (ret) |
| 451 | goto free_pcap; | 449 | goto ret; |
| 452 | 450 | ||
| 453 | pcap->spi = spi; | 451 | pcap->spi = spi; |
| 454 | 452 | ||
| @@ -458,7 +456,7 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
| 458 | if (!pcap->workqueue) { | 456 | if (!pcap->workqueue) { |
| 459 | ret = -ENOMEM; | 457 | ret = -ENOMEM; |
| 460 | dev_err(&spi->dev, "can't create pcap thread\n"); | 458 | dev_err(&spi->dev, "can't create pcap thread\n"); |
| 461 | goto free_pcap; | 459 | goto ret; |
| 462 | } | 460 | } |
| 463 | 461 | ||
| 464 | /* redirect interrupts to AP, except adcdone2 */ | 462 | /* redirect interrupts to AP, except adcdone2 */ |
| @@ -491,7 +489,8 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
| 491 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? | 489 | adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? |
| 492 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); | 490 | PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); |
| 493 | 491 | ||
| 494 | ret = request_irq(adc_irq, pcap_adc_irq, 0, "ADC", pcap); | 492 | ret = devm_request_irq(&spi->dev, adc_irq, pcap_adc_irq, 0, "ADC", |
| 493 | pcap); | ||
| 495 | if (ret) | 494 | if (ret) |
| 496 | goto free_irqchip; | 495 | goto free_irqchip; |
| 497 | 496 | ||
| @@ -511,14 +510,12 @@ static int ezx_pcap_probe(struct spi_device *spi) | |||
| 511 | remove_subdevs: | 510 | remove_subdevs: |
| 512 | device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); | 511 | device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); |
| 513 | /* free_adc: */ | 512 | /* free_adc: */ |
| 514 | free_irq(adc_irq, pcap); | 513 | devm_free_irq(&spi->dev, adc_irq, pcap); |
| 515 | free_irqchip: | 514 | free_irqchip: |
| 516 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) | 515 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
| 517 | irq_set_chip_and_handler(i, NULL, NULL); | 516 | irq_set_chip_and_handler(i, NULL, NULL); |
| 518 | /* destroy_workqueue: */ | 517 | /* destroy_workqueue: */ |
| 519 | destroy_workqueue(pcap->workqueue); | 518 | destroy_workqueue(pcap->workqueue); |
| 520 | free_pcap: | ||
| 521 | kfree(pcap); | ||
| 522 | ret: | 519 | ret: |
| 523 | return ret; | 520 | return ret; |
| 524 | } | 521 | } |
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 9e5453d21a68..0285fceb99a6 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c | |||
| @@ -208,18 +208,7 @@ static struct platform_driver pasic3_driver = { | |||
| 208 | .remove = pasic3_remove, | 208 | .remove = pasic3_remove, |
| 209 | }; | 209 | }; |
| 210 | 210 | ||
| 211 | static int __init pasic3_base_init(void) | 211 | module_platform_driver_probe(pasic3_driver, pasic3_probe); |
| 212 | { | ||
| 213 | return platform_driver_probe(&pasic3_driver, pasic3_probe); | ||
| 214 | } | ||
| 215 | |||
| 216 | static void __exit pasic3_base_exit(void) | ||
| 217 | { | ||
| 218 | platform_driver_unregister(&pasic3_driver); | ||
| 219 | } | ||
| 220 | |||
| 221 | module_init(pasic3_base_init); | ||
| 222 | module_exit(pasic3_base_exit); | ||
| 223 | 212 | ||
| 224 | MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); | 213 | MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); |
| 225 | MODULE_DESCRIPTION("Core driver for HTC PASIC3"); | 214 | MODULE_DESCRIPTION("Core driver for HTC PASIC3"); |
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 1804331bd52c..5be3b5e13855 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c | |||
| @@ -323,7 +323,8 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
| 323 | if (pdata->ocd) { | 323 | if (pdata->ocd) { |
| 324 | unsigned gpio = pdata->ocd->gpio; | 324 | unsigned gpio = pdata->ocd->gpio; |
| 325 | 325 | ||
| 326 | ret = gpio_request_one(gpio, GPIOF_IN, "ocd_gpio"); | 326 | ret = devm_gpio_request_one(&pdev->dev, gpio, |
| 327 | GPIOF_IN, "ocd_gpio"); | ||
| 327 | if (ret) { | 328 | if (ret) { |
| 328 | dev_err(&pdev->dev, "failed to register OCD GPIO\n"); | 329 | dev_err(&pdev->dev, "failed to register OCD GPIO\n"); |
| 329 | return ret; | 330 | return ret; |
| @@ -332,7 +333,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
| 332 | ret = gpio_to_irq(gpio); | 333 | ret = gpio_to_irq(gpio); |
| 333 | if (ret < 0) { | 334 | if (ret < 0) { |
| 334 | dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); | 335 | dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); |
| 335 | gpio_free(gpio); | ||
| 336 | return ret; | 336 | return ret; |
| 337 | } | 337 | } |
| 338 | 338 | ||
| @@ -359,8 +359,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) | |||
| 359 | 359 | ||
| 360 | fail: | 360 | fail: |
| 361 | mfd_remove_devices(&pdev->dev); | 361 | mfd_remove_devices(&pdev->dev); |
| 362 | if (pdata->ocd) | ||
| 363 | gpio_free(pdata->ocd->gpio); | ||
| 364 | 362 | ||
| 365 | return ret; | 363 | return ret; |
| 366 | } | 364 | } |
| @@ -368,12 +366,8 @@ fail: | |||
| 368 | static void intel_msic_remove_devices(struct intel_msic *msic) | 366 | static void intel_msic_remove_devices(struct intel_msic *msic) |
| 369 | { | 367 | { |
| 370 | struct platform_device *pdev = msic->pdev; | 368 | struct platform_device *pdev = msic->pdev; |
| 371 | struct intel_msic_platform_data *pdata = pdev->dev.platform_data; | ||
| 372 | 369 | ||
| 373 | mfd_remove_devices(&pdev->dev); | 370 | mfd_remove_devices(&pdev->dev); |
| 374 | |||
| 375 | if (pdata->ocd) | ||
| 376 | gpio_free(pdata->ocd->gpio); | ||
| 377 | } | 371 | } |
| 378 | 372 | ||
| 379 | static int intel_msic_probe(struct platform_device *pdev) | 373 | static int intel_msic_probe(struct platform_device *pdev) |
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index ceebf2c1ea97..4b7e6dac1de8 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c | |||
| @@ -496,8 +496,8 @@ static int lm3533_device_init(struct lm3533 *lm3533) | |||
| 496 | dev_set_drvdata(lm3533->dev, lm3533); | 496 | dev_set_drvdata(lm3533->dev, lm3533); |
| 497 | 497 | ||
| 498 | if (gpio_is_valid(lm3533->gpio_hwen)) { | 498 | if (gpio_is_valid(lm3533->gpio_hwen)) { |
| 499 | ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, | 499 | ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, |
| 500 | "lm3533-hwen"); | 500 | GPIOF_OUT_INIT_LOW, "lm3533-hwen"); |
| 501 | if (ret < 0) { | 501 | if (ret < 0) { |
| 502 | dev_err(lm3533->dev, | 502 | dev_err(lm3533->dev, |
| 503 | "failed to request HWEN GPIO %d\n", | 503 | "failed to request HWEN GPIO %d\n", |
| @@ -528,8 +528,6 @@ err_unregister: | |||
| 528 | mfd_remove_devices(lm3533->dev); | 528 | mfd_remove_devices(lm3533->dev); |
| 529 | err_disable: | 529 | err_disable: |
| 530 | lm3533_disable(lm3533); | 530 | lm3533_disable(lm3533); |
| 531 | if (gpio_is_valid(lm3533->gpio_hwen)) | ||
| 532 | gpio_free(lm3533->gpio_hwen); | ||
| 533 | 531 | ||
| 534 | return ret; | 532 | return ret; |
| 535 | } | 533 | } |
| @@ -542,8 +540,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533) | |||
| 542 | 540 | ||
| 543 | mfd_remove_devices(lm3533->dev); | 541 | mfd_remove_devices(lm3533->dev); |
| 544 | lm3533_disable(lm3533); | 542 | lm3533_disable(lm3533); |
| 545 | if (gpio_is_valid(lm3533->gpio_hwen)) | ||
| 546 | gpio_free(lm3533->gpio_hwen); | ||
| 547 | } | 543 | } |
| 548 | 544 | ||
| 549 | static bool lm3533_readable_register(struct device *dev, unsigned int reg) | 545 | static bool lm3533_readable_register(struct device *dev, unsigned int reg) |
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 4d73963cd8f0..1cbb17609c8b 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c | |||
| @@ -46,7 +46,7 @@ static struct regmap_config max77686_regmap_config = { | |||
| 46 | 46 | ||
| 47 | #ifdef CONFIG_OF | 47 | #ifdef CONFIG_OF |
| 48 | static struct of_device_id max77686_pmic_dt_match[] = { | 48 | static struct of_device_id max77686_pmic_dt_match[] = { |
| 49 | {.compatible = "maxim,max77686", .data = 0}, | 49 | {.compatible = "maxim,max77686", .data = NULL}, |
| 50 | {}, | 50 | {}, |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 3032bae20b62..77189daadf1e 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c | |||
| @@ -131,7 +131,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
| 131 | if (!mc13xxx) | 131 | if (!mc13xxx) |
| 132 | return -ENOMEM; | 132 | return -ENOMEM; |
| 133 | 133 | ||
| 134 | dev_set_drvdata(&spi->dev, mc13xxx); | 134 | spi_set_drvdata(spi, mc13xxx); |
| 135 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | 135 | spi->mode = SPI_MODE_0 | SPI_CS_HIGH; |
| 136 | 136 | ||
| 137 | mc13xxx->dev = &spi->dev; | 137 | mc13xxx->dev = &spi->dev; |
| @@ -144,7 +144,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
| 144 | ret = PTR_ERR(mc13xxx->regmap); | 144 | ret = PTR_ERR(mc13xxx->regmap); |
| 145 | dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", | 145 | dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", |
| 146 | ret); | 146 | ret); |
| 147 | dev_set_drvdata(&spi->dev, NULL); | 147 | spi_set_drvdata(spi, NULL); |
| 148 | return ret; | 148 | return ret; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| @@ -164,7 +164,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) | |||
| 164 | 164 | ||
| 165 | static int mc13xxx_spi_remove(struct spi_device *spi) | 165 | static int mc13xxx_spi_remove(struct spi_device *spi) |
| 166 | { | 166 | { |
| 167 | struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); | 167 | struct mc13xxx *mc13xxx = spi_get_drvdata(spi); |
| 168 | 168 | ||
| 169 | mc13xxx_common_cleanup(mc13xxx); | 169 | mc13xxx_common_cleanup(mc13xxx); |
| 170 | 170 | ||
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 4febc5c7fdee..759fae3ca7fb 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI | 2 | * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com | 4 | * Copyright (C) 2011-2013 Texas Instruments Incorporated - http://www.ti.com |
| 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
| 6 | * Author: Roger Quadros <rogerq@ti.com> | ||
| 6 | * | 7 | * |
| 7 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 of | 9 | * it under the terms of the GNU General Public License version 2 of |
| @@ -27,6 +28,9 @@ | |||
| 27 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
| 28 | #include <linux/platform_data/usb-omap.h> | 29 | #include <linux/platform_data/usb-omap.h> |
| 29 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
| 31 | #include <linux/of.h> | ||
| 32 | #include <linux/of_platform.h> | ||
| 33 | #include <linux/err.h> | ||
| 30 | 34 | ||
| 31 | #include "omap-usb.h" | 35 | #include "omap-usb.h" |
| 32 | 36 | ||
| @@ -137,6 +141,49 @@ static inline u8 usbhs_readb(void __iomem *base, u8 reg) | |||
| 137 | 141 | ||
| 138 | /*-------------------------------------------------------------------------*/ | 142 | /*-------------------------------------------------------------------------*/ |
| 139 | 143 | ||
| 144 | /** | ||
| 145 | * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h> | ||
| 146 | * to the device tree binding portN-mode found in | ||
| 147 | * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt' | ||
| 148 | */ | ||
| 149 | static const char * const port_modes[] = { | ||
| 150 | [OMAP_USBHS_PORT_MODE_UNUSED] = "", | ||
| 151 | [OMAP_EHCI_PORT_MODE_PHY] = "ehci-phy", | ||
| 152 | [OMAP_EHCI_PORT_MODE_TLL] = "ehci-tll", | ||
| 153 | [OMAP_EHCI_PORT_MODE_HSIC] = "ehci-hsic", | ||
| 154 | [OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0] = "ohci-phy-6pin-datse0", | ||
| 155 | [OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM] = "ohci-phy-6pin-dpdm", | ||
| 156 | [OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0] = "ohci-phy-3pin-datse0", | ||
| 157 | [OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM] = "ohci-phy-4pin-dpdm", | ||
| 158 | [OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0] = "ohci-tll-6pin-datse0", | ||
| 159 | [OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM] = "ohci-tll-6pin-dpdm", | ||
| 160 | [OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0] = "ohci-tll-3pin-datse0", | ||
| 161 | [OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM] = "ohci-tll-4pin-dpdm", | ||
| 162 | [OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0] = "ohci-tll-2pin-datse0", | ||
| 163 | [OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM] = "ohci-tll-2pin-dpdm", | ||
| 164 | }; | ||
| 165 | |||
| 166 | /** | ||
| 167 | * omap_usbhs_get_dt_port_mode - Get the 'enum usbhs_omap_port_mode' | ||
| 168 | * from the port mode string. | ||
| 169 | * @mode: The port mode string, usually obtained from device tree. | ||
| 170 | * | ||
| 171 | * The function returns the 'enum usbhs_omap_port_mode' that matches the | ||
| 172 | * provided port mode string as per the port_modes table. | ||
| 173 | * If no match is found it returns -ENODEV | ||
| 174 | */ | ||
| 175 | static const int omap_usbhs_get_dt_port_mode(const char *mode) | ||
| 176 | { | ||
| 177 | int i; | ||
| 178 | |||
| 179 | for (i = 0; i < ARRAY_SIZE(port_modes); i++) { | ||
| 180 | if (!strcmp(mode, port_modes[i])) | ||
| 181 | return i; | ||
| 182 | } | ||
| 183 | |||
| 184 | return -ENODEV; | ||
| 185 | } | ||
| 186 | |||
| 140 | static struct platform_device *omap_usbhs_alloc_child(const char *name, | 187 | static struct platform_device *omap_usbhs_alloc_child(const char *name, |
| 141 | struct resource *res, int num_resources, void *pdata, | 188 | struct resource *res, int num_resources, void *pdata, |
| 142 | size_t pdata_size, struct device *dev) | 189 | size_t pdata_size, struct device *dev) |
| @@ -278,7 +325,7 @@ static int usbhs_runtime_resume(struct device *dev) | |||
| 278 | 325 | ||
| 279 | dev_dbg(dev, "usbhs_runtime_resume\n"); | 326 | dev_dbg(dev, "usbhs_runtime_resume\n"); |
| 280 | 327 | ||
| 281 | omap_tll_enable(); | 328 | omap_tll_enable(pdata); |
| 282 | 329 | ||
| 283 | if (!IS_ERR(omap->ehci_logic_fck)) | 330 | if (!IS_ERR(omap->ehci_logic_fck)) |
| 284 | clk_enable(omap->ehci_logic_fck); | 331 | clk_enable(omap->ehci_logic_fck); |
| @@ -353,7 +400,7 @@ static int usbhs_runtime_suspend(struct device *dev) | |||
| 353 | if (!IS_ERR(omap->ehci_logic_fck)) | 400 | if (!IS_ERR(omap->ehci_logic_fck)) |
| 354 | clk_disable(omap->ehci_logic_fck); | 401 | clk_disable(omap->ehci_logic_fck); |
| 355 | 402 | ||
| 356 | omap_tll_disable(); | 403 | omap_tll_disable(pdata); |
| 357 | 404 | ||
| 358 | return 0; | 405 | return 0; |
| 359 | } | 406 | } |
| @@ -430,24 +477,10 @@ static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap, | |||
| 430 | static void omap_usbhs_init(struct device *dev) | 477 | static void omap_usbhs_init(struct device *dev) |
| 431 | { | 478 | { |
| 432 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 479 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); |
| 433 | struct usbhs_omap_platform_data *pdata = omap->pdata; | ||
| 434 | unsigned reg; | 480 | unsigned reg; |
| 435 | 481 | ||
| 436 | dev_dbg(dev, "starting TI HSUSB Controller\n"); | 482 | dev_dbg(dev, "starting TI HSUSB Controller\n"); |
| 437 | 483 | ||
| 438 | if (pdata->phy_reset) { | ||
| 439 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | ||
| 440 | gpio_request_one(pdata->reset_gpio_port[0], | ||
| 441 | GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); | ||
| 442 | |||
| 443 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | ||
| 444 | gpio_request_one(pdata->reset_gpio_port[1], | ||
| 445 | GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); | ||
| 446 | |||
| 447 | /* Hold the PHY in RESET for enough time till DIR is high */ | ||
| 448 | udelay(10); | ||
| 449 | } | ||
| 450 | |||
| 451 | pm_runtime_get_sync(dev); | 484 | pm_runtime_get_sync(dev); |
| 452 | 485 | ||
| 453 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); | 486 | reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); |
| @@ -476,36 +509,59 @@ static void omap_usbhs_init(struct device *dev) | |||
| 476 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); | 509 | dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); |
| 477 | 510 | ||
| 478 | pm_runtime_put_sync(dev); | 511 | pm_runtime_put_sync(dev); |
| 479 | if (pdata->phy_reset) { | 512 | } |
| 480 | /* Hold the PHY in RESET for enough time till | 513 | |
| 481 | * PHY is settled and ready | 514 | static int usbhs_omap_get_dt_pdata(struct device *dev, |
| 482 | */ | 515 | struct usbhs_omap_platform_data *pdata) |
| 483 | udelay(10); | 516 | { |
| 517 | int ret, i; | ||
| 518 | struct device_node *node = dev->of_node; | ||
| 484 | 519 | ||
| 485 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | 520 | ret = of_property_read_u32(node, "num-ports", &pdata->nports); |
| 486 | gpio_set_value_cansleep | 521 | if (ret) |
| 487 | (pdata->reset_gpio_port[0], 1); | 522 | pdata->nports = 0; |
| 488 | 523 | ||
| 489 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | 524 | if (pdata->nports > OMAP3_HS_USB_PORTS) { |
| 490 | gpio_set_value_cansleep | 525 | dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d\n", |
| 491 | (pdata->reset_gpio_port[1], 1); | 526 | pdata->nports, OMAP3_HS_USB_PORTS); |
| 527 | return -ENODEV; | ||
| 492 | } | 528 | } |
| 493 | } | ||
| 494 | 529 | ||
| 495 | static void omap_usbhs_deinit(struct device *dev) | 530 | /* get port modes */ |
| 496 | { | 531 | for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { |
| 497 | struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); | 532 | char prop[11]; |
| 498 | struct usbhs_omap_platform_data *pdata = omap->pdata; | 533 | const char *mode; |
| 499 | 534 | ||
| 500 | if (pdata->phy_reset) { | 535 | pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED; |
| 501 | if (gpio_is_valid(pdata->reset_gpio_port[0])) | 536 | |
| 502 | gpio_free(pdata->reset_gpio_port[0]); | 537 | snprintf(prop, sizeof(prop), "port%d-mode", i + 1); |
| 538 | ret = of_property_read_string(node, prop, &mode); | ||
| 539 | if (ret < 0) | ||
| 540 | continue; | ||
| 541 | |||
| 542 | ret = omap_usbhs_get_dt_port_mode(mode); | ||
| 543 | if (ret < 0) { | ||
| 544 | dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n", | ||
| 545 | i, mode); | ||
| 546 | return -ENODEV; | ||
| 547 | } | ||
| 503 | 548 | ||
| 504 | if (gpio_is_valid(pdata->reset_gpio_port[1])) | 549 | dev_dbg(dev, "port%d-mode: %s -> %d\n", i, mode, ret); |
| 505 | gpio_free(pdata->reset_gpio_port[1]); | 550 | pdata->port_mode[i] = ret; |
| 506 | } | 551 | } |
| 552 | |||
| 553 | /* get flags */ | ||
| 554 | pdata->single_ulpi_bypass = of_property_read_bool(node, | ||
| 555 | "single-ulpi-bypass"); | ||
| 556 | |||
| 557 | return 0; | ||
| 507 | } | 558 | } |
| 508 | 559 | ||
| 560 | static struct of_device_id usbhs_child_match_table[] = { | ||
| 561 | { .compatible = "ti,omap-ehci", }, | ||
| 562 | { .compatible = "ti,omap-ohci", }, | ||
| 563 | { } | ||
| 564 | }; | ||
| 509 | 565 | ||
| 510 | /** | 566 | /** |
| 511 | * usbhs_omap_probe - initialize TI-based HCDs | 567 | * usbhs_omap_probe - initialize TI-based HCDs |
| @@ -522,26 +578,46 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 522 | int i; | 578 | int i; |
| 523 | bool need_logic_fck; | 579 | bool need_logic_fck; |
| 524 | 580 | ||
| 581 | if (dev->of_node) { | ||
| 582 | /* For DT boot we populate platform data from OF node */ | ||
| 583 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | ||
| 584 | if (!pdata) | ||
| 585 | return -ENOMEM; | ||
| 586 | |||
| 587 | ret = usbhs_omap_get_dt_pdata(dev, pdata); | ||
| 588 | if (ret) | ||
| 589 | return ret; | ||
| 590 | |||
| 591 | dev->platform_data = pdata; | ||
| 592 | } | ||
| 593 | |||
| 525 | if (!pdata) { | 594 | if (!pdata) { |
| 526 | dev_err(dev, "Missing platform data\n"); | 595 | dev_err(dev, "Missing platform data\n"); |
| 527 | return -ENODEV; | 596 | return -ENODEV; |
| 528 | } | 597 | } |
| 529 | 598 | ||
| 599 | if (pdata->nports > OMAP3_HS_USB_PORTS) { | ||
| 600 | dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n", | ||
| 601 | pdata->nports, OMAP3_HS_USB_PORTS); | ||
| 602 | return -ENODEV; | ||
| 603 | } | ||
| 604 | |||
| 530 | omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); | 605 | omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); |
| 531 | if (!omap) { | 606 | if (!omap) { |
| 532 | dev_err(dev, "Memory allocation failed\n"); | 607 | dev_err(dev, "Memory allocation failed\n"); |
| 533 | return -ENOMEM; | 608 | return -ENOMEM; |
| 534 | } | 609 | } |
| 535 | 610 | ||
| 536 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh"); | 611 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 537 | omap->uhh_base = devm_request_and_ioremap(dev, res); | 612 | omap->uhh_base = devm_ioremap_resource(dev, res); |
| 538 | if (!omap->uhh_base) { | 613 | if (IS_ERR(omap->uhh_base)) |
| 539 | dev_err(dev, "Resource request/ioremap failed\n"); | 614 | return PTR_ERR(omap->uhh_base); |
| 540 | return -EADDRNOTAVAIL; | ||
| 541 | } | ||
| 542 | 615 | ||
| 543 | omap->pdata = pdata; | 616 | omap->pdata = pdata; |
| 544 | 617 | ||
| 618 | /* Initialize the TLL subsystem */ | ||
| 619 | omap_tll_init(pdata); | ||
| 620 | |||
| 545 | pm_runtime_enable(dev); | 621 | pm_runtime_enable(dev); |
| 546 | 622 | ||
| 547 | platform_set_drvdata(pdev, omap); | 623 | platform_set_drvdata(pdev, omap); |
| @@ -575,6 +651,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 575 | omap->usbhs_rev, omap->nports); | 651 | omap->usbhs_rev, omap->nports); |
| 576 | break; | 652 | break; |
| 577 | } | 653 | } |
| 654 | pdata->nports = omap->nports; | ||
| 578 | } | 655 | } |
| 579 | 656 | ||
| 580 | i = sizeof(struct clk *) * omap->nports; | 657 | i = sizeof(struct clk *) * omap->nports; |
| @@ -700,17 +777,28 @@ static int usbhs_omap_probe(struct platform_device *pdev) | |||
| 700 | } | 777 | } |
| 701 | 778 | ||
| 702 | omap_usbhs_init(dev); | 779 | omap_usbhs_init(dev); |
| 703 | ret = omap_usbhs_alloc_children(pdev); | 780 | |
| 704 | if (ret) { | 781 | if (dev->of_node) { |
| 705 | dev_err(dev, "omap_usbhs_alloc_children failed\n"); | 782 | ret = of_platform_populate(dev->of_node, |
| 706 | goto err_alloc; | 783 | usbhs_child_match_table, NULL, dev); |
| 784 | |||
| 785 | if (ret) { | ||
| 786 | dev_err(dev, "Failed to create DT children: %d\n", ret); | ||
| 787 | goto err_alloc; | ||
| 788 | } | ||
| 789 | |||
| 790 | } else { | ||
| 791 | ret = omap_usbhs_alloc_children(pdev); | ||
| 792 | if (ret) { | ||
| 793 | dev_err(dev, "omap_usbhs_alloc_children failed: %d\n", | ||
| 794 | ret); | ||
| 795 | goto err_alloc; | ||
| 796 | } | ||
| 707 | } | 797 | } |
| 708 | 798 | ||
| 709 | return 0; | 799 | return 0; |
| 710 | 800 | ||
| 711 | err_alloc: | 801 | err_alloc: |
| 712 | omap_usbhs_deinit(&pdev->dev); | ||
| 713 | |||
| 714 | for (i = 0; i < omap->nports; i++) { | 802 | for (i = 0; i < omap->nports; i++) { |
| 715 | if (!IS_ERR(omap->utmi_clk[i])) | 803 | if (!IS_ERR(omap->utmi_clk[i])) |
| 716 | clk_put(omap->utmi_clk[i]); | 804 | clk_put(omap->utmi_clk[i]); |
| @@ -744,6 +832,13 @@ err_mem: | |||
| 744 | return ret; | 832 | return ret; |
| 745 | } | 833 | } |
| 746 | 834 | ||
| 835 | static int usbhs_omap_remove_child(struct device *dev, void *data) | ||
| 836 | { | ||
| 837 | dev_info(dev, "unregistering\n"); | ||
| 838 | platform_device_unregister(to_platform_device(dev)); | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 747 | /** | 842 | /** |
| 748 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs | 843 | * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs |
| 749 | * @pdev: USB Host Controller being removed | 844 | * @pdev: USB Host Controller being removed |
| @@ -755,8 +850,6 @@ static int usbhs_omap_remove(struct platform_device *pdev) | |||
| 755 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); | 850 | struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); |
| 756 | int i; | 851 | int i; |
| 757 | 852 | ||
| 758 | omap_usbhs_deinit(&pdev->dev); | ||
| 759 | |||
| 760 | for (i = 0; i < omap->nports; i++) { | 853 | for (i = 0; i < omap->nports; i++) { |
| 761 | if (!IS_ERR(omap->utmi_clk[i])) | 854 | if (!IS_ERR(omap->utmi_clk[i])) |
| 762 | clk_put(omap->utmi_clk[i]); | 855 | clk_put(omap->utmi_clk[i]); |
| @@ -777,6 +870,8 @@ static int usbhs_omap_remove(struct platform_device *pdev) | |||
| 777 | 870 | ||
| 778 | pm_runtime_disable(&pdev->dev); | 871 | pm_runtime_disable(&pdev->dev); |
| 779 | 872 | ||
| 873 | /* remove children */ | ||
| 874 | device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child); | ||
| 780 | return 0; | 875 | return 0; |
| 781 | } | 876 | } |
| 782 | 877 | ||
| @@ -785,16 +880,26 @@ static const struct dev_pm_ops usbhsomap_dev_pm_ops = { | |||
| 785 | .runtime_resume = usbhs_runtime_resume, | 880 | .runtime_resume = usbhs_runtime_resume, |
| 786 | }; | 881 | }; |
| 787 | 882 | ||
| 883 | static const struct of_device_id usbhs_omap_dt_ids[] = { | ||
| 884 | { .compatible = "ti,usbhs-host" }, | ||
| 885 | { } | ||
| 886 | }; | ||
| 887 | |||
| 888 | MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids); | ||
| 889 | |||
| 890 | |||
| 788 | static struct platform_driver usbhs_omap_driver = { | 891 | static struct platform_driver usbhs_omap_driver = { |
| 789 | .driver = { | 892 | .driver = { |
| 790 | .name = (char *)usbhs_driver_name, | 893 | .name = (char *)usbhs_driver_name, |
| 791 | .owner = THIS_MODULE, | 894 | .owner = THIS_MODULE, |
| 792 | .pm = &usbhsomap_dev_pm_ops, | 895 | .pm = &usbhsomap_dev_pm_ops, |
| 896 | .of_match_table = of_match_ptr(usbhs_omap_dt_ids), | ||
| 793 | }, | 897 | }, |
| 794 | .remove = usbhs_omap_remove, | 898 | .remove = usbhs_omap_remove, |
| 795 | }; | 899 | }; |
| 796 | 900 | ||
| 797 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 901 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
| 902 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); | ||
| 798 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | 903 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); |
| 799 | MODULE_LICENSE("GPL v2"); | 904 | MODULE_LICENSE("GPL v2"); |
| 800 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); | 905 | MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI"); |
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 0aef1a768880..e59ac4cbac96 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI | 2 | * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com | 4 | * Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com |
| 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> | 5 | * Author: Keshava Munegowda <keshava_mgowda@ti.com> |
| 6 | * Author: Roger Quadros <rogerq@ti.com> | ||
| 6 | * | 7 | * |
| 7 | * This program is free software: you can redistribute it and/or modify | 8 | * This program is free software: you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 of | 9 | * it under the terms of the GNU General Public License version 2 of |
| @@ -27,6 +28,7 @@ | |||
| 27 | #include <linux/err.h> | 28 | #include <linux/err.h> |
| 28 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
| 29 | #include <linux/platform_data/usb-omap.h> | 30 | #include <linux/platform_data/usb-omap.h> |
| 31 | #include <linux/of.h> | ||
| 30 | 32 | ||
| 31 | #define USBTLL_DRIVER_NAME "usbhs_tll" | 33 | #define USBTLL_DRIVER_NAME "usbhs_tll" |
| 32 | 34 | ||
| @@ -105,8 +107,8 @@ | |||
| 105 | 107 | ||
| 106 | struct usbtll_omap { | 108 | struct usbtll_omap { |
| 107 | int nch; /* num. of channels */ | 109 | int nch; /* num. of channels */ |
| 108 | struct usbhs_omap_platform_data *pdata; | ||
| 109 | struct clk **ch_clk; | 110 | struct clk **ch_clk; |
| 111 | void __iomem *base; | ||
| 110 | }; | 112 | }; |
| 111 | 113 | ||
| 112 | /*-------------------------------------------------------------------------*/ | 114 | /*-------------------------------------------------------------------------*/ |
| @@ -210,14 +212,10 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) | |||
| 210 | static int usbtll_omap_probe(struct platform_device *pdev) | 212 | static int usbtll_omap_probe(struct platform_device *pdev) |
| 211 | { | 213 | { |
| 212 | struct device *dev = &pdev->dev; | 214 | struct device *dev = &pdev->dev; |
| 213 | struct usbhs_omap_platform_data *pdata = dev->platform_data; | ||
| 214 | void __iomem *base; | ||
| 215 | struct resource *res; | 215 | struct resource *res; |
| 216 | struct usbtll_omap *tll; | 216 | struct usbtll_omap *tll; |
| 217 | unsigned reg; | ||
| 218 | int ret = 0; | 217 | int ret = 0; |
| 219 | int i, ver; | 218 | int i, ver; |
| 220 | bool needs_tll; | ||
| 221 | 219 | ||
| 222 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); | 220 | dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); |
| 223 | 221 | ||
| @@ -227,26 +225,16 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
| 227 | return -ENOMEM; | 225 | return -ENOMEM; |
| 228 | } | 226 | } |
| 229 | 227 | ||
| 230 | if (!pdata) { | ||
| 231 | dev_err(dev, "Platform data missing\n"); | ||
| 232 | return -ENODEV; | ||
| 233 | } | ||
| 234 | |||
| 235 | tll->pdata = pdata; | ||
| 236 | |||
| 237 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 228 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 238 | base = devm_request_and_ioremap(dev, res); | 229 | tll->base = devm_ioremap_resource(dev, res); |
| 239 | if (!base) { | 230 | if (IS_ERR(tll->base)) |
| 240 | ret = -EADDRNOTAVAIL; | 231 | return PTR_ERR(tll->base); |
| 241 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); | ||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | 232 | ||
| 245 | platform_set_drvdata(pdev, tll); | 233 | platform_set_drvdata(pdev, tll); |
| 246 | pm_runtime_enable(dev); | 234 | pm_runtime_enable(dev); |
| 247 | pm_runtime_get_sync(dev); | 235 | pm_runtime_get_sync(dev); |
| 248 | 236 | ||
| 249 | ver = usbtll_read(base, OMAP_USBTLL_REVISION); | 237 | ver = usbtll_read(tll->base, OMAP_USBTLL_REVISION); |
| 250 | switch (ver) { | 238 | switch (ver) { |
| 251 | case OMAP_USBTLL_REV1: | 239 | case OMAP_USBTLL_REV1: |
| 252 | case OMAP_USBTLL_REV4: | 240 | case OMAP_USBTLL_REV4: |
| @@ -283,11 +271,85 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
| 283 | dev_dbg(dev, "can't get clock : %s\n", clkname); | 271 | dev_dbg(dev, "can't get clock : %s\n", clkname); |
| 284 | } | 272 | } |
| 285 | 273 | ||
| 274 | pm_runtime_put_sync(dev); | ||
| 275 | /* only after this can omap_tll_enable/disable work */ | ||
| 276 | spin_lock(&tll_lock); | ||
| 277 | tll_dev = dev; | ||
| 278 | spin_unlock(&tll_lock); | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | |||
| 282 | err_clk_alloc: | ||
| 283 | pm_runtime_put_sync(dev); | ||
| 284 | pm_runtime_disable(dev); | ||
| 285 | |||
| 286 | return ret; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
| 291 | * @pdev: USB Host Controller being removed | ||
| 292 | * | ||
| 293 | * Reverses the effect of usbtll_omap_probe(). | ||
| 294 | */ | ||
| 295 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
| 296 | { | ||
| 297 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
| 298 | int i; | ||
| 299 | |||
| 300 | spin_lock(&tll_lock); | ||
| 301 | tll_dev = NULL; | ||
| 302 | spin_unlock(&tll_lock); | ||
| 303 | |||
| 304 | for (i = 0; i < tll->nch; i++) | ||
| 305 | if (!IS_ERR(tll->ch_clk[i])) | ||
| 306 | clk_put(tll->ch_clk[i]); | ||
| 307 | |||
| 308 | pm_runtime_disable(&pdev->dev); | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | static const struct of_device_id usbtll_omap_dt_ids[] = { | ||
| 313 | { .compatible = "ti,usbhs-tll" }, | ||
| 314 | { } | ||
| 315 | }; | ||
| 316 | |||
| 317 | MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids); | ||
| 318 | |||
| 319 | static struct platform_driver usbtll_omap_driver = { | ||
| 320 | .driver = { | ||
| 321 | .name = (char *)usbtll_driver_name, | ||
| 322 | .owner = THIS_MODULE, | ||
| 323 | .of_match_table = of_match_ptr(usbtll_omap_dt_ids), | ||
| 324 | }, | ||
| 325 | .probe = usbtll_omap_probe, | ||
| 326 | .remove = usbtll_omap_remove, | ||
| 327 | }; | ||
| 328 | |||
| 329 | int omap_tll_init(struct usbhs_omap_platform_data *pdata) | ||
| 330 | { | ||
| 331 | int i; | ||
| 332 | bool needs_tll; | ||
| 333 | unsigned reg; | ||
| 334 | struct usbtll_omap *tll; | ||
| 335 | |||
| 336 | spin_lock(&tll_lock); | ||
| 337 | |||
| 338 | if (!tll_dev) { | ||
| 339 | spin_unlock(&tll_lock); | ||
| 340 | return -ENODEV; | ||
| 341 | } | ||
| 342 | |||
| 343 | tll = dev_get_drvdata(tll_dev); | ||
| 344 | |||
| 286 | needs_tll = false; | 345 | needs_tll = false; |
| 287 | for (i = 0; i < tll->nch; i++) | 346 | for (i = 0; i < tll->nch; i++) |
| 288 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); | 347 | needs_tll |= omap_usb_mode_needs_tll(pdata->port_mode[i]); |
| 289 | 348 | ||
| 349 | pm_runtime_get_sync(tll_dev); | ||
| 350 | |||
| 290 | if (needs_tll) { | 351 | if (needs_tll) { |
| 352 | void __iomem *base = tll->base; | ||
| 291 | 353 | ||
| 292 | /* Program Common TLL register */ | 354 | /* Program Common TLL register */ |
| 293 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); | 355 | reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); |
| @@ -336,51 +398,29 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
| 336 | } | 398 | } |
| 337 | } | 399 | } |
| 338 | 400 | ||
| 339 | pm_runtime_put_sync(dev); | 401 | pm_runtime_put_sync(tll_dev); |
| 340 | /* only after this can omap_tll_enable/disable work */ | 402 | |
| 341 | spin_lock(&tll_lock); | ||
| 342 | tll_dev = dev; | ||
| 343 | spin_unlock(&tll_lock); | 403 | spin_unlock(&tll_lock); |
| 344 | 404 | ||
| 345 | return 0; | 405 | return 0; |
| 346 | |||
| 347 | err_clk_alloc: | ||
| 348 | pm_runtime_put_sync(dev); | ||
| 349 | pm_runtime_disable(dev); | ||
| 350 | |||
| 351 | return ret; | ||
| 352 | } | 406 | } |
| 407 | EXPORT_SYMBOL_GPL(omap_tll_init); | ||
| 353 | 408 | ||
| 354 | /** | 409 | int omap_tll_enable(struct usbhs_omap_platform_data *pdata) |
| 355 | * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs | ||
| 356 | * @pdev: USB Host Controller being removed | ||
| 357 | * | ||
| 358 | * Reverses the effect of usbtll_omap_probe(). | ||
| 359 | */ | ||
| 360 | static int usbtll_omap_remove(struct platform_device *pdev) | ||
| 361 | { | 410 | { |
| 362 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | ||
| 363 | int i; | 411 | int i; |
| 412 | struct usbtll_omap *tll; | ||
| 364 | 413 | ||
| 365 | spin_lock(&tll_lock); | 414 | spin_lock(&tll_lock); |
| 366 | tll_dev = NULL; | ||
| 367 | spin_unlock(&tll_lock); | ||
| 368 | 415 | ||
| 369 | for (i = 0; i < tll->nch; i++) | 416 | if (!tll_dev) { |
| 370 | if (!IS_ERR(tll->ch_clk[i])) | 417 | spin_unlock(&tll_lock); |
| 371 | clk_put(tll->ch_clk[i]); | 418 | return -ENODEV; |
| 372 | 419 | } | |
| 373 | pm_runtime_disable(&pdev->dev); | ||
| 374 | return 0; | ||
| 375 | } | ||
| 376 | 420 | ||
| 377 | static int usbtll_runtime_resume(struct device *dev) | 421 | tll = dev_get_drvdata(tll_dev); |
| 378 | { | ||
| 379 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
| 380 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
| 381 | int i; | ||
| 382 | 422 | ||
| 383 | dev_dbg(dev, "usbtll_runtime_resume\n"); | 423 | pm_runtime_get_sync(tll_dev); |
| 384 | 424 | ||
| 385 | for (i = 0; i < tll->nch; i++) { | 425 | for (i = 0; i < tll->nch; i++) { |
| 386 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 426 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
| @@ -391,22 +431,31 @@ static int usbtll_runtime_resume(struct device *dev) | |||
| 391 | 431 | ||
| 392 | r = clk_enable(tll->ch_clk[i]); | 432 | r = clk_enable(tll->ch_clk[i]); |
| 393 | if (r) { | 433 | if (r) { |
| 394 | dev_err(dev, | 434 | dev_err(tll_dev, |
| 395 | "Error enabling ch %d clock: %d\n", i, r); | 435 | "Error enabling ch %d clock: %d\n", i, r); |
| 396 | } | 436 | } |
| 397 | } | 437 | } |
| 398 | } | 438 | } |
| 399 | 439 | ||
| 440 | spin_unlock(&tll_lock); | ||
| 441 | |||
| 400 | return 0; | 442 | return 0; |
| 401 | } | 443 | } |
| 444 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
| 402 | 445 | ||
| 403 | static int usbtll_runtime_suspend(struct device *dev) | 446 | int omap_tll_disable(struct usbhs_omap_platform_data *pdata) |
| 404 | { | 447 | { |
| 405 | struct usbtll_omap *tll = dev_get_drvdata(dev); | ||
| 406 | struct usbhs_omap_platform_data *pdata = tll->pdata; | ||
| 407 | int i; | 448 | int i; |
| 449 | struct usbtll_omap *tll; | ||
| 408 | 450 | ||
| 409 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | 451 | spin_lock(&tll_lock); |
| 452 | |||
| 453 | if (!tll_dev) { | ||
| 454 | spin_unlock(&tll_lock); | ||
| 455 | return -ENODEV; | ||
| 456 | } | ||
| 457 | |||
| 458 | tll = dev_get_drvdata(tll_dev); | ||
| 410 | 459 | ||
| 411 | for (i = 0; i < tll->nch; i++) { | 460 | for (i = 0; i < tll->nch; i++) { |
| 412 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { | 461 | if (omap_usb_mode_needs_tll(pdata->port_mode[i])) { |
| @@ -415,64 +464,16 @@ static int usbtll_runtime_suspend(struct device *dev) | |||
| 415 | } | 464 | } |
| 416 | } | 465 | } |
| 417 | 466 | ||
| 418 | return 0; | 467 | pm_runtime_put_sync(tll_dev); |
| 419 | } | ||
| 420 | |||
| 421 | static const struct dev_pm_ops usbtllomap_dev_pm_ops = { | ||
| 422 | SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, | ||
| 423 | usbtll_runtime_resume, | ||
| 424 | NULL) | ||
| 425 | }; | ||
| 426 | |||
| 427 | static struct platform_driver usbtll_omap_driver = { | ||
| 428 | .driver = { | ||
| 429 | .name = (char *)usbtll_driver_name, | ||
| 430 | .owner = THIS_MODULE, | ||
| 431 | .pm = &usbtllomap_dev_pm_ops, | ||
| 432 | }, | ||
| 433 | .probe = usbtll_omap_probe, | ||
| 434 | .remove = usbtll_omap_remove, | ||
| 435 | }; | ||
| 436 | |||
| 437 | int omap_tll_enable(void) | ||
| 438 | { | ||
| 439 | int ret; | ||
| 440 | |||
| 441 | spin_lock(&tll_lock); | ||
| 442 | |||
| 443 | if (!tll_dev) { | ||
| 444 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
| 445 | ret = -ENODEV; | ||
| 446 | } else { | ||
| 447 | ret = pm_runtime_get_sync(tll_dev); | ||
| 448 | } | ||
| 449 | |||
| 450 | spin_unlock(&tll_lock); | ||
| 451 | |||
| 452 | return ret; | ||
| 453 | } | ||
| 454 | EXPORT_SYMBOL_GPL(omap_tll_enable); | ||
| 455 | |||
| 456 | int omap_tll_disable(void) | ||
| 457 | { | ||
| 458 | int ret; | ||
| 459 | |||
| 460 | spin_lock(&tll_lock); | ||
| 461 | |||
| 462 | if (!tll_dev) { | ||
| 463 | pr_err("%s: OMAP USB TLL not initialized\n", __func__); | ||
| 464 | ret = -ENODEV; | ||
| 465 | } else { | ||
| 466 | ret = pm_runtime_put_sync(tll_dev); | ||
| 467 | } | ||
| 468 | 468 | ||
| 469 | spin_unlock(&tll_lock); | 469 | spin_unlock(&tll_lock); |
| 470 | 470 | ||
| 471 | return ret; | 471 | return 0; |
| 472 | } | 472 | } |
| 473 | EXPORT_SYMBOL_GPL(omap_tll_disable); | 473 | EXPORT_SYMBOL_GPL(omap_tll_disable); |
| 474 | 474 | ||
| 475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); | 475 | MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); |
| 476 | MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); | ||
| 476 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); | 477 | MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); |
| 477 | MODULE_LICENSE("GPL v2"); | 478 | MODULE_LICENSE("GPL v2"); |
| 478 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); | 479 | MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); |
diff --git a/drivers/mfd/omap-usb.h b/drivers/mfd/omap-usb.h index 972aa961b064..2a508b6aeac8 100644 --- a/drivers/mfd/omap-usb.h +++ b/drivers/mfd/omap-usb.h | |||
| @@ -1,2 +1,3 @@ | |||
| 1 | extern int omap_tll_enable(void); | 1 | extern int omap_tll_init(struct usbhs_omap_platform_data *pdata); |
| 2 | extern int omap_tll_disable(void); | 2 | extern int omap_tll_enable(struct usbhs_omap_platform_data *pdata); |
| 3 | extern int omap_tll_disable(struct usbhs_omap_platform_data *pdata); | ||
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 73bf76df1044..53e9fe638d32 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c | |||
| @@ -278,20 +278,20 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, | |||
| 278 | int ret; | 278 | int ret; |
| 279 | u32 prop; | 279 | u32 prop; |
| 280 | 280 | ||
| 281 | ret = of_property_read_u32(node, "ti,mux_pad1", &prop); | 281 | ret = of_property_read_u32(node, "ti,mux-pad1", &prop); |
| 282 | if (!ret) { | 282 | if (!ret) { |
| 283 | pdata->mux_from_pdata = 1; | 283 | pdata->mux_from_pdata = 1; |
| 284 | pdata->pad1 = prop; | 284 | pdata->pad1 = prop; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | ret = of_property_read_u32(node, "ti,mux_pad2", &prop); | 287 | ret = of_property_read_u32(node, "ti,mux-pad2", &prop); |
| 288 | if (!ret) { | 288 | if (!ret) { |
| 289 | pdata->mux_from_pdata = 1; | 289 | pdata->mux_from_pdata = 1; |
| 290 | pdata->pad2 = prop; | 290 | pdata->pad2 = prop; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | /* The default for this register is all masked */ | 293 | /* The default for this register is all masked */ |
| 294 | ret = of_property_read_u32(node, "ti,power_ctrl", &prop); | 294 | ret = of_property_read_u32(node, "ti,power-ctrl", &prop); |
| 295 | if (!ret) | 295 | if (!ret) |
| 296 | pdata->power_ctrl = prop; | 296 | pdata->power_ctrl = prop; |
| 297 | else | 297 | else |
| @@ -349,6 +349,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c, | |||
| 349 | ret = -ENOMEM; | 349 | ret = -ENOMEM; |
| 350 | goto err; | 350 | goto err; |
| 351 | } | 351 | } |
| 352 | palmas->i2c_clients[i]->dev.of_node = of_node_get(node); | ||
| 352 | } | 353 | } |
| 353 | palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], | 354 | palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], |
| 354 | &palmas_regmap_config[i]); | 355 | &palmas_regmap_config[i]); |
diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index 3ba048655bf3..a1830986eeb7 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Retu MFD driver | 2 | * Retu/Tahvo MFD driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2004, 2005 Nokia Corporation | 4 | * Copyright (C) 2004, 2005 Nokia Corporation |
| 5 | * | 5 | * |
| @@ -33,7 +33,8 @@ | |||
| 33 | #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ | 33 | #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ |
| 34 | #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ | 34 | #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ |
| 35 | #define RETU_REG_IDR 0x01 /* Interrupt ID */ | 35 | #define RETU_REG_IDR 0x01 /* Interrupt ID */ |
| 36 | #define RETU_REG_IMR 0x02 /* Interrupt mask */ | 36 | #define RETU_REG_IMR 0x02 /* Interrupt mask (Retu) */ |
| 37 | #define TAHVO_REG_IMR 0x03 /* Interrupt mask (Tahvo) */ | ||
| 37 | 38 | ||
| 38 | /* Interrupt sources */ | 39 | /* Interrupt sources */ |
| 39 | #define RETU_INT_PWR 0 /* Power button */ | 40 | #define RETU_INT_PWR 0 /* Power button */ |
| @@ -84,6 +85,62 @@ static struct regmap_irq_chip retu_irq_chip = { | |||
| 84 | /* Retu device registered for the power off. */ | 85 | /* Retu device registered for the power off. */ |
| 85 | static struct retu_dev *retu_pm_power_off; | 86 | static struct retu_dev *retu_pm_power_off; |
| 86 | 87 | ||
| 88 | static struct resource tahvo_usb_res[] = { | ||
| 89 | { | ||
| 90 | .name = "tahvo-usb", | ||
| 91 | .start = TAHVO_INT_VBUS, | ||
| 92 | .end = TAHVO_INT_VBUS, | ||
| 93 | .flags = IORESOURCE_IRQ, | ||
| 94 | }, | ||
| 95 | }; | ||
| 96 | |||
| 97 | static struct mfd_cell tahvo_devs[] = { | ||
| 98 | { | ||
| 99 | .name = "tahvo-usb", | ||
| 100 | .resources = tahvo_usb_res, | ||
| 101 | .num_resources = ARRAY_SIZE(tahvo_usb_res), | ||
| 102 | }, | ||
| 103 | }; | ||
| 104 | |||
| 105 | static struct regmap_irq tahvo_irqs[] = { | ||
| 106 | [TAHVO_INT_VBUS] = { | ||
| 107 | .mask = 1 << TAHVO_INT_VBUS, | ||
| 108 | } | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct regmap_irq_chip tahvo_irq_chip = { | ||
| 112 | .name = "TAHVO", | ||
| 113 | .irqs = tahvo_irqs, | ||
| 114 | .num_irqs = ARRAY_SIZE(tahvo_irqs), | ||
| 115 | .num_regs = 1, | ||
| 116 | .status_base = RETU_REG_IDR, | ||
| 117 | .mask_base = TAHVO_REG_IMR, | ||
| 118 | .ack_base = RETU_REG_IDR, | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const struct retu_data { | ||
| 122 | char *chip_name; | ||
| 123 | char *companion_name; | ||
| 124 | struct regmap_irq_chip *irq_chip; | ||
| 125 | struct mfd_cell *children; | ||
| 126 | int nchildren; | ||
| 127 | } retu_data[] = { | ||
| 128 | [0] = { | ||
| 129 | .chip_name = "Retu", | ||
| 130 | .companion_name = "Vilma", | ||
| 131 | .irq_chip = &retu_irq_chip, | ||
| 132 | .children = retu_devs, | ||
| 133 | .nchildren = ARRAY_SIZE(retu_devs), | ||
| 134 | }, | ||
| 135 | [1] = { | ||
| 136 | .chip_name = "Tahvo", | ||
| 137 | .companion_name = "Betty", | ||
| 138 | .irq_chip = &tahvo_irq_chip, | ||
| 139 | .children = tahvo_devs, | ||
| 140 | .nchildren = ARRAY_SIZE(tahvo_devs), | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | |||
| 87 | int retu_read(struct retu_dev *rdev, u8 reg) | 144 | int retu_read(struct retu_dev *rdev, u8 reg) |
| 88 | { | 145 | { |
| 89 | int ret; | 146 | int ret; |
| @@ -173,9 +230,14 @@ static struct regmap_config retu_config = { | |||
| 173 | 230 | ||
| 174 | static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | 231 | static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) |
| 175 | { | 232 | { |
| 233 | struct retu_data const *rdat; | ||
| 176 | struct retu_dev *rdev; | 234 | struct retu_dev *rdev; |
| 177 | int ret; | 235 | int ret; |
| 178 | 236 | ||
| 237 | if (i2c->addr > ARRAY_SIZE(retu_data)) | ||
| 238 | return -ENODEV; | ||
| 239 | rdat = &retu_data[i2c->addr - 1]; | ||
| 240 | |||
| 179 | rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); | 241 | rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); |
| 180 | if (rdev == NULL) | 242 | if (rdev == NULL) |
| 181 | return -ENOMEM; | 243 | return -ENOMEM; |
| @@ -190,25 +252,27 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
| 190 | 252 | ||
| 191 | ret = retu_read(rdev, RETU_REG_ASICR); | 253 | ret = retu_read(rdev, RETU_REG_ASICR); |
| 192 | if (ret < 0) { | 254 | if (ret < 0) { |
| 193 | dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); | 255 | dev_err(rdev->dev, "could not read %s revision: %d\n", |
| 256 | rdat->chip_name, ret); | ||
| 194 | return ret; | 257 | return ret; |
| 195 | } | 258 | } |
| 196 | 259 | ||
| 197 | dev_info(rdev->dev, "Retu%s v%d.%d found\n", | 260 | dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name, |
| 198 | (ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", | 261 | (ret & RETU_REG_ASICR_VILMA) ? " & " : "", |
| 262 | (ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "", | ||
| 199 | (ret >> 4) & 0x7, ret & 0xf); | 263 | (ret >> 4) & 0x7, ret & 0xf); |
| 200 | 264 | ||
| 201 | /* Mask all RETU interrupts. */ | 265 | /* Mask all interrupts. */ |
| 202 | ret = retu_write(rdev, RETU_REG_IMR, 0xffff); | 266 | ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff); |
| 203 | if (ret < 0) | 267 | if (ret < 0) |
| 204 | return ret; | 268 | return ret; |
| 205 | 269 | ||
| 206 | ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, | 270 | ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, |
| 207 | &retu_irq_chip, &rdev->irq_data); | 271 | rdat->irq_chip, &rdev->irq_data); |
| 208 | if (ret < 0) | 272 | if (ret < 0) |
| 209 | return ret; | 273 | return ret; |
| 210 | 274 | ||
| 211 | ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), | 275 | ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren, |
| 212 | NULL, regmap_irq_chip_get_base(rdev->irq_data), | 276 | NULL, regmap_irq_chip_get_base(rdev->irq_data), |
| 213 | NULL); | 277 | NULL); |
| 214 | if (ret < 0) { | 278 | if (ret < 0) { |
| @@ -216,7 +280,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) | |||
| 216 | return ret; | 280 | return ret; |
| 217 | } | 281 | } |
| 218 | 282 | ||
| 219 | if (!pm_power_off) { | 283 | if (i2c->addr == 1 && !pm_power_off) { |
| 220 | retu_pm_power_off = rdev; | 284 | retu_pm_power_off = rdev; |
| 221 | pm_power_off = retu_power_off; | 285 | pm_power_off = retu_power_off; |
| 222 | } | 286 | } |
| @@ -240,6 +304,7 @@ static int retu_remove(struct i2c_client *i2c) | |||
| 240 | 304 | ||
| 241 | static const struct i2c_device_id retu_id[] = { | 305 | static const struct i2c_device_id retu_id[] = { |
| 242 | { "retu-mfd", 0 }, | 306 | { "retu-mfd", 0 }, |
| 307 | { "tahvo-mfd", 0 }, | ||
| 243 | { } | 308 | { } |
| 244 | }; | 309 | }; |
| 245 | MODULE_DEVICE_TABLE(i2c, retu_id); | 310 | MODULE_DEVICE_TABLE(i2c, retu_id); |
diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c new file mode 100644 index 000000000000..15dc848bc081 --- /dev/null +++ b/drivers/mfd/rts5249.c | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* Driver for Realtek PCI-Express card reader | ||
| 2 | * | ||
| 3 | * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License as published by the | ||
| 7 | * Free Software Foundation; either version 2, or (at your option) any | ||
| 8 | * later version. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, but | ||
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | * General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along | ||
| 16 | * with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 17 | * | ||
| 18 | * Author: | ||
| 19 | * Wei WANG <wei_wang@realsil.com.cn> | ||
| 20 | * No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/mfd/rtsx_pci.h> | ||
| 26 | |||
| 27 | #include "rtsx_pcr.h" | ||
| 28 | |||
| 29 | static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) | ||
| 30 | { | ||
| 31 | u8 val; | ||
| 32 | |||
| 33 | rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); | ||
| 34 | return val & 0x0F; | ||
| 35 | } | ||
| 36 | |||
| 37 | static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) | ||
| 38 | { | ||
| 39 | rtsx_pci_init_cmd(pcr); | ||
| 40 | |||
| 41 | /* Configure GPIO as output */ | ||
| 42 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); | ||
| 43 | /* Switch LDO3318 source from DV33 to card_3v3 */ | ||
| 44 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); | ||
| 45 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); | ||
| 46 | /* LED shine disabled, set initial shine cycle period */ | ||
| 47 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); | ||
| 48 | /* Correct driving */ | ||
| 49 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
| 50 | SD30_CLK_DRIVE_SEL, 0xFF, 0x99); | ||
| 51 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
| 52 | SD30_CMD_DRIVE_SEL, 0xFF, 0x99); | ||
| 53 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, | ||
| 54 | SD30_DAT_DRIVE_SEL, 0xFF, 0x92); | ||
| 55 | |||
| 56 | return rtsx_pci_send_cmd(pcr, 100); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int rts5249_optimize_phy(struct rtsx_pcr *pcr) | ||
| 60 | { | ||
| 61 | int err; | ||
| 62 | |||
| 63 | err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV, 0xFE46); | ||
| 64 | if (err < 0) | ||
| 65 | return err; | ||
| 66 | |||
| 67 | msleep(1); | ||
| 68 | |||
| 69 | return rtsx_pci_write_phy_register(pcr, PHY_BPCR, 0x05C0); | ||
| 70 | } | ||
| 71 | |||
| 72 | static int rts5249_turn_on_led(struct rtsx_pcr *pcr) | ||
| 73 | { | ||
| 74 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); | ||
| 75 | } | ||
| 76 | |||
| 77 | static int rts5249_turn_off_led(struct rtsx_pcr *pcr) | ||
| 78 | { | ||
| 79 | return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); | ||
| 80 | } | ||
| 81 | |||
| 82 | static int rts5249_enable_auto_blink(struct rtsx_pcr *pcr) | ||
| 83 | { | ||
| 84 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); | ||
| 85 | } | ||
| 86 | |||
| 87 | static int rts5249_disable_auto_blink(struct rtsx_pcr *pcr) | ||
| 88 | { | ||
| 89 | return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); | ||
| 90 | } | ||
| 91 | |||
| 92 | static int rts5249_card_power_on(struct rtsx_pcr *pcr, int card) | ||
| 93 | { | ||
| 94 | int err; | ||
| 95 | |||
| 96 | rtsx_pci_init_cmd(pcr); | ||
| 97 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
| 98 | SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON); | ||
| 99 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
| 100 | LDO3318_PWR_MASK, 0x02); | ||
| 101 | err = rtsx_pci_send_cmd(pcr, 100); | ||
| 102 | if (err < 0) | ||
| 103 | return err; | ||
| 104 | |||
| 105 | msleep(5); | ||
| 106 | |||
| 107 | rtsx_pci_init_cmd(pcr); | ||
| 108 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
| 109 | SD_POWER_MASK, SD_VCC_POWER_ON); | ||
| 110 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
| 111 | LDO3318_PWR_MASK, 0x06); | ||
| 112 | err = rtsx_pci_send_cmd(pcr, 100); | ||
| 113 | if (err < 0) | ||
| 114 | return err; | ||
| 115 | |||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) | ||
| 120 | { | ||
| 121 | rtsx_pci_init_cmd(pcr); | ||
| 122 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, | ||
| 123 | SD_POWER_MASK, SD_POWER_OFF); | ||
| 124 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, | ||
| 125 | LDO3318_PWR_MASK, 0x00); | ||
| 126 | return rtsx_pci_send_cmd(pcr, 100); | ||
| 127 | } | ||
| 128 | |||
| 129 | static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) | ||
| 130 | { | ||
| 131 | int err; | ||
| 132 | u8 clk_drive, cmd_drive, dat_drive; | ||
| 133 | |||
| 134 | if (voltage == OUTPUT_3V3) { | ||
| 135 | err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); | ||
| 136 | if (err < 0) | ||
| 137 | return err; | ||
| 138 | clk_drive = 0x99; | ||
| 139 | cmd_drive = 0x99; | ||
| 140 | dat_drive = 0x92; | ||
| 141 | } else if (voltage == OUTPUT_1V8) { | ||
| 142 | err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); | ||
| 143 | if (err < 0) | ||
| 144 | return err; | ||
| 145 | err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); | ||
| 146 | if (err < 0) | ||
| 147 | return err; | ||
| 148 | clk_drive = 0xb3; | ||
| 149 | cmd_drive = 0xb3; | ||
| 150 | dat_drive = 0xb3; | ||
| 151 | } else { | ||
| 152 | return -EINVAL; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* set pad drive */ | ||
| 156 | rtsx_pci_init_cmd(pcr); | ||
| 157 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, | ||
| 158 | 0xFF, clk_drive); | ||
| 159 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, | ||
| 160 | 0xFF, cmd_drive); | ||
| 161 | rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, | ||
| 162 | 0xFF, dat_drive); | ||
| 163 | return rtsx_pci_send_cmd(pcr, 100); | ||
| 164 | } | ||
| 165 | |||
| 166 | static const struct pcr_ops rts5249_pcr_ops = { | ||
| 167 | .extra_init_hw = rts5249_extra_init_hw, | ||
| 168 | .optimize_phy = rts5249_optimize_phy, | ||
| 169 | .turn_on_led = rts5249_turn_on_led, | ||
| 170 | .turn_off_led = rts5249_turn_off_led, | ||
| 171 | .enable_auto_blink = rts5249_enable_auto_blink, | ||
| 172 | .disable_auto_blink = rts5249_disable_auto_blink, | ||
| 173 | .card_power_on = rts5249_card_power_on, | ||
| 174 | .card_power_off = rts5249_card_power_off, | ||
| 175 | .switch_output_voltage = rts5249_switch_output_voltage, | ||
| 176 | }; | ||
| 177 | |||
| 178 | /* SD Pull Control Enable: | ||
| 179 | * SD_DAT[3:0] ==> pull up | ||
| 180 | * SD_CD ==> pull up | ||
| 181 | * SD_WP ==> pull up | ||
| 182 | * SD_CMD ==> pull up | ||
| 183 | * SD_CLK ==> pull down | ||
| 184 | */ | ||
| 185 | static const u32 rts5249_sd_pull_ctl_enable_tbl[] = { | ||
| 186 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), | ||
| 187 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), | ||
| 188 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), | ||
| 189 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA), | ||
| 190 | 0, | ||
| 191 | }; | ||
| 192 | |||
| 193 | /* SD Pull Control Disable: | ||
| 194 | * SD_DAT[3:0] ==> pull down | ||
| 195 | * SD_CD ==> pull up | ||
| 196 | * SD_WP ==> pull down | ||
| 197 | * SD_CMD ==> pull down | ||
| 198 | * SD_CLK ==> pull down | ||
| 199 | */ | ||
| 200 | static const u32 rts5249_sd_pull_ctl_disable_tbl[] = { | ||
| 201 | RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), | ||
| 202 | RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), | ||
| 203 | RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), | ||
| 204 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
| 205 | 0, | ||
| 206 | }; | ||
| 207 | |||
| 208 | /* MS Pull Control Enable: | ||
| 209 | * MS CD ==> pull up | ||
| 210 | * others ==> pull down | ||
| 211 | */ | ||
| 212 | static const u32 rts5249_ms_pull_ctl_enable_tbl[] = { | ||
| 213 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
| 214 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
| 215 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
| 216 | 0, | ||
| 217 | }; | ||
| 218 | |||
| 219 | /* MS Pull Control Disable: | ||
| 220 | * MS CD ==> pull up | ||
| 221 | * others ==> pull down | ||
| 222 | */ | ||
| 223 | static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { | ||
| 224 | RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), | ||
| 225 | RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), | ||
| 226 | RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), | ||
| 227 | 0, | ||
| 228 | }; | ||
| 229 | |||
| 230 | void rts5249_init_params(struct rtsx_pcr *pcr) | ||
| 231 | { | ||
| 232 | pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; | ||
| 233 | pcr->num_slots = 2; | ||
| 234 | pcr->ops = &rts5249_pcr_ops; | ||
| 235 | |||
| 236 | pcr->ic_version = rts5249_get_ic_version(pcr); | ||
| 237 | pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; | ||
| 238 | pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; | ||
| 239 | pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl; | ||
| 240 | pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; | ||
| 241 | } | ||
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 2f12cc13489a..e968c01ca2ac 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c | |||
| @@ -56,6 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { | |||
| 56 | { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 56 | { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
| 57 | { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 57 | { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
| 58 | { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | 58 | { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, |
| 59 | { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 }, | ||
| 59 | { 0, } | 60 | { 0, } |
| 60 | }; | 61 | }; |
| 61 | 62 | ||
| @@ -1033,6 +1034,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) | |||
| 1033 | case 0x5227: | 1034 | case 0x5227: |
| 1034 | rts5227_init_params(pcr); | 1035 | rts5227_init_params(pcr); |
| 1035 | break; | 1036 | break; |
| 1037 | |||
| 1038 | case 0x5249: | ||
| 1039 | rts5249_init_params(pcr); | ||
| 1040 | break; | ||
| 1036 | } | 1041 | } |
| 1037 | 1042 | ||
| 1038 | dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", | 1043 | dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", |
| @@ -1138,7 +1143,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, | |||
| 1138 | 1143 | ||
| 1139 | ret = rtsx_pci_acquire_irq(pcr); | 1144 | ret = rtsx_pci_acquire_irq(pcr); |
| 1140 | if (ret < 0) | 1145 | if (ret < 0) |
| 1141 | goto free_dma; | 1146 | goto disable_msi; |
| 1142 | 1147 | ||
| 1143 | pci_set_master(pcidev); | 1148 | pci_set_master(pcidev); |
| 1144 | synchronize_irq(pcr->irq); | 1149 | synchronize_irq(pcr->irq); |
| @@ -1162,7 +1167,9 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, | |||
| 1162 | 1167 | ||
| 1163 | disable_irq: | 1168 | disable_irq: |
| 1164 | free_irq(pcr->irq, (void *)pcr); | 1169 | free_irq(pcr->irq, (void *)pcr); |
| 1165 | free_dma: | 1170 | disable_msi: |
| 1171 | if (pcr->msi_en) | ||
| 1172 | pci_disable_msi(pcr->pci); | ||
| 1166 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, | 1173 | dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, |
| 1167 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); | 1174 | pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); |
| 1168 | unmap: | 1175 | unmap: |
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index 2b3ab8a04823..55fcfc25c4e4 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h | |||
| @@ -32,5 +32,6 @@ void rts5209_init_params(struct rtsx_pcr *pcr); | |||
| 32 | void rts5229_init_params(struct rtsx_pcr *pcr); | 32 | void rts5229_init_params(struct rtsx_pcr *pcr); |
| 33 | void rtl8411_init_params(struct rtsx_pcr *pcr); | 33 | void rtl8411_init_params(struct rtsx_pcr *pcr); |
| 34 | void rts5227_init_params(struct rtsx_pcr *pcr); | 34 | void rts5227_init_params(struct rtsx_pcr *pcr); |
| 35 | void rts5249_init_params(struct rtsx_pcr *pcr); | ||
| 35 | 36 | ||
| 36 | #endif | 37 | #endif |
diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c new file mode 100644 index 000000000000..de48b4e88450 --- /dev/null +++ b/drivers/mfd/si476x-cmd.c | |||
| @@ -0,0 +1,1553 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mfd/si476x-cmd.c -- Subroutines implementing command | ||
| 3 | * protocol of si476x series of chips | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
| 6 | * Copyright (C) 2013 Andrey Smirnov | ||
| 7 | * | ||
| 8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; version 2 of the License. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/completion.h> | ||
| 23 | #include <linux/delay.h> | ||
| 24 | #include <linux/atomic.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/device.h> | ||
| 27 | #include <linux/gpio.h> | ||
| 28 | #include <linux/videodev2.h> | ||
| 29 | |||
| 30 | #include <linux/mfd/si476x-core.h> | ||
| 31 | |||
| 32 | #define msb(x) ((u8)((u16) x >> 8)) | ||
| 33 | #define lsb(x) ((u8)((u16) x & 0x00FF)) | ||
| 34 | |||
| 35 | |||
| 36 | |||
| 37 | #define CMD_POWER_UP 0x01 | ||
| 38 | #define CMD_POWER_UP_A10_NRESP 1 | ||
| 39 | #define CMD_POWER_UP_A10_NARGS 5 | ||
| 40 | |||
| 41 | #define CMD_POWER_UP_A20_NRESP 1 | ||
| 42 | #define CMD_POWER_UP_A20_NARGS 5 | ||
| 43 | |||
| 44 | #define POWER_UP_DELAY_MS 110 | ||
| 45 | |||
| 46 | #define CMD_POWER_DOWN 0x11 | ||
| 47 | #define CMD_POWER_DOWN_A10_NRESP 1 | ||
| 48 | |||
| 49 | #define CMD_POWER_DOWN_A20_NRESP 1 | ||
| 50 | #define CMD_POWER_DOWN_A20_NARGS 1 | ||
| 51 | |||
| 52 | #define CMD_FUNC_INFO 0x12 | ||
| 53 | #define CMD_FUNC_INFO_NRESP 7 | ||
| 54 | |||
| 55 | #define CMD_SET_PROPERTY 0x13 | ||
| 56 | #define CMD_SET_PROPERTY_NARGS 5 | ||
| 57 | #define CMD_SET_PROPERTY_NRESP 1 | ||
| 58 | |||
| 59 | #define CMD_GET_PROPERTY 0x14 | ||
| 60 | #define CMD_GET_PROPERTY_NARGS 3 | ||
| 61 | #define CMD_GET_PROPERTY_NRESP 4 | ||
| 62 | |||
| 63 | #define CMD_AGC_STATUS 0x17 | ||
| 64 | #define CMD_AGC_STATUS_NRESP_A10 2 | ||
| 65 | #define CMD_AGC_STATUS_NRESP_A20 6 | ||
| 66 | |||
| 67 | #define PIN_CFG_BYTE(x) (0x7F & (x)) | ||
| 68 | #define CMD_DIG_AUDIO_PIN_CFG 0x18 | ||
| 69 | #define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 | ||
| 70 | #define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 | ||
| 71 | |||
| 72 | #define CMD_ZIF_PIN_CFG 0x19 | ||
| 73 | #define CMD_ZIF_PIN_CFG_NARGS 4 | ||
| 74 | #define CMD_ZIF_PIN_CFG_NRESP 5 | ||
| 75 | |||
| 76 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A | ||
| 77 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 | ||
| 78 | #define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 | ||
| 79 | |||
| 80 | #define CMD_ANA_AUDIO_PIN_CFG 0x1B | ||
| 81 | #define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 | ||
| 82 | #define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 | ||
| 83 | |||
| 84 | #define CMD_INTB_PIN_CFG 0x1C | ||
| 85 | #define CMD_INTB_PIN_CFG_NARGS 2 | ||
| 86 | #define CMD_INTB_PIN_CFG_A10_NRESP 6 | ||
| 87 | #define CMD_INTB_PIN_CFG_A20_NRESP 3 | ||
| 88 | |||
| 89 | #define CMD_FM_TUNE_FREQ 0x30 | ||
| 90 | #define CMD_FM_TUNE_FREQ_A10_NARGS 5 | ||
| 91 | #define CMD_FM_TUNE_FREQ_A20_NARGS 3 | ||
| 92 | #define CMD_FM_TUNE_FREQ_NRESP 1 | ||
| 93 | |||
| 94 | #define CMD_FM_RSQ_STATUS 0x32 | ||
| 95 | |||
| 96 | #define CMD_FM_RSQ_STATUS_A10_NARGS 1 | ||
| 97 | #define CMD_FM_RSQ_STATUS_A10_NRESP 17 | ||
| 98 | #define CMD_FM_RSQ_STATUS_A30_NARGS 1 | ||
| 99 | #define CMD_FM_RSQ_STATUS_A30_NRESP 23 | ||
| 100 | |||
| 101 | |||
| 102 | #define CMD_FM_SEEK_START 0x31 | ||
| 103 | #define CMD_FM_SEEK_START_NARGS 1 | ||
| 104 | #define CMD_FM_SEEK_START_NRESP 1 | ||
| 105 | |||
| 106 | #define CMD_FM_RDS_STATUS 0x36 | ||
| 107 | #define CMD_FM_RDS_STATUS_NARGS 1 | ||
| 108 | #define CMD_FM_RDS_STATUS_NRESP 16 | ||
| 109 | |||
| 110 | #define CMD_FM_RDS_BLOCKCOUNT 0x37 | ||
| 111 | #define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 | ||
| 112 | #define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 | ||
| 113 | |||
| 114 | #define CMD_FM_PHASE_DIVERSITY 0x38 | ||
| 115 | #define CMD_FM_PHASE_DIVERSITY_NARGS 1 | ||
| 116 | #define CMD_FM_PHASE_DIVERSITY_NRESP 1 | ||
| 117 | |||
| 118 | #define CMD_FM_PHASE_DIV_STATUS 0x39 | ||
| 119 | #define CMD_FM_PHASE_DIV_STATUS_NRESP 2 | ||
| 120 | |||
| 121 | #define CMD_AM_TUNE_FREQ 0x40 | ||
| 122 | #define CMD_AM_TUNE_FREQ_NARGS 3 | ||
| 123 | #define CMD_AM_TUNE_FREQ_NRESP 1 | ||
| 124 | |||
| 125 | #define CMD_AM_RSQ_STATUS 0x42 | ||
| 126 | #define CMD_AM_RSQ_STATUS_NARGS 1 | ||
| 127 | #define CMD_AM_RSQ_STATUS_NRESP 13 | ||
| 128 | |||
| 129 | #define CMD_AM_SEEK_START 0x41 | ||
| 130 | #define CMD_AM_SEEK_START_NARGS 1 | ||
| 131 | #define CMD_AM_SEEK_START_NRESP 1 | ||
| 132 | |||
| 133 | |||
| 134 | #define CMD_AM_ACF_STATUS 0x45 | ||
| 135 | #define CMD_AM_ACF_STATUS_NRESP 6 | ||
| 136 | #define CMD_AM_ACF_STATUS_NARGS 1 | ||
| 137 | |||
| 138 | #define CMD_FM_ACF_STATUS 0x35 | ||
| 139 | #define CMD_FM_ACF_STATUS_NRESP 8 | ||
| 140 | #define CMD_FM_ACF_STATUS_NARGS 1 | ||
| 141 | |||
| 142 | #define CMD_MAX_ARGS_COUNT (10) | ||
| 143 | |||
| 144 | |||
| 145 | enum si476x_acf_status_report_bits { | ||
| 146 | SI476X_ACF_BLEND_INT = (1 << 4), | ||
| 147 | SI476X_ACF_HIBLEND_INT = (1 << 3), | ||
| 148 | SI476X_ACF_HICUT_INT = (1 << 2), | ||
| 149 | SI476X_ACF_CHBW_INT = (1 << 1), | ||
| 150 | SI476X_ACF_SOFTMUTE_INT = (1 << 0), | ||
| 151 | |||
| 152 | SI476X_ACF_SMUTE = (1 << 0), | ||
| 153 | SI476X_ACF_SMATTN = 0b11111, | ||
| 154 | SI476X_ACF_PILOT = (1 << 7), | ||
| 155 | SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, | ||
| 156 | }; | ||
| 157 | |||
| 158 | enum si476x_agc_status_report_bits { | ||
| 159 | SI476X_AGC_MXHI = (1 << 5), | ||
| 160 | SI476X_AGC_MXLO = (1 << 4), | ||
| 161 | SI476X_AGC_LNAHI = (1 << 3), | ||
| 162 | SI476X_AGC_LNALO = (1 << 2), | ||
| 163 | }; | ||
| 164 | |||
| 165 | enum si476x_errors { | ||
| 166 | SI476X_ERR_BAD_COMMAND = 0x10, | ||
| 167 | SI476X_ERR_BAD_ARG1 = 0x11, | ||
| 168 | SI476X_ERR_BAD_ARG2 = 0x12, | ||
| 169 | SI476X_ERR_BAD_ARG3 = 0x13, | ||
| 170 | SI476X_ERR_BAD_ARG4 = 0x14, | ||
| 171 | SI476X_ERR_BUSY = 0x18, | ||
| 172 | SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, | ||
| 173 | SI476X_ERR_BAD_PATCH = 0x30, | ||
| 174 | SI476X_ERR_BAD_BOOT_MODE = 0x31, | ||
| 175 | SI476X_ERR_BAD_PROPERTY = 0x40, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) | ||
| 179 | { | ||
| 180 | int err; | ||
| 181 | char *cause; | ||
| 182 | u8 buffer[2]; | ||
| 183 | |||
| 184 | if (core->revision != SI476X_REVISION_A10) { | ||
| 185 | err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, | ||
| 186 | buffer, sizeof(buffer)); | ||
| 187 | if (err == sizeof(buffer)) { | ||
| 188 | switch (buffer[1]) { | ||
| 189 | case SI476X_ERR_BAD_COMMAND: | ||
| 190 | cause = "Bad command"; | ||
| 191 | err = -EINVAL; | ||
| 192 | break; | ||
| 193 | case SI476X_ERR_BAD_ARG1: | ||
| 194 | cause = "Bad argument #1"; | ||
| 195 | err = -EINVAL; | ||
| 196 | break; | ||
| 197 | case SI476X_ERR_BAD_ARG2: | ||
| 198 | cause = "Bad argument #2"; | ||
| 199 | err = -EINVAL; | ||
| 200 | break; | ||
| 201 | case SI476X_ERR_BAD_ARG3: | ||
| 202 | cause = "Bad argument #3"; | ||
| 203 | err = -EINVAL; | ||
| 204 | break; | ||
| 205 | case SI476X_ERR_BAD_ARG4: | ||
| 206 | cause = "Bad argument #4"; | ||
| 207 | err = -EINVAL; | ||
| 208 | break; | ||
| 209 | case SI476X_ERR_BUSY: | ||
| 210 | cause = "Chip is busy"; | ||
| 211 | err = -EBUSY; | ||
| 212 | break; | ||
| 213 | case SI476X_ERR_BAD_INTERNAL_MEMORY: | ||
| 214 | cause = "Bad internal memory"; | ||
| 215 | err = -EIO; | ||
| 216 | break; | ||
| 217 | case SI476X_ERR_BAD_PATCH: | ||
| 218 | cause = "Bad patch"; | ||
| 219 | err = -EINVAL; | ||
| 220 | break; | ||
| 221 | case SI476X_ERR_BAD_BOOT_MODE: | ||
| 222 | cause = "Bad boot mode"; | ||
| 223 | err = -EINVAL; | ||
| 224 | break; | ||
| 225 | case SI476X_ERR_BAD_PROPERTY: | ||
| 226 | cause = "Bad property"; | ||
| 227 | err = -EINVAL; | ||
| 228 | break; | ||
| 229 | default: | ||
| 230 | cause = "Unknown"; | ||
| 231 | err = -EIO; | ||
| 232 | } | ||
| 233 | |||
| 234 | dev_err(&core->client->dev, | ||
| 235 | "[Chip error status]: %s\n", cause); | ||
| 236 | } else { | ||
| 237 | dev_err(&core->client->dev, | ||
| 238 | "Failed to fetch error code\n"); | ||
| 239 | err = (err >= 0) ? -EIO : err; | ||
| 240 | } | ||
| 241 | } else { | ||
| 242 | err = -EIO; | ||
| 243 | } | ||
| 244 | |||
| 245 | return err; | ||
| 246 | } | ||
| 247 | |||
| 248 | /** | ||
| 249 | * si476x_core_send_command() - sends a command to si476x and waits its | ||
| 250 | * response | ||
| 251 | * @core: si476x_device structure for the device we are | ||
| 252 | * communicating with | ||
| 253 | * @command: command id | ||
| 254 | * @args: command arguments we are sending | ||
| 255 | * @argn: actual size of @args | ||
| 256 | * @response: buffer to place the expected response from the device | ||
| 257 | * @respn: actual size of @response | ||
| 258 | * @usecs: amount of time to wait before reading the response (in | ||
| 259 | * usecs) | ||
| 260 | * | ||
| 261 | * Function returns 0 on succsess and negative error code on | ||
| 262 | * failure | ||
| 263 | */ | ||
| 264 | static int si476x_core_send_command(struct si476x_core *core, | ||
| 265 | const u8 command, | ||
| 266 | const u8 args[], | ||
| 267 | const int argn, | ||
| 268 | u8 resp[], | ||
| 269 | const int respn, | ||
| 270 | const int usecs) | ||
| 271 | { | ||
| 272 | struct i2c_client *client = core->client; | ||
| 273 | int err; | ||
| 274 | u8 data[CMD_MAX_ARGS_COUNT + 1]; | ||
| 275 | |||
| 276 | if (argn > CMD_MAX_ARGS_COUNT) { | ||
| 277 | err = -ENOMEM; | ||
| 278 | goto exit; | ||
| 279 | } | ||
| 280 | |||
| 281 | if (!client->adapter) { | ||
| 282 | err = -ENODEV; | ||
| 283 | goto exit; | ||
| 284 | } | ||
| 285 | |||
| 286 | /* First send the command and its arguments */ | ||
| 287 | data[0] = command; | ||
| 288 | memcpy(&data[1], args, argn); | ||
| 289 | dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); | ||
| 290 | |||
| 291 | err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, | ||
| 292 | (char *) data, argn + 1); | ||
| 293 | if (err != argn + 1) { | ||
| 294 | dev_err(&core->client->dev, | ||
| 295 | "Error while sending command 0x%02x\n", | ||
| 296 | command); | ||
| 297 | err = (err >= 0) ? -EIO : err; | ||
| 298 | goto exit; | ||
| 299 | } | ||
| 300 | /* Set CTS to zero only after the command is send to avoid | ||
| 301 | * possible racing conditions when working in polling mode */ | ||
| 302 | atomic_set(&core->cts, 0); | ||
| 303 | |||
| 304 | /* if (unlikely(command == CMD_POWER_DOWN) */ | ||
| 305 | if (!wait_event_timeout(core->command, | ||
| 306 | atomic_read(&core->cts), | ||
| 307 | usecs_to_jiffies(usecs) + 1)) | ||
| 308 | dev_warn(&core->client->dev, | ||
| 309 | "(%s) [CMD 0x%02x] Answer timeout.\n", | ||
| 310 | __func__, command); | ||
| 311 | |||
| 312 | /* | ||
| 313 | When working in polling mode, for some reason the tuner will | ||
| 314 | report CTS bit as being set in the first status byte read, | ||
| 315 | but all the consequtive ones will return zeros until the | ||
| 316 | tuner is actually completed the POWER_UP command. To | ||
| 317 | workaround that we wait for second CTS to be reported | ||
| 318 | */ | ||
| 319 | if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { | ||
| 320 | if (!wait_event_timeout(core->command, | ||
| 321 | atomic_read(&core->cts), | ||
| 322 | usecs_to_jiffies(usecs) + 1)) | ||
| 323 | dev_warn(&core->client->dev, | ||
| 324 | "(%s) Power up took too much time.\n", | ||
| 325 | __func__); | ||
| 326 | } | ||
| 327 | |||
| 328 | /* Then get the response */ | ||
| 329 | err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); | ||
| 330 | if (err != respn) { | ||
| 331 | dev_err(&core->client->dev, | ||
| 332 | "Error while reading response for command 0x%02x\n", | ||
| 333 | command); | ||
| 334 | err = (err >= 0) ? -EIO : err; | ||
| 335 | goto exit; | ||
| 336 | } | ||
| 337 | dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); | ||
| 338 | |||
| 339 | err = 0; | ||
| 340 | |||
| 341 | if (resp[0] & SI476X_ERR) { | ||
| 342 | dev_err(&core->client->dev, | ||
| 343 | "[CMD 0x%02x] Chip set error flag\n", command); | ||
| 344 | err = si476x_core_parse_and_nag_about_error(core); | ||
| 345 | goto exit; | ||
| 346 | } | ||
| 347 | |||
| 348 | if (!(resp[0] & SI476X_CTS)) | ||
| 349 | err = -EBUSY; | ||
| 350 | exit: | ||
| 351 | return err; | ||
| 352 | } | ||
| 353 | |||
| 354 | static int si476x_cmd_clear_stc(struct si476x_core *core) | ||
| 355 | { | ||
| 356 | int err; | ||
| 357 | struct si476x_rsq_status_args args = { | ||
| 358 | .primary = false, | ||
| 359 | .rsqack = false, | ||
| 360 | .attune = false, | ||
| 361 | .cancel = false, | ||
| 362 | .stcack = true, | ||
| 363 | }; | ||
| 364 | |||
| 365 | switch (core->power_up_parameters.func) { | ||
| 366 | case SI476X_FUNC_FM_RECEIVER: | ||
| 367 | err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); | ||
| 368 | break; | ||
| 369 | case SI476X_FUNC_AM_RECEIVER: | ||
| 370 | err = si476x_core_cmd_am_rsq_status(core, &args, NULL); | ||
| 371 | break; | ||
| 372 | default: | ||
| 373 | err = -EINVAL; | ||
| 374 | } | ||
| 375 | |||
| 376 | return err; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int si476x_cmd_tune_seek_freq(struct si476x_core *core, | ||
| 380 | uint8_t cmd, | ||
| 381 | const uint8_t args[], size_t argn, | ||
| 382 | uint8_t *resp, size_t respn) | ||
| 383 | { | ||
| 384 | int err; | ||
| 385 | |||
| 386 | |||
| 387 | atomic_set(&core->stc, 0); | ||
| 388 | err = si476x_core_send_command(core, cmd, args, argn, resp, respn, | ||
| 389 | SI476X_TIMEOUT_TUNE); | ||
| 390 | if (!err) { | ||
| 391 | wait_event_killable(core->tuning, | ||
| 392 | atomic_read(&core->stc)); | ||
| 393 | si476x_cmd_clear_stc(core); | ||
| 394 | } | ||
| 395 | |||
| 396 | return err; | ||
| 397 | } | ||
| 398 | |||
| 399 | /** | ||
| 400 | * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device | ||
| 401 | * @core: device to send the command to | ||
| 402 | * @info: struct si476x_func_info to fill all the information | ||
| 403 | * returned by the command | ||
| 404 | * | ||
| 405 | * The command requests the firmware and patch version for currently | ||
| 406 | * loaded firmware (dependent on the function of the device FM/AM/WB) | ||
| 407 | * | ||
| 408 | * Function returns 0 on succsess and negative error code on | ||
| 409 | * failure | ||
| 410 | */ | ||
| 411 | int si476x_core_cmd_func_info(struct si476x_core *core, | ||
| 412 | struct si476x_func_info *info) | ||
| 413 | { | ||
| 414 | int err; | ||
| 415 | u8 resp[CMD_FUNC_INFO_NRESP]; | ||
| 416 | |||
| 417 | err = si476x_core_send_command(core, CMD_FUNC_INFO, | ||
| 418 | NULL, 0, | ||
| 419 | resp, ARRAY_SIZE(resp), | ||
| 420 | SI476X_DEFAULT_TIMEOUT); | ||
| 421 | |||
| 422 | info->firmware.major = resp[1]; | ||
| 423 | info->firmware.minor[0] = resp[2]; | ||
| 424 | info->firmware.minor[1] = resp[3]; | ||
| 425 | |||
| 426 | info->patch_id = ((u16) resp[4] << 8) | resp[5]; | ||
| 427 | info->func = resp[6]; | ||
| 428 | |||
| 429 | return err; | ||
| 430 | } | ||
| 431 | EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); | ||
| 432 | |||
| 433 | /** | ||
| 434 | * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device | ||
| 435 | * @core: device to send the command to | ||
| 436 | * @property: property address | ||
| 437 | * @value: property value | ||
| 438 | * | ||
| 439 | * Function returns 0 on succsess and negative error code on | ||
| 440 | * failure | ||
| 441 | */ | ||
| 442 | int si476x_core_cmd_set_property(struct si476x_core *core, | ||
| 443 | u16 property, u16 value) | ||
| 444 | { | ||
| 445 | u8 resp[CMD_SET_PROPERTY_NRESP]; | ||
| 446 | const u8 args[CMD_SET_PROPERTY_NARGS] = { | ||
| 447 | 0x00, | ||
| 448 | msb(property), | ||
| 449 | lsb(property), | ||
| 450 | msb(value), | ||
| 451 | lsb(value), | ||
| 452 | }; | ||
| 453 | |||
| 454 | return si476x_core_send_command(core, CMD_SET_PROPERTY, | ||
| 455 | args, ARRAY_SIZE(args), | ||
| 456 | resp, ARRAY_SIZE(resp), | ||
| 457 | SI476X_DEFAULT_TIMEOUT); | ||
| 458 | } | ||
| 459 | EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); | ||
| 460 | |||
| 461 | /** | ||
| 462 | * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device | ||
| 463 | * @core: device to send the command to | ||
| 464 | * @property: property address | ||
| 465 | * | ||
| 466 | * Function return the value of property as u16 on success or a | ||
| 467 | * negative error on failure | ||
| 468 | */ | ||
| 469 | int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) | ||
| 470 | { | ||
| 471 | int err; | ||
| 472 | u8 resp[CMD_GET_PROPERTY_NRESP]; | ||
| 473 | const u8 args[CMD_GET_PROPERTY_NARGS] = { | ||
| 474 | 0x00, | ||
| 475 | msb(property), | ||
| 476 | lsb(property), | ||
| 477 | }; | ||
| 478 | |||
| 479 | err = si476x_core_send_command(core, CMD_GET_PROPERTY, | ||
| 480 | args, ARRAY_SIZE(args), | ||
| 481 | resp, ARRAY_SIZE(resp), | ||
| 482 | SI476X_DEFAULT_TIMEOUT); | ||
| 483 | if (err < 0) | ||
| 484 | return err; | ||
| 485 | else | ||
| 486 | return be16_to_cpup((__be16 *)(resp + 2)); | ||
| 487 | } | ||
| 488 | EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); | ||
| 489 | |||
| 490 | /** | ||
| 491 | * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to | ||
| 492 | * the device | ||
| 493 | * @core: device to send the command to | ||
| 494 | * @dclk: DCLK pin function configuration: | ||
| 495 | * #SI476X_DCLK_NOOP - do not modify the behaviour | ||
| 496 | * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, | ||
| 497 | * enable 1MOhm pulldown | ||
| 498 | * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital | ||
| 499 | * audio interface | ||
| 500 | * @dfs: DFS pin function configuration: | ||
| 501 | * #SI476X_DFS_NOOP - do not modify the behaviour | ||
| 502 | * #SI476X_DFS_TRISTATE - put the pin in tristate condition, | ||
| 503 | * enable 1MOhm pulldown | ||
| 504 | * SI476X_DFS_DAUDIO - set the pin to be a part of digital | ||
| 505 | * audio interface | ||
| 506 | * @dout - DOUT pin function configuration: | ||
| 507 | * SI476X_DOUT_NOOP - do not modify the behaviour | ||
| 508 | * SI476X_DOUT_TRISTATE - put the pin in tristate condition, | ||
| 509 | * enable 1MOhm pulldown | ||
| 510 | * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S | ||
| 511 | * port 1 | ||
| 512 | * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S | ||
| 513 | * port 1 | ||
| 514 | * @xout - XOUT pin function configuration: | ||
| 515 | * SI476X_XOUT_NOOP - do not modify the behaviour | ||
| 516 | * SI476X_XOUT_TRISTATE - put the pin in tristate condition, | ||
| 517 | * enable 1MOhm pulldown | ||
| 518 | * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S | ||
| 519 | * port 1 | ||
| 520 | * SI476X_XOUT_MODE_SELECT - set this pin to be the input that | ||
| 521 | * selects the mode of the I2S audio | ||
| 522 | * combiner (analog or HD) | ||
| 523 | * [SI4761/63/65/67 Only] | ||
| 524 | * | ||
| 525 | * Function returns 0 on success and negative error code on failure | ||
| 526 | */ | ||
| 527 | int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, | ||
| 528 | enum si476x_dclk_config dclk, | ||
| 529 | enum si476x_dfs_config dfs, | ||
| 530 | enum si476x_dout_config dout, | ||
| 531 | enum si476x_xout_config xout) | ||
| 532 | { | ||
| 533 | u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; | ||
| 534 | const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { | ||
| 535 | PIN_CFG_BYTE(dclk), | ||
| 536 | PIN_CFG_BYTE(dfs), | ||
| 537 | PIN_CFG_BYTE(dout), | ||
| 538 | PIN_CFG_BYTE(xout), | ||
| 539 | }; | ||
| 540 | |||
| 541 | return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, | ||
| 542 | args, ARRAY_SIZE(args), | ||
| 543 | resp, ARRAY_SIZE(resp), | ||
| 544 | SI476X_DEFAULT_TIMEOUT); | ||
| 545 | } | ||
| 546 | EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); | ||
| 547 | |||
| 548 | /** | ||
| 549 | * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' | ||
| 550 | * @core - device to send the command to | ||
| 551 | * @iqclk - IQCL pin function configuration: | ||
| 552 | * SI476X_IQCLK_NOOP - do not modify the behaviour | ||
| 553 | * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, | ||
| 554 | * enable 1MOhm pulldown | ||
| 555 | * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace | ||
| 556 | * in master mode | ||
| 557 | * @iqfs - IQFS pin function configuration: | ||
| 558 | * SI476X_IQFS_NOOP - do not modify the behaviour | ||
| 559 | * SI476X_IQFS_TRISTATE - put the pin in tristate condition, | ||
| 560 | * enable 1MOhm pulldown | ||
| 561 | * SI476X_IQFS_IQ - set pin to be a part of I/Q interace | ||
| 562 | * in master mode | ||
| 563 | * @iout - IOUT pin function configuration: | ||
| 564 | * SI476X_IOUT_NOOP - do not modify the behaviour | ||
| 565 | * SI476X_IOUT_TRISTATE - put the pin in tristate condition, | ||
| 566 | * enable 1MOhm pulldown | ||
| 567 | * SI476X_IOUT_OUTPUT - set pin to be I out | ||
| 568 | * @qout - QOUT pin function configuration: | ||
| 569 | * SI476X_QOUT_NOOP - do not modify the behaviour | ||
| 570 | * SI476X_QOUT_TRISTATE - put the pin in tristate condition, | ||
| 571 | * enable 1MOhm pulldown | ||
| 572 | * SI476X_QOUT_OUTPUT - set pin to be Q out | ||
| 573 | * | ||
| 574 | * Function returns 0 on success and negative error code on failure | ||
| 575 | */ | ||
| 576 | int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, | ||
| 577 | enum si476x_iqclk_config iqclk, | ||
| 578 | enum si476x_iqfs_config iqfs, | ||
| 579 | enum si476x_iout_config iout, | ||
| 580 | enum si476x_qout_config qout) | ||
| 581 | { | ||
| 582 | u8 resp[CMD_ZIF_PIN_CFG_NRESP]; | ||
| 583 | const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { | ||
| 584 | PIN_CFG_BYTE(iqclk), | ||
| 585 | PIN_CFG_BYTE(iqfs), | ||
| 586 | PIN_CFG_BYTE(iout), | ||
| 587 | PIN_CFG_BYTE(qout), | ||
| 588 | }; | ||
| 589 | |||
| 590 | return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, | ||
| 591 | args, ARRAY_SIZE(args), | ||
| 592 | resp, ARRAY_SIZE(resp), | ||
| 593 | SI476X_DEFAULT_TIMEOUT); | ||
| 594 | } | ||
| 595 | EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); | ||
| 596 | |||
| 597 | /** | ||
| 598 | * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send | ||
| 599 | * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device | ||
| 600 | * @core - device to send the command to | ||
| 601 | * @icin - ICIN pin function configuration: | ||
| 602 | * SI476X_ICIN_NOOP - do not modify the behaviour | ||
| 603 | * SI476X_ICIN_TRISTATE - put the pin in tristate condition, | ||
| 604 | * enable 1MOhm pulldown | ||
| 605 | * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high | ||
| 606 | * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low | ||
| 607 | * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link | ||
| 608 | * @icip - ICIP pin function configuration: | ||
| 609 | * SI476X_ICIP_NOOP - do not modify the behaviour | ||
| 610 | * SI476X_ICIP_TRISTATE - put the pin in tristate condition, | ||
| 611 | * enable 1MOhm pulldown | ||
| 612 | * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high | ||
| 613 | * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low | ||
| 614 | * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link | ||
| 615 | * @icon - ICON pin function configuration: | ||
| 616 | * SI476X_ICON_NOOP - do not modify the behaviour | ||
| 617 | * SI476X_ICON_TRISTATE - put the pin in tristate condition, | ||
| 618 | * enable 1MOhm pulldown | ||
| 619 | * SI476X_ICON_I2S - set the pin to be a part of audio | ||
| 620 | * interface in slave mode (DCLK) | ||
| 621 | * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link | ||
| 622 | * @icop - ICOP pin function configuration: | ||
| 623 | * SI476X_ICOP_NOOP - do not modify the behaviour | ||
| 624 | * SI476X_ICOP_TRISTATE - put the pin in tristate condition, | ||
| 625 | * enable 1MOhm pulldown | ||
| 626 | * SI476X_ICOP_I2S - set the pin to be a part of audio | ||
| 627 | * interface in slave mode (DOUT) | ||
| 628 | * [Si4761/63/65/67 Only] | ||
| 629 | * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link | ||
| 630 | * | ||
| 631 | * Function returns 0 on success and negative error code on failure | ||
| 632 | */ | ||
| 633 | int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, | ||
| 634 | enum si476x_icin_config icin, | ||
| 635 | enum si476x_icip_config icip, | ||
| 636 | enum si476x_icon_config icon, | ||
| 637 | enum si476x_icop_config icop) | ||
| 638 | { | ||
| 639 | u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; | ||
| 640 | const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { | ||
| 641 | PIN_CFG_BYTE(icin), | ||
| 642 | PIN_CFG_BYTE(icip), | ||
| 643 | PIN_CFG_BYTE(icon), | ||
| 644 | PIN_CFG_BYTE(icop), | ||
| 645 | }; | ||
| 646 | |||
| 647 | return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, | ||
| 648 | args, ARRAY_SIZE(args), | ||
| 649 | resp, ARRAY_SIZE(resp), | ||
| 650 | SI476X_DEFAULT_TIMEOUT); | ||
| 651 | } | ||
| 652 | EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); | ||
| 653 | |||
| 654 | /** | ||
| 655 | * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the | ||
| 656 | * device | ||
| 657 | * @core - device to send the command to | ||
| 658 | * @lrout - LROUT pin function configuration: | ||
| 659 | * SI476X_LROUT_NOOP - do not modify the behaviour | ||
| 660 | * SI476X_LROUT_TRISTATE - put the pin in tristate condition, | ||
| 661 | * enable 1MOhm pulldown | ||
| 662 | * SI476X_LROUT_AUDIO - set pin to be audio output | ||
| 663 | * SI476X_LROUT_MPX - set pin to be MPX output | ||
| 664 | * | ||
| 665 | * Function returns 0 on success and negative error code on failure | ||
| 666 | */ | ||
| 667 | int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, | ||
| 668 | enum si476x_lrout_config lrout) | ||
| 669 | { | ||
| 670 | u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; | ||
| 671 | const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { | ||
| 672 | PIN_CFG_BYTE(lrout), | ||
| 673 | }; | ||
| 674 | |||
| 675 | return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, | ||
| 676 | args, ARRAY_SIZE(args), | ||
| 677 | resp, ARRAY_SIZE(resp), | ||
| 678 | SI476X_DEFAULT_TIMEOUT); | ||
| 679 | } | ||
| 680 | EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); | ||
| 681 | |||
| 682 | |||
| 683 | /** | ||
| 684 | * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device | ||
| 685 | * @core - device to send the command to | ||
| 686 | * @intb - INTB pin function configuration: | ||
| 687 | * SI476X_INTB_NOOP - do not modify the behaviour | ||
| 688 | * SI476X_INTB_TRISTATE - put the pin in tristate condition, | ||
| 689 | * enable 1MOhm pulldown | ||
| 690 | * SI476X_INTB_DAUDIO - set pin to be a part of digital | ||
| 691 | * audio interface in slave mode | ||
| 692 | * SI476X_INTB_IRQ - set pin to be an interrupt request line | ||
| 693 | * @a1 - A1 pin function configuration: | ||
| 694 | * SI476X_A1_NOOP - do not modify the behaviour | ||
| 695 | * SI476X_A1_TRISTATE - put the pin in tristate condition, | ||
| 696 | * enable 1MOhm pulldown | ||
| 697 | * SI476X_A1_IRQ - set pin to be an interrupt request line | ||
| 698 | * | ||
| 699 | * Function returns 0 on success and negative error code on failure | ||
| 700 | */ | ||
| 701 | static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, | ||
| 702 | enum si476x_intb_config intb, | ||
| 703 | enum si476x_a1_config a1) | ||
| 704 | { | ||
| 705 | u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; | ||
| 706 | const u8 args[CMD_INTB_PIN_CFG_NARGS] = { | ||
| 707 | PIN_CFG_BYTE(intb), | ||
| 708 | PIN_CFG_BYTE(a1), | ||
| 709 | }; | ||
| 710 | |||
| 711 | return si476x_core_send_command(core, CMD_INTB_PIN_CFG, | ||
| 712 | args, ARRAY_SIZE(args), | ||
| 713 | resp, ARRAY_SIZE(resp), | ||
| 714 | SI476X_DEFAULT_TIMEOUT); | ||
| 715 | } | ||
| 716 | |||
| 717 | static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, | ||
| 718 | enum si476x_intb_config intb, | ||
| 719 | enum si476x_a1_config a1) | ||
| 720 | { | ||
| 721 | u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; | ||
| 722 | const u8 args[CMD_INTB_PIN_CFG_NARGS] = { | ||
| 723 | PIN_CFG_BYTE(intb), | ||
| 724 | PIN_CFG_BYTE(a1), | ||
| 725 | }; | ||
| 726 | |||
| 727 | return si476x_core_send_command(core, CMD_INTB_PIN_CFG, | ||
| 728 | args, ARRAY_SIZE(args), | ||
| 729 | resp, ARRAY_SIZE(resp), | ||
| 730 | SI476X_DEFAULT_TIMEOUT); | ||
| 731 | } | ||
| 732 | |||
| 733 | |||
| 734 | |||
| 735 | /** | ||
| 736 | * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the | ||
| 737 | * device | ||
| 738 | * @core - device to send the command to | ||
| 739 | * @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, | ||
| 740 | * RSSSILINT, BLENDINT, MULTHINT and MULTLINT | ||
| 741 | * @attune - when set the values in the status report are the values | ||
| 742 | * that were calculated at tune | ||
| 743 | * @cancel - abort ongoing seek/tune opertation | ||
| 744 | * @stcack - clear the STCINT bin in status register | ||
| 745 | * @report - all signal quality information retured by the command | ||
| 746 | * (if NULL then the output of the command is ignored) | ||
| 747 | * | ||
| 748 | * Function returns 0 on success and negative error code on failure | ||
| 749 | */ | ||
| 750 | int si476x_core_cmd_am_rsq_status(struct si476x_core *core, | ||
| 751 | struct si476x_rsq_status_args *rsqargs, | ||
| 752 | struct si476x_rsq_status_report *report) | ||
| 753 | { | ||
| 754 | int err; | ||
| 755 | u8 resp[CMD_AM_RSQ_STATUS_NRESP]; | ||
| 756 | const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { | ||
| 757 | rsqargs->rsqack << 3 | rsqargs->attune << 2 | | ||
| 758 | rsqargs->cancel << 1 | rsqargs->stcack, | ||
| 759 | }; | ||
| 760 | |||
| 761 | err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, | ||
| 762 | args, ARRAY_SIZE(args), | ||
| 763 | resp, ARRAY_SIZE(resp), | ||
| 764 | SI476X_DEFAULT_TIMEOUT); | ||
| 765 | /* | ||
| 766 | * Besides getting received signal quality information this | ||
| 767 | * command can be used to just acknowledge different interrupt | ||
| 768 | * flags in those cases it is useless to copy and parse | ||
| 769 | * received data so user can pass NULL, and thus avoid | ||
| 770 | * unnecessary copying. | ||
| 771 | */ | ||
| 772 | if (!report) | ||
| 773 | return err; | ||
| 774 | |||
| 775 | report->snrhint = 0b00001000 & resp[1]; | ||
| 776 | report->snrlint = 0b00000100 & resp[1]; | ||
| 777 | report->rssihint = 0b00000010 & resp[1]; | ||
| 778 | report->rssilint = 0b00000001 & resp[1]; | ||
| 779 | |||
| 780 | report->bltf = 0b10000000 & resp[2]; | ||
| 781 | report->snr_ready = 0b00100000 & resp[2]; | ||
| 782 | report->rssiready = 0b00001000 & resp[2]; | ||
| 783 | report->afcrl = 0b00000010 & resp[2]; | ||
| 784 | report->valid = 0b00000001 & resp[2]; | ||
| 785 | |||
| 786 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
| 787 | report->freqoff = resp[5]; | ||
| 788 | report->rssi = resp[6]; | ||
| 789 | report->snr = resp[7]; | ||
| 790 | report->lassi = resp[9]; | ||
| 791 | report->hassi = resp[10]; | ||
| 792 | report->mult = resp[11]; | ||
| 793 | report->dev = resp[12]; | ||
| 794 | |||
| 795 | return err; | ||
| 796 | } | ||
| 797 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); | ||
| 798 | |||
| 799 | int si476x_core_cmd_fm_acf_status(struct si476x_core *core, | ||
| 800 | struct si476x_acf_status_report *report) | ||
| 801 | { | ||
| 802 | int err; | ||
| 803 | u8 resp[CMD_FM_ACF_STATUS_NRESP]; | ||
| 804 | const u8 args[CMD_FM_ACF_STATUS_NARGS] = { | ||
| 805 | 0x0, | ||
| 806 | }; | ||
| 807 | |||
| 808 | if (!report) | ||
| 809 | return -EINVAL; | ||
| 810 | |||
| 811 | err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, | ||
| 812 | args, ARRAY_SIZE(args), | ||
| 813 | resp, ARRAY_SIZE(resp), | ||
| 814 | SI476X_DEFAULT_TIMEOUT); | ||
| 815 | if (err < 0) | ||
| 816 | return err; | ||
| 817 | |||
| 818 | report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; | ||
| 819 | report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; | ||
| 820 | report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; | ||
| 821 | report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; | ||
| 822 | report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; | ||
| 823 | report->smute = resp[2] & SI476X_ACF_SMUTE; | ||
| 824 | report->smattn = resp[3] & SI476X_ACF_SMATTN; | ||
| 825 | report->chbw = resp[4]; | ||
| 826 | report->hicut = resp[5]; | ||
| 827 | report->hiblend = resp[6]; | ||
| 828 | report->pilot = resp[7] & SI476X_ACF_PILOT; | ||
| 829 | report->stblend = resp[7] & SI476X_ACF_STBLEND; | ||
| 830 | |||
| 831 | return err; | ||
| 832 | } | ||
| 833 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); | ||
| 834 | |||
| 835 | int si476x_core_cmd_am_acf_status(struct si476x_core *core, | ||
| 836 | struct si476x_acf_status_report *report) | ||
| 837 | { | ||
| 838 | int err; | ||
| 839 | u8 resp[CMD_AM_ACF_STATUS_NRESP]; | ||
| 840 | const u8 args[CMD_AM_ACF_STATUS_NARGS] = { | ||
| 841 | 0x0, | ||
| 842 | }; | ||
| 843 | |||
| 844 | if (!report) | ||
| 845 | return -EINVAL; | ||
| 846 | |||
| 847 | err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, | ||
| 848 | args, ARRAY_SIZE(args), | ||
| 849 | resp, ARRAY_SIZE(resp), | ||
| 850 | SI476X_DEFAULT_TIMEOUT); | ||
| 851 | if (err < 0) | ||
| 852 | return err; | ||
| 853 | |||
| 854 | report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; | ||
| 855 | report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; | ||
| 856 | report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; | ||
| 857 | report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; | ||
| 858 | report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; | ||
| 859 | report->smute = resp[2] & SI476X_ACF_SMUTE; | ||
| 860 | report->smattn = resp[3] & SI476X_ACF_SMATTN; | ||
| 861 | report->chbw = resp[4]; | ||
| 862 | report->hicut = resp[5]; | ||
| 863 | |||
| 864 | return err; | ||
| 865 | } | ||
| 866 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); | ||
| 867 | |||
| 868 | |||
| 869 | /** | ||
| 870 | * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the | ||
| 871 | * device | ||
| 872 | * @core - device to send the command to | ||
| 873 | * @seekup - if set the direction of the search is 'up' | ||
| 874 | * @wrap - if set seek wraps when hitting band limit | ||
| 875 | * | ||
| 876 | * This function begins search for a valid station. The station is | ||
| 877 | * considered valid when 'FM_VALID_SNR_THRESHOLD' and | ||
| 878 | * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria | ||
| 879 | * are met. | ||
| 880 | } * | ||
| 881 | * Function returns 0 on success and negative error code on failure | ||
| 882 | */ | ||
| 883 | int si476x_core_cmd_fm_seek_start(struct si476x_core *core, | ||
| 884 | bool seekup, bool wrap) | ||
| 885 | { | ||
| 886 | u8 resp[CMD_FM_SEEK_START_NRESP]; | ||
| 887 | const u8 args[CMD_FM_SEEK_START_NARGS] = { | ||
| 888 | seekup << 3 | wrap << 2, | ||
| 889 | }; | ||
| 890 | |||
| 891 | return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, | ||
| 892 | args, sizeof(args), | ||
| 893 | resp, sizeof(resp)); | ||
| 894 | } | ||
| 895 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); | ||
| 896 | |||
| 897 | /** | ||
| 898 | * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the | ||
| 899 | * device | ||
| 900 | * @core - device to send the command to | ||
| 901 | * @status_only - if set the data is not removed from RDSFIFO, | ||
| 902 | * RDSFIFOUSED is not decremented and data in all the | ||
| 903 | * rest RDS data contains the last valid info received | ||
| 904 | * @mtfifo if set the command clears RDS receive FIFO | ||
| 905 | * @intack if set the command clards the RDSINT bit. | ||
| 906 | * | ||
| 907 | * Function returns 0 on success and negative error code on failure | ||
| 908 | */ | ||
| 909 | int si476x_core_cmd_fm_rds_status(struct si476x_core *core, | ||
| 910 | bool status_only, | ||
| 911 | bool mtfifo, | ||
| 912 | bool intack, | ||
| 913 | struct si476x_rds_status_report *report) | ||
| 914 | { | ||
| 915 | int err; | ||
| 916 | u8 resp[CMD_FM_RDS_STATUS_NRESP]; | ||
| 917 | const u8 args[CMD_FM_RDS_STATUS_NARGS] = { | ||
| 918 | status_only << 2 | mtfifo << 1 | intack, | ||
| 919 | }; | ||
| 920 | |||
| 921 | err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, | ||
| 922 | args, ARRAY_SIZE(args), | ||
| 923 | resp, ARRAY_SIZE(resp), | ||
| 924 | SI476X_DEFAULT_TIMEOUT); | ||
| 925 | /* | ||
| 926 | * Besides getting RDS status information this command can be | ||
| 927 | * used to just acknowledge different interrupt flags in those | ||
| 928 | * cases it is useless to copy and parse received data so user | ||
| 929 | * can pass NULL, and thus avoid unnecessary copying. | ||
| 930 | */ | ||
| 931 | if (err < 0 || report == NULL) | ||
| 932 | return err; | ||
| 933 | |||
| 934 | report->rdstpptyint = 0b00010000 & resp[1]; | ||
| 935 | report->rdspiint = 0b00001000 & resp[1]; | ||
| 936 | report->rdssyncint = 0b00000010 & resp[1]; | ||
| 937 | report->rdsfifoint = 0b00000001 & resp[1]; | ||
| 938 | |||
| 939 | report->tpptyvalid = 0b00010000 & resp[2]; | ||
| 940 | report->pivalid = 0b00001000 & resp[2]; | ||
| 941 | report->rdssync = 0b00000010 & resp[2]; | ||
| 942 | report->rdsfifolost = 0b00000001 & resp[2]; | ||
| 943 | |||
| 944 | report->tp = 0b00100000 & resp[3]; | ||
| 945 | report->pty = 0b00011111 & resp[3]; | ||
| 946 | |||
| 947 | report->pi = be16_to_cpup((__be16 *)(resp + 4)); | ||
| 948 | report->rdsfifoused = resp[6]; | ||
| 949 | |||
| 950 | report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; | ||
| 951 | report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; | ||
| 952 | report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; | ||
| 953 | report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; | ||
| 954 | |||
| 955 | report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; | ||
| 956 | report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; | ||
| 957 | report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; | ||
| 958 | |||
| 959 | report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; | ||
| 960 | report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; | ||
| 961 | report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; | ||
| 962 | |||
| 963 | report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; | ||
| 964 | report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; | ||
| 965 | report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; | ||
| 966 | |||
| 967 | report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; | ||
| 968 | report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; | ||
| 969 | report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; | ||
| 970 | |||
| 971 | return err; | ||
| 972 | } | ||
| 973 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); | ||
| 974 | |||
| 975 | int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, | ||
| 976 | bool clear, | ||
| 977 | struct si476x_rds_blockcount_report *report) | ||
| 978 | { | ||
| 979 | int err; | ||
| 980 | u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; | ||
| 981 | const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { | ||
| 982 | clear, | ||
| 983 | }; | ||
| 984 | |||
| 985 | if (!report) | ||
| 986 | return -EINVAL; | ||
| 987 | |||
| 988 | err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, | ||
| 989 | args, ARRAY_SIZE(args), | ||
| 990 | resp, ARRAY_SIZE(resp), | ||
| 991 | SI476X_DEFAULT_TIMEOUT); | ||
| 992 | |||
| 993 | if (!err) { | ||
| 994 | report->expected = be16_to_cpup((__be16 *)(resp + 2)); | ||
| 995 | report->received = be16_to_cpup((__be16 *)(resp + 4)); | ||
| 996 | report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); | ||
| 997 | } | ||
| 998 | |||
| 999 | return err; | ||
| 1000 | } | ||
| 1001 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); | ||
| 1002 | |||
| 1003 | int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, | ||
| 1004 | enum si476x_phase_diversity_mode mode) | ||
| 1005 | { | ||
| 1006 | u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; | ||
| 1007 | const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { | ||
| 1008 | mode & 0b111, | ||
| 1009 | }; | ||
| 1010 | |||
| 1011 | return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, | ||
| 1012 | args, ARRAY_SIZE(args), | ||
| 1013 | resp, ARRAY_SIZE(resp), | ||
| 1014 | SI476X_DEFAULT_TIMEOUT); | ||
| 1015 | } | ||
| 1016 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); | ||
| 1017 | /** | ||
| 1018 | * si476x_core_cmd_fm_phase_div_status() - get the phase diversity | ||
| 1019 | * status | ||
| 1020 | * | ||
| 1021 | * @core: si476x device | ||
| 1022 | * | ||
| 1023 | * NOTE caller must hold core lock | ||
| 1024 | * | ||
| 1025 | * Function returns the value of the status bit in case of success and | ||
| 1026 | * negative error code in case of failre. | ||
| 1027 | */ | ||
| 1028 | int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) | ||
| 1029 | { | ||
| 1030 | int err; | ||
| 1031 | u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; | ||
| 1032 | |||
| 1033 | err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, | ||
| 1034 | NULL, 0, | ||
| 1035 | resp, ARRAY_SIZE(resp), | ||
| 1036 | SI476X_DEFAULT_TIMEOUT); | ||
| 1037 | |||
| 1038 | return (err < 0) ? err : resp[1]; | ||
| 1039 | } | ||
| 1040 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); | ||
| 1041 | |||
| 1042 | |||
| 1043 | /** | ||
| 1044 | * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the | ||
| 1045 | * device | ||
| 1046 | * @core - device to send the command to | ||
| 1047 | * @seekup - if set the direction of the search is 'up' | ||
| 1048 | * @wrap - if set seek wraps when hitting band limit | ||
| 1049 | * | ||
| 1050 | * This function begins search for a valid station. The station is | ||
| 1051 | * considered valid when 'FM_VALID_SNR_THRESHOLD' and | ||
| 1052 | * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria | ||
| 1053 | * are met. | ||
| 1054 | * | ||
| 1055 | * Function returns 0 on success and negative error code on failure | ||
| 1056 | */ | ||
| 1057 | int si476x_core_cmd_am_seek_start(struct si476x_core *core, | ||
| 1058 | bool seekup, bool wrap) | ||
| 1059 | { | ||
| 1060 | u8 resp[CMD_AM_SEEK_START_NRESP]; | ||
| 1061 | const u8 args[CMD_AM_SEEK_START_NARGS] = { | ||
| 1062 | seekup << 3 | wrap << 2, | ||
| 1063 | }; | ||
| 1064 | |||
| 1065 | return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, | ||
| 1066 | args, sizeof(args), | ||
| 1067 | resp, sizeof(resp)); | ||
| 1068 | } | ||
| 1069 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); | ||
| 1070 | |||
| 1071 | |||
| 1072 | |||
| 1073 | static int si476x_core_cmd_power_up_a10(struct si476x_core *core, | ||
| 1074 | struct si476x_power_up_args *puargs) | ||
| 1075 | { | ||
| 1076 | u8 resp[CMD_POWER_UP_A10_NRESP]; | ||
| 1077 | const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); | ||
| 1078 | const bool ctsen = (core->client->irq != 0); | ||
| 1079 | const u8 args[CMD_POWER_UP_A10_NARGS] = { | ||
| 1080 | 0xF7, /* Reserved, always 0xF7 */ | ||
| 1081 | 0x3F & puargs->xcload, /* First two bits are reserved to be | ||
| 1082 | * zeros */ | ||
| 1083 | ctsen << 7 | intsel << 6 | 0x07, /* Last five bits | ||
| 1084 | * are reserved to | ||
| 1085 | * be written as 0x7 */ | ||
| 1086 | puargs->func << 4 | puargs->freq, | ||
| 1087 | 0x11, /* Reserved, always 0x11 */ | ||
| 1088 | }; | ||
| 1089 | |||
| 1090 | return si476x_core_send_command(core, CMD_POWER_UP, | ||
| 1091 | args, ARRAY_SIZE(args), | ||
| 1092 | resp, ARRAY_SIZE(resp), | ||
| 1093 | SI476X_TIMEOUT_POWER_UP); | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | static int si476x_core_cmd_power_up_a20(struct si476x_core *core, | ||
| 1097 | struct si476x_power_up_args *puargs) | ||
| 1098 | { | ||
| 1099 | u8 resp[CMD_POWER_UP_A20_NRESP]; | ||
| 1100 | const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); | ||
| 1101 | const bool ctsen = (core->client->irq != 0); | ||
| 1102 | const u8 args[CMD_POWER_UP_A20_NARGS] = { | ||
| 1103 | puargs->ibias6x << 7 | puargs->xstart, | ||
| 1104 | 0x3F & puargs->xcload, /* First two bits are reserved to be | ||
| 1105 | * zeros */ | ||
| 1106 | ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | | ||
| 1107 | puargs->xbiashc << 3 | puargs->xbias, | ||
| 1108 | puargs->func << 4 | puargs->freq, | ||
| 1109 | 0x10 | puargs->xmode, | ||
| 1110 | }; | ||
| 1111 | |||
| 1112 | return si476x_core_send_command(core, CMD_POWER_UP, | ||
| 1113 | args, ARRAY_SIZE(args), | ||
| 1114 | resp, ARRAY_SIZE(resp), | ||
| 1115 | SI476X_TIMEOUT_POWER_UP); | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | static int si476x_core_cmd_power_down_a10(struct si476x_core *core, | ||
| 1119 | struct si476x_power_down_args *pdargs) | ||
| 1120 | { | ||
| 1121 | u8 resp[CMD_POWER_DOWN_A10_NRESP]; | ||
| 1122 | |||
| 1123 | return si476x_core_send_command(core, CMD_POWER_DOWN, | ||
| 1124 | NULL, 0, | ||
| 1125 | resp, ARRAY_SIZE(resp), | ||
| 1126 | SI476X_DEFAULT_TIMEOUT); | ||
| 1127 | } | ||
| 1128 | |||
| 1129 | static int si476x_core_cmd_power_down_a20(struct si476x_core *core, | ||
| 1130 | struct si476x_power_down_args *pdargs) | ||
| 1131 | { | ||
| 1132 | u8 resp[CMD_POWER_DOWN_A20_NRESP]; | ||
| 1133 | const u8 args[CMD_POWER_DOWN_A20_NARGS] = { | ||
| 1134 | pdargs->xosc, | ||
| 1135 | }; | ||
| 1136 | return si476x_core_send_command(core, CMD_POWER_DOWN, | ||
| 1137 | args, ARRAY_SIZE(args), | ||
| 1138 | resp, ARRAY_SIZE(resp), | ||
| 1139 | SI476X_DEFAULT_TIMEOUT); | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, | ||
| 1143 | struct si476x_tune_freq_args *tuneargs) | ||
| 1144 | { | ||
| 1145 | |||
| 1146 | const int am_freq = tuneargs->freq; | ||
| 1147 | u8 resp[CMD_AM_TUNE_FREQ_NRESP]; | ||
| 1148 | const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { | ||
| 1149 | (tuneargs->hd << 6), | ||
| 1150 | msb(am_freq), | ||
| 1151 | lsb(am_freq), | ||
| 1152 | }; | ||
| 1153 | |||
| 1154 | return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, | ||
| 1155 | sizeof(args), | ||
| 1156 | resp, sizeof(resp)); | ||
| 1157 | } | ||
| 1158 | |||
| 1159 | static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, | ||
| 1160 | struct si476x_tune_freq_args *tuneargs) | ||
| 1161 | { | ||
| 1162 | const int am_freq = tuneargs->freq; | ||
| 1163 | u8 resp[CMD_AM_TUNE_FREQ_NRESP]; | ||
| 1164 | const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { | ||
| 1165 | (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), | ||
| 1166 | msb(am_freq), | ||
| 1167 | lsb(am_freq), | ||
| 1168 | }; | ||
| 1169 | |||
| 1170 | return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, | ||
| 1171 | args, sizeof(args), | ||
| 1172 | resp, sizeof(resp)); | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, | ||
| 1176 | struct si476x_rsq_status_args *rsqargs, | ||
| 1177 | struct si476x_rsq_status_report *report) | ||
| 1178 | { | ||
| 1179 | int err; | ||
| 1180 | u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; | ||
| 1181 | const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { | ||
| 1182 | rsqargs->rsqack << 3 | rsqargs->attune << 2 | | ||
| 1183 | rsqargs->cancel << 1 | rsqargs->stcack, | ||
| 1184 | }; | ||
| 1185 | |||
| 1186 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
| 1187 | args, ARRAY_SIZE(args), | ||
| 1188 | resp, ARRAY_SIZE(resp), | ||
| 1189 | SI476X_DEFAULT_TIMEOUT); | ||
| 1190 | /* | ||
| 1191 | * Besides getting received signal quality information this | ||
| 1192 | * command can be used to just acknowledge different interrupt | ||
| 1193 | * flags in those cases it is useless to copy and parse | ||
| 1194 | * received data so user can pass NULL, and thus avoid | ||
| 1195 | * unnecessary copying. | ||
| 1196 | */ | ||
| 1197 | if (err < 0 || report == NULL) | ||
| 1198 | return err; | ||
| 1199 | |||
| 1200 | report->multhint = 0b10000000 & resp[1]; | ||
| 1201 | report->multlint = 0b01000000 & resp[1]; | ||
| 1202 | report->snrhint = 0b00001000 & resp[1]; | ||
| 1203 | report->snrlint = 0b00000100 & resp[1]; | ||
| 1204 | report->rssihint = 0b00000010 & resp[1]; | ||
| 1205 | report->rssilint = 0b00000001 & resp[1]; | ||
| 1206 | |||
| 1207 | report->bltf = 0b10000000 & resp[2]; | ||
| 1208 | report->snr_ready = 0b00100000 & resp[2]; | ||
| 1209 | report->rssiready = 0b00001000 & resp[2]; | ||
| 1210 | report->afcrl = 0b00000010 & resp[2]; | ||
| 1211 | report->valid = 0b00000001 & resp[2]; | ||
| 1212 | |||
| 1213 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
| 1214 | report->freqoff = resp[5]; | ||
| 1215 | report->rssi = resp[6]; | ||
| 1216 | report->snr = resp[7]; | ||
| 1217 | report->lassi = resp[9]; | ||
| 1218 | report->hassi = resp[10]; | ||
| 1219 | report->mult = resp[11]; | ||
| 1220 | report->dev = resp[12]; | ||
| 1221 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
| 1222 | report->assi = resp[15]; | ||
| 1223 | report->usn = resp[16]; | ||
| 1224 | |||
| 1225 | return err; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, | ||
| 1229 | struct si476x_rsq_status_args *rsqargs, | ||
| 1230 | struct si476x_rsq_status_report *report) | ||
| 1231 | { | ||
| 1232 | int err; | ||
| 1233 | u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; | ||
| 1234 | const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { | ||
| 1235 | rsqargs->primary << 4 | rsqargs->rsqack << 3 | | ||
| 1236 | rsqargs->attune << 2 | rsqargs->cancel << 1 | | ||
| 1237 | rsqargs->stcack, | ||
| 1238 | }; | ||
| 1239 | |||
| 1240 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
| 1241 | args, ARRAY_SIZE(args), | ||
| 1242 | resp, ARRAY_SIZE(resp), | ||
| 1243 | SI476X_DEFAULT_TIMEOUT); | ||
| 1244 | /* | ||
| 1245 | * Besides getting received signal quality information this | ||
| 1246 | * command can be used to just acknowledge different interrupt | ||
| 1247 | * flags in those cases it is useless to copy and parse | ||
| 1248 | * received data so user can pass NULL, and thus avoid | ||
| 1249 | * unnecessary copying. | ||
| 1250 | */ | ||
| 1251 | if (err < 0 || report == NULL) | ||
| 1252 | return err; | ||
| 1253 | |||
| 1254 | report->multhint = 0b10000000 & resp[1]; | ||
| 1255 | report->multlint = 0b01000000 & resp[1]; | ||
| 1256 | report->snrhint = 0b00001000 & resp[1]; | ||
| 1257 | report->snrlint = 0b00000100 & resp[1]; | ||
| 1258 | report->rssihint = 0b00000010 & resp[1]; | ||
| 1259 | report->rssilint = 0b00000001 & resp[1]; | ||
| 1260 | |||
| 1261 | report->bltf = 0b10000000 & resp[2]; | ||
| 1262 | report->snr_ready = 0b00100000 & resp[2]; | ||
| 1263 | report->rssiready = 0b00001000 & resp[2]; | ||
| 1264 | report->afcrl = 0b00000010 & resp[2]; | ||
| 1265 | report->valid = 0b00000001 & resp[2]; | ||
| 1266 | |||
| 1267 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
| 1268 | report->freqoff = resp[5]; | ||
| 1269 | report->rssi = resp[6]; | ||
| 1270 | report->snr = resp[7]; | ||
| 1271 | report->lassi = resp[9]; | ||
| 1272 | report->hassi = resp[10]; | ||
| 1273 | report->mult = resp[11]; | ||
| 1274 | report->dev = resp[12]; | ||
| 1275 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
| 1276 | report->assi = resp[15]; | ||
| 1277 | report->usn = resp[16]; | ||
| 1278 | |||
| 1279 | return err; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | |||
| 1283 | static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, | ||
| 1284 | struct si476x_rsq_status_args *rsqargs, | ||
| 1285 | struct si476x_rsq_status_report *report) | ||
| 1286 | { | ||
| 1287 | int err; | ||
| 1288 | u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; | ||
| 1289 | const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { | ||
| 1290 | rsqargs->primary << 4 | rsqargs->rsqack << 3 | | ||
| 1291 | rsqargs->attune << 2 | rsqargs->cancel << 1 | | ||
| 1292 | rsqargs->stcack, | ||
| 1293 | }; | ||
| 1294 | |||
| 1295 | err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, | ||
| 1296 | args, ARRAY_SIZE(args), | ||
| 1297 | resp, ARRAY_SIZE(resp), | ||
| 1298 | SI476X_DEFAULT_TIMEOUT); | ||
| 1299 | /* | ||
| 1300 | * Besides getting received signal quality information this | ||
| 1301 | * command can be used to just acknowledge different interrupt | ||
| 1302 | * flags in those cases it is useless to copy and parse | ||
| 1303 | * received data so user can pass NULL, and thus avoid | ||
| 1304 | * unnecessary copying. | ||
| 1305 | */ | ||
| 1306 | if (err < 0 || report == NULL) | ||
| 1307 | return err; | ||
| 1308 | |||
| 1309 | report->multhint = 0b10000000 & resp[1]; | ||
| 1310 | report->multlint = 0b01000000 & resp[1]; | ||
| 1311 | report->snrhint = 0b00001000 & resp[1]; | ||
| 1312 | report->snrlint = 0b00000100 & resp[1]; | ||
| 1313 | report->rssihint = 0b00000010 & resp[1]; | ||
| 1314 | report->rssilint = 0b00000001 & resp[1]; | ||
| 1315 | |||
| 1316 | report->bltf = 0b10000000 & resp[2]; | ||
| 1317 | report->snr_ready = 0b00100000 & resp[2]; | ||
| 1318 | report->rssiready = 0b00001000 & resp[2]; | ||
| 1319 | report->injside = 0b00000100 & resp[2]; | ||
| 1320 | report->afcrl = 0b00000010 & resp[2]; | ||
| 1321 | report->valid = 0b00000001 & resp[2]; | ||
| 1322 | |||
| 1323 | report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); | ||
| 1324 | report->freqoff = resp[5]; | ||
| 1325 | report->rssi = resp[6]; | ||
| 1326 | report->snr = resp[7]; | ||
| 1327 | report->issi = resp[8]; | ||
| 1328 | report->lassi = resp[9]; | ||
| 1329 | report->hassi = resp[10]; | ||
| 1330 | report->mult = resp[11]; | ||
| 1331 | report->dev = resp[12]; | ||
| 1332 | report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); | ||
| 1333 | report->assi = resp[15]; | ||
| 1334 | report->usn = resp[16]; | ||
| 1335 | |||
| 1336 | report->pilotdev = resp[17]; | ||
| 1337 | report->rdsdev = resp[18]; | ||
| 1338 | report->assidev = resp[19]; | ||
| 1339 | report->strongdev = resp[20]; | ||
| 1340 | report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); | ||
| 1341 | |||
| 1342 | return err; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, | ||
| 1346 | struct si476x_tune_freq_args *tuneargs) | ||
| 1347 | { | ||
| 1348 | u8 resp[CMD_FM_TUNE_FREQ_NRESP]; | ||
| 1349 | const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { | ||
| 1350 | (tuneargs->hd << 6) | (tuneargs->tunemode << 4) | ||
| 1351 | | (tuneargs->smoothmetrics << 2), | ||
| 1352 | msb(tuneargs->freq), | ||
| 1353 | lsb(tuneargs->freq), | ||
| 1354 | msb(tuneargs->antcap), | ||
| 1355 | lsb(tuneargs->antcap) | ||
| 1356 | }; | ||
| 1357 | |||
| 1358 | return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, | ||
| 1359 | args, sizeof(args), | ||
| 1360 | resp, sizeof(resp)); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, | ||
| 1364 | struct si476x_tune_freq_args *tuneargs) | ||
| 1365 | { | ||
| 1366 | u8 resp[CMD_FM_TUNE_FREQ_NRESP]; | ||
| 1367 | const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { | ||
| 1368 | (tuneargs->hd << 6) | (tuneargs->tunemode << 4) | ||
| 1369 | | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), | ||
| 1370 | msb(tuneargs->freq), | ||
| 1371 | lsb(tuneargs->freq), | ||
| 1372 | }; | ||
| 1373 | |||
| 1374 | return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, | ||
| 1375 | args, sizeof(args), | ||
| 1376 | resp, sizeof(resp)); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | static int si476x_core_cmd_agc_status_a20(struct si476x_core *core, | ||
| 1380 | struct si476x_agc_status_report *report) | ||
| 1381 | { | ||
| 1382 | int err; | ||
| 1383 | u8 resp[CMD_AGC_STATUS_NRESP_A20]; | ||
| 1384 | |||
| 1385 | if (!report) | ||
| 1386 | return -EINVAL; | ||
| 1387 | |||
| 1388 | err = si476x_core_send_command(core, CMD_AGC_STATUS, | ||
| 1389 | NULL, 0, | ||
| 1390 | resp, ARRAY_SIZE(resp), | ||
| 1391 | SI476X_DEFAULT_TIMEOUT); | ||
| 1392 | if (err < 0) | ||
| 1393 | return err; | ||
| 1394 | |||
| 1395 | report->mxhi = resp[1] & SI476X_AGC_MXHI; | ||
| 1396 | report->mxlo = resp[1] & SI476X_AGC_MXLO; | ||
| 1397 | report->lnahi = resp[1] & SI476X_AGC_LNAHI; | ||
| 1398 | report->lnalo = resp[1] & SI476X_AGC_LNALO; | ||
| 1399 | report->fmagc1 = resp[2]; | ||
| 1400 | report->fmagc2 = resp[3]; | ||
| 1401 | report->pgagain = resp[4]; | ||
| 1402 | report->fmwblang = resp[5]; | ||
| 1403 | |||
| 1404 | return err; | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | static int si476x_core_cmd_agc_status_a10(struct si476x_core *core, | ||
| 1408 | struct si476x_agc_status_report *report) | ||
| 1409 | { | ||
| 1410 | int err; | ||
| 1411 | u8 resp[CMD_AGC_STATUS_NRESP_A10]; | ||
| 1412 | |||
| 1413 | if (!report) | ||
| 1414 | return -EINVAL; | ||
| 1415 | |||
| 1416 | err = si476x_core_send_command(core, CMD_AGC_STATUS, | ||
| 1417 | NULL, 0, | ||
| 1418 | resp, ARRAY_SIZE(resp), | ||
| 1419 | SI476X_DEFAULT_TIMEOUT); | ||
| 1420 | if (err < 0) | ||
| 1421 | return err; | ||
| 1422 | |||
| 1423 | report->mxhi = resp[1] & SI476X_AGC_MXHI; | ||
| 1424 | report->mxlo = resp[1] & SI476X_AGC_MXLO; | ||
| 1425 | report->lnahi = resp[1] & SI476X_AGC_LNAHI; | ||
| 1426 | report->lnalo = resp[1] & SI476X_AGC_LNALO; | ||
| 1427 | |||
| 1428 | return err; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | typedef int (*tune_freq_func_t) (struct si476x_core *core, | ||
| 1432 | struct si476x_tune_freq_args *tuneargs); | ||
| 1433 | |||
| 1434 | static struct { | ||
| 1435 | int (*power_up) (struct si476x_core *, | ||
| 1436 | struct si476x_power_up_args *); | ||
| 1437 | int (*power_down) (struct si476x_core *, | ||
| 1438 | struct si476x_power_down_args *); | ||
| 1439 | |||
| 1440 | tune_freq_func_t fm_tune_freq; | ||
| 1441 | tune_freq_func_t am_tune_freq; | ||
| 1442 | |||
| 1443 | int (*fm_rsq_status)(struct si476x_core *, | ||
| 1444 | struct si476x_rsq_status_args *, | ||
| 1445 | struct si476x_rsq_status_report *); | ||
| 1446 | |||
| 1447 | int (*agc_status)(struct si476x_core *, | ||
| 1448 | struct si476x_agc_status_report *); | ||
| 1449 | int (*intb_pin_cfg)(struct si476x_core *core, | ||
| 1450 | enum si476x_intb_config intb, | ||
| 1451 | enum si476x_a1_config a1); | ||
| 1452 | } si476x_cmds_vtable[] = { | ||
| 1453 | [SI476X_REVISION_A10] = { | ||
| 1454 | .power_up = si476x_core_cmd_power_up_a10, | ||
| 1455 | .power_down = si476x_core_cmd_power_down_a10, | ||
| 1456 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, | ||
| 1457 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, | ||
| 1458 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, | ||
| 1459 | .agc_status = si476x_core_cmd_agc_status_a10, | ||
| 1460 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, | ||
| 1461 | }, | ||
| 1462 | [SI476X_REVISION_A20] = { | ||
| 1463 | .power_up = si476x_core_cmd_power_up_a20, | ||
| 1464 | .power_down = si476x_core_cmd_power_down_a20, | ||
| 1465 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, | ||
| 1466 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, | ||
| 1467 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, | ||
| 1468 | .agc_status = si476x_core_cmd_agc_status_a20, | ||
| 1469 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, | ||
| 1470 | }, | ||
| 1471 | [SI476X_REVISION_A30] = { | ||
| 1472 | .power_up = si476x_core_cmd_power_up_a20, | ||
| 1473 | .power_down = si476x_core_cmd_power_down_a20, | ||
| 1474 | .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, | ||
| 1475 | .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, | ||
| 1476 | .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, | ||
| 1477 | .agc_status = si476x_core_cmd_agc_status_a20, | ||
| 1478 | .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, | ||
| 1479 | }, | ||
| 1480 | }; | ||
| 1481 | |||
| 1482 | int si476x_core_cmd_power_up(struct si476x_core *core, | ||
| 1483 | struct si476x_power_up_args *args) | ||
| 1484 | { | ||
| 1485 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1486 | core->revision == -1); | ||
| 1487 | return si476x_cmds_vtable[core->revision].power_up(core, args); | ||
| 1488 | } | ||
| 1489 | EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); | ||
| 1490 | |||
| 1491 | int si476x_core_cmd_power_down(struct si476x_core *core, | ||
| 1492 | struct si476x_power_down_args *args) | ||
| 1493 | { | ||
| 1494 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1495 | core->revision == -1); | ||
| 1496 | return si476x_cmds_vtable[core->revision].power_down(core, args); | ||
| 1497 | } | ||
| 1498 | EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); | ||
| 1499 | |||
| 1500 | int si476x_core_cmd_fm_tune_freq(struct si476x_core *core, | ||
| 1501 | struct si476x_tune_freq_args *args) | ||
| 1502 | { | ||
| 1503 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1504 | core->revision == -1); | ||
| 1505 | return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); | ||
| 1506 | } | ||
| 1507 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); | ||
| 1508 | |||
| 1509 | int si476x_core_cmd_am_tune_freq(struct si476x_core *core, | ||
| 1510 | struct si476x_tune_freq_args *args) | ||
| 1511 | { | ||
| 1512 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1513 | core->revision == -1); | ||
| 1514 | return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); | ||
| 1515 | } | ||
| 1516 | EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); | ||
| 1517 | |||
| 1518 | int si476x_core_cmd_fm_rsq_status(struct si476x_core *core, | ||
| 1519 | struct si476x_rsq_status_args *args, | ||
| 1520 | struct si476x_rsq_status_report *report) | ||
| 1521 | |||
| 1522 | { | ||
| 1523 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1524 | core->revision == -1); | ||
| 1525 | return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, | ||
| 1526 | report); | ||
| 1527 | } | ||
| 1528 | EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); | ||
| 1529 | |||
| 1530 | int si476x_core_cmd_agc_status(struct si476x_core *core, | ||
| 1531 | struct si476x_agc_status_report *report) | ||
| 1532 | |||
| 1533 | { | ||
| 1534 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1535 | core->revision == -1); | ||
| 1536 | return si476x_cmds_vtable[core->revision].agc_status(core, report); | ||
| 1537 | } | ||
| 1538 | EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); | ||
| 1539 | |||
| 1540 | int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, | ||
| 1541 | enum si476x_intb_config intb, | ||
| 1542 | enum si476x_a1_config a1) | ||
| 1543 | { | ||
| 1544 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 1545 | core->revision == -1); | ||
| 1546 | |||
| 1547 | return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); | ||
| 1548 | } | ||
| 1549 | EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); | ||
| 1550 | |||
| 1551 | MODULE_LICENSE("GPL"); | ||
| 1552 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
| 1553 | MODULE_DESCRIPTION("API for command exchange for si476x"); | ||
diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c new file mode 100644 index 000000000000..f5bc8e4bd4bf --- /dev/null +++ b/drivers/mfd/si476x-i2c.c | |||
| @@ -0,0 +1,886 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD | ||
| 3 | * device | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
| 6 | * Copyright (C) 2013 Andrey Smirnov | ||
| 7 | * | ||
| 8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; version 2 of the License. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | #include <linux/module.h> | ||
| 21 | |||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/gpio.h> | ||
| 26 | #include <linux/regulator/consumer.h> | ||
| 27 | #include <linux/i2c.h> | ||
| 28 | #include <linux/err.h> | ||
| 29 | |||
| 30 | #include <linux/mfd/si476x-core.h> | ||
| 31 | |||
| 32 | #define SI476X_MAX_IO_ERRORS 10 | ||
| 33 | #define SI476X_DRIVER_RDS_FIFO_DEPTH 128 | ||
| 34 | |||
| 35 | /** | ||
| 36 | * si476x_core_config_pinmux() - pin function configuration function | ||
| 37 | * | ||
| 38 | * @core: Core device structure | ||
| 39 | * | ||
| 40 | * Configure the functions of the pins of the radio chip. | ||
| 41 | * | ||
| 42 | * The function returns zero in case of succes or negative error code | ||
| 43 | * otherwise. | ||
| 44 | */ | ||
| 45 | static int si476x_core_config_pinmux(struct si476x_core *core) | ||
| 46 | { | ||
| 47 | int err; | ||
| 48 | dev_dbg(&core->client->dev, "Configuring pinmux\n"); | ||
| 49 | err = si476x_core_cmd_dig_audio_pin_cfg(core, | ||
| 50 | core->pinmux.dclk, | ||
| 51 | core->pinmux.dfs, | ||
| 52 | core->pinmux.dout, | ||
| 53 | core->pinmux.xout); | ||
| 54 | if (err < 0) { | ||
| 55 | dev_err(&core->client->dev, | ||
| 56 | "Failed to configure digital audio pins(err = %d)\n", | ||
| 57 | err); | ||
| 58 | return err; | ||
| 59 | } | ||
| 60 | |||
| 61 | err = si476x_core_cmd_zif_pin_cfg(core, | ||
| 62 | core->pinmux.iqclk, | ||
| 63 | core->pinmux.iqfs, | ||
| 64 | core->pinmux.iout, | ||
| 65 | core->pinmux.qout); | ||
| 66 | if (err < 0) { | ||
| 67 | dev_err(&core->client->dev, | ||
| 68 | "Failed to configure ZIF pins(err = %d)\n", | ||
| 69 | err); | ||
| 70 | return err; | ||
| 71 | } | ||
| 72 | |||
| 73 | err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core, | ||
| 74 | core->pinmux.icin, | ||
| 75 | core->pinmux.icip, | ||
| 76 | core->pinmux.icon, | ||
| 77 | core->pinmux.icop); | ||
| 78 | if (err < 0) { | ||
| 79 | dev_err(&core->client->dev, | ||
| 80 | "Failed to configure IC-Link/GPO pins(err = %d)\n", | ||
| 81 | err); | ||
| 82 | return err; | ||
| 83 | } | ||
| 84 | |||
| 85 | err = si476x_core_cmd_ana_audio_pin_cfg(core, | ||
| 86 | core->pinmux.lrout); | ||
| 87 | if (err < 0) { | ||
| 88 | dev_err(&core->client->dev, | ||
| 89 | "Failed to configure analog audio pins(err = %d)\n", | ||
| 90 | err); | ||
| 91 | return err; | ||
| 92 | } | ||
| 93 | |||
| 94 | err = si476x_core_cmd_intb_pin_cfg(core, | ||
| 95 | core->pinmux.intb, | ||
| 96 | core->pinmux.a1); | ||
| 97 | if (err < 0) { | ||
| 98 | dev_err(&core->client->dev, | ||
| 99 | "Failed to configure interrupt pins(err = %d)\n", | ||
| 100 | err); | ||
| 101 | return err; | ||
| 102 | } | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline void si476x_core_schedule_polling_work(struct si476x_core *core) | ||
| 108 | { | ||
| 109 | schedule_delayed_work(&core->status_monitor, | ||
| 110 | usecs_to_jiffies(SI476X_STATUS_POLL_US)); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * si476x_core_start() - early chip startup function | ||
| 115 | * @core: Core device structure | ||
| 116 | * @soft: When set, this flag forces "soft" startup, where "soft" | ||
| 117 | * power down is the one done by sending appropriate command instead | ||
| 118 | * of using reset pin of the tuner | ||
| 119 | * | ||
| 120 | * Perform required startup sequence to correctly power | ||
| 121 | * up the chip and perform initial configuration. It does the | ||
| 122 | * following sequence of actions: | ||
| 123 | * 1. Claims and enables the power supplies VD and VIO1 required | ||
| 124 | * for I2C interface of the chip operation. | ||
| 125 | * 2. Waits for 100us, pulls the reset line up, enables irq, | ||
| 126 | * waits for another 100us as it is specified by the | ||
| 127 | * datasheet. | ||
| 128 | * 3. Sends 'POWER_UP' command to the device with all provided | ||
| 129 | * information about power-up parameters. | ||
| 130 | * 4. Configures, pin multiplexor, disables digital audio and | ||
| 131 | * configures interrupt sources. | ||
| 132 | * | ||
| 133 | * The function returns zero in case of succes or negative error code | ||
| 134 | * otherwise. | ||
| 135 | */ | ||
| 136 | int si476x_core_start(struct si476x_core *core, bool soft) | ||
| 137 | { | ||
| 138 | struct i2c_client *client = core->client; | ||
| 139 | int err; | ||
| 140 | |||
| 141 | if (!soft) { | ||
| 142 | if (gpio_is_valid(core->gpio_reset)) | ||
| 143 | gpio_set_value_cansleep(core->gpio_reset, 1); | ||
| 144 | |||
| 145 | if (client->irq) | ||
| 146 | enable_irq(client->irq); | ||
| 147 | |||
| 148 | udelay(100); | ||
| 149 | |||
| 150 | if (!client->irq) { | ||
| 151 | atomic_set(&core->is_alive, 1); | ||
| 152 | si476x_core_schedule_polling_work(core); | ||
| 153 | } | ||
| 154 | } else { | ||
| 155 | if (client->irq) | ||
| 156 | enable_irq(client->irq); | ||
| 157 | else { | ||
| 158 | atomic_set(&core->is_alive, 1); | ||
| 159 | si476x_core_schedule_polling_work(core); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | err = si476x_core_cmd_power_up(core, | ||
| 164 | &core->power_up_parameters); | ||
| 165 | |||
| 166 | if (err < 0) { | ||
| 167 | dev_err(&core->client->dev, | ||
| 168 | "Power up failure(err = %d)\n", | ||
| 169 | err); | ||
| 170 | goto disable_irq; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (client->irq) | ||
| 174 | atomic_set(&core->is_alive, 1); | ||
| 175 | |||
| 176 | err = si476x_core_config_pinmux(core); | ||
| 177 | if (err < 0) { | ||
| 178 | dev_err(&core->client->dev, | ||
| 179 | "Failed to configure pinmux(err = %d)\n", | ||
| 180 | err); | ||
| 181 | goto disable_irq; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (client->irq) { | ||
| 185 | err = regmap_write(core->regmap, | ||
| 186 | SI476X_PROP_INT_CTL_ENABLE, | ||
| 187 | SI476X_RDSIEN | | ||
| 188 | SI476X_STCIEN | | ||
| 189 | SI476X_CTSIEN); | ||
| 190 | if (err < 0) { | ||
| 191 | dev_err(&core->client->dev, | ||
| 192 | "Failed to configure interrupt sources" | ||
| 193 | "(err = %d)\n", err); | ||
| 194 | goto disable_irq; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | return 0; | ||
| 199 | |||
| 200 | disable_irq: | ||
| 201 | if (err == -ENODEV) | ||
| 202 | atomic_set(&core->is_alive, 0); | ||
| 203 | |||
| 204 | if (client->irq) | ||
| 205 | disable_irq(client->irq); | ||
| 206 | else | ||
| 207 | cancel_delayed_work_sync(&core->status_monitor); | ||
| 208 | |||
| 209 | if (gpio_is_valid(core->gpio_reset)) | ||
| 210 | gpio_set_value_cansleep(core->gpio_reset, 0); | ||
| 211 | |||
| 212 | return err; | ||
| 213 | } | ||
| 214 | EXPORT_SYMBOL_GPL(si476x_core_start); | ||
| 215 | |||
| 216 | /** | ||
| 217 | * si476x_core_stop() - chip power-down function | ||
| 218 | * @core: Core device structure | ||
| 219 | * @soft: When set, function sends a POWER_DOWN command instead of | ||
| 220 | * bringing reset line low | ||
| 221 | * | ||
| 222 | * Power down the chip by performing following actions: | ||
| 223 | * 1. Disable IRQ or stop the polling worker | ||
| 224 | * 2. Send the POWER_DOWN command if the power down is soft or bring | ||
| 225 | * reset line low if not. | ||
| 226 | * | ||
| 227 | * The function returns zero in case of succes or negative error code | ||
| 228 | * otherwise. | ||
| 229 | */ | ||
| 230 | int si476x_core_stop(struct si476x_core *core, bool soft) | ||
| 231 | { | ||
| 232 | int err = 0; | ||
| 233 | atomic_set(&core->is_alive, 0); | ||
| 234 | |||
| 235 | if (soft) { | ||
| 236 | /* TODO: This probably shoud be a configurable option, | ||
| 237 | * so it is possible to have the chips keep their | ||
| 238 | * oscillators running | ||
| 239 | */ | ||
| 240 | struct si476x_power_down_args args = { | ||
| 241 | .xosc = false, | ||
| 242 | }; | ||
| 243 | err = si476x_core_cmd_power_down(core, &args); | ||
| 244 | } | ||
| 245 | |||
| 246 | /* We couldn't disable those before | ||
| 247 | * 'si476x_core_cmd_power_down' since we expect to get CTS | ||
| 248 | * interrupt */ | ||
| 249 | if (core->client->irq) | ||
| 250 | disable_irq(core->client->irq); | ||
| 251 | else | ||
| 252 | cancel_delayed_work_sync(&core->status_monitor); | ||
| 253 | |||
| 254 | if (!soft) { | ||
| 255 | if (gpio_is_valid(core->gpio_reset)) | ||
| 256 | gpio_set_value_cansleep(core->gpio_reset, 0); | ||
| 257 | } | ||
| 258 | return err; | ||
| 259 | } | ||
| 260 | EXPORT_SYMBOL_GPL(si476x_core_stop); | ||
| 261 | |||
| 262 | /** | ||
| 263 | * si476x_core_set_power_state() - set the level at which the power is | ||
| 264 | * supplied for the chip. | ||
| 265 | * @core: Core device structure | ||
| 266 | * @next_state: enum si476x_power_state describing power state to | ||
| 267 | * switch to. | ||
| 268 | * | ||
| 269 | * Switch on all the required power supplies | ||
| 270 | * | ||
| 271 | * This function returns 0 in case of suvccess and negative error code | ||
| 272 | * otherwise. | ||
| 273 | */ | ||
| 274 | int si476x_core_set_power_state(struct si476x_core *core, | ||
| 275 | enum si476x_power_state next_state) | ||
| 276 | { | ||
| 277 | /* | ||
| 278 | It is not clear form the datasheet if it is possible to | ||
| 279 | work with device if not all power domains are operational. | ||
| 280 | So for now the power-up policy is "power-up all the things!" | ||
| 281 | */ | ||
| 282 | int err = 0; | ||
| 283 | |||
| 284 | if (core->power_state == SI476X_POWER_INCONSISTENT) { | ||
| 285 | dev_err(&core->client->dev, | ||
| 286 | "The device in inconsistent power state\n"); | ||
| 287 | return -EINVAL; | ||
| 288 | } | ||
| 289 | |||
| 290 | if (next_state != core->power_state) { | ||
| 291 | switch (next_state) { | ||
| 292 | case SI476X_POWER_UP_FULL: | ||
| 293 | err = regulator_bulk_enable(ARRAY_SIZE(core->supplies), | ||
| 294 | core->supplies); | ||
| 295 | if (err < 0) { | ||
| 296 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
| 297 | break; | ||
| 298 | } | ||
| 299 | /* | ||
| 300 | * Startup timing diagram recommends to have a | ||
| 301 | * 100 us delay between enabling of the power | ||
| 302 | * supplies and turning the tuner on. | ||
| 303 | */ | ||
| 304 | udelay(100); | ||
| 305 | |||
| 306 | err = si476x_core_start(core, false); | ||
| 307 | if (err < 0) | ||
| 308 | goto disable_regulators; | ||
| 309 | |||
| 310 | core->power_state = next_state; | ||
| 311 | break; | ||
| 312 | |||
| 313 | case SI476X_POWER_DOWN: | ||
| 314 | core->power_state = next_state; | ||
| 315 | err = si476x_core_stop(core, false); | ||
| 316 | if (err < 0) | ||
| 317 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
| 318 | disable_regulators: | ||
| 319 | err = regulator_bulk_disable(ARRAY_SIZE(core->supplies), | ||
| 320 | core->supplies); | ||
| 321 | if (err < 0) | ||
| 322 | core->power_state = SI476X_POWER_INCONSISTENT; | ||
| 323 | break; | ||
| 324 | default: | ||
| 325 | BUG(); | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | return err; | ||
| 330 | } | ||
| 331 | EXPORT_SYMBOL_GPL(si476x_core_set_power_state); | ||
| 332 | |||
| 333 | /** | ||
| 334 | * si476x_core_report_drainer_stop() - mark the completion of the RDS | ||
| 335 | * buffer drain porcess by the worker. | ||
| 336 | * | ||
| 337 | * @core: Core device structure | ||
| 338 | */ | ||
| 339 | static inline void si476x_core_report_drainer_stop(struct si476x_core *core) | ||
| 340 | { | ||
| 341 | mutex_lock(&core->rds_drainer_status_lock); | ||
| 342 | core->rds_drainer_is_working = false; | ||
| 343 | mutex_unlock(&core->rds_drainer_status_lock); | ||
| 344 | } | ||
| 345 | |||
| 346 | /** | ||
| 347 | * si476x_core_start_rds_drainer_once() - start RDS drainer worker if | ||
| 348 | * ther is none working, do nothing otherwise | ||
| 349 | * | ||
| 350 | * @core: Datastructure corresponding to the chip. | ||
| 351 | */ | ||
| 352 | static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) | ||
| 353 | { | ||
| 354 | mutex_lock(&core->rds_drainer_status_lock); | ||
| 355 | if (!core->rds_drainer_is_working) { | ||
| 356 | core->rds_drainer_is_working = true; | ||
| 357 | schedule_work(&core->rds_fifo_drainer); | ||
| 358 | } | ||
| 359 | mutex_unlock(&core->rds_drainer_status_lock); | ||
| 360 | } | ||
| 361 | /** | ||
| 362 | * si476x_drain_rds_fifo() - RDS buffer drainer. | ||
| 363 | * @work: struct work_struct being ppassed to the function by the | ||
| 364 | * kernel. | ||
| 365 | * | ||
| 366 | * Drain the contents of the RDS FIFO of | ||
| 367 | */ | ||
| 368 | static void si476x_core_drain_rds_fifo(struct work_struct *work) | ||
| 369 | { | ||
| 370 | int err; | ||
| 371 | |||
| 372 | struct si476x_core *core = container_of(work, struct si476x_core, | ||
| 373 | rds_fifo_drainer); | ||
| 374 | |||
| 375 | struct si476x_rds_status_report report; | ||
| 376 | |||
| 377 | si476x_core_lock(core); | ||
| 378 | err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); | ||
| 379 | if (!err) { | ||
| 380 | int i = report.rdsfifoused; | ||
| 381 | dev_dbg(&core->client->dev, | ||
| 382 | "%d elements in RDS FIFO. Draining.\n", i); | ||
| 383 | for (; i > 0; --i) { | ||
| 384 | err = si476x_core_cmd_fm_rds_status(core, false, false, | ||
| 385 | (i == 1), &report); | ||
| 386 | if (err < 0) | ||
| 387 | goto unlock; | ||
| 388 | |||
| 389 | kfifo_in(&core->rds_fifo, report.rds, | ||
| 390 | sizeof(report.rds)); | ||
| 391 | dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", | ||
| 392 | (int)sizeof(report.rds), report.rds); | ||
| 393 | } | ||
| 394 | dev_dbg(&core->client->dev, "Drrrrained!\n"); | ||
| 395 | wake_up_interruptible(&core->rds_read_queue); | ||
| 396 | } | ||
| 397 | |||
| 398 | unlock: | ||
| 399 | si476x_core_unlock(core); | ||
| 400 | si476x_core_report_drainer_stop(core); | ||
| 401 | } | ||
| 402 | |||
| 403 | /** | ||
| 404 | * si476x_core_pronounce_dead() | ||
| 405 | * | ||
| 406 | * @core: Core device structure | ||
| 407 | * | ||
| 408 | * Mark the device as being dead and wake up all potentially waiting | ||
| 409 | * threads of execution. | ||
| 410 | * | ||
| 411 | */ | ||
| 412 | static void si476x_core_pronounce_dead(struct si476x_core *core) | ||
| 413 | { | ||
| 414 | dev_info(&core->client->dev, "Core device is dead.\n"); | ||
| 415 | |||
| 416 | atomic_set(&core->is_alive, 0); | ||
| 417 | |||
| 418 | /* Wake up al possible waiting processes */ | ||
| 419 | wake_up_interruptible(&core->rds_read_queue); | ||
| 420 | |||
| 421 | atomic_set(&core->cts, 1); | ||
| 422 | wake_up(&core->command); | ||
| 423 | |||
| 424 | atomic_set(&core->stc, 1); | ||
| 425 | wake_up(&core->tuning); | ||
| 426 | } | ||
| 427 | |||
| 428 | /** | ||
| 429 | * si476x_core_i2c_xfer() | ||
| 430 | * | ||
| 431 | * @core: Core device structure | ||
| 432 | * @type: Transfer type | ||
| 433 | * @buf: Transfer buffer for/with data | ||
| 434 | * @count: Transfer buffer size | ||
| 435 | * | ||
| 436 | * Perfrom and I2C transfer(either read or write) and keep a counter | ||
| 437 | * of I/O errors. If the error counter rises above the threshold | ||
| 438 | * pronounce device dead. | ||
| 439 | * | ||
| 440 | * The function returns zero on succes or negative error code on | ||
| 441 | * failure. | ||
| 442 | */ | ||
| 443 | int si476x_core_i2c_xfer(struct si476x_core *core, | ||
| 444 | enum si476x_i2c_type type, | ||
| 445 | char *buf, int count) | ||
| 446 | { | ||
| 447 | static int io_errors_count; | ||
| 448 | int err; | ||
| 449 | if (type == SI476X_I2C_SEND) | ||
| 450 | err = i2c_master_send(core->client, buf, count); | ||
| 451 | else | ||
| 452 | err = i2c_master_recv(core->client, buf, count); | ||
| 453 | |||
| 454 | if (err < 0) { | ||
| 455 | if (io_errors_count++ > SI476X_MAX_IO_ERRORS) | ||
| 456 | si476x_core_pronounce_dead(core); | ||
| 457 | } else { | ||
| 458 | io_errors_count = 0; | ||
| 459 | } | ||
| 460 | |||
| 461 | return err; | ||
| 462 | } | ||
| 463 | EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer); | ||
| 464 | |||
| 465 | /** | ||
| 466 | * si476x_get_status() | ||
| 467 | * @core: Core device structure | ||
| 468 | * | ||
| 469 | * Get the status byte of the core device by berforming one byte I2C | ||
| 470 | * read. | ||
| 471 | * | ||
| 472 | * The function returns a status value or a negative error code on | ||
| 473 | * error. | ||
| 474 | */ | ||
| 475 | static int si476x_core_get_status(struct si476x_core *core) | ||
| 476 | { | ||
| 477 | u8 response; | ||
| 478 | int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, | ||
| 479 | &response, sizeof(response)); | ||
| 480 | |||
| 481 | return (err < 0) ? err : response; | ||
| 482 | } | ||
| 483 | |||
| 484 | /** | ||
| 485 | * si476x_get_and_signal_status() - IRQ dispatcher | ||
| 486 | * @core: Core device structure | ||
| 487 | * | ||
| 488 | * Dispatch the arrived interrupt request based on the value of the | ||
| 489 | * status byte reported by the tuner. | ||
| 490 | * | ||
| 491 | */ | ||
| 492 | static void si476x_core_get_and_signal_status(struct si476x_core *core) | ||
| 493 | { | ||
| 494 | int status = si476x_core_get_status(core); | ||
| 495 | if (status < 0) { | ||
| 496 | dev_err(&core->client->dev, "Failed to get status\n"); | ||
| 497 | return; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (status & SI476X_CTS) { | ||
| 501 | /* Unfortunately completions could not be used for | ||
| 502 | * signalling CTS since this flag cannot be cleared | ||
| 503 | * in status byte, and therefore once it becomes true | ||
| 504 | * multiple calls to 'complete' would cause the | ||
| 505 | * commands following the current one to be completed | ||
| 506 | * before they actually are */ | ||
| 507 | dev_dbg(&core->client->dev, "[interrupt] CTSINT\n"); | ||
| 508 | atomic_set(&core->cts, 1); | ||
| 509 | wake_up(&core->command); | ||
| 510 | } | ||
| 511 | |||
| 512 | if (status & SI476X_FM_RDS_INT) { | ||
| 513 | dev_dbg(&core->client->dev, "[interrupt] RDSINT\n"); | ||
| 514 | si476x_core_start_rds_drainer_once(core); | ||
| 515 | } | ||
| 516 | |||
| 517 | if (status & SI476X_STC_INT) { | ||
| 518 | dev_dbg(&core->client->dev, "[interrupt] STCINT\n"); | ||
| 519 | atomic_set(&core->stc, 1); | ||
| 520 | wake_up(&core->tuning); | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 524 | static void si476x_core_poll_loop(struct work_struct *work) | ||
| 525 | { | ||
| 526 | struct si476x_core *core = SI476X_WORK_TO_CORE(work); | ||
| 527 | |||
| 528 | si476x_core_get_and_signal_status(core); | ||
| 529 | |||
| 530 | if (atomic_read(&core->is_alive)) | ||
| 531 | si476x_core_schedule_polling_work(core); | ||
| 532 | } | ||
| 533 | |||
| 534 | static irqreturn_t si476x_core_interrupt(int irq, void *dev) | ||
| 535 | { | ||
| 536 | struct si476x_core *core = dev; | ||
| 537 | |||
| 538 | si476x_core_get_and_signal_status(core); | ||
| 539 | |||
| 540 | return IRQ_HANDLED; | ||
| 541 | } | ||
| 542 | |||
| 543 | /** | ||
| 544 | * si476x_firmware_version_to_revision() | ||
| 545 | * @core: Core device structure | ||
| 546 | * @major: Firmware major number | ||
| 547 | * @minor1: Firmware first minor number | ||
| 548 | * @minor2: Firmware second minor number | ||
| 549 | * | ||
| 550 | * Convert a chip's firmware version number into an offset that later | ||
| 551 | * will be used to as offset in "vtable" of tuner functions | ||
| 552 | * | ||
| 553 | * This function returns a positive offset in case of success and a -1 | ||
| 554 | * in case of failure. | ||
| 555 | */ | ||
| 556 | static int si476x_core_fwver_to_revision(struct si476x_core *core, | ||
| 557 | int func, int major, | ||
| 558 | int minor1, int minor2) | ||
| 559 | { | ||
| 560 | switch (func) { | ||
| 561 | case SI476X_FUNC_FM_RECEIVER: | ||
| 562 | switch (major) { | ||
| 563 | case 5: | ||
| 564 | return SI476X_REVISION_A10; | ||
| 565 | case 8: | ||
| 566 | return SI476X_REVISION_A20; | ||
| 567 | case 10: | ||
| 568 | return SI476X_REVISION_A30; | ||
| 569 | default: | ||
| 570 | goto unknown_revision; | ||
| 571 | } | ||
| 572 | case SI476X_FUNC_AM_RECEIVER: | ||
| 573 | switch (major) { | ||
| 574 | case 5: | ||
| 575 | return SI476X_REVISION_A10; | ||
| 576 | case 7: | ||
| 577 | return SI476X_REVISION_A20; | ||
| 578 | case 9: | ||
| 579 | return SI476X_REVISION_A30; | ||
| 580 | default: | ||
| 581 | goto unknown_revision; | ||
| 582 | } | ||
| 583 | case SI476X_FUNC_WB_RECEIVER: | ||
| 584 | switch (major) { | ||
| 585 | case 3: | ||
| 586 | return SI476X_REVISION_A10; | ||
| 587 | case 5: | ||
| 588 | return SI476X_REVISION_A20; | ||
| 589 | case 7: | ||
| 590 | return SI476X_REVISION_A30; | ||
| 591 | default: | ||
| 592 | goto unknown_revision; | ||
| 593 | } | ||
| 594 | case SI476X_FUNC_BOOTLOADER: | ||
| 595 | default: /* FALLTHROUG */ | ||
| 596 | BUG(); | ||
| 597 | return -1; | ||
| 598 | } | ||
| 599 | |||
| 600 | unknown_revision: | ||
| 601 | dev_err(&core->client->dev, | ||
| 602 | "Unsupported version of the firmware: %d.%d.%d, " | ||
| 603 | "reverting to A10 comptible functions\n", | ||
| 604 | major, minor1, minor2); | ||
| 605 | |||
| 606 | return SI476X_REVISION_A10; | ||
| 607 | } | ||
| 608 | |||
| 609 | /** | ||
| 610 | * si476x_get_revision_info() | ||
| 611 | * @core: Core device structure | ||
| 612 | * | ||
| 613 | * Get the firmware version number of the device. It is done in | ||
| 614 | * following three steps: | ||
| 615 | * 1. Power-up the device | ||
| 616 | * 2. Send the 'FUNC_INFO' command | ||
| 617 | * 3. Powering the device down. | ||
| 618 | * | ||
| 619 | * The function return zero on success and a negative error code on | ||
| 620 | * failure. | ||
| 621 | */ | ||
| 622 | static int si476x_core_get_revision_info(struct si476x_core *core) | ||
| 623 | { | ||
| 624 | int rval; | ||
| 625 | struct si476x_func_info info; | ||
| 626 | |||
| 627 | si476x_core_lock(core); | ||
| 628 | rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); | ||
| 629 | if (rval < 0) | ||
| 630 | goto exit; | ||
| 631 | |||
| 632 | rval = si476x_core_cmd_func_info(core, &info); | ||
| 633 | if (rval < 0) | ||
| 634 | goto power_down; | ||
| 635 | |||
| 636 | core->revision = si476x_core_fwver_to_revision(core, info.func, | ||
| 637 | info.firmware.major, | ||
| 638 | info.firmware.minor[0], | ||
| 639 | info.firmware.minor[1]); | ||
| 640 | power_down: | ||
| 641 | si476x_core_set_power_state(core, SI476X_POWER_DOWN); | ||
| 642 | exit: | ||
| 643 | si476x_core_unlock(core); | ||
| 644 | |||
| 645 | return rval; | ||
| 646 | } | ||
| 647 | |||
| 648 | bool si476x_core_has_am(struct si476x_core *core) | ||
| 649 | { | ||
| 650 | return core->chip_id == SI476X_CHIP_SI4761 || | ||
| 651 | core->chip_id == SI476X_CHIP_SI4764; | ||
| 652 | } | ||
| 653 | EXPORT_SYMBOL_GPL(si476x_core_has_am); | ||
| 654 | |||
| 655 | bool si476x_core_has_diversity(struct si476x_core *core) | ||
| 656 | { | ||
| 657 | return core->chip_id == SI476X_CHIP_SI4764; | ||
| 658 | } | ||
| 659 | EXPORT_SYMBOL_GPL(si476x_core_has_diversity); | ||
| 660 | |||
| 661 | bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) | ||
| 662 | { | ||
| 663 | return si476x_core_has_diversity(core) && | ||
| 664 | (core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA || | ||
| 665 | core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING); | ||
| 666 | } | ||
| 667 | EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner); | ||
| 668 | |||
| 669 | bool si476x_core_is_a_primary_tuner(struct si476x_core *core) | ||
| 670 | { | ||
| 671 | return si476x_core_has_diversity(core) && | ||
| 672 | (core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA || | ||
| 673 | core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING); | ||
| 674 | } | ||
| 675 | EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner); | ||
| 676 | |||
| 677 | bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) | ||
| 678 | { | ||
| 679 | return si476x_core_has_am(core) && | ||
| 680 | (core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER); | ||
| 681 | } | ||
| 682 | EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode); | ||
| 683 | |||
| 684 | bool si476x_core_is_powered_up(struct si476x_core *core) | ||
| 685 | { | ||
| 686 | return core->power_state == SI476X_POWER_UP_FULL; | ||
| 687 | } | ||
| 688 | EXPORT_SYMBOL_GPL(si476x_core_is_powered_up); | ||
| 689 | |||
| 690 | static int si476x_core_probe(struct i2c_client *client, | ||
| 691 | const struct i2c_device_id *id) | ||
| 692 | { | ||
| 693 | int rval; | ||
| 694 | struct si476x_core *core; | ||
| 695 | struct si476x_platform_data *pdata; | ||
| 696 | struct mfd_cell *cell; | ||
| 697 | int cell_num; | ||
| 698 | |||
| 699 | core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); | ||
| 700 | if (!core) { | ||
| 701 | dev_err(&client->dev, | ||
| 702 | "failed to allocate 'struct si476x_core'\n"); | ||
| 703 | return -ENOMEM; | ||
| 704 | } | ||
| 705 | core->client = client; | ||
| 706 | |||
| 707 | core->regmap = devm_regmap_init_si476x(core); | ||
| 708 | if (IS_ERR(core->regmap)) { | ||
| 709 | rval = PTR_ERR(core->regmap); | ||
| 710 | dev_err(&client->dev, | ||
| 711 | "Failed to allocate register map: %d\n", | ||
| 712 | rval); | ||
| 713 | return rval; | ||
| 714 | } | ||
| 715 | |||
| 716 | i2c_set_clientdata(client, core); | ||
| 717 | |||
| 718 | atomic_set(&core->is_alive, 0); | ||
| 719 | core->power_state = SI476X_POWER_DOWN; | ||
| 720 | |||
| 721 | pdata = client->dev.platform_data; | ||
| 722 | if (pdata) { | ||
| 723 | memcpy(&core->power_up_parameters, | ||
| 724 | &pdata->power_up_parameters, | ||
| 725 | sizeof(core->power_up_parameters)); | ||
| 726 | |||
| 727 | core->gpio_reset = -1; | ||
| 728 | if (gpio_is_valid(pdata->gpio_reset)) { | ||
| 729 | rval = gpio_request(pdata->gpio_reset, "si476x reset"); | ||
| 730 | if (rval) { | ||
| 731 | dev_err(&client->dev, | ||
| 732 | "Failed to request gpio: %d\n", rval); | ||
| 733 | return rval; | ||
| 734 | } | ||
| 735 | core->gpio_reset = pdata->gpio_reset; | ||
| 736 | gpio_direction_output(core->gpio_reset, 0); | ||
| 737 | } | ||
| 738 | |||
| 739 | core->diversity_mode = pdata->diversity_mode; | ||
| 740 | memcpy(&core->pinmux, &pdata->pinmux, | ||
| 741 | sizeof(struct si476x_pinmux)); | ||
| 742 | } else { | ||
| 743 | dev_err(&client->dev, "No platform data provided\n"); | ||
| 744 | return -EINVAL; | ||
| 745 | } | ||
| 746 | |||
| 747 | core->supplies[0].supply = "vd"; | ||
| 748 | core->supplies[1].supply = "va"; | ||
| 749 | core->supplies[2].supply = "vio1"; | ||
| 750 | core->supplies[3].supply = "vio2"; | ||
| 751 | |||
| 752 | rval = devm_regulator_bulk_get(&client->dev, | ||
| 753 | ARRAY_SIZE(core->supplies), | ||
| 754 | core->supplies); | ||
| 755 | if (rval) { | ||
| 756 | dev_err(&client->dev, "Failet to gett all of the regulators\n"); | ||
| 757 | goto free_gpio; | ||
| 758 | } | ||
| 759 | |||
| 760 | mutex_init(&core->cmd_lock); | ||
| 761 | init_waitqueue_head(&core->command); | ||
| 762 | init_waitqueue_head(&core->tuning); | ||
| 763 | |||
| 764 | rval = kfifo_alloc(&core->rds_fifo, | ||
| 765 | SI476X_DRIVER_RDS_FIFO_DEPTH * | ||
| 766 | sizeof(struct v4l2_rds_data), | ||
| 767 | GFP_KERNEL); | ||
| 768 | if (rval) { | ||
| 769 | dev_err(&client->dev, "Could not alloate the FIFO\n"); | ||
| 770 | goto free_gpio; | ||
| 771 | } | ||
| 772 | mutex_init(&core->rds_drainer_status_lock); | ||
| 773 | init_waitqueue_head(&core->rds_read_queue); | ||
| 774 | INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo); | ||
| 775 | |||
| 776 | if (client->irq) { | ||
| 777 | rval = devm_request_threaded_irq(&client->dev, | ||
| 778 | client->irq, NULL, | ||
| 779 | si476x_core_interrupt, | ||
| 780 | IRQF_TRIGGER_FALLING, | ||
| 781 | client->name, core); | ||
| 782 | if (rval < 0) { | ||
| 783 | dev_err(&client->dev, "Could not request IRQ %d\n", | ||
| 784 | client->irq); | ||
| 785 | goto free_kfifo; | ||
| 786 | } | ||
| 787 | disable_irq(client->irq); | ||
| 788 | dev_dbg(&client->dev, "IRQ requested.\n"); | ||
| 789 | |||
| 790 | core->rds_fifo_depth = 20; | ||
| 791 | } else { | ||
| 792 | INIT_DELAYED_WORK(&core->status_monitor, | ||
| 793 | si476x_core_poll_loop); | ||
| 794 | dev_info(&client->dev, | ||
| 795 | "No IRQ number specified, will use polling\n"); | ||
| 796 | |||
| 797 | core->rds_fifo_depth = 5; | ||
| 798 | } | ||
| 799 | |||
| 800 | core->chip_id = id->driver_data; | ||
| 801 | |||
| 802 | rval = si476x_core_get_revision_info(core); | ||
| 803 | if (rval < 0) { | ||
| 804 | rval = -ENODEV; | ||
| 805 | goto free_kfifo; | ||
| 806 | } | ||
| 807 | |||
| 808 | cell_num = 0; | ||
| 809 | |||
| 810 | cell = &core->cells[SI476X_RADIO_CELL]; | ||
| 811 | cell->name = "si476x-radio"; | ||
| 812 | cell_num++; | ||
| 813 | |||
| 814 | #ifdef CONFIG_SND_SOC_SI476X | ||
| 815 | if ((core->chip_id == SI476X_CHIP_SI4761 || | ||
| 816 | core->chip_id == SI476X_CHIP_SI4764) && | ||
| 817 | core->pinmux.dclk == SI476X_DCLK_DAUDIO && | ||
| 818 | core->pinmux.dfs == SI476X_DFS_DAUDIO && | ||
| 819 | core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT && | ||
| 820 | core->pinmux.xout == SI476X_XOUT_TRISTATE) { | ||
| 821 | cell = &core->cells[SI476X_CODEC_CELL]; | ||
| 822 | cell->name = "si476x-codec"; | ||
| 823 | cell_num++; | ||
| 824 | } | ||
| 825 | #endif | ||
| 826 | rval = mfd_add_devices(&client->dev, | ||
| 827 | (client->adapter->nr << 8) + client->addr, | ||
| 828 | core->cells, cell_num, | ||
| 829 | NULL, 0, NULL); | ||
| 830 | if (!rval) | ||
| 831 | return 0; | ||
| 832 | |||
| 833 | free_kfifo: | ||
| 834 | kfifo_free(&core->rds_fifo); | ||
| 835 | |||
| 836 | free_gpio: | ||
| 837 | if (gpio_is_valid(core->gpio_reset)) | ||
| 838 | gpio_free(core->gpio_reset); | ||
| 839 | |||
| 840 | return rval; | ||
| 841 | } | ||
| 842 | |||
| 843 | static int si476x_core_remove(struct i2c_client *client) | ||
| 844 | { | ||
| 845 | struct si476x_core *core = i2c_get_clientdata(client); | ||
| 846 | |||
| 847 | si476x_core_pronounce_dead(core); | ||
| 848 | mfd_remove_devices(&client->dev); | ||
| 849 | |||
| 850 | if (client->irq) | ||
| 851 | disable_irq(client->irq); | ||
| 852 | else | ||
| 853 | cancel_delayed_work_sync(&core->status_monitor); | ||
| 854 | |||
| 855 | kfifo_free(&core->rds_fifo); | ||
| 856 | |||
| 857 | if (gpio_is_valid(core->gpio_reset)) | ||
| 858 | gpio_free(core->gpio_reset); | ||
| 859 | |||
| 860 | return 0; | ||
| 861 | } | ||
| 862 | |||
| 863 | |||
| 864 | static const struct i2c_device_id si476x_id[] = { | ||
| 865 | { "si4761", SI476X_CHIP_SI4761 }, | ||
| 866 | { "si4764", SI476X_CHIP_SI4764 }, | ||
| 867 | { "si4768", SI476X_CHIP_SI4768 }, | ||
| 868 | { }, | ||
| 869 | }; | ||
| 870 | MODULE_DEVICE_TABLE(i2c, si476x_id); | ||
| 871 | |||
| 872 | static struct i2c_driver si476x_core_driver = { | ||
| 873 | .driver = { | ||
| 874 | .name = "si476x-core", | ||
| 875 | .owner = THIS_MODULE, | ||
| 876 | }, | ||
| 877 | .probe = si476x_core_probe, | ||
| 878 | .remove = si476x_core_remove, | ||
| 879 | .id_table = si476x_id, | ||
| 880 | }; | ||
| 881 | module_i2c_driver(si476x_core_driver); | ||
| 882 | |||
| 883 | |||
| 884 | MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); | ||
| 885 | MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver"); | ||
| 886 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/si476x-prop.c b/drivers/mfd/si476x-prop.c new file mode 100644 index 000000000000..cfeffa6e15d9 --- /dev/null +++ b/drivers/mfd/si476x-prop.c | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* | ||
| 2 | * drivers/mfd/si476x-prop.c -- Subroutines to access | ||
| 3 | * properties of si476x chips | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
| 6 | * Copyright (C) 2013 Andrey Smirnov | ||
| 7 | * | ||
| 8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; version 2 of the License. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | */ | ||
| 19 | #include <linux/module.h> | ||
| 20 | |||
| 21 | #include <linux/mfd/si476x-core.h> | ||
| 22 | |||
| 23 | struct si476x_property_range { | ||
| 24 | u16 low, high; | ||
| 25 | }; | ||
| 26 | |||
| 27 | static bool si476x_core_element_is_in_array(u16 element, | ||
| 28 | const u16 array[], | ||
| 29 | size_t size) | ||
| 30 | { | ||
| 31 | int i; | ||
| 32 | |||
| 33 | for (i = 0; i < size; i++) | ||
| 34 | if (element == array[i]) | ||
| 35 | return true; | ||
| 36 | |||
| 37 | return false; | ||
| 38 | } | ||
| 39 | |||
| 40 | static bool si476x_core_element_is_in_range(u16 element, | ||
| 41 | const struct si476x_property_range range[], | ||
| 42 | size_t size) | ||
| 43 | { | ||
| 44 | int i; | ||
| 45 | |||
| 46 | for (i = 0; i < size; i++) | ||
| 47 | if (element <= range[i].high && element >= range[i].low) | ||
| 48 | return true; | ||
| 49 | |||
| 50 | return false; | ||
| 51 | } | ||
| 52 | |||
| 53 | static bool si476x_core_is_valid_property_a10(struct si476x_core *core, | ||
| 54 | u16 property) | ||
| 55 | { | ||
| 56 | static const u16 valid_properties[] = { | ||
| 57 | 0x0000, | ||
| 58 | 0x0500, 0x0501, | ||
| 59 | 0x0600, | ||
| 60 | 0x0709, 0x070C, 0x070D, 0x70E, 0x710, | ||
| 61 | 0x0718, | ||
| 62 | 0x1207, 0x1208, | ||
| 63 | 0x2007, | ||
| 64 | 0x2300, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static const struct si476x_property_range valid_ranges[] = { | ||
| 68 | { 0x0200, 0x0203 }, | ||
| 69 | { 0x0300, 0x0303 }, | ||
| 70 | { 0x0400, 0x0404 }, | ||
| 71 | { 0x0700, 0x0707 }, | ||
| 72 | { 0x1100, 0x1102 }, | ||
| 73 | { 0x1200, 0x1204 }, | ||
| 74 | { 0x1300, 0x1306 }, | ||
| 75 | { 0x2000, 0x2005 }, | ||
| 76 | { 0x2100, 0x2104 }, | ||
| 77 | { 0x2106, 0x2106 }, | ||
| 78 | { 0x2200, 0x220E }, | ||
| 79 | { 0x3100, 0x3104 }, | ||
| 80 | { 0x3207, 0x320F }, | ||
| 81 | { 0x3300, 0x3304 }, | ||
| 82 | { 0x3500, 0x3517 }, | ||
| 83 | { 0x3600, 0x3617 }, | ||
| 84 | { 0x3700, 0x3717 }, | ||
| 85 | { 0x4000, 0x4003 }, | ||
| 86 | }; | ||
| 87 | |||
| 88 | return si476x_core_element_is_in_range(property, valid_ranges, | ||
| 89 | ARRAY_SIZE(valid_ranges)) || | ||
| 90 | si476x_core_element_is_in_array(property, valid_properties, | ||
| 91 | ARRAY_SIZE(valid_properties)); | ||
| 92 | } | ||
| 93 | |||
| 94 | static bool si476x_core_is_valid_property_a20(struct si476x_core *core, | ||
| 95 | u16 property) | ||
| 96 | { | ||
| 97 | static const u16 valid_properties[] = { | ||
| 98 | 0x071B, | ||
| 99 | 0x1006, | ||
| 100 | 0x2210, | ||
| 101 | 0x3401, | ||
| 102 | }; | ||
| 103 | |||
| 104 | static const struct si476x_property_range valid_ranges[] = { | ||
| 105 | { 0x2215, 0x2219 }, | ||
| 106 | }; | ||
| 107 | |||
| 108 | return si476x_core_is_valid_property_a10(core, property) || | ||
| 109 | si476x_core_element_is_in_range(property, valid_ranges, | ||
| 110 | ARRAY_SIZE(valid_ranges)) || | ||
| 111 | si476x_core_element_is_in_array(property, valid_properties, | ||
| 112 | ARRAY_SIZE(valid_properties)); | ||
| 113 | } | ||
| 114 | |||
| 115 | static bool si476x_core_is_valid_property_a30(struct si476x_core *core, | ||
| 116 | u16 property) | ||
| 117 | { | ||
| 118 | static const u16 valid_properties[] = { | ||
| 119 | 0x071C, 0x071D, | ||
| 120 | 0x1007, 0x1008, | ||
| 121 | 0x220F, 0x2214, | ||
| 122 | 0x2301, | ||
| 123 | 0x3105, 0x3106, | ||
| 124 | 0x3402, | ||
| 125 | }; | ||
| 126 | |||
| 127 | static const struct si476x_property_range valid_ranges[] = { | ||
| 128 | { 0x0405, 0x0411 }, | ||
| 129 | { 0x2008, 0x200B }, | ||
| 130 | { 0x2220, 0x2223 }, | ||
| 131 | { 0x3100, 0x3106 }, | ||
| 132 | }; | ||
| 133 | |||
| 134 | return si476x_core_is_valid_property_a20(core, property) || | ||
| 135 | si476x_core_element_is_in_range(property, valid_ranges, | ||
| 136 | ARRAY_SIZE(valid_ranges)) || | ||
| 137 | si476x_core_element_is_in_array(property, valid_properties, | ||
| 138 | ARRAY_SIZE(valid_properties)); | ||
| 139 | } | ||
| 140 | |||
| 141 | typedef bool (*valid_property_pred_t) (struct si476x_core *, u16); | ||
| 142 | |||
| 143 | static bool si476x_core_is_valid_property(struct si476x_core *core, | ||
| 144 | u16 property) | ||
| 145 | { | ||
| 146 | static const valid_property_pred_t is_valid_property[] = { | ||
| 147 | [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10, | ||
| 148 | [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20, | ||
| 149 | [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30, | ||
| 150 | }; | ||
| 151 | |||
| 152 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 153 | core->revision == -1); | ||
| 154 | return is_valid_property[core->revision](core, property); | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static bool si476x_core_is_readonly_property(struct si476x_core *core, | ||
| 159 | u16 property) | ||
| 160 | { | ||
| 161 | BUG_ON(core->revision > SI476X_REVISION_A30 || | ||
| 162 | core->revision == -1); | ||
| 163 | |||
| 164 | switch (core->revision) { | ||
| 165 | case SI476X_REVISION_A10: | ||
| 166 | return (property == 0x3200); | ||
| 167 | case SI476X_REVISION_A20: | ||
| 168 | return (property == 0x1006 || | ||
| 169 | property == 0x2210 || | ||
| 170 | property == 0x3200); | ||
| 171 | case SI476X_REVISION_A30: | ||
| 172 | return false; | ||
| 173 | } | ||
| 174 | |||
| 175 | return false; | ||
| 176 | } | ||
| 177 | |||
| 178 | static bool si476x_core_regmap_readable_register(struct device *dev, | ||
| 179 | unsigned int reg) | ||
| 180 | { | ||
| 181 | struct i2c_client *client = to_i2c_client(dev); | ||
| 182 | struct si476x_core *core = i2c_get_clientdata(client); | ||
| 183 | |||
| 184 | return si476x_core_is_valid_property(core, (u16) reg); | ||
| 185 | |||
| 186 | } | ||
| 187 | |||
| 188 | static bool si476x_core_regmap_writable_register(struct device *dev, | ||
| 189 | unsigned int reg) | ||
| 190 | { | ||
| 191 | struct i2c_client *client = to_i2c_client(dev); | ||
| 192 | struct si476x_core *core = i2c_get_clientdata(client); | ||
| 193 | |||
| 194 | return si476x_core_is_valid_property(core, (u16) reg) && | ||
| 195 | !si476x_core_is_readonly_property(core, (u16) reg); | ||
| 196 | } | ||
| 197 | |||
| 198 | |||
| 199 | static int si476x_core_regmap_write(void *context, unsigned int reg, | ||
| 200 | unsigned int val) | ||
| 201 | { | ||
| 202 | return si476x_core_cmd_set_property(context, reg, val); | ||
| 203 | } | ||
| 204 | |||
| 205 | static int si476x_core_regmap_read(void *context, unsigned int reg, | ||
| 206 | unsigned *val) | ||
| 207 | { | ||
| 208 | struct si476x_core *core = context; | ||
| 209 | int err; | ||
| 210 | |||
| 211 | err = si476x_core_cmd_get_property(core, reg); | ||
| 212 | if (err < 0) | ||
| 213 | return err; | ||
| 214 | |||
| 215 | *val = err; | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | |||
| 221 | static const struct regmap_config si476x_regmap_config = { | ||
| 222 | .reg_bits = 16, | ||
| 223 | .val_bits = 16, | ||
| 224 | |||
| 225 | .max_register = 0x4003, | ||
| 226 | |||
| 227 | .writeable_reg = si476x_core_regmap_writable_register, | ||
| 228 | .readable_reg = si476x_core_regmap_readable_register, | ||
| 229 | |||
| 230 | .reg_read = si476x_core_regmap_read, | ||
| 231 | .reg_write = si476x_core_regmap_write, | ||
| 232 | |||
| 233 | .cache_type = REGCACHE_RBTREE, | ||
| 234 | }; | ||
| 235 | |||
| 236 | struct regmap *devm_regmap_init_si476x(struct si476x_core *core) | ||
| 237 | { | ||
| 238 | return devm_regmap_init(&core->client->dev, NULL, | ||
| 239 | core, &si476x_regmap_config); | ||
| 240 | } | ||
| 241 | EXPORT_SYMBOL_GPL(devm_regmap_init_si476x); | ||
diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index 9bd33169a111..d70a343078fd 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c | |||
| @@ -98,17 +98,6 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) | |||
| 98 | return 0; | 98 | return 0; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | static int mfd_remove(struct pci_dev *pdev) | ||
| 102 | { | ||
| 103 | struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); | ||
| 104 | |||
| 105 | if (!mfd) | ||
| 106 | return -ENODEV; | ||
| 107 | list_del(&mfd->list); | ||
| 108 | kfree(mfd); | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | /* This function is exported and is not expected to fail */ | 101 | /* This function is exported and is not expected to fail */ |
| 113 | u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, | 102 | u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, |
| 114 | enum sta2x11_mfd_plat_dev index) | 103 | enum sta2x11_mfd_plat_dev index) |
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index fd5fcb630685..0da02e11d58e 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c | |||
| @@ -75,6 +75,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = { | |||
| 75 | { "stmpe801", STMPE801 }, | 75 | { "stmpe801", STMPE801 }, |
| 76 | { "stmpe811", STMPE811 }, | 76 | { "stmpe811", STMPE811 }, |
| 77 | { "stmpe1601", STMPE1601 }, | 77 | { "stmpe1601", STMPE1601 }, |
| 78 | { "stmpe1801", STMPE1801 }, | ||
| 78 | { "stmpe2401", STMPE2401 }, | 79 | { "stmpe2401", STMPE2401 }, |
| 79 | { "stmpe2403", STMPE2403 }, | 80 | { "stmpe2403", STMPE2403 }, |
| 80 | { } | 81 | { } |
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 973659f8abd9..a81badbaa917 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c | |||
| @@ -103,7 +103,7 @@ stmpe_spi_probe(struct spi_device *spi) | |||
| 103 | 103 | ||
| 104 | static int stmpe_spi_remove(struct spi_device *spi) | 104 | static int stmpe_spi_remove(struct spi_device *spi) |
| 105 | { | 105 | { |
| 106 | struct stmpe *stmpe = dev_get_drvdata(&spi->dev); | 106 | struct stmpe *stmpe = spi_get_drvdata(spi); |
| 107 | 107 | ||
| 108 | return stmpe_remove(stmpe); | 108 | return stmpe_remove(stmpe); |
| 109 | } | 109 | } |
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 4b11202061be..bbccd514d3ec 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
| 20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
| 21 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
| 22 | #include <linux/delay.h> | ||
| 22 | #include "stmpe.h" | 23 | #include "stmpe.h" |
| 23 | 24 | ||
| 24 | static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) | 25 | static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) |
| @@ -643,6 +644,88 @@ static struct stmpe_variant_info stmpe1601 = { | |||
| 643 | }; | 644 | }; |
| 644 | 645 | ||
| 645 | /* | 646 | /* |
| 647 | * STMPE1801 | ||
| 648 | */ | ||
| 649 | static const u8 stmpe1801_regs[] = { | ||
| 650 | [STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID, | ||
| 651 | [STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW, | ||
| 652 | [STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW, | ||
| 653 | [STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW, | ||
| 654 | [STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW, | ||
| 655 | [STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW, | ||
| 656 | [STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW, | ||
| 657 | [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW, | ||
| 658 | [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW, | ||
| 659 | [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW, | ||
| 660 | [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW, | ||
| 661 | [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW, | ||
| 662 | }; | ||
| 663 | |||
| 664 | static struct stmpe_variant_block stmpe1801_blocks[] = { | ||
| 665 | { | ||
| 666 | .cell = &stmpe_gpio_cell, | ||
| 667 | .irq = STMPE1801_IRQ_GPIOC, | ||
| 668 | .block = STMPE_BLOCK_GPIO, | ||
| 669 | }, | ||
| 670 | { | ||
| 671 | .cell = &stmpe_keypad_cell, | ||
| 672 | .irq = STMPE1801_IRQ_KEYPAD, | ||
| 673 | .block = STMPE_BLOCK_KEYPAD, | ||
| 674 | }, | ||
| 675 | }; | ||
| 676 | |||
| 677 | static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks, | ||
| 678 | bool enable) | ||
| 679 | { | ||
| 680 | unsigned int mask = 0; | ||
| 681 | if (blocks & STMPE_BLOCK_GPIO) | ||
| 682 | mask |= STMPE1801_MSK_INT_EN_GPIO; | ||
| 683 | |||
| 684 | if (blocks & STMPE_BLOCK_KEYPAD) | ||
| 685 | mask |= STMPE1801_MSK_INT_EN_KPC; | ||
| 686 | |||
| 687 | return __stmpe_set_bits(stmpe, STMPE1801_REG_INT_EN_MASK_LOW, mask, | ||
| 688 | enable ? mask : 0); | ||
| 689 | } | ||
| 690 | |||
| 691 | static int stmpe1801_reset(struct stmpe *stmpe) | ||
| 692 | { | ||
| 693 | unsigned long timeout; | ||
| 694 | int ret = 0; | ||
| 695 | |||
| 696 | ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL, | ||
| 697 | STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET); | ||
| 698 | if (ret < 0) | ||
| 699 | return ret; | ||
| 700 | |||
| 701 | timeout = jiffies + msecs_to_jiffies(100); | ||
| 702 | while (time_before(jiffies, timeout)) { | ||
| 703 | ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL); | ||
| 704 | if (ret < 0) | ||
| 705 | return ret; | ||
| 706 | if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET)) | ||
| 707 | return 0; | ||
| 708 | usleep_range(100, 200); | ||
| 709 | }; | ||
| 710 | return -EIO; | ||
| 711 | } | ||
| 712 | |||
| 713 | static struct stmpe_variant_info stmpe1801 = { | ||
| 714 | .name = "stmpe1801", | ||
| 715 | .id_val = STMPE1801_ID, | ||
| 716 | .id_mask = 0xfff0, | ||
| 717 | .num_gpios = 18, | ||
| 718 | .af_bits = 0, | ||
| 719 | .regs = stmpe1801_regs, | ||
| 720 | .blocks = stmpe1801_blocks, | ||
| 721 | .num_blocks = ARRAY_SIZE(stmpe1801_blocks), | ||
| 722 | .num_irqs = STMPE1801_NR_INTERNAL_IRQS, | ||
| 723 | .enable = stmpe1801_enable, | ||
| 724 | /* stmpe1801 do not have any gpio alternate function */ | ||
| 725 | .get_altfunc = NULL, | ||
| 726 | }; | ||
| 727 | |||
| 728 | /* | ||
| 646 | * STMPE24XX | 729 | * STMPE24XX |
| 647 | */ | 730 | */ |
| 648 | 731 | ||
| @@ -740,6 +823,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = { | |||
| 740 | [STMPE801] = &stmpe801, | 823 | [STMPE801] = &stmpe801, |
| 741 | [STMPE811] = &stmpe811, | 824 | [STMPE811] = &stmpe811, |
| 742 | [STMPE1601] = &stmpe1601, | 825 | [STMPE1601] = &stmpe1601, |
| 826 | [STMPE1801] = &stmpe1801, | ||
| 743 | [STMPE2401] = &stmpe2401, | 827 | [STMPE2401] = &stmpe2401, |
| 744 | [STMPE2403] = &stmpe2403, | 828 | [STMPE2403] = &stmpe2403, |
| 745 | }; | 829 | }; |
| @@ -759,7 +843,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
| 759 | struct stmpe *stmpe = data; | 843 | struct stmpe *stmpe = data; |
| 760 | struct stmpe_variant_info *variant = stmpe->variant; | 844 | struct stmpe_variant_info *variant = stmpe->variant; |
| 761 | int num = DIV_ROUND_UP(variant->num_irqs, 8); | 845 | int num = DIV_ROUND_UP(variant->num_irqs, 8); |
| 762 | u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; | 846 | u8 israddr; |
| 763 | u8 isr[num]; | 847 | u8 isr[num]; |
| 764 | int ret; | 848 | int ret; |
| 765 | int i; | 849 | int i; |
| @@ -771,6 +855,11 @@ static irqreturn_t stmpe_irq(int irq, void *data) | |||
| 771 | return IRQ_HANDLED; | 855 | return IRQ_HANDLED; |
| 772 | } | 856 | } |
| 773 | 857 | ||
| 858 | if (variant->id_val == STMPE1801_ID) | ||
| 859 | israddr = stmpe->regs[STMPE_IDX_ISR_LSB]; | ||
| 860 | else | ||
| 861 | israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; | ||
| 862 | |||
| 774 | ret = stmpe_block_read(stmpe, israddr, num, isr); | 863 | ret = stmpe_block_read(stmpe, israddr, num, isr); |
| 775 | if (ret < 0) | 864 | if (ret < 0) |
| 776 | return IRQ_NONE; | 865 | return IRQ_NONE; |
| @@ -938,6 +1027,12 @@ static int stmpe_chip_init(struct stmpe *stmpe) | |||
| 938 | if (ret) | 1027 | if (ret) |
| 939 | return ret; | 1028 | return ret; |
| 940 | 1029 | ||
| 1030 | if (id == STMPE1801_ID) { | ||
| 1031 | ret = stmpe1801_reset(stmpe); | ||
| 1032 | if (ret < 0) | ||
| 1033 | return ret; | ||
| 1034 | } | ||
| 1035 | |||
| 941 | if (stmpe->irq >= 0) { | 1036 | if (stmpe->irq >= 0) { |
| 942 | if (id == STMPE801_ID) | 1037 | if (id == STMPE801_ID) |
| 943 | icr = STMPE801_REG_SYS_CTRL_INT_EN; | 1038 | icr = STMPE801_REG_SYS_CTRL_INT_EN; |
| @@ -1015,7 +1110,10 @@ void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np) | |||
| 1015 | { | 1110 | { |
| 1016 | struct device_node *child; | 1111 | struct device_node *child; |
| 1017 | 1112 | ||
| 1018 | pdata->id = -1; | 1113 | pdata->id = of_alias_get_id(np, "stmpe-i2c"); |
| 1114 | if (pdata->id < 0) | ||
| 1115 | pdata->id = -1; | ||
| 1116 | |||
| 1019 | pdata->irq_trigger = IRQF_TRIGGER_NONE; | 1117 | pdata->irq_trigger = IRQF_TRIGGER_NONE; |
| 1020 | 1118 | ||
| 1021 | of_property_read_u32(np, "st,autosleep-timeout", | 1119 | of_property_read_u32(np, "st,autosleep-timeout", |
| @@ -1057,6 +1155,9 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) | |||
| 1057 | return -ENOMEM; | 1155 | return -ENOMEM; |
| 1058 | 1156 | ||
| 1059 | stmpe_of_probe(pdata, np); | 1157 | stmpe_of_probe(pdata, np); |
| 1158 | |||
| 1159 | if (of_find_property(np, "interrupts", NULL) == NULL) | ||
| 1160 | ci->irq = -1; | ||
| 1060 | } | 1161 | } |
| 1061 | 1162 | ||
| 1062 | stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); | 1163 | stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); |
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 7b8e13f5b764..ff2b09ba8797 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h | |||
| @@ -199,6 +199,55 @@ int stmpe_remove(struct stmpe *stmpe); | |||
| 199 | #define STPME1601_AUTOSLEEP_ENABLE (1 << 3) | 199 | #define STPME1601_AUTOSLEEP_ENABLE (1 << 3) |
| 200 | 200 | ||
| 201 | /* | 201 | /* |
| 202 | * STMPE1801 | ||
| 203 | */ | ||
| 204 | #define STMPE1801_ID 0xc110 | ||
| 205 | #define STMPE1801_NR_INTERNAL_IRQS 5 | ||
| 206 | #define STMPE1801_IRQ_KEYPAD_COMBI 4 | ||
| 207 | #define STMPE1801_IRQ_GPIOC 3 | ||
| 208 | #define STMPE1801_IRQ_KEYPAD_OVER 2 | ||
| 209 | #define STMPE1801_IRQ_KEYPAD 1 | ||
| 210 | #define STMPE1801_IRQ_WAKEUP 0 | ||
| 211 | |||
| 212 | #define STMPE1801_REG_CHIP_ID 0x00 | ||
| 213 | #define STMPE1801_REG_SYS_CTRL 0x02 | ||
| 214 | #define STMPE1801_REG_INT_CTRL_LOW 0x04 | ||
| 215 | #define STMPE1801_REG_INT_EN_MASK_LOW 0x06 | ||
| 216 | #define STMPE1801_REG_INT_STA_LOW 0x08 | ||
| 217 | #define STMPE1801_REG_INT_EN_GPIO_MASK_LOW 0x0A | ||
| 218 | #define STMPE1801_REG_INT_EN_GPIO_MASK_MID 0x0B | ||
| 219 | #define STMPE1801_REG_INT_EN_GPIO_MASK_HIGH 0x0C | ||
| 220 | #define STMPE1801_REG_INT_STA_GPIO_LOW 0x0D | ||
| 221 | #define STMPE1801_REG_INT_STA_GPIO_MID 0x0E | ||
| 222 | #define STMPE1801_REG_INT_STA_GPIO_HIGH 0x0F | ||
| 223 | #define STMPE1801_REG_GPIO_SET_LOW 0x10 | ||
| 224 | #define STMPE1801_REG_GPIO_SET_MID 0x11 | ||
| 225 | #define STMPE1801_REG_GPIO_SET_HIGH 0x12 | ||
| 226 | #define STMPE1801_REG_GPIO_CLR_LOW 0x13 | ||
| 227 | #define STMPE1801_REG_GPIO_CLR_MID 0x14 | ||
| 228 | #define STMPE1801_REG_GPIO_CLR_HIGH 0x15 | ||
| 229 | #define STMPE1801_REG_GPIO_MP_LOW 0x16 | ||
| 230 | #define STMPE1801_REG_GPIO_MP_MID 0x17 | ||
| 231 | #define STMPE1801_REG_GPIO_MP_HIGH 0x18 | ||
| 232 | #define STMPE1801_REG_GPIO_SET_DIR_LOW 0x19 | ||
| 233 | #define STMPE1801_REG_GPIO_SET_DIR_MID 0x1A | ||
| 234 | #define STMPE1801_REG_GPIO_SET_DIR_HIGH 0x1B | ||
| 235 | #define STMPE1801_REG_GPIO_RE_LOW 0x1C | ||
| 236 | #define STMPE1801_REG_GPIO_RE_MID 0x1D | ||
| 237 | #define STMPE1801_REG_GPIO_RE_HIGH 0x1E | ||
| 238 | #define STMPE1801_REG_GPIO_FE_LOW 0x1F | ||
| 239 | #define STMPE1801_REG_GPIO_FE_MID 0x20 | ||
| 240 | #define STMPE1801_REG_GPIO_FE_HIGH 0x21 | ||
| 241 | #define STMPE1801_REG_GPIO_PULL_UP_LOW 0x22 | ||
| 242 | #define STMPE1801_REG_GPIO_PULL_UP_MID 0x23 | ||
| 243 | #define STMPE1801_REG_GPIO_PULL_UP_HIGH 0x24 | ||
| 244 | |||
| 245 | #define STMPE1801_MSK_SYS_CTRL_RESET (1 << 7) | ||
| 246 | |||
| 247 | #define STMPE1801_MSK_INT_EN_KPC (1 << 1) | ||
| 248 | #define STMPE1801_MSK_INT_EN_GPIO (1 << 3) | ||
| 249 | |||
| 250 | /* | ||
| 202 | * STMPE24xx | 251 | * STMPE24xx |
| 203 | */ | 252 | */ |
| 204 | 253 | ||
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 61aea6381cdf..962a6e17a01a 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c | |||
| @@ -25,17 +25,15 @@ | |||
| 25 | static struct platform_driver syscon_driver; | 25 | static struct platform_driver syscon_driver; |
| 26 | 26 | ||
| 27 | struct syscon { | 27 | struct syscon { |
| 28 | struct device *dev; | ||
| 29 | void __iomem *base; | 28 | void __iomem *base; |
| 30 | struct regmap *regmap; | 29 | struct regmap *regmap; |
| 31 | }; | 30 | }; |
| 32 | 31 | ||
| 33 | static int syscon_match(struct device *dev, void *data) | 32 | static int syscon_match_node(struct device *dev, void *data) |
| 34 | { | 33 | { |
| 35 | struct syscon *syscon = dev_get_drvdata(dev); | ||
| 36 | struct device_node *dn = data; | 34 | struct device_node *dn = data; |
| 37 | 35 | ||
| 38 | return (syscon->dev->of_node == dn) ? 1 : 0; | 36 | return (dev->of_node == dn) ? 1 : 0; |
| 39 | } | 37 | } |
| 40 | 38 | ||
| 41 | struct regmap *syscon_node_to_regmap(struct device_node *np) | 39 | struct regmap *syscon_node_to_regmap(struct device_node *np) |
| @@ -44,7 +42,7 @@ struct regmap *syscon_node_to_regmap(struct device_node *np) | |||
| 44 | struct device *dev; | 42 | struct device *dev; |
| 45 | 43 | ||
| 46 | dev = driver_find_device(&syscon_driver.driver, NULL, np, | 44 | dev = driver_find_device(&syscon_driver.driver, NULL, np, |
| 47 | syscon_match); | 45 | syscon_match_node); |
| 48 | if (!dev) | 46 | if (!dev) |
| 49 | return ERR_PTR(-EPROBE_DEFER); | 47 | return ERR_PTR(-EPROBE_DEFER); |
| 50 | 48 | ||
| @@ -70,6 +68,34 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s) | |||
| 70 | } | 68 | } |
| 71 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); | 69 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); |
| 72 | 70 | ||
| 71 | static int syscon_match_pdevname(struct device *dev, void *data) | ||
| 72 | { | ||
| 73 | struct platform_device *pdev = to_platform_device(dev); | ||
| 74 | const struct platform_device_id *id = platform_get_device_id(pdev); | ||
| 75 | |||
| 76 | if (id) | ||
| 77 | if (!strcmp(id->name, (const char *)data)) | ||
| 78 | return 1; | ||
| 79 | |||
| 80 | return !strcmp(dev_name(dev), (const char *)data); | ||
| 81 | } | ||
| 82 | |||
| 83 | struct regmap *syscon_regmap_lookup_by_pdevname(const char *s) | ||
| 84 | { | ||
| 85 | struct device *dev; | ||
| 86 | struct syscon *syscon; | ||
| 87 | |||
| 88 | dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s, | ||
| 89 | syscon_match_pdevname); | ||
| 90 | if (!dev) | ||
| 91 | return ERR_PTR(-EPROBE_DEFER); | ||
| 92 | |||
| 93 | syscon = dev_get_drvdata(dev); | ||
| 94 | |||
| 95 | return syscon->regmap; | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname); | ||
| 98 | |||
| 73 | struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, | 99 | struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, |
| 74 | const char *property) | 100 | const char *property) |
| 75 | { | 101 | { |
| @@ -101,28 +127,22 @@ static struct regmap_config syscon_regmap_config = { | |||
| 101 | static int syscon_probe(struct platform_device *pdev) | 127 | static int syscon_probe(struct platform_device *pdev) |
| 102 | { | 128 | { |
| 103 | struct device *dev = &pdev->dev; | 129 | struct device *dev = &pdev->dev; |
| 104 | struct device_node *np = dev->of_node; | ||
| 105 | struct syscon *syscon; | 130 | struct syscon *syscon; |
| 106 | struct resource res; | 131 | struct resource *res; |
| 107 | int ret; | ||
| 108 | |||
| 109 | if (!np) | ||
| 110 | return -ENOENT; | ||
| 111 | 132 | ||
| 112 | syscon = devm_kzalloc(dev, sizeof(struct syscon), | 133 | syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); |
| 113 | GFP_KERNEL); | ||
| 114 | if (!syscon) | 134 | if (!syscon) |
| 115 | return -ENOMEM; | 135 | return -ENOMEM; |
| 116 | 136 | ||
| 117 | syscon->base = of_iomap(np, 0); | 137 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 118 | if (!syscon->base) | 138 | if (!res) |
| 119 | return -EADDRNOTAVAIL; | 139 | return -ENOENT; |
| 120 | 140 | ||
| 121 | ret = of_address_to_resource(np, 0, &res); | 141 | syscon->base = devm_ioremap(dev, res->start, resource_size(res)); |
| 122 | if (ret) | 142 | if (!syscon->base) |
| 123 | return ret; | 143 | return -ENOMEM; |
| 124 | 144 | ||
| 125 | syscon_regmap_config.max_register = res.end - res.start - 3; | 145 | syscon_regmap_config.max_register = res->end - res->start - 3; |
| 126 | syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, | 146 | syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, |
| 127 | &syscon_regmap_config); | 147 | &syscon_regmap_config); |
| 128 | if (IS_ERR(syscon->regmap)) { | 148 | if (IS_ERR(syscon->regmap)) { |
| @@ -130,25 +150,17 @@ static int syscon_probe(struct platform_device *pdev) | |||
| 130 | return PTR_ERR(syscon->regmap); | 150 | return PTR_ERR(syscon->regmap); |
| 131 | } | 151 | } |
| 132 | 152 | ||
| 133 | syscon->dev = dev; | ||
| 134 | platform_set_drvdata(pdev, syscon); | 153 | platform_set_drvdata(pdev, syscon); |
| 135 | 154 | ||
| 136 | dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", | 155 | dev_info(dev, "regmap %pR registered\n", res); |
| 137 | res.start, res.end); | ||
| 138 | 156 | ||
| 139 | return 0; | 157 | return 0; |
| 140 | } | 158 | } |
| 141 | 159 | ||
| 142 | static int syscon_remove(struct platform_device *pdev) | 160 | static const struct platform_device_id syscon_ids[] = { |
| 143 | { | 161 | { "syscon", }, |
| 144 | struct syscon *syscon; | 162 | { } |
| 145 | 163 | }; | |
| 146 | syscon = platform_get_drvdata(pdev); | ||
| 147 | iounmap(syscon->base); | ||
| 148 | platform_set_drvdata(pdev, NULL); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | 164 | ||
| 153 | static struct platform_driver syscon_driver = { | 165 | static struct platform_driver syscon_driver = { |
| 154 | .driver = { | 166 | .driver = { |
| @@ -157,7 +169,7 @@ static struct platform_driver syscon_driver = { | |||
| 157 | .of_match_table = of_syscon_match, | 169 | .of_match_table = of_syscon_match, |
| 158 | }, | 170 | }, |
| 159 | .probe = syscon_probe, | 171 | .probe = syscon_probe, |
| 160 | .remove = syscon_remove, | 172 | .id_table = syscon_ids, |
| 161 | }; | 173 | }; |
| 162 | 174 | ||
| 163 | static int __init syscon_init(void) | 175 | static int __init syscon_init(void) |
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index ecc092c7f745..4cb92bb2aea2 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c | |||
| @@ -350,7 +350,8 @@ static int tc3589x_probe(struct i2c_client *i2c, | |||
| 350 | | I2C_FUNC_SMBUS_I2C_BLOCK)) | 350 | | I2C_FUNC_SMBUS_I2C_BLOCK)) |
| 351 | return -EIO; | 351 | return -EIO; |
| 352 | 352 | ||
| 353 | tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL); | 353 | tc3589x = devm_kzalloc(&i2c->dev, sizeof(struct tc3589x), |
| 354 | GFP_KERNEL); | ||
| 354 | if (!tc3589x) | 355 | if (!tc3589x) |
| 355 | return -ENOMEM; | 356 | return -ENOMEM; |
| 356 | 357 | ||
| @@ -366,33 +367,27 @@ static int tc3589x_probe(struct i2c_client *i2c, | |||
| 366 | 367 | ||
| 367 | ret = tc3589x_chip_init(tc3589x); | 368 | ret = tc3589x_chip_init(tc3589x); |
| 368 | if (ret) | 369 | if (ret) |
| 369 | goto out_free; | 370 | return ret; |
| 370 | 371 | ||
| 371 | ret = tc3589x_irq_init(tc3589x, np); | 372 | ret = tc3589x_irq_init(tc3589x, np); |
| 372 | if (ret) | 373 | if (ret) |
| 373 | goto out_free; | 374 | return ret; |
| 374 | 375 | ||
| 375 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, | 376 | ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq, |
| 376 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 377 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
| 377 | "tc3589x", tc3589x); | 378 | "tc3589x", tc3589x); |
| 378 | if (ret) { | 379 | if (ret) { |
| 379 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); | 380 | dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); |
| 380 | goto out_free; | 381 | return ret; |
| 381 | } | 382 | } |
| 382 | 383 | ||
| 383 | ret = tc3589x_device_init(tc3589x); | 384 | ret = tc3589x_device_init(tc3589x); |
| 384 | if (ret) { | 385 | if (ret) { |
| 385 | dev_err(tc3589x->dev, "failed to add child devices\n"); | 386 | dev_err(tc3589x->dev, "failed to add child devices\n"); |
| 386 | goto out_freeirq; | 387 | return ret; |
| 387 | } | 388 | } |
| 388 | 389 | ||
| 389 | return 0; | 390 | return 0; |
| 390 | |||
| 391 | out_freeirq: | ||
| 392 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
| 393 | out_free: | ||
| 394 | kfree(tc3589x); | ||
| 395 | return ret; | ||
| 396 | } | 391 | } |
| 397 | 392 | ||
| 398 | static int tc3589x_remove(struct i2c_client *client) | 393 | static int tc3589x_remove(struct i2c_client *client) |
| @@ -401,10 +396,6 @@ static int tc3589x_remove(struct i2c_client *client) | |||
| 401 | 396 | ||
| 402 | mfd_remove_devices(tc3589x->dev); | 397 | mfd_remove_devices(tc3589x->dev); |
| 403 | 398 | ||
| 404 | free_irq(tc3589x->i2c->irq, tc3589x); | ||
| 405 | |||
| 406 | kfree(tc3589x); | ||
| 407 | |||
| 408 | return 0; | 399 | return 0; |
| 409 | } | 400 | } |
| 410 | 401 | ||
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 98edb5be85c6..fbd6ee67b5a5 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c | |||
| @@ -56,12 +56,23 @@ | |||
| 56 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 | 56 | #define TPS65090_INT2_MASK_OVERLOAD_FET6 6 |
| 57 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 | 57 | #define TPS65090_INT2_MASK_OVERLOAD_FET7 7 |
| 58 | 58 | ||
| 59 | static struct resource charger_resources[] = { | ||
| 60 | { | ||
| 61 | .start = TPS65090_IRQ_VAC_STATUS_CHANGE, | ||
| 62 | .end = TPS65090_IRQ_VAC_STATUS_CHANGE, | ||
| 63 | .flags = IORESOURCE_IRQ, | ||
| 64 | } | ||
| 65 | }; | ||
| 66 | |||
| 59 | static struct mfd_cell tps65090s[] = { | 67 | static struct mfd_cell tps65090s[] = { |
| 60 | { | 68 | { |
| 61 | .name = "tps65090-pmic", | 69 | .name = "tps65090-pmic", |
| 62 | }, | 70 | }, |
| 63 | { | 71 | { |
| 64 | .name = "tps65090-charger", | 72 | .name = "tps65090-charger", |
| 73 | .num_resources = ARRAY_SIZE(charger_resources), | ||
| 74 | .resources = &charger_resources[0], | ||
| 75 | .of_compatible = "ti,tps65090-charger", | ||
| 65 | }, | 76 | }, |
| 66 | }; | 77 | }; |
| 67 | 78 | ||
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 942b666a2a07..42bd3ea5df3c 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c | |||
| @@ -211,12 +211,14 @@ static int twl4030battery_current(int raw_volt) | |||
| 211 | * @reg_base - Base address of the first channel | 211 | * @reg_base - Base address of the first channel |
| 212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read | 212 | * @Channels - 16 bit bitmap. If the bit is set, channel value is read |
| 213 | * @buf - The channel values are stored here. if read fails error | 213 | * @buf - The channel values are stored here. if read fails error |
| 214 | * @raw - Return raw values without conversion | ||
| 214 | * value is stored | 215 | * value is stored |
| 215 | * Returns the number of successfully read channels. | 216 | * Returns the number of successfully read channels. |
| 216 | */ | 217 | */ |
| 217 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | 218 | static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, |
| 218 | u8 reg_base, unsigned | 219 | u8 reg_base, unsigned |
| 219 | long channels, int *buf) | 220 | long channels, int *buf, |
| 221 | bool raw) | ||
| 220 | { | 222 | { |
| 221 | int count = 0, count_req = 0, i; | 223 | int count = 0, count_req = 0, i; |
| 222 | u8 reg; | 224 | u8 reg; |
| @@ -230,6 +232,10 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc, | |||
| 230 | count_req++; | 232 | count_req++; |
| 231 | continue; | 233 | continue; |
| 232 | } | 234 | } |
| 235 | if (raw) { | ||
| 236 | count++; | ||
| 237 | continue; | ||
| 238 | } | ||
| 233 | switch (i) { | 239 | switch (i) { |
| 234 | case 10: | 240 | case 10: |
| 235 | buf[i] = twl4030battery_current(buf[i]); | 241 | buf[i] = twl4030battery_current(buf[i]); |
| @@ -371,7 +377,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) | |||
| 371 | method = &twl4030_conversion_methods[r->method]; | 377 | method = &twl4030_conversion_methods[r->method]; |
| 372 | /* Read results */ | 378 | /* Read results */ |
| 373 | len = twl4030_madc_read_channels(madc, method->rbase, | 379 | len = twl4030_madc_read_channels(madc, method->rbase, |
| 374 | r->channels, r->rbuf); | 380 | r->channels, r->rbuf, r->raw); |
| 375 | /* Return results to caller */ | 381 | /* Return results to caller */ |
| 376 | if (r->func_cb != NULL) { | 382 | if (r->func_cb != NULL) { |
| 377 | r->func_cb(len, r->channels, r->rbuf); | 383 | r->func_cb(len, r->channels, r->rbuf); |
| @@ -397,7 +403,7 @@ err_i2c: | |||
| 397 | method = &twl4030_conversion_methods[r->method]; | 403 | method = &twl4030_conversion_methods[r->method]; |
| 398 | /* Read results */ | 404 | /* Read results */ |
| 399 | len = twl4030_madc_read_channels(madc, method->rbase, | 405 | len = twl4030_madc_read_channels(madc, method->rbase, |
| 400 | r->channels, r->rbuf); | 406 | r->channels, r->rbuf, r->raw); |
| 401 | /* Return results to caller */ | 407 | /* Return results to caller */ |
| 402 | if (r->func_cb != NULL) { | 408 | if (r->func_cb != NULL) { |
| 403 | r->func_cb(len, r->channels, r->rbuf); | 409 | r->func_cb(len, r->channels, r->rbuf); |
| @@ -585,7 +591,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) | |||
| 585 | goto out; | 591 | goto out; |
| 586 | } | 592 | } |
| 587 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, | 593 | ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, |
| 588 | req->channels, req->rbuf); | 594 | req->channels, req->rbuf, req->raw); |
| 589 | twl4030_madc->requests[req->method].active = 0; | 595 | twl4030_madc->requests[req->method].active = 0; |
| 590 | 596 | ||
| 591 | out: | 597 | out: |
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index f361bf38a0aa..492ee2cd3400 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c | |||
| @@ -554,7 +554,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 554 | 554 | ||
| 555 | twl6040->supplies[0].supply = "vio"; | 555 | twl6040->supplies[0].supply = "vio"; |
| 556 | twl6040->supplies[1].supply = "v2v1"; | 556 | twl6040->supplies[1].supply = "v2v1"; |
| 557 | ret = regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, | 557 | ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, |
| 558 | twl6040->supplies); | 558 | twl6040->supplies); |
| 559 | if (ret != 0) { | 559 | if (ret != 0) { |
| 560 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); | 560 | dev_err(&client->dev, "Failed to get supplies: %d\n", ret); |
| @@ -564,7 +564,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 564 | ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 564 | ret = regulator_bulk_enable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
| 565 | if (ret != 0) { | 565 | if (ret != 0) { |
| 566 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); | 566 | dev_err(&client->dev, "Failed to enable supplies: %d\n", ret); |
| 567 | goto power_err; | 567 | goto regulator_get_err; |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | twl6040->dev = &client->dev; | 570 | twl6040->dev = &client->dev; |
| @@ -586,8 +586,8 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 586 | twl6040->audpwron = -EINVAL; | 586 | twl6040->audpwron = -EINVAL; |
| 587 | 587 | ||
| 588 | if (gpio_is_valid(twl6040->audpwron)) { | 588 | if (gpio_is_valid(twl6040->audpwron)) { |
| 589 | ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW, | 589 | ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, |
| 590 | "audpwron"); | 590 | GPIOF_OUT_INIT_LOW, "audpwron"); |
| 591 | if (ret) | 591 | if (ret) |
| 592 | goto gpio_err; | 592 | goto gpio_err; |
| 593 | } | 593 | } |
| @@ -596,14 +596,14 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, | 596 | IRQF_ONESHOT, 0, &twl6040_irq_chip, |
| 597 | &twl6040->irq_data); | 597 | &twl6040->irq_data); |
| 598 | if (ret < 0) | 598 | if (ret < 0) |
| 599 | goto irq_init_err; | 599 | goto gpio_err; |
| 600 | 600 | ||
| 601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, | 601 | twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, |
| 602 | TWL6040_IRQ_READY); | 602 | TWL6040_IRQ_READY); |
| 603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, | 603 | twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, |
| 604 | TWL6040_IRQ_TH); | 604 | TWL6040_IRQ_TH); |
| 605 | 605 | ||
| 606 | ret = request_threaded_irq(twl6040->irq_ready, NULL, | 606 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, |
| 607 | twl6040_readyint_handler, IRQF_ONESHOT, | 607 | twl6040_readyint_handler, IRQF_ONESHOT, |
| 608 | "twl6040_irq_ready", twl6040); | 608 | "twl6040_irq_ready", twl6040); |
| 609 | if (ret) { | 609 | if (ret) { |
| @@ -611,7 +611,7 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 611 | goto readyirq_err; | 611 | goto readyirq_err; |
| 612 | } | 612 | } |
| 613 | 613 | ||
| 614 | ret = request_threaded_irq(twl6040->irq_th, NULL, | 614 | ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, |
| 615 | twl6040_thint_handler, IRQF_ONESHOT, | 615 | twl6040_thint_handler, IRQF_ONESHOT, |
| 616 | "twl6040_irq_th", twl6040); | 616 | "twl6040_irq_th", twl6040); |
| 617 | if (ret) { | 617 | if (ret) { |
| @@ -681,18 +681,13 @@ static int twl6040_probe(struct i2c_client *client, | |||
| 681 | return 0; | 681 | return 0; |
| 682 | 682 | ||
| 683 | mfd_err: | 683 | mfd_err: |
| 684 | free_irq(twl6040->irq_th, twl6040); | 684 | devm_free_irq(&client->dev, twl6040->irq_th, twl6040); |
| 685 | thirq_err: | 685 | thirq_err: |
| 686 | free_irq(twl6040->irq_ready, twl6040); | 686 | devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); |
| 687 | readyirq_err: | 687 | readyirq_err: |
| 688 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | 688 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); |
| 689 | irq_init_err: | ||
| 690 | if (gpio_is_valid(twl6040->audpwron)) | ||
| 691 | gpio_free(twl6040->audpwron); | ||
| 692 | gpio_err: | 689 | gpio_err: |
| 693 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 690 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
| 694 | power_err: | ||
| 695 | regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); | ||
| 696 | regulator_get_err: | 691 | regulator_get_err: |
| 697 | i2c_set_clientdata(client, NULL); | 692 | i2c_set_clientdata(client, NULL); |
| 698 | err: | 693 | err: |
| @@ -706,18 +701,14 @@ static int twl6040_remove(struct i2c_client *client) | |||
| 706 | if (twl6040->power_count) | 701 | if (twl6040->power_count) |
| 707 | twl6040_power(twl6040, 0); | 702 | twl6040_power(twl6040, 0); |
| 708 | 703 | ||
| 709 | if (gpio_is_valid(twl6040->audpwron)) | 704 | devm_free_irq(&client->dev, twl6040->irq_ready, twl6040); |
| 710 | gpio_free(twl6040->audpwron); | 705 | devm_free_irq(&client->dev, twl6040->irq_th, twl6040); |
| 711 | |||
| 712 | free_irq(twl6040->irq_ready, twl6040); | ||
| 713 | free_irq(twl6040->irq_th, twl6040); | ||
| 714 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); | 706 | regmap_del_irq_chip(twl6040->irq, twl6040->irq_data); |
| 715 | 707 | ||
| 716 | mfd_remove_devices(&client->dev); | 708 | mfd_remove_devices(&client->dev); |
| 717 | i2c_set_clientdata(client, NULL); | 709 | i2c_set_clientdata(client, NULL); |
| 718 | 710 | ||
| 719 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); | 711 | regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); |
| 720 | regulator_bulk_free(TWL6040_NUM_SUPPLIES, twl6040->supplies); | ||
| 721 | 712 | ||
| 722 | return 0; | 713 | return 0; |
| 723 | } | 714 | } |
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index daf69527ed83..e9031fa9d53d 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c | |||
| @@ -75,6 +75,11 @@ static int ucb1400_core_probe(struct device *dev) | |||
| 75 | 75 | ||
| 76 | /* GPIO */ | 76 | /* GPIO */ |
| 77 | ucb_gpio.ac97 = ac97; | 77 | ucb_gpio.ac97 = ac97; |
| 78 | if (pdata) { | ||
| 79 | ucb_gpio.gpio_setup = pdata->gpio_setup; | ||
| 80 | ucb_gpio.gpio_teardown = pdata->gpio_teardown; | ||
| 81 | ucb_gpio.gpio_offset = pdata->gpio_offset; | ||
| 82 | } | ||
| 78 | ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); | 83 | ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); |
| 79 | if (!ucb->ucb1400_gpio) { | 84 | if (!ucb->ucb1400_gpio) { |
| 80 | err = -ENOMEM; | 85 | err = -ENOMEM; |
diff --git a/drivers/mfd/vexpress-config.c b/drivers/mfd/vexpress-config.c index 3c1723aa6225..84ce6b9daa3d 100644 --- a/drivers/mfd/vexpress-config.c +++ b/drivers/mfd/vexpress-config.c | |||
| @@ -184,13 +184,14 @@ static int vexpress_config_schedule(struct vexpress_config_trans *trans) | |||
| 184 | 184 | ||
| 185 | spin_lock_irqsave(&bridge->transactions_lock, flags); | 185 | spin_lock_irqsave(&bridge->transactions_lock, flags); |
| 186 | 186 | ||
| 187 | vexpress_config_dump_trans("Executing", trans); | 187 | if (list_empty(&bridge->transactions)) { |
| 188 | 188 | vexpress_config_dump_trans("Executing", trans); | |
| 189 | if (list_empty(&bridge->transactions)) | ||
| 190 | status = bridge->info->func_exec(trans->func->func, | 189 | status = bridge->info->func_exec(trans->func->func, |
| 191 | trans->offset, trans->write, trans->data); | 190 | trans->offset, trans->write, trans->data); |
| 192 | else | 191 | } else { |
| 192 | vexpress_config_dump_trans("Queuing", trans); | ||
| 193 | status = VEXPRESS_CONFIG_STATUS_WAIT; | 193 | status = VEXPRESS_CONFIG_STATUS_WAIT; |
| 194 | } | ||
| 194 | 195 | ||
| 195 | switch (status) { | 196 | switch (status) { |
| 196 | case VEXPRESS_CONFIG_STATUS_DONE: | 197 | case VEXPRESS_CONFIG_STATUS_DONE: |
| @@ -212,25 +213,31 @@ void vexpress_config_complete(struct vexpress_config_bridge *bridge, | |||
| 212 | { | 213 | { |
| 213 | struct vexpress_config_trans *trans; | 214 | struct vexpress_config_trans *trans; |
| 214 | unsigned long flags; | 215 | unsigned long flags; |
| 216 | const char *message = "Completed"; | ||
| 215 | 217 | ||
| 216 | spin_lock_irqsave(&bridge->transactions_lock, flags); | 218 | spin_lock_irqsave(&bridge->transactions_lock, flags); |
| 217 | 219 | ||
| 218 | trans = list_first_entry(&bridge->transactions, | 220 | trans = list_first_entry(&bridge->transactions, |
| 219 | struct vexpress_config_trans, list); | 221 | struct vexpress_config_trans, list); |
| 220 | vexpress_config_dump_trans("Completed", trans); | ||
| 221 | |||
| 222 | trans->status = status; | 222 | trans->status = status; |
| 223 | list_del(&trans->list); | ||
| 224 | 223 | ||
| 225 | if (!list_empty(&bridge->transactions)) { | 224 | do { |
| 226 | vexpress_config_dump_trans("Pending", trans); | 225 | vexpress_config_dump_trans(message, trans); |
| 226 | list_del(&trans->list); | ||
| 227 | complete(&trans->completion); | ||
| 227 | 228 | ||
| 228 | bridge->info->func_exec(trans->func->func, trans->offset, | 229 | if (list_empty(&bridge->transactions)) |
| 229 | trans->write, trans->data); | 230 | break; |
| 230 | } | 231 | |
| 231 | spin_unlock_irqrestore(&bridge->transactions_lock, flags); | 232 | trans = list_first_entry(&bridge->transactions, |
| 233 | struct vexpress_config_trans, list); | ||
| 234 | vexpress_config_dump_trans("Executing pending", trans); | ||
| 235 | trans->status = bridge->info->func_exec(trans->func->func, | ||
| 236 | trans->offset, trans->write, trans->data); | ||
| 237 | message = "Finished pending"; | ||
| 238 | } while (trans->status == VEXPRESS_CONFIG_STATUS_DONE); | ||
| 232 | 239 | ||
| 233 | complete(&trans->completion); | 240 | spin_unlock_irqrestore(&bridge->transactions_lock, flags); |
| 234 | } | 241 | } |
| 235 | EXPORT_SYMBOL(vexpress_config_complete); | 242 | EXPORT_SYMBOL(vexpress_config_complete); |
| 236 | 243 | ||
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index bf75e967a1f3..96a020b1dcd1 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c | |||
| @@ -490,12 +490,12 @@ static int vexpress_sysreg_probe(struct platform_device *pdev) | |||
| 490 | return err; | 490 | return err; |
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | vexpress_sysreg_dev = &pdev->dev; | ||
| 494 | |||
| 493 | platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", | 495 | platform_device_register_data(vexpress_sysreg_dev, "leds-gpio", |
| 494 | PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, | 496 | PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata, |
| 495 | sizeof(vexpress_sysreg_leds_pdata)); | 497 | sizeof(vexpress_sysreg_leds_pdata)); |
| 496 | 498 | ||
| 497 | vexpress_sysreg_dev = &pdev->dev; | ||
| 498 | |||
| 499 | device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); | 499 | device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id); |
| 500 | 500 | ||
| 501 | return 0; | 501 | return 0; |
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index f70c4956ff9d..155c4a1a6a99 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/device.h> | ||
| 13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 14 | 15 | ||
| 15 | #include <linux/mfd/arizona/core.h> | 16 | #include <linux/mfd/arizona/core.h> |
| @@ -57,31 +58,54 @@ static const struct reg_default wm5102_reva_patch[] = { | |||
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | static const struct reg_default wm5102_revb_patch[] = { | 60 | static const struct reg_default wm5102_revb_patch[] = { |
| 61 | { 0x19, 0x0001 }, | ||
| 60 | { 0x80, 0x0003 }, | 62 | { 0x80, 0x0003 }, |
| 61 | { 0x081, 0xE022 }, | 63 | { 0x081, 0xE022 }, |
| 62 | { 0x410, 0x4080 }, | 64 | { 0x410, 0x6080 }, |
| 63 | { 0x418, 0x4080 }, | 65 | { 0x418, 0xa080 }, |
| 64 | { 0x420, 0x4080 }, | 66 | { 0x420, 0xa080 }, |
| 65 | { 0x428, 0xC000 }, | 67 | { 0x428, 0xe000 }, |
| 68 | { 0x443, 0xDC1A }, | ||
| 66 | { 0x4B0, 0x0066 }, | 69 | { 0x4B0, 0x0066 }, |
| 67 | { 0x458, 0x000b }, | 70 | { 0x458, 0x000b }, |
| 68 | { 0x212, 0x0000 }, | 71 | { 0x212, 0x0000 }, |
| 72 | { 0x171, 0x0000 }, | ||
| 73 | { 0x35E, 0x000C }, | ||
| 74 | { 0x2D4, 0x0000 }, | ||
| 69 | { 0x80, 0x0000 }, | 75 | { 0x80, 0x0000 }, |
| 70 | }; | 76 | }; |
| 71 | 77 | ||
| 72 | /* We use a function so we can use ARRAY_SIZE() */ | 78 | /* We use a function so we can use ARRAY_SIZE() */ |
| 73 | int wm5102_patch(struct arizona *arizona) | 79 | int wm5102_patch(struct arizona *arizona) |
| 74 | { | 80 | { |
| 81 | const struct reg_default *wm5102_patch; | ||
| 82 | int ret = 0; | ||
| 83 | int i, patch_size; | ||
| 84 | |||
| 75 | switch (arizona->rev) { | 85 | switch (arizona->rev) { |
| 76 | case 0: | 86 | case 0: |
| 77 | return regmap_register_patch(arizona->regmap, | 87 | wm5102_patch = wm5102_reva_patch; |
| 78 | wm5102_reva_patch, | 88 | patch_size = ARRAY_SIZE(wm5102_reva_patch); |
| 79 | ARRAY_SIZE(wm5102_reva_patch)); | ||
| 80 | default: | 89 | default: |
| 81 | return regmap_register_patch(arizona->regmap, | 90 | wm5102_patch = wm5102_revb_patch; |
| 82 | wm5102_revb_patch, | 91 | patch_size = ARRAY_SIZE(wm5102_revb_patch); |
| 83 | ARRAY_SIZE(wm5102_revb_patch)); | 92 | } |
| 93 | |||
| 94 | regcache_cache_bypass(arizona->regmap, true); | ||
| 95 | |||
| 96 | for (i = 0; i < patch_size; i++) { | ||
| 97 | ret = regmap_write(arizona->regmap, wm5102_patch[i].reg, | ||
| 98 | wm5102_patch[i].def); | ||
| 99 | if (ret != 0) { | ||
| 100 | dev_err(arizona->dev, "Failed to write %x = %x: %d\n", | ||
| 101 | wm5102_patch[i].reg, wm5102_patch[i].def, ret); | ||
| 102 | goto out; | ||
| 103 | } | ||
| 84 | } | 104 | } |
| 105 | |||
| 106 | out: | ||
| 107 | regcache_cache_bypass(arizona->regmap, false); | ||
| 108 | return ret; | ||
| 85 | } | 109 | } |
| 86 | 110 | ||
| 87 | static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { | 111 | static const struct regmap_irq wm5102_aod_irqs[ARIZONA_NUM_IRQ] = { |
| @@ -282,7 +306,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
| 282 | { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ | 306 | { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ |
| 283 | { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ | 307 | { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ |
| 284 | { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ | 308 | { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ |
| 285 | { 0x00000171, 0x0002 }, /* R369 - FLL1 Control 1 */ | 309 | { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */ |
| 286 | { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ | 310 | { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ |
| 287 | { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ | 311 | { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ |
| 288 | { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ | 312 | { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ |
| @@ -366,7 +390,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
| 366 | { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ | 390 | { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ |
| 367 | { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ | 391 | { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ |
| 368 | { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ | 392 | { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ |
| 369 | { 0x00000410, 0x4080 }, /* R1040 - Output Path Config 1L */ | 393 | { 0x00000410, 0x6080 }, /* R1040 - Output Path Config 1L */ |
| 370 | { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ | 394 | { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ |
| 371 | { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ | 395 | { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ |
| 372 | { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ | 396 | { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ |
| @@ -374,7 +398,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
| 374 | { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ | 398 | { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ |
| 375 | { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ | 399 | { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ |
| 376 | { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ | 400 | { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ |
| 377 | { 0x00000418, 0x4080 }, /* R1048 - Output Path Config 2L */ | 401 | { 0x00000418, 0xA080 }, /* R1048 - Output Path Config 2L */ |
| 378 | { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ | 402 | { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ |
| 379 | { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ | 403 | { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ |
| 380 | { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ | 404 | { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ |
| @@ -382,11 +406,11 @@ static const struct reg_default wm5102_reg_default[] = { | |||
| 382 | { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ | 406 | { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ |
| 383 | { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ | 407 | { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ |
| 384 | { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ | 408 | { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ |
| 385 | { 0x00000420, 0x4080 }, /* R1056 - Output Path Config 3L */ | 409 | { 0x00000420, 0xA080 }, /* R1056 - Output Path Config 3L */ |
| 386 | { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ | 410 | { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ |
| 387 | { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ | 411 | { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ |
| 388 | { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ | 412 | { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ |
| 389 | { 0x00000428, 0xC000 }, /* R1064 - Output Path Config 4L */ | 413 | { 0x00000428, 0xE000 }, /* R1064 - Output Path Config 4L */ |
| 390 | { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ | 414 | { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ |
| 391 | { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ | 415 | { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ |
| 392 | { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ | 416 | { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ |
| @@ -401,7 +425,7 @@ static const struct reg_default wm5102_reg_default[] = { | |||
| 401 | { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ | 425 | { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ |
| 402 | { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ | 426 | { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ |
| 403 | { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ | 427 | { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ |
| 404 | { 0x00000458, 0x0001 }, /* R1112 - Noise Gate Control */ | 428 | { 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */ |
| 405 | { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ | 429 | { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ |
| 406 | { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ | 430 | { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ |
| 407 | { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ | 431 | { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ |
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 4e70e157a909..e7ed14f661d8 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c | |||
| @@ -37,7 +37,7 @@ static int wm831x_spi_probe(struct spi_device *spi) | |||
| 37 | spi->bits_per_word = 16; | 37 | spi->bits_per_word = 16; |
| 38 | spi->mode = SPI_MODE_0; | 38 | spi->mode = SPI_MODE_0; |
| 39 | 39 | ||
| 40 | dev_set_drvdata(&spi->dev, wm831x); | 40 | spi_set_drvdata(spi, wm831x); |
| 41 | wm831x->dev = &spi->dev; | 41 | wm831x->dev = &spi->dev; |
| 42 | 42 | ||
| 43 | wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config); | 43 | wm831x->regmap = devm_regmap_init_spi(spi, &wm831x_regmap_config); |
| @@ -53,7 +53,7 @@ static int wm831x_spi_probe(struct spi_device *spi) | |||
| 53 | 53 | ||
| 54 | static int wm831x_spi_remove(struct spi_device *spi) | 54 | static int wm831x_spi_remove(struct spi_device *spi) |
| 55 | { | 55 | { |
| 56 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | 56 | struct wm831x *wm831x = spi_get_drvdata(spi); |
| 57 | 57 | ||
| 58 | wm831x_device_exit(wm831x); | 58 | wm831x_device_exit(wm831x); |
| 59 | 59 | ||
| @@ -69,7 +69,7 @@ static int wm831x_spi_suspend(struct device *dev) | |||
| 69 | 69 | ||
| 70 | static void wm831x_spi_shutdown(struct spi_device *spi) | 70 | static void wm831x_spi_shutdown(struct spi_device *spi) |
| 71 | { | 71 | { |
| 72 | struct wm831x *wm831x = dev_get_drvdata(&spi->dev); | 72 | struct wm831x *wm831x = spi_get_drvdata(spi); |
| 73 | 73 | ||
| 74 | wm831x_device_shutdown(wm831x); | 74 | wm831x_device_shutdown(wm831x); |
| 75 | } | 75 | } |
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 803e93fae56a..00e4fe2f3c75 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c | |||
| @@ -19,6 +19,9 @@ | |||
| 19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
| 20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 21 | #include <linux/mfd/core.h> | 21 | #include <linux/mfd/core.h> |
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/of_device.h> | ||
| 24 | #include <linux/of_gpio.h> | ||
| 22 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
| 23 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
| 24 | #include <linux/regulator/consumer.h> | 27 | #include <linux/regulator/consumer.h> |
| @@ -191,7 +194,7 @@ static const char *wm8958_main_supplies[] = { | |||
| 191 | "SPKVDD2", | 194 | "SPKVDD2", |
| 192 | }; | 195 | }; |
| 193 | 196 | ||
| 194 | #ifdef CONFIG_PM | 197 | #ifdef CONFIG_PM_RUNTIME |
| 195 | static int wm8994_suspend(struct device *dev) | 198 | static int wm8994_suspend(struct device *dev) |
| 196 | { | 199 | { |
| 197 | struct wm8994 *wm8994 = dev_get_drvdata(dev); | 200 | struct wm8994 *wm8994 = dev_get_drvdata(dev); |
| @@ -396,6 +399,60 @@ static const struct reg_default wm1811_reva_patch[] = { | |||
| 396 | { 0x102, 0x0 }, | 399 | { 0x102, 0x0 }, |
| 397 | }; | 400 | }; |
| 398 | 401 | ||
| 402 | #ifdef CONFIG_OF | ||
| 403 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | ||
| 404 | { | ||
| 405 | struct device_node *np = wm8994->dev->of_node; | ||
| 406 | struct wm8994_pdata *pdata = &wm8994->pdata; | ||
| 407 | int i; | ||
| 408 | |||
| 409 | if (!np) | ||
| 410 | return 0; | ||
| 411 | |||
| 412 | if (of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_defaults, | ||
| 413 | ARRAY_SIZE(pdata->gpio_defaults)) >= 0) { | ||
| 414 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { | ||
| 415 | if (wm8994->pdata.gpio_defaults[i] == 0) | ||
| 416 | pdata->gpio_defaults[i] | ||
| 417 | = WM8994_CONFIGURE_GPIO; | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->micbias, | ||
| 422 | ARRAY_SIZE(pdata->micbias)); | ||
| 423 | |||
| 424 | pdata->lineout1_diff = true; | ||
| 425 | pdata->lineout2_diff = true; | ||
| 426 | if (of_find_property(np, "wlf,lineout1-se", NULL)) | ||
| 427 | pdata->lineout1_diff = false; | ||
| 428 | if (of_find_property(np, "wlf,lineout2-se", NULL)) | ||
| 429 | pdata->lineout2_diff = false; | ||
| 430 | |||
| 431 | if (of_find_property(np, "wlf,lineout1-feedback", NULL)) | ||
| 432 | pdata->lineout1fb = true; | ||
| 433 | if (of_find_property(np, "wlf,lineout2-feedback", NULL)) | ||
| 434 | pdata->lineout2fb = true; | ||
| 435 | |||
| 436 | if (of_find_property(np, "wlf,ldoena-always-driven", NULL)) | ||
| 437 | pdata->lineout2fb = true; | ||
| 438 | |||
| 439 | pdata->ldo[0].enable = of_get_named_gpio(np, "wlf,ldo1ena", 0); | ||
| 440 | if (pdata->ldo[0].enable < 0) | ||
| 441 | pdata->ldo[0].enable = 0; | ||
| 442 | |||
| 443 | pdata->ldo[1].enable = of_get_named_gpio(np, "wlf,ldo2ena", 0); | ||
| 444 | if (pdata->ldo[1].enable < 0) | ||
| 445 | pdata->ldo[1].enable = 0; | ||
| 446 | |||
| 447 | return 0; | ||
| 448 | } | ||
| 449 | #else | ||
| 450 | static int wm8994_set_pdata_from_of(struct wm8994 *wm8994) | ||
| 451 | { | ||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | #endif | ||
| 455 | |||
| 399 | /* | 456 | /* |
| 400 | * Instantiate the generic non-control parts of the device. | 457 | * Instantiate the generic non-control parts of the device. |
| 401 | */ | 458 | */ |
| @@ -405,7 +462,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
| 405 | struct regmap_config *regmap_config; | 462 | struct regmap_config *regmap_config; |
| 406 | const struct reg_default *regmap_patch = NULL; | 463 | const struct reg_default *regmap_patch = NULL; |
| 407 | const char *devname; | 464 | const char *devname; |
| 408 | int ret, i, patch_regs; | 465 | int ret, i, patch_regs = 0; |
| 409 | int pulls = 0; | 466 | int pulls = 0; |
| 410 | 467 | ||
| 411 | if (dev_get_platdata(wm8994->dev)) { | 468 | if (dev_get_platdata(wm8994->dev)) { |
| @@ -414,6 +471,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) | |||
| 414 | } | 471 | } |
| 415 | pdata = &wm8994->pdata; | 472 | pdata = &wm8994->pdata; |
| 416 | 473 | ||
| 474 | ret = wm8994_set_pdata_from_of(wm8994); | ||
| 475 | if (ret != 0) | ||
| 476 | return ret; | ||
| 477 | |||
| 417 | dev_set_drvdata(wm8994->dev, wm8994); | 478 | dev_set_drvdata(wm8994->dev, wm8994); |
| 418 | 479 | ||
| 419 | /* Add the on-chip regulators first for bootstrapping */ | 480 | /* Add the on-chip regulators first for bootstrapping */ |
| @@ -673,9 +734,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994) | |||
| 673 | } | 734 | } |
| 674 | 735 | ||
| 675 | static const struct of_device_id wm8994_of_match[] = { | 736 | static const struct of_device_id wm8994_of_match[] = { |
| 676 | { .compatible = "wlf,wm1811", }, | 737 | { .compatible = "wlf,wm1811", .data = (void *)WM1811 }, |
| 677 | { .compatible = "wlf,wm8994", }, | 738 | { .compatible = "wlf,wm8994", .data = (void *)WM8994 }, |
| 678 | { .compatible = "wlf,wm8958", }, | 739 | { .compatible = "wlf,wm8958", .data = (void *)WM8958 }, |
| 679 | { } | 740 | { } |
| 680 | }; | 741 | }; |
| 681 | MODULE_DEVICE_TABLE(of, wm8994_of_match); | 742 | MODULE_DEVICE_TABLE(of, wm8994_of_match); |
| @@ -683,6 +744,7 @@ MODULE_DEVICE_TABLE(of, wm8994_of_match); | |||
| 683 | static int wm8994_i2c_probe(struct i2c_client *i2c, | 744 | static int wm8994_i2c_probe(struct i2c_client *i2c, |
| 684 | const struct i2c_device_id *id) | 745 | const struct i2c_device_id *id) |
| 685 | { | 746 | { |
| 747 | const struct of_device_id *of_id; | ||
| 686 | struct wm8994 *wm8994; | 748 | struct wm8994 *wm8994; |
| 687 | int ret; | 749 | int ret; |
| 688 | 750 | ||
| @@ -693,7 +755,14 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, | |||
| 693 | i2c_set_clientdata(i2c, wm8994); | 755 | i2c_set_clientdata(i2c, wm8994); |
| 694 | wm8994->dev = &i2c->dev; | 756 | wm8994->dev = &i2c->dev; |
| 695 | wm8994->irq = i2c->irq; | 757 | wm8994->irq = i2c->irq; |
| 696 | wm8994->type = id->driver_data; | 758 | |
| 759 | if (i2c->dev.of_node) { | ||
| 760 | of_id = of_match_device(wm8994_of_match, &i2c->dev); | ||
| 761 | if (of_id) | ||
| 762 | wm8994->type = (int)of_id->data; | ||
| 763 | } else { | ||
| 764 | wm8994->type = id->driver_data; | ||
| 765 | } | ||
| 697 | 766 | ||
| 698 | wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); | 767 | wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); |
| 699 | if (IS_ERR(wm8994->regmap)) { | 768 | if (IS_ERR(wm8994->regmap)) { |
| @@ -724,15 +793,16 @@ static const struct i2c_device_id wm8994_i2c_id[] = { | |||
| 724 | }; | 793 | }; |
| 725 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); | 794 | MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id); |
| 726 | 795 | ||
| 727 | static UNIVERSAL_DEV_PM_OPS(wm8994_pm_ops, wm8994_suspend, wm8994_resume, | 796 | static const struct dev_pm_ops wm8994_pm_ops = { |
| 728 | NULL); | 797 | SET_RUNTIME_PM_OPS(wm8994_suspend, wm8994_resume, NULL) |
| 798 | }; | ||
| 729 | 799 | ||
| 730 | static struct i2c_driver wm8994_i2c_driver = { | 800 | static struct i2c_driver wm8994_i2c_driver = { |
| 731 | .driver = { | 801 | .driver = { |
| 732 | .name = "wm8994", | 802 | .name = "wm8994", |
| 733 | .owner = THIS_MODULE, | 803 | .owner = THIS_MODULE, |
| 734 | .pm = &wm8994_pm_ops, | 804 | .pm = &wm8994_pm_ops, |
| 735 | .of_match_table = wm8994_of_match, | 805 | .of_match_table = of_match_ptr(wm8994_of_match), |
| 736 | }, | 806 | }, |
| 737 | .probe = wm8994_i2c_probe, | 807 | .probe = wm8994_i2c_probe, |
| 738 | .remove = wm8994_i2c_remove, | 808 | .remove = wm8994_i2c_remove, |
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c index 1a1dcb831a17..cbde1d6d3228 100644 --- a/drivers/power/rx51_battery.c +++ b/drivers/power/rx51_battery.c | |||
| @@ -42,6 +42,7 @@ static int rx51_battery_read_adc(int channel) | |||
| 42 | req.method = TWL4030_MADC_SW1; | 42 | req.method = TWL4030_MADC_SW1; |
| 43 | req.func_cb = NULL; | 43 | req.func_cb = NULL; |
| 44 | req.type = TWL4030_MADC_WAIT; | 44 | req.type = TWL4030_MADC_WAIT; |
| 45 | req.raw = true; | ||
| 45 | 46 | ||
| 46 | if (twl4030_madc_conversion(&req) <= 0) | 47 | if (twl4030_madc_conversion(&req) <= 0) |
| 47 | return -ENODATA; | 48 | return -ENODATA; |
diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index 530e11ba0738..01f595107048 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h | |||
| @@ -39,6 +39,7 @@ struct twl4030_madc_conversion_method { | |||
| 39 | * @do_avgP: sample the input channel for 4 consecutive cycles | 39 | * @do_avgP: sample the input channel for 4 consecutive cycles |
| 40 | * @method: RT, SW1, SW2 | 40 | * @method: RT, SW1, SW2 |
| 41 | * @type: Polling or interrupt based method | 41 | * @type: Polling or interrupt based method |
| 42 | * @raw: Return raw value, do not convert it | ||
| 42 | */ | 43 | */ |
| 43 | 44 | ||
| 44 | struct twl4030_madc_request { | 45 | struct twl4030_madc_request { |
| @@ -48,6 +49,7 @@ struct twl4030_madc_request { | |||
| 48 | u16 type; | 49 | u16 type; |
| 49 | bool active; | 50 | bool active; |
| 50 | bool result_pending; | 51 | bool result_pending; |
| 52 | bool raw; | ||
| 51 | int rbuf[TWL4030_MADC_MAX_CHANNELS]; | 53 | int rbuf[TWL4030_MADC_MAX_CHANNELS]; |
| 52 | void (*func_cb)(int len, int channels, int *buf); | 54 | void (*func_cb)(int len, int channels, int *buf); |
| 53 | }; | 55 | }; |
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h index 5f3aa6b11bfa..27e06acc509a 100644 --- a/include/linux/input/matrix_keypad.h +++ b/include/linux/input/matrix_keypad.h | |||
| @@ -81,4 +81,23 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, | |||
| 81 | unsigned short *keymap, | 81 | unsigned short *keymap, |
| 82 | struct input_dev *input_dev); | 82 | struct input_dev *input_dev); |
| 83 | 83 | ||
| 84 | #ifdef CONFIG_OF | ||
| 85 | /** | ||
| 86 | * matrix_keypad_parse_of_params() - Read parameters from matrix-keypad node | ||
| 87 | * | ||
| 88 | * @dev: Device containing of_node | ||
| 89 | * @rows: Returns number of matrix rows | ||
| 90 | * @cols: Returns number of matrix columns | ||
| 91 | * @return 0 if OK, <0 on error | ||
| 92 | */ | ||
| 93 | int matrix_keypad_parse_of_params(struct device *dev, | ||
| 94 | unsigned int *rows, unsigned int *cols); | ||
| 95 | #else | ||
| 96 | static inline int matrix_keypad_parse_of_params(struct device *dev, | ||
| 97 | unsigned int *rows, unsigned int *cols) | ||
| 98 | { | ||
| 99 | return -ENOSYS; | ||
| 100 | } | ||
| 101 | #endif /* CONFIG_OF */ | ||
| 102 | |||
| 84 | #endif /* _MATRIX_KEYPAD_H */ | 103 | #endif /* _MATRIX_KEYPAD_H */ |
diff --git a/include/linux/mfd/arizona/pdata.h b/include/linux/mfd/arizona/pdata.h index a0f940987a3e..80dead1f7100 100644 --- a/include/linux/mfd/arizona/pdata.h +++ b/include/linux/mfd/arizona/pdata.h | |||
| @@ -78,6 +78,7 @@ struct arizona_micbias { | |||
| 78 | unsigned int ext_cap:1; /** External capacitor fitted */ | 78 | unsigned int ext_cap:1; /** External capacitor fitted */ |
| 79 | unsigned int discharge:1; /** Actively discharge */ | 79 | unsigned int discharge:1; /** Actively discharge */ |
| 80 | unsigned int fast_start:1; /** Enable aggressive startup ramp rate */ | 80 | unsigned int fast_start:1; /** Enable aggressive startup ramp rate */ |
| 81 | unsigned int bypass:1; /** Use bypass mode */ | ||
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| 83 | struct arizona_micd_config { | 84 | struct arizona_micd_config { |
| @@ -104,7 +105,8 @@ struct arizona_pdata { | |||
| 104 | /** If a direct 32kHz clock is provided on an MCLK specify it here */ | 105 | /** If a direct 32kHz clock is provided on an MCLK specify it here */ |
| 105 | int clk32k_src; | 106 | int clk32k_src; |
| 106 | 107 | ||
| 107 | bool irq_active_high; /** IRQ polarity */ | 108 | /** Mode for primary IRQ (defaults to active low) */ |
| 109 | unsigned int irq_flags; | ||
| 108 | 110 | ||
| 109 | /* Base GPIO */ | 111 | /* Base GPIO */ |
| 110 | int gpio_base; | 112 | int gpio_base; |
| @@ -183,6 +185,9 @@ struct arizona_pdata { | |||
| 183 | 185 | ||
| 184 | /** Haptic actuator type */ | 186 | /** Haptic actuator type */ |
| 185 | unsigned int hap_act; | 187 | unsigned int hap_act; |
| 188 | |||
| 189 | /** GPIO for primary IRQ (used for edge triggered emulation) */ | ||
| 190 | int irq_gpio; | ||
| 186 | }; | 191 | }; |
| 187 | 192 | ||
| 188 | #endif | 193 | #endif |
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h new file mode 100644 index 000000000000..032af7fc5b2e --- /dev/null +++ b/include/linux/mfd/cros_ec.h | |||
| @@ -0,0 +1,170 @@ | |||
| 1 | /* | ||
| 2 | * ChromeOS EC multi-function device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef __LINUX_MFD_CROS_EC_H | ||
| 17 | #define __LINUX_MFD_CROS_EC_H | ||
| 18 | |||
| 19 | #include <linux/mfd/cros_ec_commands.h> | ||
| 20 | |||
| 21 | /* | ||
| 22 | * Command interface between EC and AP, for LPC, I2C and SPI interfaces. | ||
| 23 | */ | ||
| 24 | enum { | ||
| 25 | EC_MSG_TX_HEADER_BYTES = 3, | ||
| 26 | EC_MSG_TX_TRAILER_BYTES = 1, | ||
| 27 | EC_MSG_TX_PROTO_BYTES = EC_MSG_TX_HEADER_BYTES + | ||
| 28 | EC_MSG_TX_TRAILER_BYTES, | ||
| 29 | EC_MSG_RX_PROTO_BYTES = 3, | ||
| 30 | |||
| 31 | /* Max length of messages */ | ||
| 32 | EC_MSG_BYTES = EC_HOST_PARAM_SIZE + EC_MSG_TX_PROTO_BYTES, | ||
| 33 | |||
| 34 | }; | ||
| 35 | |||
| 36 | /** | ||
| 37 | * struct cros_ec_msg - A message sent to the EC, and its reply | ||
| 38 | * | ||
| 39 | * @version: Command version number (often 0) | ||
| 40 | * @cmd: Command to send (EC_CMD_...) | ||
| 41 | * @out_buf: Outgoing payload (to EC) | ||
| 42 | * @outlen: Outgoing length | ||
| 43 | * @in_buf: Incoming payload (from EC) | ||
| 44 | * @in_len: Incoming length | ||
| 45 | */ | ||
| 46 | struct cros_ec_msg { | ||
| 47 | u8 version; | ||
| 48 | u8 cmd; | ||
| 49 | uint8_t *out_buf; | ||
| 50 | int out_len; | ||
| 51 | uint8_t *in_buf; | ||
| 52 | int in_len; | ||
| 53 | }; | ||
| 54 | |||
| 55 | /** | ||
| 56 | * struct cros_ec_device - Information about a ChromeOS EC device | ||
| 57 | * | ||
| 58 | * @name: Name of this EC interface | ||
| 59 | * @priv: Private data | ||
| 60 | * @irq: Interrupt to use | ||
| 61 | * @din: input buffer (from EC) | ||
| 62 | * @dout: output buffer (to EC) | ||
| 63 | * \note | ||
| 64 | * These two buffers will always be dword-aligned and include enough | ||
| 65 | * space for up to 7 word-alignment bytes also, so we can ensure that | ||
| 66 | * the body of the message is always dword-aligned (64-bit). | ||
| 67 | * | ||
| 68 | * We use this alignment to keep ARM and x86 happy. Probably word | ||
| 69 | * alignment would be OK, there might be a small performance advantage | ||
| 70 | * to using dword. | ||
| 71 | * @din_size: size of din buffer | ||
| 72 | * @dout_size: size of dout buffer | ||
| 73 | * @command_send: send a command | ||
| 74 | * @command_recv: receive a command | ||
| 75 | * @ec_name: name of EC device (e.g. 'chromeos-ec') | ||
| 76 | * @phys_name: name of physical comms layer (e.g. 'i2c-4') | ||
| 77 | * @parent: pointer to parent device (e.g. i2c or spi device) | ||
| 78 | * @dev: Device pointer | ||
| 79 | * dev_lock: Lock to prevent concurrent access | ||
| 80 | * @wake_enabled: true if this device can wake the system from sleep | ||
| 81 | * @was_wake_device: true if this device was set to wake the system from | ||
| 82 | * sleep at the last suspend | ||
| 83 | * @event_notifier: interrupt event notifier for transport devices | ||
| 84 | */ | ||
| 85 | struct cros_ec_device { | ||
| 86 | const char *name; | ||
| 87 | void *priv; | ||
| 88 | int irq; | ||
| 89 | uint8_t *din; | ||
| 90 | uint8_t *dout; | ||
| 91 | int din_size; | ||
| 92 | int dout_size; | ||
| 93 | int (*command_send)(struct cros_ec_device *ec, | ||
| 94 | uint16_t cmd, void *out_buf, int out_len); | ||
| 95 | int (*command_recv)(struct cros_ec_device *ec, | ||
| 96 | uint16_t cmd, void *in_buf, int in_len); | ||
| 97 | int (*command_sendrecv)(struct cros_ec_device *ec, | ||
| 98 | uint16_t cmd, void *out_buf, int out_len, | ||
| 99 | void *in_buf, int in_len); | ||
| 100 | int (*command_xfer)(struct cros_ec_device *ec, | ||
| 101 | struct cros_ec_msg *msg); | ||
| 102 | |||
| 103 | const char *ec_name; | ||
| 104 | const char *phys_name; | ||
| 105 | struct device *parent; | ||
| 106 | |||
| 107 | /* These are --private-- fields - do not assign */ | ||
| 108 | struct device *dev; | ||
| 109 | struct mutex dev_lock; | ||
| 110 | bool wake_enabled; | ||
| 111 | bool was_wake_device; | ||
| 112 | struct blocking_notifier_head event_notifier; | ||
| 113 | }; | ||
| 114 | |||
| 115 | /** | ||
| 116 | * cros_ec_suspend - Handle a suspend operation for the ChromeOS EC device | ||
| 117 | * | ||
| 118 | * This can be called by drivers to handle a suspend event. | ||
| 119 | * | ||
| 120 | * ec_dev: Device to suspend | ||
| 121 | * @return 0 if ok, -ve on error | ||
| 122 | */ | ||
| 123 | int cros_ec_suspend(struct cros_ec_device *ec_dev); | ||
| 124 | |||
| 125 | /** | ||
| 126 | * cros_ec_resume - Handle a resume operation for the ChromeOS EC device | ||
| 127 | * | ||
| 128 | * This can be called by drivers to handle a resume event. | ||
| 129 | * | ||
| 130 | * @ec_dev: Device to resume | ||
| 131 | * @return 0 if ok, -ve on error | ||
| 132 | */ | ||
| 133 | int cros_ec_resume(struct cros_ec_device *ec_dev); | ||
| 134 | |||
| 135 | /** | ||
| 136 | * cros_ec_prepare_tx - Prepare an outgoing message in the output buffer | ||
| 137 | * | ||
| 138 | * This is intended to be used by all ChromeOS EC drivers, but at present | ||
| 139 | * only SPI uses it. Once LPC uses the same protocol it can start using it. | ||
| 140 | * I2C could use it now, with a refactor of the existing code. | ||
| 141 | * | ||
| 142 | * @ec_dev: Device to register | ||
| 143 | * @msg: Message to write | ||
| 144 | */ | ||
| 145 | int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, | ||
| 146 | struct cros_ec_msg *msg); | ||
| 147 | |||
| 148 | /** | ||
| 149 | * cros_ec_remove - Remove a ChromeOS EC | ||
| 150 | * | ||
| 151 | * Call this to deregister a ChromeOS EC. After this you should call | ||
| 152 | * cros_ec_free(). | ||
| 153 | * | ||
| 154 | * @ec_dev: Device to register | ||
| 155 | * @return 0 if ok, -ve on error | ||
| 156 | */ | ||
| 157 | int cros_ec_remove(struct cros_ec_device *ec_dev); | ||
| 158 | |||
| 159 | /** | ||
| 160 | * cros_ec_register - Register a new ChromeOS EC, using the provided info | ||
| 161 | * | ||
| 162 | * Before calling this, allocate a pointer to a new device and then fill | ||
| 163 | * in all the fields up to the --private-- marker. | ||
| 164 | * | ||
| 165 | * @ec_dev: Device to register | ||
| 166 | * @return 0 if ok, -ve on error | ||
| 167 | */ | ||
| 168 | int cros_ec_register(struct cros_ec_device *ec_dev); | ||
| 169 | |||
| 170 | #endif /* __LINUX_MFD_CROS_EC_H */ | ||
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h new file mode 100644 index 000000000000..86fd06953bcd --- /dev/null +++ b/include/linux/mfd/cros_ec_commands.h | |||
| @@ -0,0 +1,1369 @@ | |||
| 1 | /* | ||
| 2 | * Host communication command constants for ChromeOS EC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Google, Inc | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * The ChromeOS EC multi function device is used to mux all the requests | ||
| 16 | * to the EC device for its multiple features: keyboard controller, | ||
| 17 | * battery charging and regulator control, firmware update. | ||
| 18 | * | ||
| 19 | * NOTE: This file is copied verbatim from the ChromeOS EC Open Source | ||
| 20 | * project in an attempt to make future updates easy to make. | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef __CROS_EC_COMMANDS_H | ||
| 24 | #define __CROS_EC_COMMANDS_H | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Protocol overview | ||
| 28 | * | ||
| 29 | * request: CMD [ P0 P1 P2 ... Pn S ] | ||
| 30 | * response: ERR [ P0 P1 P2 ... Pn S ] | ||
| 31 | * | ||
| 32 | * where the bytes are defined as follow : | ||
| 33 | * - CMD is the command code. (defined by EC_CMD_ constants) | ||
| 34 | * - ERR is the error code. (defined by EC_RES_ constants) | ||
| 35 | * - Px is the optional payload. | ||
| 36 | * it is not sent if the error code is not success. | ||
| 37 | * (defined by ec_params_ and ec_response_ structures) | ||
| 38 | * - S is the checksum which is the sum of all payload bytes. | ||
| 39 | * | ||
| 40 | * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD | ||
| 41 | * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM. | ||
| 42 | * On I2C, all bytes are sent serially in the same message. | ||
| 43 | */ | ||
| 44 | |||
| 45 | /* Current version of this protocol */ | ||
| 46 | #define EC_PROTO_VERSION 0x00000002 | ||
| 47 | |||
| 48 | /* Command version mask */ | ||
| 49 | #define EC_VER_MASK(version) (1UL << (version)) | ||
| 50 | |||
| 51 | /* I/O addresses for ACPI commands */ | ||
| 52 | #define EC_LPC_ADDR_ACPI_DATA 0x62 | ||
| 53 | #define EC_LPC_ADDR_ACPI_CMD 0x66 | ||
| 54 | |||
| 55 | /* I/O addresses for host command */ | ||
| 56 | #define EC_LPC_ADDR_HOST_DATA 0x200 | ||
| 57 | #define EC_LPC_ADDR_HOST_CMD 0x204 | ||
| 58 | |||
| 59 | /* I/O addresses for host command args and params */ | ||
| 60 | #define EC_LPC_ADDR_HOST_ARGS 0x800 | ||
| 61 | #define EC_LPC_ADDR_HOST_PARAM 0x804 | ||
| 62 | #define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */ | ||
| 63 | |||
| 64 | /* I/O addresses for host command params, old interface */ | ||
| 65 | #define EC_LPC_ADDR_OLD_PARAM 0x880 | ||
| 66 | #define EC_OLD_PARAM_SIZE 0x080 /* Size of param area in bytes */ | ||
| 67 | |||
| 68 | /* EC command register bit functions */ | ||
| 69 | #define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */ | ||
| 70 | #define EC_LPC_CMDR_PENDING (1 << 1) /* Write pending to EC */ | ||
| 71 | #define EC_LPC_CMDR_BUSY (1 << 2) /* EC is busy processing a command */ | ||
| 72 | #define EC_LPC_CMDR_CMD (1 << 3) /* Last host write was a command */ | ||
| 73 | #define EC_LPC_CMDR_ACPI_BRST (1 << 4) /* Burst mode (not used) */ | ||
| 74 | #define EC_LPC_CMDR_SCI (1 << 5) /* SCI event is pending */ | ||
| 75 | #define EC_LPC_CMDR_SMI (1 << 6) /* SMI event is pending */ | ||
| 76 | |||
| 77 | #define EC_LPC_ADDR_MEMMAP 0x900 | ||
| 78 | #define EC_MEMMAP_SIZE 255 /* ACPI IO buffer max is 255 bytes */ | ||
| 79 | #define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */ | ||
| 80 | |||
| 81 | /* The offset address of each type of data in mapped memory. */ | ||
| 82 | #define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors */ | ||
| 83 | #define EC_MEMMAP_FAN 0x10 /* Fan speeds */ | ||
| 84 | #define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* Temp sensors (second set) */ | ||
| 85 | #define EC_MEMMAP_ID 0x20 /* 'E' 'C' */ | ||
| 86 | #define EC_MEMMAP_ID_VERSION 0x22 /* Version of data in 0x20 - 0x2f */ | ||
| 87 | #define EC_MEMMAP_THERMAL_VERSION 0x23 /* Version of data in 0x00 - 0x1f */ | ||
| 88 | #define EC_MEMMAP_BATTERY_VERSION 0x24 /* Version of data in 0x40 - 0x7f */ | ||
| 89 | #define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */ | ||
| 90 | #define EC_MEMMAP_EVENTS_VERSION 0x26 /* Version of data in 0x34 - 0x3f */ | ||
| 91 | #define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host command interface flags */ | ||
| 92 | #define EC_MEMMAP_SWITCHES 0x30 | ||
| 93 | #define EC_MEMMAP_HOST_EVENTS 0x34 | ||
| 94 | #define EC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */ | ||
| 95 | #define EC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */ | ||
| 96 | #define EC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */ | ||
| 97 | #define EC_MEMMAP_BATT_FLAG 0x4c /* Battery State, defined below */ | ||
| 98 | #define EC_MEMMAP_BATT_DCAP 0x50 /* Battery Design Capacity */ | ||
| 99 | #define EC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */ | ||
| 100 | #define EC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */ | ||
| 101 | #define EC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */ | ||
| 102 | #define EC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */ | ||
| 103 | #define EC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */ | ||
| 104 | #define EC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */ | ||
| 105 | #define EC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */ | ||
| 106 | |||
| 107 | /* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */ | ||
| 108 | #define EC_TEMP_SENSOR_ENTRIES 16 | ||
| 109 | /* | ||
| 110 | * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B. | ||
| 111 | * | ||
| 112 | * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2. | ||
| 113 | */ | ||
| 114 | #define EC_TEMP_SENSOR_B_ENTRIES 8 | ||
| 115 | #define EC_TEMP_SENSOR_NOT_PRESENT 0xff | ||
| 116 | #define EC_TEMP_SENSOR_ERROR 0xfe | ||
| 117 | #define EC_TEMP_SENSOR_NOT_POWERED 0xfd | ||
| 118 | #define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc | ||
| 119 | /* | ||
| 120 | * The offset of temperature value stored in mapped memory. This allows | ||
| 121 | * reporting a temperature range of 200K to 454K = -73C to 181C. | ||
| 122 | */ | ||
| 123 | #define EC_TEMP_SENSOR_OFFSET 200 | ||
| 124 | |||
| 125 | #define EC_FAN_SPEED_ENTRIES 4 /* Number of fans at EC_MEMMAP_FAN */ | ||
| 126 | #define EC_FAN_SPEED_NOT_PRESENT 0xffff /* Entry not present */ | ||
| 127 | #define EC_FAN_SPEED_STALLED 0xfffe /* Fan stalled */ | ||
| 128 | |||
| 129 | /* Battery bit flags at EC_MEMMAP_BATT_FLAG. */ | ||
| 130 | #define EC_BATT_FLAG_AC_PRESENT 0x01 | ||
| 131 | #define EC_BATT_FLAG_BATT_PRESENT 0x02 | ||
| 132 | #define EC_BATT_FLAG_DISCHARGING 0x04 | ||
| 133 | #define EC_BATT_FLAG_CHARGING 0x08 | ||
| 134 | #define EC_BATT_FLAG_LEVEL_CRITICAL 0x10 | ||
| 135 | |||
| 136 | /* Switch flags at EC_MEMMAP_SWITCHES */ | ||
| 137 | #define EC_SWITCH_LID_OPEN 0x01 | ||
| 138 | #define EC_SWITCH_POWER_BUTTON_PRESSED 0x02 | ||
| 139 | #define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04 | ||
| 140 | /* Recovery requested via keyboard */ | ||
| 141 | #define EC_SWITCH_KEYBOARD_RECOVERY 0x08 | ||
| 142 | /* Recovery requested via dedicated signal (from servo board) */ | ||
| 143 | #define EC_SWITCH_DEDICATED_RECOVERY 0x10 | ||
| 144 | /* Was fake developer mode switch; now unused. Remove in next refactor. */ | ||
| 145 | #define EC_SWITCH_IGNORE0 0x20 | ||
| 146 | |||
| 147 | /* Host command interface flags */ | ||
| 148 | /* Host command interface supports LPC args (LPC interface only) */ | ||
| 149 | #define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED 0x01 | ||
| 150 | |||
| 151 | /* Wireless switch flags */ | ||
| 152 | #define EC_WIRELESS_SWITCH_WLAN 0x01 | ||
| 153 | #define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 | ||
| 154 | |||
| 155 | /* | ||
| 156 | * This header file is used in coreboot both in C and ACPI code. The ACPI code | ||
| 157 | * is pre-processed to handle constants but the ASL compiler is unable to | ||
| 158 | * handle actual C code so keep it separate. | ||
| 159 | */ | ||
| 160 | #ifndef __ACPI__ | ||
| 161 | |||
| 162 | /* LPC command status byte masks */ | ||
| 163 | /* EC has written a byte in the data register and host hasn't read it yet */ | ||
| 164 | #define EC_LPC_STATUS_TO_HOST 0x01 | ||
| 165 | /* Host has written a command/data byte and the EC hasn't read it yet */ | ||
| 166 | #define EC_LPC_STATUS_FROM_HOST 0x02 | ||
| 167 | /* EC is processing a command */ | ||
| 168 | #define EC_LPC_STATUS_PROCESSING 0x04 | ||
| 169 | /* Last write to EC was a command, not data */ | ||
| 170 | #define EC_LPC_STATUS_LAST_CMD 0x08 | ||
| 171 | /* EC is in burst mode. Unsupported by Chrome EC, so this bit is never set */ | ||
| 172 | #define EC_LPC_STATUS_BURST_MODE 0x10 | ||
| 173 | /* SCI event is pending (requesting SCI query) */ | ||
| 174 | #define EC_LPC_STATUS_SCI_PENDING 0x20 | ||
| 175 | /* SMI event is pending (requesting SMI query) */ | ||
| 176 | #define EC_LPC_STATUS_SMI_PENDING 0x40 | ||
| 177 | /* (reserved) */ | ||
| 178 | #define EC_LPC_STATUS_RESERVED 0x80 | ||
| 179 | |||
| 180 | /* | ||
| 181 | * EC is busy. This covers both the EC processing a command, and the host has | ||
| 182 | * written a new command but the EC hasn't picked it up yet. | ||
| 183 | */ | ||
| 184 | #define EC_LPC_STATUS_BUSY_MASK \ | ||
| 185 | (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING) | ||
| 186 | |||
| 187 | /* Host command response codes */ | ||
| 188 | enum ec_status { | ||
| 189 | EC_RES_SUCCESS = 0, | ||
| 190 | EC_RES_INVALID_COMMAND = 1, | ||
| 191 | EC_RES_ERROR = 2, | ||
| 192 | EC_RES_INVALID_PARAM = 3, | ||
| 193 | EC_RES_ACCESS_DENIED = 4, | ||
| 194 | EC_RES_INVALID_RESPONSE = 5, | ||
| 195 | EC_RES_INVALID_VERSION = 6, | ||
| 196 | EC_RES_INVALID_CHECKSUM = 7, | ||
| 197 | EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */ | ||
| 198 | EC_RES_UNAVAILABLE = 9, /* No response available */ | ||
| 199 | EC_RES_TIMEOUT = 10, /* We got a timeout */ | ||
| 200 | EC_RES_OVERFLOW = 11, /* Table / data overflow */ | ||
| 201 | }; | ||
| 202 | |||
| 203 | /* | ||
| 204 | * Host event codes. Note these are 1-based, not 0-based, because ACPI query | ||
| 205 | * EC command uses code 0 to mean "no event pending". We explicitly specify | ||
| 206 | * each value in the enum listing so they won't change if we delete/insert an | ||
| 207 | * item or rearrange the list (it needs to be stable across platforms, not | ||
| 208 | * just within a single compiled instance). | ||
| 209 | */ | ||
| 210 | enum host_event_code { | ||
| 211 | EC_HOST_EVENT_LID_CLOSED = 1, | ||
| 212 | EC_HOST_EVENT_LID_OPEN = 2, | ||
| 213 | EC_HOST_EVENT_POWER_BUTTON = 3, | ||
| 214 | EC_HOST_EVENT_AC_CONNECTED = 4, | ||
| 215 | EC_HOST_EVENT_AC_DISCONNECTED = 5, | ||
| 216 | EC_HOST_EVENT_BATTERY_LOW = 6, | ||
| 217 | EC_HOST_EVENT_BATTERY_CRITICAL = 7, | ||
| 218 | EC_HOST_EVENT_BATTERY = 8, | ||
| 219 | EC_HOST_EVENT_THERMAL_THRESHOLD = 9, | ||
| 220 | EC_HOST_EVENT_THERMAL_OVERLOAD = 10, | ||
| 221 | EC_HOST_EVENT_THERMAL = 11, | ||
| 222 | EC_HOST_EVENT_USB_CHARGER = 12, | ||
| 223 | EC_HOST_EVENT_KEY_PRESSED = 13, | ||
| 224 | /* | ||
| 225 | * EC has finished initializing the host interface. The host can check | ||
| 226 | * for this event following sending a EC_CMD_REBOOT_EC command to | ||
| 227 | * determine when the EC is ready to accept subsequent commands. | ||
| 228 | */ | ||
| 229 | EC_HOST_EVENT_INTERFACE_READY = 14, | ||
| 230 | /* Keyboard recovery combo has been pressed */ | ||
| 231 | EC_HOST_EVENT_KEYBOARD_RECOVERY = 15, | ||
| 232 | |||
| 233 | /* Shutdown due to thermal overload */ | ||
| 234 | EC_HOST_EVENT_THERMAL_SHUTDOWN = 16, | ||
| 235 | /* Shutdown due to battery level too low */ | ||
| 236 | EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, | ||
| 237 | |||
| 238 | /* | ||
| 239 | * The high bit of the event mask is not used as a host event code. If | ||
| 240 | * it reads back as set, then the entire event mask should be | ||
| 241 | * considered invalid by the host. This can happen when reading the | ||
| 242 | * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is | ||
| 243 | * not initialized on the EC, or improperly configured on the host. | ||
| 244 | */ | ||
| 245 | EC_HOST_EVENT_INVALID = 32 | ||
| 246 | }; | ||
| 247 | /* Host event mask */ | ||
| 248 | #define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1)) | ||
| 249 | |||
| 250 | /* Arguments at EC_LPC_ADDR_HOST_ARGS */ | ||
| 251 | struct ec_lpc_host_args { | ||
| 252 | uint8_t flags; | ||
| 253 | uint8_t command_version; | ||
| 254 | uint8_t data_size; | ||
| 255 | /* | ||
| 256 | * Checksum; sum of command + flags + command_version + data_size + | ||
| 257 | * all params/response data bytes. | ||
| 258 | */ | ||
| 259 | uint8_t checksum; | ||
| 260 | } __packed; | ||
| 261 | |||
| 262 | /* Flags for ec_lpc_host_args.flags */ | ||
| 263 | /* | ||
| 264 | * Args are from host. Data area at EC_LPC_ADDR_HOST_PARAM contains command | ||
| 265 | * params. | ||
| 266 | * | ||
| 267 | * If EC gets a command and this flag is not set, this is an old-style command. | ||
| 268 | * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with | ||
| 269 | * unknown length. EC must respond with an old-style response (that is, | ||
| 270 | * withouth setting EC_HOST_ARGS_FLAG_TO_HOST). | ||
| 271 | */ | ||
| 272 | #define EC_HOST_ARGS_FLAG_FROM_HOST 0x01 | ||
| 273 | /* | ||
| 274 | * Args are from EC. Data area at EC_LPC_ADDR_HOST_PARAM contains response. | ||
| 275 | * | ||
| 276 | * If EC responds to a command and this flag is not set, this is an old-style | ||
| 277 | * response. Command version is 0 and response data from EC is at | ||
| 278 | * EC_LPC_ADDR_OLD_PARAM with unknown length. | ||
| 279 | */ | ||
| 280 | #define EC_HOST_ARGS_FLAG_TO_HOST 0x02 | ||
| 281 | |||
| 282 | /* | ||
| 283 | * Notes on commands: | ||
| 284 | * | ||
| 285 | * Each command is an 8-byte command value. Commands which take params or | ||
| 286 | * return response data specify structs for that data. If no struct is | ||
| 287 | * specified, the command does not input or output data, respectively. | ||
| 288 | * Parameter/response length is implicit in the structs. Some underlying | ||
| 289 | * communication protocols (I2C, SPI) may add length or checksum headers, but | ||
| 290 | * those are implementation-dependent and not defined here. | ||
| 291 | */ | ||
| 292 | |||
| 293 | /*****************************************************************************/ | ||
| 294 | /* General / test commands */ | ||
| 295 | |||
| 296 | /* | ||
| 297 | * Get protocol version, used to deal with non-backward compatible protocol | ||
| 298 | * changes. | ||
| 299 | */ | ||
| 300 | #define EC_CMD_PROTO_VERSION 0x00 | ||
| 301 | |||
| 302 | struct ec_response_proto_version { | ||
| 303 | uint32_t version; | ||
| 304 | } __packed; | ||
| 305 | |||
| 306 | /* | ||
| 307 | * Hello. This is a simple command to test the EC is responsive to | ||
| 308 | * commands. | ||
| 309 | */ | ||
| 310 | #define EC_CMD_HELLO 0x01 | ||
| 311 | |||
| 312 | struct ec_params_hello { | ||
| 313 | uint32_t in_data; /* Pass anything here */ | ||
| 314 | } __packed; | ||
| 315 | |||
| 316 | struct ec_response_hello { | ||
| 317 | uint32_t out_data; /* Output will be in_data + 0x01020304 */ | ||
| 318 | } __packed; | ||
| 319 | |||
| 320 | /* Get version number */ | ||
| 321 | #define EC_CMD_GET_VERSION 0x02 | ||
| 322 | |||
| 323 | enum ec_current_image { | ||
| 324 | EC_IMAGE_UNKNOWN = 0, | ||
| 325 | EC_IMAGE_RO, | ||
| 326 | EC_IMAGE_RW | ||
| 327 | }; | ||
| 328 | |||
| 329 | struct ec_response_get_version { | ||
| 330 | /* Null-terminated version strings for RO, RW */ | ||
| 331 | char version_string_ro[32]; | ||
| 332 | char version_string_rw[32]; | ||
| 333 | char reserved[32]; /* Was previously RW-B string */ | ||
| 334 | uint32_t current_image; /* One of ec_current_image */ | ||
| 335 | } __packed; | ||
| 336 | |||
| 337 | /* Read test */ | ||
| 338 | #define EC_CMD_READ_TEST 0x03 | ||
| 339 | |||
| 340 | struct ec_params_read_test { | ||
| 341 | uint32_t offset; /* Starting value for read buffer */ | ||
| 342 | uint32_t size; /* Size to read in bytes */ | ||
| 343 | } __packed; | ||
| 344 | |||
| 345 | struct ec_response_read_test { | ||
| 346 | uint32_t data[32]; | ||
| 347 | } __packed; | ||
| 348 | |||
| 349 | /* | ||
| 350 | * Get build information | ||
| 351 | * | ||
| 352 | * Response is null-terminated string. | ||
| 353 | */ | ||
| 354 | #define EC_CMD_GET_BUILD_INFO 0x04 | ||
| 355 | |||
| 356 | /* Get chip info */ | ||
| 357 | #define EC_CMD_GET_CHIP_INFO 0x05 | ||
| 358 | |||
| 359 | struct ec_response_get_chip_info { | ||
| 360 | /* Null-terminated strings */ | ||
| 361 | char vendor[32]; | ||
| 362 | char name[32]; | ||
| 363 | char revision[32]; /* Mask version */ | ||
| 364 | } __packed; | ||
| 365 | |||
| 366 | /* Get board HW version */ | ||
| 367 | #define EC_CMD_GET_BOARD_VERSION 0x06 | ||
| 368 | |||
| 369 | struct ec_response_board_version { | ||
| 370 | uint16_t board_version; /* A monotonously incrementing number. */ | ||
| 371 | } __packed; | ||
| 372 | |||
| 373 | /* | ||
| 374 | * Read memory-mapped data. | ||
| 375 | * | ||
| 376 | * This is an alternate interface to memory-mapped data for bus protocols | ||
| 377 | * which don't support direct-mapped memory - I2C, SPI, etc. | ||
| 378 | * | ||
| 379 | * Response is params.size bytes of data. | ||
| 380 | */ | ||
| 381 | #define EC_CMD_READ_MEMMAP 0x07 | ||
| 382 | |||
| 383 | struct ec_params_read_memmap { | ||
| 384 | uint8_t offset; /* Offset in memmap (EC_MEMMAP_*) */ | ||
| 385 | uint8_t size; /* Size to read in bytes */ | ||
| 386 | } __packed; | ||
| 387 | |||
| 388 | /* Read versions supported for a command */ | ||
| 389 | #define EC_CMD_GET_CMD_VERSIONS 0x08 | ||
| 390 | |||
| 391 | struct ec_params_get_cmd_versions { | ||
| 392 | uint8_t cmd; /* Command to check */ | ||
| 393 | } __packed; | ||
| 394 | |||
| 395 | struct ec_response_get_cmd_versions { | ||
| 396 | /* | ||
| 397 | * Mask of supported versions; use EC_VER_MASK() to compare with a | ||
| 398 | * desired version. | ||
| 399 | */ | ||
| 400 | uint32_t version_mask; | ||
| 401 | } __packed; | ||
| 402 | |||
| 403 | /* | ||
| 404 | * Check EC communcations status (busy). This is needed on i2c/spi but not | ||
| 405 | * on lpc since it has its own out-of-band busy indicator. | ||
| 406 | * | ||
| 407 | * lpc must read the status from the command register. Attempting this on | ||
| 408 | * lpc will overwrite the args/parameter space and corrupt its data. | ||
| 409 | */ | ||
| 410 | #define EC_CMD_GET_COMMS_STATUS 0x09 | ||
| 411 | |||
| 412 | /* Avoid using ec_status which is for return values */ | ||
| 413 | enum ec_comms_status { | ||
| 414 | EC_COMMS_STATUS_PROCESSING = 1 << 0, /* Processing cmd */ | ||
| 415 | }; | ||
| 416 | |||
| 417 | struct ec_response_get_comms_status { | ||
| 418 | uint32_t flags; /* Mask of enum ec_comms_status */ | ||
| 419 | } __packed; | ||
| 420 | |||
| 421 | |||
| 422 | /*****************************************************************************/ | ||
| 423 | /* Flash commands */ | ||
| 424 | |||
| 425 | /* Get flash info */ | ||
| 426 | #define EC_CMD_FLASH_INFO 0x10 | ||
| 427 | |||
| 428 | struct ec_response_flash_info { | ||
| 429 | /* Usable flash size, in bytes */ | ||
| 430 | uint32_t flash_size; | ||
| 431 | /* | ||
| 432 | * Write block size. Write offset and size must be a multiple | ||
| 433 | * of this. | ||
| 434 | */ | ||
| 435 | uint32_t write_block_size; | ||
| 436 | /* | ||
| 437 | * Erase block size. Erase offset and size must be a multiple | ||
| 438 | * of this. | ||
| 439 | */ | ||
| 440 | uint32_t erase_block_size; | ||
| 441 | /* | ||
| 442 | * Protection block size. Protection offset and size must be a | ||
| 443 | * multiple of this. | ||
| 444 | */ | ||
| 445 | uint32_t protect_block_size; | ||
| 446 | } __packed; | ||
| 447 | |||
| 448 | /* | ||
| 449 | * Read flash | ||
| 450 | * | ||
| 451 | * Response is params.size bytes of data. | ||
| 452 | */ | ||
| 453 | #define EC_CMD_FLASH_READ 0x11 | ||
| 454 | |||
| 455 | struct ec_params_flash_read { | ||
| 456 | uint32_t offset; /* Byte offset to read */ | ||
| 457 | uint32_t size; /* Size to read in bytes */ | ||
| 458 | } __packed; | ||
| 459 | |||
| 460 | /* Write flash */ | ||
| 461 | #define EC_CMD_FLASH_WRITE 0x12 | ||
| 462 | |||
| 463 | struct ec_params_flash_write { | ||
| 464 | uint32_t offset; /* Byte offset to write */ | ||
| 465 | uint32_t size; /* Size to write in bytes */ | ||
| 466 | /* | ||
| 467 | * Data to write. Could really use EC_PARAM_SIZE - 8, but tidiest to | ||
| 468 | * use a power of 2 so writes stay aligned. | ||
| 469 | */ | ||
| 470 | uint8_t data[64]; | ||
| 471 | } __packed; | ||
| 472 | |||
| 473 | /* Erase flash */ | ||
| 474 | #define EC_CMD_FLASH_ERASE 0x13 | ||
| 475 | |||
| 476 | struct ec_params_flash_erase { | ||
| 477 | uint32_t offset; /* Byte offset to erase */ | ||
| 478 | uint32_t size; /* Size to erase in bytes */ | ||
| 479 | } __packed; | ||
| 480 | |||
| 481 | /* | ||
| 482 | * Get/set flash protection. | ||
| 483 | * | ||
| 484 | * If mask!=0, sets/clear the requested bits of flags. Depending on the | ||
| 485 | * firmware write protect GPIO, not all flags will take effect immediately; | ||
| 486 | * some flags require a subsequent hard reset to take effect. Check the | ||
| 487 | * returned flags bits to see what actually happened. | ||
| 488 | * | ||
| 489 | * If mask=0, simply returns the current flags state. | ||
| 490 | */ | ||
| 491 | #define EC_CMD_FLASH_PROTECT 0x15 | ||
| 492 | #define EC_VER_FLASH_PROTECT 1 /* Command version 1 */ | ||
| 493 | |||
| 494 | /* Flags for flash protection */ | ||
| 495 | /* RO flash code protected when the EC boots */ | ||
| 496 | #define EC_FLASH_PROTECT_RO_AT_BOOT (1 << 0) | ||
| 497 | /* | ||
| 498 | * RO flash code protected now. If this bit is set, at-boot status cannot | ||
| 499 | * be changed. | ||
| 500 | */ | ||
| 501 | #define EC_FLASH_PROTECT_RO_NOW (1 << 1) | ||
| 502 | /* Entire flash code protected now, until reboot. */ | ||
| 503 | #define EC_FLASH_PROTECT_ALL_NOW (1 << 2) | ||
| 504 | /* Flash write protect GPIO is asserted now */ | ||
| 505 | #define EC_FLASH_PROTECT_GPIO_ASSERTED (1 << 3) | ||
| 506 | /* Error - at least one bank of flash is stuck locked, and cannot be unlocked */ | ||
| 507 | #define EC_FLASH_PROTECT_ERROR_STUCK (1 << 4) | ||
| 508 | /* | ||
| 509 | * Error - flash protection is in inconsistent state. At least one bank of | ||
| 510 | * flash which should be protected is not protected. Usually fixed by | ||
| 511 | * re-requesting the desired flags, or by a hard reset if that fails. | ||
| 512 | */ | ||
| 513 | #define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5) | ||
| 514 | /* Entile flash code protected when the EC boots */ | ||
| 515 | #define EC_FLASH_PROTECT_ALL_AT_BOOT (1 << 6) | ||
| 516 | |||
| 517 | struct ec_params_flash_protect { | ||
| 518 | uint32_t mask; /* Bits in flags to apply */ | ||
| 519 | uint32_t flags; /* New flags to apply */ | ||
| 520 | } __packed; | ||
| 521 | |||
| 522 | struct ec_response_flash_protect { | ||
| 523 | /* Current value of flash protect flags */ | ||
| 524 | uint32_t flags; | ||
| 525 | /* | ||
| 526 | * Flags which are valid on this platform. This allows the caller | ||
| 527 | * to distinguish between flags which aren't set vs. flags which can't | ||
| 528 | * be set on this platform. | ||
| 529 | */ | ||
| 530 | uint32_t valid_flags; | ||
| 531 | /* Flags which can be changed given the current protection state */ | ||
| 532 | uint32_t writable_flags; | ||
| 533 | } __packed; | ||
| 534 | |||
| 535 | /* | ||
| 536 | * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash | ||
| 537 | * write protect. These commands may be reused with version > 0. | ||
| 538 | */ | ||
| 539 | |||
| 540 | /* Get the region offset/size */ | ||
| 541 | #define EC_CMD_FLASH_REGION_INFO 0x16 | ||
| 542 | #define EC_VER_FLASH_REGION_INFO 1 | ||
| 543 | |||
| 544 | enum ec_flash_region { | ||
| 545 | /* Region which holds read-only EC image */ | ||
| 546 | EC_FLASH_REGION_RO, | ||
| 547 | /* Region which holds rewritable EC image */ | ||
| 548 | EC_FLASH_REGION_RW, | ||
| 549 | /* | ||
| 550 | * Region which should be write-protected in the factory (a superset of | ||
| 551 | * EC_FLASH_REGION_RO) | ||
| 552 | */ | ||
| 553 | EC_FLASH_REGION_WP_RO, | ||
| 554 | }; | ||
| 555 | |||
| 556 | struct ec_params_flash_region_info { | ||
| 557 | uint32_t region; /* enum ec_flash_region */ | ||
| 558 | } __packed; | ||
| 559 | |||
| 560 | struct ec_response_flash_region_info { | ||
| 561 | uint32_t offset; | ||
| 562 | uint32_t size; | ||
| 563 | } __packed; | ||
| 564 | |||
| 565 | /* Read/write VbNvContext */ | ||
| 566 | #define EC_CMD_VBNV_CONTEXT 0x17 | ||
| 567 | #define EC_VER_VBNV_CONTEXT 1 | ||
| 568 | #define EC_VBNV_BLOCK_SIZE 16 | ||
| 569 | |||
| 570 | enum ec_vbnvcontext_op { | ||
| 571 | EC_VBNV_CONTEXT_OP_READ, | ||
| 572 | EC_VBNV_CONTEXT_OP_WRITE, | ||
| 573 | }; | ||
| 574 | |||
| 575 | struct ec_params_vbnvcontext { | ||
| 576 | uint32_t op; | ||
| 577 | uint8_t block[EC_VBNV_BLOCK_SIZE]; | ||
| 578 | } __packed; | ||
| 579 | |||
| 580 | struct ec_response_vbnvcontext { | ||
| 581 | uint8_t block[EC_VBNV_BLOCK_SIZE]; | ||
| 582 | } __packed; | ||
| 583 | |||
| 584 | /*****************************************************************************/ | ||
| 585 | /* PWM commands */ | ||
| 586 | |||
| 587 | /* Get fan target RPM */ | ||
| 588 | #define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20 | ||
| 589 | |||
| 590 | struct ec_response_pwm_get_fan_rpm { | ||
| 591 | uint32_t rpm; | ||
| 592 | } __packed; | ||
| 593 | |||
| 594 | /* Set target fan RPM */ | ||
| 595 | #define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21 | ||
| 596 | |||
| 597 | struct ec_params_pwm_set_fan_target_rpm { | ||
| 598 | uint32_t rpm; | ||
| 599 | } __packed; | ||
| 600 | |||
| 601 | /* Get keyboard backlight */ | ||
| 602 | #define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22 | ||
| 603 | |||
| 604 | struct ec_response_pwm_get_keyboard_backlight { | ||
| 605 | uint8_t percent; | ||
| 606 | uint8_t enabled; | ||
| 607 | } __packed; | ||
| 608 | |||
| 609 | /* Set keyboard backlight */ | ||
| 610 | #define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23 | ||
| 611 | |||
| 612 | struct ec_params_pwm_set_keyboard_backlight { | ||
| 613 | uint8_t percent; | ||
| 614 | } __packed; | ||
| 615 | |||
| 616 | /* Set target fan PWM duty cycle */ | ||
| 617 | #define EC_CMD_PWM_SET_FAN_DUTY 0x24 | ||
| 618 | |||
| 619 | struct ec_params_pwm_set_fan_duty { | ||
| 620 | uint32_t percent; | ||
| 621 | } __packed; | ||
| 622 | |||
| 623 | /*****************************************************************************/ | ||
| 624 | /* | ||
| 625 | * Lightbar commands. This looks worse than it is. Since we only use one HOST | ||
| 626 | * command to say "talk to the lightbar", we put the "and tell it to do X" part | ||
| 627 | * into a subcommand. We'll make separate structs for subcommands with | ||
| 628 | * different input args, so that we know how much to expect. | ||
| 629 | */ | ||
| 630 | #define EC_CMD_LIGHTBAR_CMD 0x28 | ||
| 631 | |||
| 632 | struct rgb_s { | ||
| 633 | uint8_t r, g, b; | ||
| 634 | }; | ||
| 635 | |||
| 636 | #define LB_BATTERY_LEVELS 4 | ||
| 637 | /* List of tweakable parameters. NOTE: It's __packed so it can be sent in a | ||
| 638 | * host command, but the alignment is the same regardless. Keep it that way. | ||
| 639 | */ | ||
| 640 | struct lightbar_params { | ||
| 641 | /* Timing */ | ||
| 642 | int google_ramp_up; | ||
| 643 | int google_ramp_down; | ||
| 644 | int s3s0_ramp_up; | ||
| 645 | int s0_tick_delay[2]; /* AC=0/1 */ | ||
| 646 | int s0a_tick_delay[2]; /* AC=0/1 */ | ||
| 647 | int s0s3_ramp_down; | ||
| 648 | int s3_sleep_for; | ||
| 649 | int s3_ramp_up; | ||
| 650 | int s3_ramp_down; | ||
| 651 | |||
| 652 | /* Oscillation */ | ||
| 653 | uint8_t new_s0; | ||
| 654 | uint8_t osc_min[2]; /* AC=0/1 */ | ||
| 655 | uint8_t osc_max[2]; /* AC=0/1 */ | ||
| 656 | uint8_t w_ofs[2]; /* AC=0/1 */ | ||
| 657 | |||
| 658 | /* Brightness limits based on the backlight and AC. */ | ||
| 659 | uint8_t bright_bl_off_fixed[2]; /* AC=0/1 */ | ||
| 660 | uint8_t bright_bl_on_min[2]; /* AC=0/1 */ | ||
| 661 | uint8_t bright_bl_on_max[2]; /* AC=0/1 */ | ||
| 662 | |||
| 663 | /* Battery level thresholds */ | ||
| 664 | uint8_t battery_threshold[LB_BATTERY_LEVELS - 1]; | ||
| 665 | |||
| 666 | /* Map [AC][battery_level] to color index */ | ||
| 667 | uint8_t s0_idx[2][LB_BATTERY_LEVELS]; /* AP is running */ | ||
| 668 | uint8_t s3_idx[2][LB_BATTERY_LEVELS]; /* AP is sleeping */ | ||
| 669 | |||
| 670 | /* Color palette */ | ||
| 671 | struct rgb_s color[8]; /* 0-3 are Google colors */ | ||
| 672 | } __packed; | ||
| 673 | |||
| 674 | struct ec_params_lightbar { | ||
| 675 | uint8_t cmd; /* Command (see enum lightbar_command) */ | ||
| 676 | union { | ||
| 677 | struct { | ||
| 678 | /* no args */ | ||
| 679 | } dump, off, on, init, get_seq, get_params; | ||
| 680 | |||
| 681 | struct num { | ||
| 682 | uint8_t num; | ||
| 683 | } brightness, seq, demo; | ||
| 684 | |||
| 685 | struct reg { | ||
| 686 | uint8_t ctrl, reg, value; | ||
| 687 | } reg; | ||
| 688 | |||
| 689 | struct rgb { | ||
| 690 | uint8_t led, red, green, blue; | ||
| 691 | } rgb; | ||
| 692 | |||
| 693 | struct lightbar_params set_params; | ||
| 694 | }; | ||
| 695 | } __packed; | ||
| 696 | |||
| 697 | struct ec_response_lightbar { | ||
| 698 | union { | ||
| 699 | struct dump { | ||
| 700 | struct { | ||
| 701 | uint8_t reg; | ||
| 702 | uint8_t ic0; | ||
| 703 | uint8_t ic1; | ||
| 704 | } vals[23]; | ||
| 705 | } dump; | ||
| 706 | |||
| 707 | struct get_seq { | ||
| 708 | uint8_t num; | ||
| 709 | } get_seq; | ||
| 710 | |||
| 711 | struct lightbar_params get_params; | ||
| 712 | |||
| 713 | struct { | ||
| 714 | /* no return params */ | ||
| 715 | } off, on, init, brightness, seq, reg, rgb, demo, set_params; | ||
| 716 | }; | ||
| 717 | } __packed; | ||
| 718 | |||
| 719 | /* Lightbar commands */ | ||
| 720 | enum lightbar_command { | ||
| 721 | LIGHTBAR_CMD_DUMP = 0, | ||
| 722 | LIGHTBAR_CMD_OFF = 1, | ||
| 723 | LIGHTBAR_CMD_ON = 2, | ||
| 724 | LIGHTBAR_CMD_INIT = 3, | ||
| 725 | LIGHTBAR_CMD_BRIGHTNESS = 4, | ||
| 726 | LIGHTBAR_CMD_SEQ = 5, | ||
| 727 | LIGHTBAR_CMD_REG = 6, | ||
| 728 | LIGHTBAR_CMD_RGB = 7, | ||
| 729 | LIGHTBAR_CMD_GET_SEQ = 8, | ||
| 730 | LIGHTBAR_CMD_DEMO = 9, | ||
| 731 | LIGHTBAR_CMD_GET_PARAMS = 10, | ||
| 732 | LIGHTBAR_CMD_SET_PARAMS = 11, | ||
| 733 | LIGHTBAR_NUM_CMDS | ||
| 734 | }; | ||
| 735 | |||
| 736 | /*****************************************************************************/ | ||
| 737 | /* Verified boot commands */ | ||
| 738 | |||
| 739 | /* | ||
| 740 | * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be | ||
| 741 | * reused for other purposes with version > 0. | ||
| 742 | */ | ||
| 743 | |||
| 744 | /* Verified boot hash command */ | ||
| 745 | #define EC_CMD_VBOOT_HASH 0x2A | ||
| 746 | |||
| 747 | struct ec_params_vboot_hash { | ||
| 748 | uint8_t cmd; /* enum ec_vboot_hash_cmd */ | ||
| 749 | uint8_t hash_type; /* enum ec_vboot_hash_type */ | ||
| 750 | uint8_t nonce_size; /* Nonce size; may be 0 */ | ||
| 751 | uint8_t reserved0; /* Reserved; set 0 */ | ||
| 752 | uint32_t offset; /* Offset in flash to hash */ | ||
| 753 | uint32_t size; /* Number of bytes to hash */ | ||
| 754 | uint8_t nonce_data[64]; /* Nonce data; ignored if nonce_size=0 */ | ||
| 755 | } __packed; | ||
| 756 | |||
| 757 | struct ec_response_vboot_hash { | ||
| 758 | uint8_t status; /* enum ec_vboot_hash_status */ | ||
| 759 | uint8_t hash_type; /* enum ec_vboot_hash_type */ | ||
| 760 | uint8_t digest_size; /* Size of hash digest in bytes */ | ||
| 761 | uint8_t reserved0; /* Ignore; will be 0 */ | ||
| 762 | uint32_t offset; /* Offset in flash which was hashed */ | ||
| 763 | uint32_t size; /* Number of bytes hashed */ | ||
| 764 | uint8_t hash_digest[64]; /* Hash digest data */ | ||
| 765 | } __packed; | ||
| 766 | |||
| 767 | enum ec_vboot_hash_cmd { | ||
| 768 | EC_VBOOT_HASH_GET = 0, /* Get current hash status */ | ||
| 769 | EC_VBOOT_HASH_ABORT = 1, /* Abort calculating current hash */ | ||
| 770 | EC_VBOOT_HASH_START = 2, /* Start computing a new hash */ | ||
| 771 | EC_VBOOT_HASH_RECALC = 3, /* Synchronously compute a new hash */ | ||
| 772 | }; | ||
| 773 | |||
| 774 | enum ec_vboot_hash_type { | ||
| 775 | EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */ | ||
| 776 | }; | ||
| 777 | |||
| 778 | enum ec_vboot_hash_status { | ||
| 779 | EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */ | ||
| 780 | EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */ | ||
| 781 | EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */ | ||
| 782 | }; | ||
| 783 | |||
| 784 | /* | ||
| 785 | * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC. | ||
| 786 | * If one of these is specified, the EC will automatically update offset and | ||
| 787 | * size to the correct values for the specified image (RO or RW). | ||
| 788 | */ | ||
| 789 | #define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe | ||
| 790 | #define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd | ||
| 791 | |||
| 792 | /*****************************************************************************/ | ||
| 793 | /* USB charging control commands */ | ||
| 794 | |||
| 795 | /* Set USB port charging mode */ | ||
| 796 | #define EC_CMD_USB_CHARGE_SET_MODE 0x30 | ||
| 797 | |||
| 798 | struct ec_params_usb_charge_set_mode { | ||
| 799 | uint8_t usb_port_id; | ||
| 800 | uint8_t mode; | ||
| 801 | } __packed; | ||
| 802 | |||
| 803 | /*****************************************************************************/ | ||
| 804 | /* Persistent storage for host */ | ||
| 805 | |||
| 806 | /* Maximum bytes that can be read/written in a single command */ | ||
| 807 | #define EC_PSTORE_SIZE_MAX 64 | ||
| 808 | |||
| 809 | /* Get persistent storage info */ | ||
| 810 | #define EC_CMD_PSTORE_INFO 0x40 | ||
| 811 | |||
| 812 | struct ec_response_pstore_info { | ||
| 813 | /* Persistent storage size, in bytes */ | ||
| 814 | uint32_t pstore_size; | ||
| 815 | /* Access size; read/write offset and size must be a multiple of this */ | ||
| 816 | uint32_t access_size; | ||
| 817 | } __packed; | ||
| 818 | |||
| 819 | /* | ||
| 820 | * Read persistent storage | ||
| 821 | * | ||
| 822 | * Response is params.size bytes of data. | ||
| 823 | */ | ||
| 824 | #define EC_CMD_PSTORE_READ 0x41 | ||
| 825 | |||
| 826 | struct ec_params_pstore_read { | ||
| 827 | uint32_t offset; /* Byte offset to read */ | ||
| 828 | uint32_t size; /* Size to read in bytes */ | ||
| 829 | } __packed; | ||
| 830 | |||
| 831 | /* Write persistent storage */ | ||
| 832 | #define EC_CMD_PSTORE_WRITE 0x42 | ||
| 833 | |||
| 834 | struct ec_params_pstore_write { | ||
| 835 | uint32_t offset; /* Byte offset to write */ | ||
| 836 | uint32_t size; /* Size to write in bytes */ | ||
| 837 | uint8_t data[EC_PSTORE_SIZE_MAX]; | ||
| 838 | } __packed; | ||
| 839 | |||
| 840 | /*****************************************************************************/ | ||
| 841 | /* Real-time clock */ | ||
| 842 | |||
| 843 | /* RTC params and response structures */ | ||
| 844 | struct ec_params_rtc { | ||
| 845 | uint32_t time; | ||
| 846 | } __packed; | ||
| 847 | |||
| 848 | struct ec_response_rtc { | ||
| 849 | uint32_t time; | ||
| 850 | } __packed; | ||
| 851 | |||
| 852 | /* These use ec_response_rtc */ | ||
| 853 | #define EC_CMD_RTC_GET_VALUE 0x44 | ||
| 854 | #define EC_CMD_RTC_GET_ALARM 0x45 | ||
| 855 | |||
| 856 | /* These all use ec_params_rtc */ | ||
| 857 | #define EC_CMD_RTC_SET_VALUE 0x46 | ||
| 858 | #define EC_CMD_RTC_SET_ALARM 0x47 | ||
| 859 | |||
| 860 | /*****************************************************************************/ | ||
| 861 | /* Port80 log access */ | ||
| 862 | |||
| 863 | /* Get last port80 code from previous boot */ | ||
| 864 | #define EC_CMD_PORT80_LAST_BOOT 0x48 | ||
| 865 | |||
| 866 | struct ec_response_port80_last_boot { | ||
| 867 | uint16_t code; | ||
| 868 | } __packed; | ||
| 869 | |||
| 870 | /*****************************************************************************/ | ||
| 871 | /* Thermal engine commands */ | ||
| 872 | |||
| 873 | /* Set thershold value */ | ||
| 874 | #define EC_CMD_THERMAL_SET_THRESHOLD 0x50 | ||
| 875 | |||
| 876 | struct ec_params_thermal_set_threshold { | ||
| 877 | uint8_t sensor_type; | ||
| 878 | uint8_t threshold_id; | ||
| 879 | uint16_t value; | ||
| 880 | } __packed; | ||
| 881 | |||
| 882 | /* Get threshold value */ | ||
| 883 | #define EC_CMD_THERMAL_GET_THRESHOLD 0x51 | ||
| 884 | |||
| 885 | struct ec_params_thermal_get_threshold { | ||
| 886 | uint8_t sensor_type; | ||
| 887 | uint8_t threshold_id; | ||
| 888 | } __packed; | ||
| 889 | |||
| 890 | struct ec_response_thermal_get_threshold { | ||
| 891 | uint16_t value; | ||
| 892 | } __packed; | ||
| 893 | |||
| 894 | /* Toggle automatic fan control */ | ||
| 895 | #define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52 | ||
| 896 | |||
| 897 | /* Get TMP006 calibration data */ | ||
| 898 | #define EC_CMD_TMP006_GET_CALIBRATION 0x53 | ||
| 899 | |||
| 900 | struct ec_params_tmp006_get_calibration { | ||
| 901 | uint8_t index; | ||
| 902 | } __packed; | ||
| 903 | |||
| 904 | struct ec_response_tmp006_get_calibration { | ||
| 905 | float s0; | ||
| 906 | float b0; | ||
| 907 | float b1; | ||
| 908 | float b2; | ||
| 909 | } __packed; | ||
| 910 | |||
| 911 | /* Set TMP006 calibration data */ | ||
| 912 | #define EC_CMD_TMP006_SET_CALIBRATION 0x54 | ||
| 913 | |||
| 914 | struct ec_params_tmp006_set_calibration { | ||
| 915 | uint8_t index; | ||
| 916 | uint8_t reserved[3]; /* Reserved; set 0 */ | ||
| 917 | float s0; | ||
| 918 | float b0; | ||
| 919 | float b1; | ||
| 920 | float b2; | ||
| 921 | } __packed; | ||
| 922 | |||
| 923 | /*****************************************************************************/ | ||
| 924 | /* MKBP - Matrix KeyBoard Protocol */ | ||
| 925 | |||
| 926 | /* | ||
| 927 | * Read key state | ||
| 928 | * | ||
| 929 | * Returns raw data for keyboard cols; see ec_response_mkbp_info.cols for | ||
| 930 | * expected response size. | ||
| 931 | */ | ||
| 932 | #define EC_CMD_MKBP_STATE 0x60 | ||
| 933 | |||
| 934 | /* Provide information about the matrix : number of rows and columns */ | ||
| 935 | #define EC_CMD_MKBP_INFO 0x61 | ||
| 936 | |||
| 937 | struct ec_response_mkbp_info { | ||
| 938 | uint32_t rows; | ||
| 939 | uint32_t cols; | ||
| 940 | uint8_t switches; | ||
| 941 | } __packed; | ||
| 942 | |||
| 943 | /* Simulate key press */ | ||
| 944 | #define EC_CMD_MKBP_SIMULATE_KEY 0x62 | ||
| 945 | |||
| 946 | struct ec_params_mkbp_simulate_key { | ||
| 947 | uint8_t col; | ||
| 948 | uint8_t row; | ||
| 949 | uint8_t pressed; | ||
| 950 | } __packed; | ||
| 951 | |||
| 952 | /* Configure keyboard scanning */ | ||
| 953 | #define EC_CMD_MKBP_SET_CONFIG 0x64 | ||
| 954 | #define EC_CMD_MKBP_GET_CONFIG 0x65 | ||
| 955 | |||
| 956 | /* flags */ | ||
| 957 | enum mkbp_config_flags { | ||
| 958 | EC_MKBP_FLAGS_ENABLE = 1, /* Enable keyboard scanning */ | ||
| 959 | }; | ||
| 960 | |||
| 961 | enum mkbp_config_valid { | ||
| 962 | EC_MKBP_VALID_SCAN_PERIOD = 1 << 0, | ||
| 963 | EC_MKBP_VALID_POLL_TIMEOUT = 1 << 1, | ||
| 964 | EC_MKBP_VALID_MIN_POST_SCAN_DELAY = 1 << 3, | ||
| 965 | EC_MKBP_VALID_OUTPUT_SETTLE = 1 << 4, | ||
| 966 | EC_MKBP_VALID_DEBOUNCE_DOWN = 1 << 5, | ||
| 967 | EC_MKBP_VALID_DEBOUNCE_UP = 1 << 6, | ||
| 968 | EC_MKBP_VALID_FIFO_MAX_DEPTH = 1 << 7, | ||
| 969 | }; | ||
| 970 | |||
| 971 | /* Configuration for our key scanning algorithm */ | ||
| 972 | struct ec_mkbp_config { | ||
| 973 | uint32_t valid_mask; /* valid fields */ | ||
| 974 | uint8_t flags; /* some flags (enum mkbp_config_flags) */ | ||
| 975 | uint8_t valid_flags; /* which flags are valid */ | ||
| 976 | uint16_t scan_period_us; /* period between start of scans */ | ||
| 977 | /* revert to interrupt mode after no activity for this long */ | ||
| 978 | uint32_t poll_timeout_us; | ||
| 979 | /* | ||
| 980 | * minimum post-scan relax time. Once we finish a scan we check | ||
| 981 | * the time until we are due to start the next one. If this time is | ||
| 982 | * shorter this field, we use this instead. | ||
| 983 | */ | ||
| 984 | uint16_t min_post_scan_delay_us; | ||
| 985 | /* delay between setting up output and waiting for it to settle */ | ||
| 986 | uint16_t output_settle_us; | ||
| 987 | uint16_t debounce_down_us; /* time for debounce on key down */ | ||
| 988 | uint16_t debounce_up_us; /* time for debounce on key up */ | ||
| 989 | /* maximum depth to allow for fifo (0 = no keyscan output) */ | ||
| 990 | uint8_t fifo_max_depth; | ||
| 991 | } __packed; | ||
| 992 | |||
| 993 | struct ec_params_mkbp_set_config { | ||
| 994 | struct ec_mkbp_config config; | ||
| 995 | } __packed; | ||
| 996 | |||
| 997 | struct ec_response_mkbp_get_config { | ||
| 998 | struct ec_mkbp_config config; | ||
| 999 | } __packed; | ||
| 1000 | |||
| 1001 | /* Run the key scan emulation */ | ||
| 1002 | #define EC_CMD_KEYSCAN_SEQ_CTRL 0x66 | ||
| 1003 | |||
| 1004 | enum ec_keyscan_seq_cmd { | ||
| 1005 | EC_KEYSCAN_SEQ_STATUS = 0, /* Get status information */ | ||
| 1006 | EC_KEYSCAN_SEQ_CLEAR = 1, /* Clear sequence */ | ||
| 1007 | EC_KEYSCAN_SEQ_ADD = 2, /* Add item to sequence */ | ||
| 1008 | EC_KEYSCAN_SEQ_START = 3, /* Start running sequence */ | ||
| 1009 | EC_KEYSCAN_SEQ_COLLECT = 4, /* Collect sequence summary data */ | ||
| 1010 | }; | ||
| 1011 | |||
| 1012 | enum ec_collect_flags { | ||
| 1013 | /* | ||
| 1014 | * Indicates this scan was processed by the EC. Due to timing, some | ||
| 1015 | * scans may be skipped. | ||
| 1016 | */ | ||
| 1017 | EC_KEYSCAN_SEQ_FLAG_DONE = 1 << 0, | ||
| 1018 | }; | ||
| 1019 | |||
| 1020 | struct ec_collect_item { | ||
| 1021 | uint8_t flags; /* some flags (enum ec_collect_flags) */ | ||
| 1022 | }; | ||
| 1023 | |||
| 1024 | struct ec_params_keyscan_seq_ctrl { | ||
| 1025 | uint8_t cmd; /* Command to send (enum ec_keyscan_seq_cmd) */ | ||
| 1026 | union { | ||
| 1027 | struct { | ||
| 1028 | uint8_t active; /* still active */ | ||
| 1029 | uint8_t num_items; /* number of items */ | ||
| 1030 | /* Current item being presented */ | ||
| 1031 | uint8_t cur_item; | ||
| 1032 | } status; | ||
| 1033 | struct { | ||
| 1034 | /* | ||
| 1035 | * Absolute time for this scan, measured from the | ||
| 1036 | * start of the sequence. | ||
| 1037 | */ | ||
| 1038 | uint32_t time_us; | ||
| 1039 | uint8_t scan[0]; /* keyscan data */ | ||
| 1040 | } add; | ||
| 1041 | struct { | ||
| 1042 | uint8_t start_item; /* First item to return */ | ||
| 1043 | uint8_t num_items; /* Number of items to return */ | ||
| 1044 | } collect; | ||
| 1045 | }; | ||
| 1046 | } __packed; | ||
| 1047 | |||
| 1048 | struct ec_result_keyscan_seq_ctrl { | ||
| 1049 | union { | ||
| 1050 | struct { | ||
| 1051 | uint8_t num_items; /* Number of items */ | ||
| 1052 | /* Data for each item */ | ||
| 1053 | struct ec_collect_item item[0]; | ||
| 1054 | } collect; | ||
| 1055 | }; | ||
| 1056 | } __packed; | ||
| 1057 | |||
| 1058 | /*****************************************************************************/ | ||
| 1059 | /* Temperature sensor commands */ | ||
| 1060 | |||
| 1061 | /* Read temperature sensor info */ | ||
| 1062 | #define EC_CMD_TEMP_SENSOR_GET_INFO 0x70 | ||
| 1063 | |||
| 1064 | struct ec_params_temp_sensor_get_info { | ||
| 1065 | uint8_t id; | ||
| 1066 | } __packed; | ||
| 1067 | |||
| 1068 | struct ec_response_temp_sensor_get_info { | ||
| 1069 | char sensor_name[32]; | ||
| 1070 | uint8_t sensor_type; | ||
| 1071 | } __packed; | ||
| 1072 | |||
| 1073 | /*****************************************************************************/ | ||
| 1074 | |||
| 1075 | /* | ||
| 1076 | * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI | ||
| 1077 | * commands accidentally sent to the wrong interface. See the ACPI section | ||
| 1078 | * below. | ||
| 1079 | */ | ||
| 1080 | |||
| 1081 | /*****************************************************************************/ | ||
| 1082 | /* Host event commands */ | ||
| 1083 | |||
| 1084 | /* | ||
| 1085 | * Host event mask params and response structures, shared by all of the host | ||
| 1086 | * event commands below. | ||
| 1087 | */ | ||
| 1088 | struct ec_params_host_event_mask { | ||
| 1089 | uint32_t mask; | ||
| 1090 | } __packed; | ||
| 1091 | |||
| 1092 | struct ec_response_host_event_mask { | ||
| 1093 | uint32_t mask; | ||
| 1094 | } __packed; | ||
| 1095 | |||
| 1096 | /* These all use ec_response_host_event_mask */ | ||
| 1097 | #define EC_CMD_HOST_EVENT_GET_B 0x87 | ||
| 1098 | #define EC_CMD_HOST_EVENT_GET_SMI_MASK 0x88 | ||
| 1099 | #define EC_CMD_HOST_EVENT_GET_SCI_MASK 0x89 | ||
| 1100 | #define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d | ||
| 1101 | |||
| 1102 | /* These all use ec_params_host_event_mask */ | ||
| 1103 | #define EC_CMD_HOST_EVENT_SET_SMI_MASK 0x8a | ||
| 1104 | #define EC_CMD_HOST_EVENT_SET_SCI_MASK 0x8b | ||
| 1105 | #define EC_CMD_HOST_EVENT_CLEAR 0x8c | ||
| 1106 | #define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e | ||
| 1107 | #define EC_CMD_HOST_EVENT_CLEAR_B 0x8f | ||
| 1108 | |||
| 1109 | /*****************************************************************************/ | ||
| 1110 | /* Switch commands */ | ||
| 1111 | |||
| 1112 | /* Enable/disable LCD backlight */ | ||
| 1113 | #define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90 | ||
| 1114 | |||
| 1115 | struct ec_params_switch_enable_backlight { | ||
| 1116 | uint8_t enabled; | ||
| 1117 | } __packed; | ||
| 1118 | |||
| 1119 | /* Enable/disable WLAN/Bluetooth */ | ||
| 1120 | #define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91 | ||
| 1121 | |||
| 1122 | struct ec_params_switch_enable_wireless { | ||
| 1123 | uint8_t enabled; | ||
| 1124 | } __packed; | ||
| 1125 | |||
| 1126 | /*****************************************************************************/ | ||
| 1127 | /* GPIO commands. Only available on EC if write protect has been disabled. */ | ||
| 1128 | |||
| 1129 | /* Set GPIO output value */ | ||
| 1130 | #define EC_CMD_GPIO_SET 0x92 | ||
| 1131 | |||
| 1132 | struct ec_params_gpio_set { | ||
| 1133 | char name[32]; | ||
| 1134 | uint8_t val; | ||
| 1135 | } __packed; | ||
| 1136 | |||
| 1137 | /* Get GPIO value */ | ||
| 1138 | #define EC_CMD_GPIO_GET 0x93 | ||
| 1139 | |||
| 1140 | struct ec_params_gpio_get { | ||
| 1141 | char name[32]; | ||
| 1142 | } __packed; | ||
| 1143 | struct ec_response_gpio_get { | ||
| 1144 | uint8_t val; | ||
| 1145 | } __packed; | ||
| 1146 | |||
| 1147 | /*****************************************************************************/ | ||
| 1148 | /* I2C commands. Only available when flash write protect is unlocked. */ | ||
| 1149 | |||
| 1150 | /* Read I2C bus */ | ||
| 1151 | #define EC_CMD_I2C_READ 0x94 | ||
| 1152 | |||
| 1153 | struct ec_params_i2c_read { | ||
| 1154 | uint16_t addr; | ||
| 1155 | uint8_t read_size; /* Either 8 or 16. */ | ||
| 1156 | uint8_t port; | ||
| 1157 | uint8_t offset; | ||
| 1158 | } __packed; | ||
| 1159 | struct ec_response_i2c_read { | ||
| 1160 | uint16_t data; | ||
| 1161 | } __packed; | ||
| 1162 | |||
| 1163 | /* Write I2C bus */ | ||
| 1164 | #define EC_CMD_I2C_WRITE 0x95 | ||
| 1165 | |||
| 1166 | struct ec_params_i2c_write { | ||
| 1167 | uint16_t data; | ||
| 1168 | uint16_t addr; | ||
| 1169 | uint8_t write_size; /* Either 8 or 16. */ | ||
| 1170 | uint8_t port; | ||
| 1171 | uint8_t offset; | ||
| 1172 | } __packed; | ||
| 1173 | |||
| 1174 | /*****************************************************************************/ | ||
| 1175 | /* Charge state commands. Only available when flash write protect unlocked. */ | ||
| 1176 | |||
| 1177 | /* Force charge state machine to stop in idle mode */ | ||
| 1178 | #define EC_CMD_CHARGE_FORCE_IDLE 0x96 | ||
| 1179 | |||
| 1180 | struct ec_params_force_idle { | ||
| 1181 | uint8_t enabled; | ||
| 1182 | } __packed; | ||
| 1183 | |||
| 1184 | /*****************************************************************************/ | ||
| 1185 | /* Console commands. Only available when flash write protect is unlocked. */ | ||
| 1186 | |||
| 1187 | /* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */ | ||
| 1188 | #define EC_CMD_CONSOLE_SNAPSHOT 0x97 | ||
| 1189 | |||
| 1190 | /* | ||
| 1191 | * Read next chunk of data from saved snapshot. | ||
| 1192 | * | ||
| 1193 | * Response is null-terminated string. Empty string, if there is no more | ||
| 1194 | * remaining output. | ||
| 1195 | */ | ||
| 1196 | #define EC_CMD_CONSOLE_READ 0x98 | ||
| 1197 | |||
| 1198 | /*****************************************************************************/ | ||
| 1199 | |||
| 1200 | /* | ||
| 1201 | * Cut off battery power output if the battery supports. | ||
| 1202 | * | ||
| 1203 | * For unsupported battery, just don't implement this command and lets EC | ||
| 1204 | * return EC_RES_INVALID_COMMAND. | ||
| 1205 | */ | ||
| 1206 | #define EC_CMD_BATTERY_CUT_OFF 0x99 | ||
| 1207 | |||
| 1208 | /*****************************************************************************/ | ||
| 1209 | /* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */ | ||
| 1210 | |||
| 1211 | /* | ||
| 1212 | * Dump charge state machine context. | ||
| 1213 | * | ||
| 1214 | * Response is a binary dump of charge state machine context. | ||
| 1215 | */ | ||
| 1216 | #define EC_CMD_CHARGE_DUMP 0xa0 | ||
| 1217 | |||
| 1218 | /* | ||
| 1219 | * Set maximum battery charging current. | ||
| 1220 | */ | ||
| 1221 | #define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1 | ||
| 1222 | |||
| 1223 | struct ec_params_current_limit { | ||
| 1224 | uint32_t limit; | ||
| 1225 | } __packed; | ||
| 1226 | |||
| 1227 | /*****************************************************************************/ | ||
| 1228 | /* System commands */ | ||
| 1229 | |||
| 1230 | /* | ||
| 1231 | * TODO: this is a confusing name, since it doesn't necessarily reboot the EC. | ||
| 1232 | * Rename to "set image" or something similar. | ||
| 1233 | */ | ||
| 1234 | #define EC_CMD_REBOOT_EC 0xd2 | ||
| 1235 | |||
| 1236 | /* Command */ | ||
| 1237 | enum ec_reboot_cmd { | ||
| 1238 | EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */ | ||
| 1239 | EC_REBOOT_JUMP_RO = 1, /* Jump to RO without rebooting */ | ||
| 1240 | EC_REBOOT_JUMP_RW = 2, /* Jump to RW without rebooting */ | ||
| 1241 | /* (command 3 was jump to RW-B) */ | ||
| 1242 | EC_REBOOT_COLD = 4, /* Cold-reboot */ | ||
| 1243 | EC_REBOOT_DISABLE_JUMP = 5, /* Disable jump until next reboot */ | ||
| 1244 | EC_REBOOT_HIBERNATE = 6 /* Hibernate EC */ | ||
| 1245 | }; | ||
| 1246 | |||
| 1247 | /* Flags for ec_params_reboot_ec.reboot_flags */ | ||
| 1248 | #define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */ | ||
| 1249 | #define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1) /* Reboot after AP shutdown */ | ||
| 1250 | |||
| 1251 | struct ec_params_reboot_ec { | ||
| 1252 | uint8_t cmd; /* enum ec_reboot_cmd */ | ||
| 1253 | uint8_t flags; /* See EC_REBOOT_FLAG_* */ | ||
| 1254 | } __packed; | ||
| 1255 | |||
| 1256 | /* | ||
| 1257 | * Get information on last EC panic. | ||
| 1258 | * | ||
| 1259 | * Returns variable-length platform-dependent panic information. See panic.h | ||
| 1260 | * for details. | ||
| 1261 | */ | ||
| 1262 | #define EC_CMD_GET_PANIC_INFO 0xd3 | ||
| 1263 | |||
| 1264 | /*****************************************************************************/ | ||
| 1265 | /* | ||
| 1266 | * ACPI commands | ||
| 1267 | * | ||
| 1268 | * These are valid ONLY on the ACPI command/data port. | ||
| 1269 | */ | ||
| 1270 | |||
| 1271 | /* | ||
| 1272 | * ACPI Read Embedded Controller | ||
| 1273 | * | ||
| 1274 | * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). | ||
| 1275 | * | ||
| 1276 | * Use the following sequence: | ||
| 1277 | * | ||
| 1278 | * - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD | ||
| 1279 | * - Wait for EC_LPC_CMDR_PENDING bit to clear | ||
| 1280 | * - Write address to EC_LPC_ADDR_ACPI_DATA | ||
| 1281 | * - Wait for EC_LPC_CMDR_DATA bit to set | ||
| 1282 | * - Read value from EC_LPC_ADDR_ACPI_DATA | ||
| 1283 | */ | ||
| 1284 | #define EC_CMD_ACPI_READ 0x80 | ||
| 1285 | |||
| 1286 | /* | ||
| 1287 | * ACPI Write Embedded Controller | ||
| 1288 | * | ||
| 1289 | * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). | ||
| 1290 | * | ||
| 1291 | * Use the following sequence: | ||
| 1292 | * | ||
| 1293 | * - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD | ||
| 1294 | * - Wait for EC_LPC_CMDR_PENDING bit to clear | ||
| 1295 | * - Write address to EC_LPC_ADDR_ACPI_DATA | ||
| 1296 | * - Wait for EC_LPC_CMDR_PENDING bit to clear | ||
| 1297 | * - Write value to EC_LPC_ADDR_ACPI_DATA | ||
| 1298 | */ | ||
| 1299 | #define EC_CMD_ACPI_WRITE 0x81 | ||
| 1300 | |||
| 1301 | /* | ||
| 1302 | * ACPI Query Embedded Controller | ||
| 1303 | * | ||
| 1304 | * This clears the lowest-order bit in the currently pending host events, and | ||
| 1305 | * sets the result code to the 1-based index of the bit (event 0x00000001 = 1, | ||
| 1306 | * event 0x80000000 = 32), or 0 if no event was pending. | ||
| 1307 | */ | ||
| 1308 | #define EC_CMD_ACPI_QUERY_EVENT 0x84 | ||
| 1309 | |||
| 1310 | /* Valid addresses in ACPI memory space, for read/write commands */ | ||
| 1311 | /* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */ | ||
| 1312 | #define EC_ACPI_MEM_VERSION 0x00 | ||
| 1313 | /* | ||
| 1314 | * Test location; writing value here updates test compliment byte to (0xff - | ||
| 1315 | * value). | ||
| 1316 | */ | ||
| 1317 | #define EC_ACPI_MEM_TEST 0x01 | ||
| 1318 | /* Test compliment; writes here are ignored. */ | ||
| 1319 | #define EC_ACPI_MEM_TEST_COMPLIMENT 0x02 | ||
| 1320 | /* Keyboard backlight brightness percent (0 - 100) */ | ||
| 1321 | #define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03 | ||
| 1322 | |||
| 1323 | /* Current version of ACPI memory address space */ | ||
| 1324 | #define EC_ACPI_MEM_VERSION_CURRENT 1 | ||
| 1325 | |||
| 1326 | |||
| 1327 | /*****************************************************************************/ | ||
| 1328 | /* | ||
| 1329 | * Special commands | ||
| 1330 | * | ||
| 1331 | * These do not follow the normal rules for commands. See each command for | ||
| 1332 | * details. | ||
| 1333 | */ | ||
| 1334 | |||
| 1335 | /* | ||
| 1336 | * Reboot NOW | ||
| 1337 | * | ||
| 1338 | * This command will work even when the EC LPC interface is busy, because the | ||
| 1339 | * reboot command is processed at interrupt level. Note that when the EC | ||
| 1340 | * reboots, the host will reboot too, so there is no response to this command. | ||
| 1341 | * | ||
| 1342 | * Use EC_CMD_REBOOT_EC to reboot the EC more politely. | ||
| 1343 | */ | ||
| 1344 | #define EC_CMD_REBOOT 0xd1 /* Think "die" */ | ||
| 1345 | |||
| 1346 | /* | ||
| 1347 | * Resend last response (not supported on LPC). | ||
| 1348 | * | ||
| 1349 | * Returns EC_RES_UNAVAILABLE if there is no response available - for example, | ||
| 1350 | * there was no previous command, or the previous command's response was too | ||
| 1351 | * big to save. | ||
| 1352 | */ | ||
| 1353 | #define EC_CMD_RESEND_RESPONSE 0xdb | ||
| 1354 | |||
| 1355 | /* | ||
| 1356 | * This header byte on a command indicate version 0. Any header byte less | ||
| 1357 | * than this means that we are talking to an old EC which doesn't support | ||
| 1358 | * versioning. In that case, we assume version 0. | ||
| 1359 | * | ||
| 1360 | * Header bytes greater than this indicate a later version. For example, | ||
| 1361 | * EC_CMD_VERSION0 + 1 means we are using version 1. | ||
| 1362 | * | ||
| 1363 | * The old EC interface must not use commands 0dc or higher. | ||
| 1364 | */ | ||
| 1365 | #define EC_CMD_VERSION0 0xdc | ||
| 1366 | |||
| 1367 | #endif /* !__ACPI__ */ | ||
| 1368 | |||
| 1369 | #endif /* __CROS_EC_COMMANDS_H */ | ||
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index ecddc5173c7c..8f21daf62fb5 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h | |||
| @@ -1,9 +1,10 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * TI Palmas | 2 | * TI Palmas |
| 3 | * | 3 | * |
| 4 | * Copyright 2011 Texas Instruments Inc. | 4 | * Copyright 2011-2013 Texas Instruments Inc. |
| 5 | * | 5 | * |
| 6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | 6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> |
| 7 | * Author: Ian Lartey <ian@slimlogic.co.uk> | ||
| 7 | * | 8 | * |
| 8 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
| 9 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
| @@ -22,6 +23,15 @@ | |||
| 22 | 23 | ||
| 23 | #define PALMAS_NUM_CLIENTS 3 | 24 | #define PALMAS_NUM_CLIENTS 3 |
| 24 | 25 | ||
| 26 | /* The ID_REVISION NUMBERS */ | ||
| 27 | #define PALMAS_CHIP_OLD_ID 0x0000 | ||
| 28 | #define PALMAS_CHIP_ID 0xC035 | ||
| 29 | #define PALMAS_CHIP_CHARGER_ID 0xC036 | ||
| 30 | |||
| 31 | #define is_palmas(a) (((a) == PALMAS_CHIP_OLD_ID) || \ | ||
| 32 | ((a) == PALMAS_CHIP_ID)) | ||
| 33 | #define is_palmas_charger(a) ((a) == PALMAS_CHIP_CHARGER_ID) | ||
| 34 | |||
| 25 | struct palmas_pmic; | 35 | struct palmas_pmic; |
| 26 | struct palmas_gpadc; | 36 | struct palmas_gpadc; |
| 27 | struct palmas_resource; | 37 | struct palmas_resource; |
diff --git a/include/linux/mfd/retu.h b/include/linux/mfd/retu.h index 1e2715d5b836..65471c4a3926 100644 --- a/include/linux/mfd/retu.h +++ b/include/linux/mfd/retu.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Retu MFD driver interface | 2 | * Retu/Tahvo MFD driver interface |
| 3 | * | 3 | * |
| 4 | * This file is subject to the terms and conditions of the GNU General | 4 | * This file is subject to the terms and conditions of the GNU General |
| 5 | * Public License. See the file "COPYING" in the main directory of this | 5 | * Public License. See the file "COPYING" in the main directory of this |
| @@ -19,4 +19,10 @@ int retu_write(struct retu_dev *, u8, u16); | |||
| 19 | #define RETU_REG_CC1 0x0d /* Common control register 1 */ | 19 | #define RETU_REG_CC1 0x0d /* Common control register 1 */ |
| 20 | #define RETU_REG_STATUS 0x16 /* Status register */ | 20 | #define RETU_REG_STATUS 0x16 /* Status register */ |
| 21 | 21 | ||
| 22 | /* Interrupt sources */ | ||
| 23 | #define TAHVO_INT_VBUS 0 /* VBUS state */ | ||
| 24 | |||
| 25 | /* Interrupt status */ | ||
| 26 | #define TAHVO_STAT_VBUS (1 << TAHVO_INT_VBUS) | ||
| 27 | |||
| 22 | #endif /* __LINUX_MFD_RETU_H */ | 28 | #endif /* __LINUX_MFD_RETU_H */ |
diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 26ea7f1b7caf..86bc635f8385 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h | |||
| @@ -500,6 +500,8 @@ | |||
| 500 | #define BPP_POWER_15_PERCENT_ON 0x08 | 500 | #define BPP_POWER_15_PERCENT_ON 0x08 |
| 501 | #define BPP_POWER_ON 0x00 | 501 | #define BPP_POWER_ON 0x00 |
| 502 | #define BPP_POWER_MASK 0x0F | 502 | #define BPP_POWER_MASK 0x0F |
| 503 | #define SD_VCC_PARTIAL_POWER_ON 0x02 | ||
| 504 | #define SD_VCC_POWER_ON 0x00 | ||
| 503 | 505 | ||
| 504 | /* PWR_GATE_CTRL */ | 506 | /* PWR_GATE_CTRL */ |
| 505 | #define PWR_GATE_EN 0x01 | 507 | #define PWR_GATE_EN 0x01 |
| @@ -689,6 +691,40 @@ | |||
| 689 | #define IMAGE_FLAG_ADDR0 0xCE80 | 691 | #define IMAGE_FLAG_ADDR0 0xCE80 |
| 690 | #define IMAGE_FLAG_ADDR1 0xCE81 | 692 | #define IMAGE_FLAG_ADDR1 0xCE81 |
| 691 | 693 | ||
| 694 | /* Phy register */ | ||
| 695 | #define PHY_PCR 0x00 | ||
| 696 | #define PHY_RCR0 0x01 | ||
| 697 | #define PHY_RCR1 0x02 | ||
| 698 | #define PHY_RCR2 0x03 | ||
| 699 | #define PHY_RTCR 0x04 | ||
| 700 | #define PHY_RDR 0x05 | ||
| 701 | #define PHY_TCR0 0x06 | ||
| 702 | #define PHY_TCR1 0x07 | ||
| 703 | #define PHY_TUNE 0x08 | ||
| 704 | #define PHY_IMR 0x09 | ||
| 705 | #define PHY_BPCR 0x0A | ||
| 706 | #define PHY_BIST 0x0B | ||
| 707 | #define PHY_RAW_L 0x0C | ||
| 708 | #define PHY_RAW_H 0x0D | ||
| 709 | #define PHY_RAW_DATA 0x0E | ||
| 710 | #define PHY_HOST_CLK_CTRL 0x0F | ||
| 711 | #define PHY_DMR 0x10 | ||
| 712 | #define PHY_BACR 0x11 | ||
| 713 | #define PHY_IER 0x12 | ||
| 714 | #define PHY_BCSR 0x13 | ||
| 715 | #define PHY_BPR 0x14 | ||
| 716 | #define PHY_BPNR2 0x15 | ||
| 717 | #define PHY_BPNR 0x16 | ||
| 718 | #define PHY_BRNR2 0x17 | ||
| 719 | #define PHY_BENR 0x18 | ||
| 720 | #define PHY_REG_REV 0x19 | ||
| 721 | #define PHY_FLD0 0x1A | ||
| 722 | #define PHY_FLD1 0x1B | ||
| 723 | #define PHY_FLD2 0x1C | ||
| 724 | #define PHY_FLD3 0x1D | ||
| 725 | #define PHY_FLD4 0x1E | ||
| 726 | #define PHY_DUM_REG 0x1F | ||
| 727 | |||
| 692 | #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) | 728 | #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) |
| 693 | 729 | ||
| 694 | struct rtsx_pcr; | 730 | struct rtsx_pcr; |
diff --git a/include/linux/mfd/si476x-core.h b/include/linux/mfd/si476x-core.h new file mode 100644 index 000000000000..ba89b94e4a56 --- /dev/null +++ b/include/linux/mfd/si476x-core.h | |||
| @@ -0,0 +1,533 @@ | |||
| 1 | /* | ||
| 2 | * include/media/si476x-core.h -- Common definitions for si476x core | ||
| 3 | * device | ||
| 4 | * | ||
| 5 | * Copyright (C) 2012 Innovative Converged Devices(ICD) | ||
| 6 | * Copyright (C) 2013 Andrey Smirnov | ||
| 7 | * | ||
| 8 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; version 2 of the License. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, but | ||
| 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 17 | * General Public License for more details. | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef SI476X_CORE_H | ||
| 22 | #define SI476X_CORE_H | ||
| 23 | |||
| 24 | #include <linux/kfifo.h> | ||
| 25 | #include <linux/atomic.h> | ||
| 26 | #include <linux/i2c.h> | ||
| 27 | #include <linux/regmap.h> | ||
| 28 | #include <linux/mutex.h> | ||
| 29 | #include <linux/mfd/core.h> | ||
| 30 | #include <linux/videodev2.h> | ||
| 31 | #include <linux/regulator/consumer.h> | ||
| 32 | |||
| 33 | #include <linux/mfd/si476x-platform.h> | ||
| 34 | #include <linux/mfd/si476x-reports.h> | ||
| 35 | |||
| 36 | /* Command Timeouts */ | ||
| 37 | #define SI476X_DEFAULT_TIMEOUT 100000 | ||
| 38 | #define SI476X_TIMEOUT_TUNE 700000 | ||
| 39 | #define SI476X_TIMEOUT_POWER_UP 330000 | ||
| 40 | #define SI476X_STATUS_POLL_US 0 | ||
| 41 | |||
| 42 | /* -------------------- si476x-i2c.c ----------------------- */ | ||
| 43 | |||
| 44 | enum si476x_freq_supported_chips { | ||
| 45 | SI476X_CHIP_SI4761 = 1, | ||
| 46 | SI476X_CHIP_SI4764, | ||
| 47 | SI476X_CHIP_SI4768, | ||
| 48 | }; | ||
| 49 | |||
| 50 | enum si476x_part_revisions { | ||
| 51 | SI476X_REVISION_A10 = 0, | ||
| 52 | SI476X_REVISION_A20 = 1, | ||
| 53 | SI476X_REVISION_A30 = 2, | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum si476x_mfd_cells { | ||
| 57 | SI476X_RADIO_CELL = 0, | ||
| 58 | SI476X_CODEC_CELL, | ||
| 59 | SI476X_MFD_CELLS, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /** | ||
| 63 | * enum si476x_power_state - possible power state of the si476x | ||
| 64 | * device. | ||
| 65 | * | ||
| 66 | * @SI476X_POWER_DOWN: In this state all regulators are turned off | ||
| 67 | * and the reset line is pulled low. The device is completely | ||
| 68 | * inactive. | ||
| 69 | * @SI476X_POWER_UP_FULL: In this state all the power regualtors are | ||
| 70 | * turned on, reset line pulled high, IRQ line is enabled(polling is | ||
| 71 | * active for polling use scenario) and device is turned on with | ||
| 72 | * POWER_UP command. The device is ready to be used. | ||
| 73 | * @SI476X_POWER_INCONSISTENT: This state indicates that previous | ||
| 74 | * power down was inconsistent, meaning some of the regulators were | ||
| 75 | * not turned down and thus use of the device, without power-cycling | ||
| 76 | * is impossible. | ||
| 77 | */ | ||
| 78 | enum si476x_power_state { | ||
| 79 | SI476X_POWER_DOWN = 0, | ||
| 80 | SI476X_POWER_UP_FULL = 1, | ||
| 81 | SI476X_POWER_INCONSISTENT = 2, | ||
| 82 | }; | ||
| 83 | |||
| 84 | /** | ||
| 85 | * struct si476x_core - internal data structure representing the | ||
| 86 | * underlying "core" device which all the MFD cell-devices use. | ||
| 87 | * | ||
| 88 | * @client: Actual I2C client used to transfer commands to the chip. | ||
| 89 | * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) | ||
| 90 | * @cells: MFD cell devices created by this driver. | ||
| 91 | * @cmd_lock: Mutex used to serialize all the requests to the core | ||
| 92 | * device. This filed should not be used directly. Instead | ||
| 93 | * si476x_core_lock()/si476x_core_unlock() should be used to get | ||
| 94 | * exclusive access to the "core" device. | ||
| 95 | * @users: Active users counter(Used by the radio cell) | ||
| 96 | * @rds_read_queue: Wait queue used to wait for RDS data. | ||
| 97 | * @rds_fifo: FIFO in which all the RDS data received from the chip is | ||
| 98 | * placed. | ||
| 99 | * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. | ||
| 100 | * @rds_drainer_is_working: Flag used for launching only one instance | ||
| 101 | * of the @rds_fifo_drainer. | ||
| 102 | * @rds_drainer_status_lock: Lock used to guard access to the | ||
| 103 | * @rds_drainer_is_working variable. | ||
| 104 | * @command: Wait queue for wainting on the command comapletion. | ||
| 105 | * @cts: Clear To Send flag set upon receiving first status with CTS | ||
| 106 | * set. | ||
| 107 | * @tuning: Wait queue used for wainting for tune/seek comand | ||
| 108 | * completion. | ||
| 109 | * @stc: Similar to @cts, but for the STC bit of the status value. | ||
| 110 | * @power_up_parameters: Parameters used as argument for POWER_UP | ||
| 111 | * command when the device is started. | ||
| 112 | * @state: Current power state of the device. | ||
| 113 | * @supplues: Structure containing handles to all power supplies used | ||
| 114 | * by the device (NULL ones are ignored). | ||
| 115 | * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. | ||
| 116 | * @pinmux: Chip's configurable pins configuration. | ||
| 117 | * @diversity_mode: Chips role when functioning in diversity mode. | ||
| 118 | * @status_monitor: Polling worker used in polling use case scenarion | ||
| 119 | * (when IRQ is not avalible). | ||
| 120 | * @revision: Chip's running firmware revision number(Used for correct | ||
| 121 | * command set support). | ||
| 122 | */ | ||
| 123 | |||
| 124 | struct si476x_core { | ||
| 125 | struct i2c_client *client; | ||
| 126 | struct regmap *regmap; | ||
| 127 | int chip_id; | ||
| 128 | struct mfd_cell cells[SI476X_MFD_CELLS]; | ||
| 129 | |||
| 130 | struct mutex cmd_lock; /* for serializing fm radio operations */ | ||
| 131 | atomic_t users; | ||
| 132 | |||
| 133 | wait_queue_head_t rds_read_queue; | ||
| 134 | struct kfifo rds_fifo; | ||
| 135 | struct work_struct rds_fifo_drainer; | ||
| 136 | bool rds_drainer_is_working; | ||
| 137 | struct mutex rds_drainer_status_lock; | ||
| 138 | |||
| 139 | wait_queue_head_t command; | ||
| 140 | atomic_t cts; | ||
| 141 | |||
| 142 | wait_queue_head_t tuning; | ||
| 143 | atomic_t stc; | ||
| 144 | |||
| 145 | struct si476x_power_up_args power_up_parameters; | ||
| 146 | |||
| 147 | enum si476x_power_state power_state; | ||
| 148 | |||
| 149 | struct regulator_bulk_data supplies[4]; | ||
| 150 | |||
| 151 | int gpio_reset; | ||
| 152 | |||
| 153 | struct si476x_pinmux pinmux; | ||
| 154 | enum si476x_phase_diversity_mode diversity_mode; | ||
| 155 | |||
| 156 | atomic_t is_alive; | ||
| 157 | |||
| 158 | struct delayed_work status_monitor; | ||
| 159 | #define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ | ||
| 160 | struct si476x_core, \ | ||
| 161 | status_monitor) | ||
| 162 | |||
| 163 | int revision; | ||
| 164 | |||
| 165 | int rds_fifo_depth; | ||
| 166 | }; | ||
| 167 | |||
| 168 | static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) | ||
| 169 | { | ||
| 170 | struct i2c_client *client = to_i2c_client(dev->parent); | ||
| 171 | return i2c_get_clientdata(client); | ||
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | /** | ||
| 176 | * si476x_core_lock() - lock the core device to get an exclusive access | ||
| 177 | * to it. | ||
| 178 | */ | ||
| 179 | static inline void si476x_core_lock(struct si476x_core *core) | ||
| 180 | { | ||
| 181 | mutex_lock(&core->cmd_lock); | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * si476x_core_unlock() - unlock the core device to relinquish an | ||
| 186 | * exclusive access to it. | ||
| 187 | */ | ||
| 188 | static inline void si476x_core_unlock(struct si476x_core *core) | ||
| 189 | { | ||
| 190 | mutex_unlock(&core->cmd_lock); | ||
| 191 | } | ||
| 192 | |||
| 193 | /* *_TUNE_FREQ family of commands accept frequency in multiples of | ||
| 194 | 10kHz */ | ||
| 195 | static inline u16 hz_to_si476x(struct si476x_core *core, int freq) | ||
| 196 | { | ||
| 197 | u16 result; | ||
| 198 | |||
| 199 | switch (core->power_up_parameters.func) { | ||
| 200 | default: | ||
| 201 | case SI476X_FUNC_FM_RECEIVER: | ||
| 202 | result = freq / 10000; | ||
| 203 | break; | ||
| 204 | case SI476X_FUNC_AM_RECEIVER: | ||
| 205 | result = freq / 1000; | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | |||
| 209 | return result; | ||
| 210 | } | ||
| 211 | |||
| 212 | static inline int si476x_to_hz(struct si476x_core *core, u16 freq) | ||
| 213 | { | ||
| 214 | int result; | ||
| 215 | |||
| 216 | switch (core->power_up_parameters.func) { | ||
| 217 | default: | ||
| 218 | case SI476X_FUNC_FM_RECEIVER: | ||
| 219 | result = freq * 10000; | ||
| 220 | break; | ||
| 221 | case SI476X_FUNC_AM_RECEIVER: | ||
| 222 | result = freq * 1000; | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | |||
| 226 | return result; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem | ||
| 230 | * mesures frequency in 62.5 Hz units */ | ||
| 231 | |||
| 232 | static inline int hz_to_v4l2(int freq) | ||
| 233 | { | ||
| 234 | return (freq * 10) / 625; | ||
| 235 | } | ||
| 236 | |||
| 237 | static inline int v4l2_to_hz(int freq) | ||
| 238 | { | ||
| 239 | return (freq * 625) / 10; | ||
| 240 | } | ||
| 241 | |||
| 242 | static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) | ||
| 243 | { | ||
| 244 | return hz_to_si476x(core, v4l2_to_hz(freq)); | ||
| 245 | } | ||
| 246 | |||
| 247 | static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) | ||
| 248 | { | ||
| 249 | return hz_to_v4l2(si476x_to_hz(core, freq)); | ||
| 250 | } | ||
| 251 | |||
| 252 | |||
| 253 | |||
| 254 | /** | ||
| 255 | * struct si476x_func_info - structure containing result of the | ||
| 256 | * FUNC_INFO command. | ||
| 257 | * | ||
| 258 | * @firmware.major: Firmware major number. | ||
| 259 | * @firmware.minor[...]: Firmware minor numbers. | ||
| 260 | * @patch_id: | ||
| 261 | * @func: Mode tuner is working in. | ||
| 262 | */ | ||
| 263 | struct si476x_func_info { | ||
| 264 | struct { | ||
| 265 | u8 major, minor[2]; | ||
| 266 | } firmware; | ||
| 267 | u16 patch_id; | ||
| 268 | enum si476x_func func; | ||
| 269 | }; | ||
| 270 | |||
| 271 | /** | ||
| 272 | * struct si476x_power_down_args - structure used to pass parameters | ||
| 273 | * to POWER_DOWN command | ||
| 274 | * | ||
| 275 | * @xosc: true - Power down, but leav oscillator running. | ||
| 276 | * false - Full power down. | ||
| 277 | */ | ||
| 278 | struct si476x_power_down_args { | ||
| 279 | bool xosc; | ||
| 280 | }; | ||
| 281 | |||
| 282 | /** | ||
| 283 | * enum si476x_tunemode - enum representing possible tune modes for | ||
| 284 | * the chip. | ||
| 285 | * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new | ||
| 286 | * channel after tune, tune status is valid. | ||
| 287 | * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new | ||
| 288 | * channel after tune, tune status invalid. | ||
| 289 | * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if | ||
| 290 | * metric thresholds are not met. | ||
| 291 | * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the | ||
| 292 | * previous channel. | ||
| 293 | */ | ||
| 294 | enum si476x_tunemode { | ||
| 295 | SI476X_TM_VALIDATED_NORMAL_TUNE = 0, | ||
| 296 | SI476X_TM_INVALIDATED_FAST_TUNE = 1, | ||
| 297 | SI476X_TM_VALIDATED_AF_TUNE = 2, | ||
| 298 | SI476X_TM_VALIDATED_AF_CHECK = 3, | ||
| 299 | }; | ||
| 300 | |||
| 301 | /** | ||
| 302 | * enum si476x_smoothmetrics - enum containing the possible setting fo | ||
| 303 | * audio transitioning of the chip | ||
| 304 | * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this | ||
| 305 | * new channel | ||
| 306 | * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous | ||
| 307 | * channel values to the new values | ||
| 308 | */ | ||
| 309 | enum si476x_smoothmetrics { | ||
| 310 | SI476X_SM_INITIALIZE_AUDIO = 0, | ||
| 311 | SI476X_SM_TRANSITION_AUDIO = 1, | ||
| 312 | }; | ||
| 313 | |||
| 314 | /** | ||
| 315 | * struct si476x_rds_status_report - the structure representing the | ||
| 316 | * response to 'FM_RD_STATUS' command | ||
| 317 | * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) | ||
| 318 | * code has changed. | ||
| 319 | * @rdspiint: Program indentifiaction(PI) code has changed. | ||
| 320 | * @rdssyncint: RDS synchronization has changed. | ||
| 321 | * @rdsfifoint: RDS was received and the RDS FIFO has at least | ||
| 322 | * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. | ||
| 323 | * @tpptyvalid: TP flag and PTY code are valid falg. | ||
| 324 | * @pivalid: PI code is valid flag. | ||
| 325 | * @rdssync: RDS is currently synchronized. | ||
| 326 | * @rdsfifolost: On or more RDS groups have been lost/discarded flag. | ||
| 327 | * @tp: Current channel's TP flag. | ||
| 328 | * @pty: Current channel's PTY code. | ||
| 329 | * @pi: Current channel's PI code. | ||
| 330 | * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if | ||
| 331 | * empty). | ||
| 332 | */ | ||
| 333 | struct si476x_rds_status_report { | ||
| 334 | bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; | ||
| 335 | bool tpptyvalid, pivalid, rdssync, rdsfifolost; | ||
| 336 | bool tp; | ||
| 337 | |||
| 338 | u8 pty; | ||
| 339 | u16 pi; | ||
| 340 | |||
| 341 | u8 rdsfifoused; | ||
| 342 | u8 ble[4]; | ||
| 343 | |||
| 344 | struct v4l2_rds_data rds[4]; | ||
| 345 | }; | ||
| 346 | |||
| 347 | struct si476x_rsq_status_args { | ||
| 348 | bool primary; | ||
| 349 | bool rsqack; | ||
| 350 | bool attune; | ||
| 351 | bool cancel; | ||
| 352 | bool stcack; | ||
| 353 | }; | ||
| 354 | |||
| 355 | enum si476x_injside { | ||
| 356 | SI476X_INJSIDE_AUTO = 0, | ||
| 357 | SI476X_INJSIDE_LOW = 1, | ||
| 358 | SI476X_INJSIDE_HIGH = 2, | ||
| 359 | }; | ||
| 360 | |||
| 361 | struct si476x_tune_freq_args { | ||
| 362 | bool zifsr; | ||
| 363 | bool hd; | ||
| 364 | enum si476x_injside injside; | ||
| 365 | int freq; | ||
| 366 | enum si476x_tunemode tunemode; | ||
| 367 | enum si476x_smoothmetrics smoothmetrics; | ||
| 368 | int antcap; | ||
| 369 | }; | ||
| 370 | |||
| 371 | int si476x_core_stop(struct si476x_core *, bool); | ||
| 372 | int si476x_core_start(struct si476x_core *, bool); | ||
| 373 | int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); | ||
| 374 | bool si476x_core_has_am(struct si476x_core *); | ||
| 375 | bool si476x_core_has_diversity(struct si476x_core *); | ||
| 376 | bool si476x_core_is_a_secondary_tuner(struct si476x_core *); | ||
| 377 | bool si476x_core_is_a_primary_tuner(struct si476x_core *); | ||
| 378 | bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); | ||
| 379 | bool si476x_core_is_powered_up(struct si476x_core *core); | ||
| 380 | |||
| 381 | enum si476x_i2c_type { | ||
| 382 | SI476X_I2C_SEND, | ||
| 383 | SI476X_I2C_RECV | ||
| 384 | }; | ||
| 385 | |||
| 386 | int si476x_core_i2c_xfer(struct si476x_core *, | ||
| 387 | enum si476x_i2c_type, | ||
| 388 | char *, int); | ||
| 389 | |||
| 390 | |||
| 391 | /* -------------------- si476x-cmd.c ----------------------- */ | ||
| 392 | |||
| 393 | int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); | ||
| 394 | int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); | ||
| 395 | int si476x_core_cmd_get_property(struct si476x_core *, u16); | ||
| 396 | int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, | ||
| 397 | enum si476x_dclk_config, | ||
| 398 | enum si476x_dfs_config, | ||
| 399 | enum si476x_dout_config, | ||
| 400 | enum si476x_xout_config); | ||
| 401 | int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, | ||
| 402 | enum si476x_iqclk_config, | ||
| 403 | enum si476x_iqfs_config, | ||
| 404 | enum si476x_iout_config, | ||
| 405 | enum si476x_qout_config); | ||
| 406 | int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, | ||
| 407 | enum si476x_icin_config, | ||
| 408 | enum si476x_icip_config, | ||
| 409 | enum si476x_icon_config, | ||
| 410 | enum si476x_icop_config); | ||
| 411 | int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, | ||
| 412 | enum si476x_lrout_config); | ||
| 413 | int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, | ||
| 414 | enum si476x_a1_config); | ||
| 415 | int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); | ||
| 416 | int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); | ||
| 417 | int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, | ||
| 418 | struct si476x_rds_status_report *); | ||
| 419 | int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, | ||
| 420 | struct si476x_rds_blockcount_report *); | ||
| 421 | int si476x_core_cmd_fm_tune_freq(struct si476x_core *, | ||
| 422 | struct si476x_tune_freq_args *); | ||
| 423 | int si476x_core_cmd_am_tune_freq(struct si476x_core *, | ||
| 424 | struct si476x_tune_freq_args *); | ||
| 425 | int si476x_core_cmd_am_rsq_status(struct si476x_core *, | ||
| 426 | struct si476x_rsq_status_args *, | ||
| 427 | struct si476x_rsq_status_report *); | ||
| 428 | int si476x_core_cmd_fm_rsq_status(struct si476x_core *, | ||
| 429 | struct si476x_rsq_status_args *, | ||
| 430 | struct si476x_rsq_status_report *); | ||
| 431 | int si476x_core_cmd_power_up(struct si476x_core *, | ||
| 432 | struct si476x_power_up_args *); | ||
| 433 | int si476x_core_cmd_power_down(struct si476x_core *, | ||
| 434 | struct si476x_power_down_args *); | ||
| 435 | int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); | ||
| 436 | int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, | ||
| 437 | enum si476x_phase_diversity_mode); | ||
| 438 | |||
| 439 | int si476x_core_cmd_fm_acf_status(struct si476x_core *, | ||
| 440 | struct si476x_acf_status_report *); | ||
| 441 | int si476x_core_cmd_am_acf_status(struct si476x_core *, | ||
| 442 | struct si476x_acf_status_report *); | ||
| 443 | int si476x_core_cmd_agc_status(struct si476x_core *, | ||
| 444 | struct si476x_agc_status_report *); | ||
| 445 | |||
| 446 | enum si476x_power_grid_type { | ||
| 447 | SI476X_POWER_GRID_50HZ = 0, | ||
| 448 | SI476X_POWER_GRID_60HZ, | ||
| 449 | }; | ||
| 450 | |||
| 451 | /* Properties */ | ||
| 452 | |||
| 453 | enum si476x_interrupt_flags { | ||
| 454 | SI476X_STCIEN = (1 << 0), | ||
| 455 | SI476X_ACFIEN = (1 << 1), | ||
| 456 | SI476X_RDSIEN = (1 << 2), | ||
| 457 | SI476X_RSQIEN = (1 << 3), | ||
| 458 | |||
| 459 | SI476X_ERRIEN = (1 << 6), | ||
| 460 | SI476X_CTSIEN = (1 << 7), | ||
| 461 | |||
| 462 | SI476X_STCREP = (1 << 8), | ||
| 463 | SI476X_ACFREP = (1 << 9), | ||
| 464 | SI476X_RDSREP = (1 << 10), | ||
| 465 | SI476X_RSQREP = (1 << 11), | ||
| 466 | }; | ||
| 467 | |||
| 468 | enum si476x_rdsint_sources { | ||
| 469 | SI476X_RDSTPPTY = (1 << 4), | ||
| 470 | SI476X_RDSPI = (1 << 3), | ||
| 471 | SI476X_RDSSYNC = (1 << 1), | ||
| 472 | SI476X_RDSRECV = (1 << 0), | ||
| 473 | }; | ||
| 474 | |||
| 475 | enum si476x_status_response_bits { | ||
| 476 | SI476X_CTS = (1 << 7), | ||
| 477 | SI476X_ERR = (1 << 6), | ||
| 478 | /* Status response for WB receiver */ | ||
| 479 | SI476X_WB_ASQ_INT = (1 << 4), | ||
| 480 | SI476X_RSQ_INT = (1 << 3), | ||
| 481 | /* Status response for FM receiver */ | ||
| 482 | SI476X_FM_RDS_INT = (1 << 2), | ||
| 483 | SI476X_ACF_INT = (1 << 1), | ||
| 484 | SI476X_STC_INT = (1 << 0), | ||
| 485 | }; | ||
| 486 | |||
| 487 | /* -------------------- si476x-prop.c ----------------------- */ | ||
| 488 | |||
| 489 | enum si476x_common_receiver_properties { | ||
| 490 | SI476X_PROP_INT_CTL_ENABLE = 0x0000, | ||
| 491 | SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, | ||
| 492 | SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, | ||
| 493 | SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, | ||
| 494 | SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, | ||
| 495 | |||
| 496 | SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, | ||
| 497 | SI476X_PROP_SEEK_BAND_TOP = 0x1101, | ||
| 498 | SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, | ||
| 499 | |||
| 500 | SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, | ||
| 501 | SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, | ||
| 502 | SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, | ||
| 503 | }; | ||
| 504 | |||
| 505 | enum si476x_am_receiver_properties { | ||
| 506 | SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, | ||
| 507 | }; | ||
| 508 | |||
| 509 | enum si476x_fm_receiver_properties { | ||
| 510 | SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, | ||
| 511 | |||
| 512 | SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, | ||
| 513 | SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, | ||
| 514 | SI476X_PROP_FM_RDS_CONFIG = 0x4002, | ||
| 515 | }; | ||
| 516 | |||
| 517 | enum si476x_prop_audio_pwr_line_filter_bits { | ||
| 518 | SI476X_PROP_PWR_HARMONICS_MASK = 0x001f, | ||
| 519 | SI476X_PROP_PWR_GRID_MASK = 0x0100, | ||
| 520 | SI476X_PROP_PWR_ENABLE_MASK = 0x0200, | ||
| 521 | SI476X_PROP_PWR_GRID_50HZ = 0x0000, | ||
| 522 | SI476X_PROP_PWR_GRID_60HZ = 0x0100, | ||
| 523 | }; | ||
| 524 | |||
| 525 | enum si476x_prop_fm_rds_config_bits { | ||
| 526 | SI476X_PROP_RDSEN_MASK = 0x1, | ||
| 527 | SI476X_PROP_RDSEN = 0x1, | ||
| 528 | }; | ||
| 529 | |||
| 530 | |||
| 531 | struct regmap *devm_regmap_init_si476x(struct si476x_core *); | ||
| 532 | |||
| 533 | #endif /* SI476X_CORE_H */ | ||
diff --git a/include/linux/mfd/si476x-platform.h b/include/linux/mfd/si476x-platform.h new file mode 100644 index 000000000000..88bb93b7a9d5 --- /dev/null +++ b/include/linux/mfd/si476x-platform.h | |||
| @@ -0,0 +1,267 @@ | |||
| 1 | /* | ||
| 2 | * include/media/si476x-platform.h -- Platform data specific definitions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Andrey Smirnov | ||
| 5 | * | ||
| 6 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __SI476X_PLATFORM_H__ | ||
| 20 | #define __SI476X_PLATFORM_H__ | ||
| 21 | |||
| 22 | /* It is possible to select one of the four adresses using pins A0 | ||
| 23 | * and A1 on SI476x */ | ||
| 24 | #define SI476X_I2C_ADDR_1 0x60 | ||
| 25 | #define SI476X_I2C_ADDR_2 0x61 | ||
| 26 | #define SI476X_I2C_ADDR_3 0x62 | ||
| 27 | #define SI476X_I2C_ADDR_4 0x63 | ||
| 28 | |||
| 29 | enum si476x_iqclk_config { | ||
| 30 | SI476X_IQCLK_NOOP = 0, | ||
| 31 | SI476X_IQCLK_TRISTATE = 1, | ||
| 32 | SI476X_IQCLK_IQ = 21, | ||
| 33 | }; | ||
| 34 | enum si476x_iqfs_config { | ||
| 35 | SI476X_IQFS_NOOP = 0, | ||
| 36 | SI476X_IQFS_TRISTATE = 1, | ||
| 37 | SI476X_IQFS_IQ = 21, | ||
| 38 | }; | ||
| 39 | enum si476x_iout_config { | ||
| 40 | SI476X_IOUT_NOOP = 0, | ||
| 41 | SI476X_IOUT_TRISTATE = 1, | ||
| 42 | SI476X_IOUT_OUTPUT = 22, | ||
| 43 | }; | ||
| 44 | enum si476x_qout_config { | ||
| 45 | SI476X_QOUT_NOOP = 0, | ||
| 46 | SI476X_QOUT_TRISTATE = 1, | ||
| 47 | SI476X_QOUT_OUTPUT = 22, | ||
| 48 | }; | ||
| 49 | |||
| 50 | enum si476x_dclk_config { | ||
| 51 | SI476X_DCLK_NOOP = 0, | ||
| 52 | SI476X_DCLK_TRISTATE = 1, | ||
| 53 | SI476X_DCLK_DAUDIO = 10, | ||
| 54 | }; | ||
| 55 | |||
| 56 | enum si476x_dfs_config { | ||
| 57 | SI476X_DFS_NOOP = 0, | ||
| 58 | SI476X_DFS_TRISTATE = 1, | ||
| 59 | SI476X_DFS_DAUDIO = 10, | ||
| 60 | }; | ||
| 61 | |||
| 62 | enum si476x_dout_config { | ||
| 63 | SI476X_DOUT_NOOP = 0, | ||
| 64 | SI476X_DOUT_TRISTATE = 1, | ||
| 65 | SI476X_DOUT_I2S_OUTPUT = 12, | ||
| 66 | SI476X_DOUT_I2S_INPUT = 13, | ||
| 67 | }; | ||
| 68 | |||
| 69 | enum si476x_xout_config { | ||
| 70 | SI476X_XOUT_NOOP = 0, | ||
| 71 | SI476X_XOUT_TRISTATE = 1, | ||
| 72 | SI476X_XOUT_I2S_INPUT = 13, | ||
| 73 | SI476X_XOUT_MODE_SELECT = 23, | ||
| 74 | }; | ||
| 75 | |||
| 76 | enum si476x_icin_config { | ||
| 77 | SI476X_ICIN_NOOP = 0, | ||
| 78 | SI476X_ICIN_TRISTATE = 1, | ||
| 79 | SI476X_ICIN_GPO1_HIGH = 2, | ||
| 80 | SI476X_ICIN_GPO1_LOW = 3, | ||
| 81 | SI476X_ICIN_IC_LINK = 30, | ||
| 82 | }; | ||
| 83 | |||
| 84 | enum si476x_icip_config { | ||
| 85 | SI476X_ICIP_NOOP = 0, | ||
| 86 | SI476X_ICIP_TRISTATE = 1, | ||
| 87 | SI476X_ICIP_GPO2_HIGH = 2, | ||
| 88 | SI476X_ICIP_GPO2_LOW = 3, | ||
| 89 | SI476X_ICIP_IC_LINK = 30, | ||
| 90 | }; | ||
| 91 | |||
| 92 | enum si476x_icon_config { | ||
| 93 | SI476X_ICON_NOOP = 0, | ||
| 94 | SI476X_ICON_TRISTATE = 1, | ||
| 95 | SI476X_ICON_I2S = 10, | ||
| 96 | SI476X_ICON_IC_LINK = 30, | ||
| 97 | }; | ||
| 98 | |||
| 99 | enum si476x_icop_config { | ||
| 100 | SI476X_ICOP_NOOP = 0, | ||
| 101 | SI476X_ICOP_TRISTATE = 1, | ||
| 102 | SI476X_ICOP_I2S = 10, | ||
| 103 | SI476X_ICOP_IC_LINK = 30, | ||
| 104 | }; | ||
| 105 | |||
| 106 | |||
| 107 | enum si476x_lrout_config { | ||
| 108 | SI476X_LROUT_NOOP = 0, | ||
| 109 | SI476X_LROUT_TRISTATE = 1, | ||
| 110 | SI476X_LROUT_AUDIO = 2, | ||
| 111 | SI476X_LROUT_MPX = 3, | ||
| 112 | }; | ||
| 113 | |||
| 114 | |||
| 115 | enum si476x_intb_config { | ||
| 116 | SI476X_INTB_NOOP = 0, | ||
| 117 | SI476X_INTB_TRISTATE = 1, | ||
| 118 | SI476X_INTB_DAUDIO = 10, | ||
| 119 | SI476X_INTB_IRQ = 40, | ||
| 120 | }; | ||
| 121 | |||
| 122 | enum si476x_a1_config { | ||
| 123 | SI476X_A1_NOOP = 0, | ||
| 124 | SI476X_A1_TRISTATE = 1, | ||
| 125 | SI476X_A1_IRQ = 40, | ||
| 126 | }; | ||
| 127 | |||
| 128 | |||
| 129 | struct si476x_pinmux { | ||
| 130 | enum si476x_dclk_config dclk; | ||
| 131 | enum si476x_dfs_config dfs; | ||
| 132 | enum si476x_dout_config dout; | ||
| 133 | enum si476x_xout_config xout; | ||
| 134 | |||
| 135 | enum si476x_iqclk_config iqclk; | ||
| 136 | enum si476x_iqfs_config iqfs; | ||
| 137 | enum si476x_iout_config iout; | ||
| 138 | enum si476x_qout_config qout; | ||
| 139 | |||
| 140 | enum si476x_icin_config icin; | ||
| 141 | enum si476x_icip_config icip; | ||
| 142 | enum si476x_icon_config icon; | ||
| 143 | enum si476x_icop_config icop; | ||
| 144 | |||
| 145 | enum si476x_lrout_config lrout; | ||
| 146 | |||
| 147 | enum si476x_intb_config intb; | ||
| 148 | enum si476x_a1_config a1; | ||
| 149 | }; | ||
| 150 | |||
| 151 | enum si476x_ibias6x { | ||
| 152 | SI476X_IBIAS6X_OTHER = 0, | ||
| 153 | SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, | ||
| 154 | }; | ||
| 155 | |||
| 156 | enum si476x_xstart { | ||
| 157 | SI476X_XSTART_MULTIPLE_TUNER = 0x11, | ||
| 158 | SI476X_XSTART_NORMAL = 0x77, | ||
| 159 | }; | ||
| 160 | |||
| 161 | enum si476x_freq { | ||
| 162 | SI476X_FREQ_4_MHZ = 0, | ||
| 163 | SI476X_FREQ_37P209375_MHZ = 1, | ||
| 164 | SI476X_FREQ_36P4_MHZ = 2, | ||
| 165 | SI476X_FREQ_37P8_MHZ = 3, | ||
| 166 | }; | ||
| 167 | |||
| 168 | enum si476x_xmode { | ||
| 169 | SI476X_XMODE_CRYSTAL_RCVR1 = 1, | ||
| 170 | SI476X_XMODE_EXT_CLOCK = 2, | ||
| 171 | SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, | ||
| 172 | }; | ||
| 173 | |||
| 174 | enum si476x_xbiashc { | ||
| 175 | SI476X_XBIASHC_SINGLE_RECEIVER = 0, | ||
| 176 | SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, | ||
| 177 | }; | ||
| 178 | |||
| 179 | enum si476x_xbias { | ||
| 180 | SI476X_XBIAS_RCVR2_3 = 0, | ||
| 181 | SI476X_XBIAS_4MHZ_RCVR1 = 3, | ||
| 182 | SI476X_XBIAS_RCVR1 = 7, | ||
| 183 | }; | ||
| 184 | |||
| 185 | enum si476x_func { | ||
| 186 | SI476X_FUNC_BOOTLOADER = 0, | ||
| 187 | SI476X_FUNC_FM_RECEIVER = 1, | ||
| 188 | SI476X_FUNC_AM_RECEIVER = 2, | ||
| 189 | SI476X_FUNC_WB_RECEIVER = 3, | ||
| 190 | }; | ||
| 191 | |||
| 192 | |||
| 193 | /** | ||
| 194 | * @xcload: Selects the amount of additional on-chip capacitance to | ||
| 195 | * be connected between XTAL1 and gnd and between XTAL2 and | ||
| 196 | * GND. One half of the capacitance value shown here is the | ||
| 197 | * additional load capacitance presented to the xtal. The | ||
| 198 | * minimum step size is 0.277 pF. Recommended value is 0x28 | ||
| 199 | * but it will be layout dependent. Range is 0–0x3F i.e. | ||
| 200 | * (0–16.33 pF) | ||
| 201 | * @ctsien: enable CTSINT(interrupt request when CTS condition | ||
| 202 | * arises) when set | ||
| 203 | * @intsel: when set A1 pin becomes the interrupt pin; otherwise, | ||
| 204 | * INTB is the interrupt pin | ||
| 205 | * @func: selects the boot function of the device. I.e. | ||
| 206 | * SI476X_BOOTLOADER - Boot loader | ||
| 207 | * SI476X_FM_RECEIVER - FM receiver | ||
| 208 | * SI476X_AM_RECEIVER - AM receiver | ||
| 209 | * SI476X_WB_RECEIVER - Weatherband receiver | ||
| 210 | * @freq: oscillator's crystal frequency: | ||
| 211 | * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz | ||
| 212 | * SI476X_XTAL_36P4_MHZ - 36.4 Mhz | ||
| 213 | * SI476X_XTAL_37P8_MHZ - 37.8 Mhz | ||
| 214 | */ | ||
| 215 | struct si476x_power_up_args { | ||
| 216 | enum si476x_ibias6x ibias6x; | ||
| 217 | enum si476x_xstart xstart; | ||
| 218 | u8 xcload; | ||
| 219 | bool fastboot; | ||
| 220 | enum si476x_xbiashc xbiashc; | ||
| 221 | enum si476x_xbias xbias; | ||
| 222 | enum si476x_func func; | ||
| 223 | enum si476x_freq freq; | ||
| 224 | enum si476x_xmode xmode; | ||
| 225 | }; | ||
| 226 | |||
| 227 | |||
| 228 | /** | ||
| 229 | * enum si476x_phase_diversity_mode - possbile phase diversity modes | ||
| 230 | * for SI4764/5/6/7 chips. | ||
| 231 | * | ||
| 232 | * @SI476X_PHDIV_DISABLED: Phase diversity feature is | ||
| 233 | * disabled. | ||
| 234 | * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner | ||
| 235 | * in combination with a | ||
| 236 | * secondary one. | ||
| 237 | * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner | ||
| 238 | * using only its own antenna. | ||
| 239 | * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner | ||
| 240 | * usning seconary tuner's antenna. | ||
| 241 | * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary | ||
| 242 | * tuner in combination with the | ||
| 243 | * primary one. | ||
| 244 | */ | ||
| 245 | enum si476x_phase_diversity_mode { | ||
| 246 | SI476X_PHDIV_DISABLED = 0, | ||
| 247 | SI476X_PHDIV_PRIMARY_COMBINING = 1, | ||
| 248 | SI476X_PHDIV_PRIMARY_ANTENNA = 2, | ||
| 249 | SI476X_PHDIV_SECONDARY_ANTENNA = 3, | ||
| 250 | SI476X_PHDIV_SECONDARY_COMBINING = 5, | ||
| 251 | }; | ||
| 252 | |||
| 253 | |||
| 254 | /* | ||
| 255 | * Platform dependent definition | ||
| 256 | */ | ||
| 257 | struct si476x_platform_data { | ||
| 258 | int gpio_reset; /* < 0 if not used */ | ||
| 259 | |||
| 260 | struct si476x_power_up_args power_up_parameters; | ||
| 261 | enum si476x_phase_diversity_mode diversity_mode; | ||
| 262 | |||
| 263 | struct si476x_pinmux pinmux; | ||
| 264 | }; | ||
| 265 | |||
| 266 | |||
| 267 | #endif /* __SI476X_PLATFORM_H__ */ | ||
diff --git a/include/linux/mfd/si476x-reports.h b/include/linux/mfd/si476x-reports.h new file mode 100644 index 000000000000..e0b9455a79c0 --- /dev/null +++ b/include/linux/mfd/si476x-reports.h | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | /* | ||
| 2 | * include/media/si476x-platform.h -- Definitions of the data formats | ||
| 3 | * returned by debugfs hooks | ||
| 4 | * | ||
| 5 | * Copyright (C) 2013 Andrey Smirnov | ||
| 6 | * | ||
| 7 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; version 2 of the License. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but | ||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | * General Public License for more details. | ||
| 17 | * | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __SI476X_REPORTS_H__ | ||
| 21 | #define __SI476X_REPORTS_H__ | ||
| 22 | |||
| 23 | /** | ||
| 24 | * struct si476x_rsq_status - structure containing received signal | ||
| 25 | * quality | ||
| 26 | * @multhint: Multipath Detect High. | ||
| 27 | * true - Indicatedes that the value is below | ||
| 28 | * FM_RSQ_MULTIPATH_HIGH_THRESHOLD | ||
| 29 | * false - Indicatedes that the value is above | ||
| 30 | * FM_RSQ_MULTIPATH_HIGH_THRESHOLD | ||
| 31 | * @multlint: Multipath Detect Low. | ||
| 32 | * true - Indicatedes that the value is below | ||
| 33 | * FM_RSQ_MULTIPATH_LOW_THRESHOLD | ||
| 34 | * false - Indicatedes that the value is above | ||
| 35 | * FM_RSQ_MULTIPATH_LOW_THRESHOLD | ||
| 36 | * @snrhint: SNR Detect High. | ||
| 37 | * true - Indicatedes that the value is below | ||
| 38 | * FM_RSQ_SNR_HIGH_THRESHOLD | ||
| 39 | * false - Indicatedes that the value is above | ||
| 40 | * FM_RSQ_SNR_HIGH_THRESHOLD | ||
| 41 | * @snrlint: SNR Detect Low. | ||
| 42 | * true - Indicatedes that the value is below | ||
| 43 | * FM_RSQ_SNR_LOW_THRESHOLD | ||
| 44 | * false - Indicatedes that the value is above | ||
| 45 | * FM_RSQ_SNR_LOW_THRESHOLD | ||
| 46 | * @rssihint: RSSI Detect High. | ||
| 47 | * true - Indicatedes that the value is below | ||
| 48 | * FM_RSQ_RSSI_HIGH_THRESHOLD | ||
| 49 | * false - Indicatedes that the value is above | ||
| 50 | * FM_RSQ_RSSI_HIGH_THRESHOLD | ||
| 51 | * @rssilint: RSSI Detect Low. | ||
| 52 | * true - Indicatedes that the value is below | ||
| 53 | * FM_RSQ_RSSI_LOW_THRESHOLD | ||
| 54 | * false - Indicatedes that the value is above | ||
| 55 | * FM_RSQ_RSSI_LOW_THRESHOLD | ||
| 56 | * @bltf: Band Limit. | ||
| 57 | * Set if seek command hits the band limit or wrapped to | ||
| 58 | * the original frequency. | ||
| 59 | * @snr_ready: SNR measurement in progress. | ||
| 60 | * @rssiready: RSSI measurement in progress. | ||
| 61 | * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR | ||
| 62 | * @valid: Set if the channel is valid | ||
| 63 | * rssi < FM_VALID_RSSI_THRESHOLD | ||
| 64 | * snr < FM_VALID_SNR_THRESHOLD | ||
| 65 | * tune_error < FM_VALID_MAX_TUNE_ERROR | ||
| 66 | * @readfreq: Current tuned frequency. | ||
| 67 | * @freqoff: Signed frequency offset. | ||
| 68 | * @rssi: Received Signal Strength Indicator(dBuV). | ||
| 69 | * @snr: RF SNR Indicator(dB). | ||
| 70 | * @lassi: | ||
| 71 | * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator | ||
| 72 | * @mult: Multipath indicator | ||
| 73 | * @dev: Who knows? But values may vary. | ||
| 74 | * @readantcap: Antenna tuning capacity value. | ||
| 75 | * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator | ||
| 76 | * @usn: Ultrasonic Noise Inticator in -DBFS | ||
| 77 | */ | ||
| 78 | struct si476x_rsq_status_report { | ||
| 79 | __u8 multhint, multlint; | ||
| 80 | __u8 snrhint, snrlint; | ||
| 81 | __u8 rssihint, rssilint; | ||
| 82 | __u8 bltf; | ||
| 83 | __u8 snr_ready; | ||
| 84 | __u8 rssiready; | ||
| 85 | __u8 injside; | ||
| 86 | __u8 afcrl; | ||
| 87 | __u8 valid; | ||
| 88 | |||
| 89 | __u16 readfreq; | ||
| 90 | __s8 freqoff; | ||
| 91 | __s8 rssi; | ||
| 92 | __s8 snr; | ||
| 93 | __s8 issi; | ||
| 94 | __s8 lassi, hassi; | ||
| 95 | __s8 mult; | ||
| 96 | __u8 dev; | ||
| 97 | __u16 readantcap; | ||
| 98 | __s8 assi; | ||
| 99 | __s8 usn; | ||
| 100 | |||
| 101 | __u8 pilotdev; | ||
| 102 | __u8 rdsdev; | ||
| 103 | __u8 assidev; | ||
| 104 | __u8 strongdev; | ||
| 105 | __u16 rdspi; | ||
| 106 | } __packed; | ||
| 107 | |||
| 108 | /** | ||
| 109 | * si476x_acf_status_report - ACF report results | ||
| 110 | * | ||
| 111 | * @blend_int: If set, indicates that stereo separation has crossed | ||
| 112 | * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD | ||
| 113 | * @hblend_int: If set, indicates that HiBlend cutoff frequency is | ||
| 114 | * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD | ||
| 115 | * @hicut_int: If set, indicates that HiCut cutoff frequency is lower | ||
| 116 | * than the threshold set by ACF_ | ||
| 117 | |||
| 118 | */ | ||
| 119 | struct si476x_acf_status_report { | ||
| 120 | __u8 blend_int; | ||
| 121 | __u8 hblend_int; | ||
| 122 | __u8 hicut_int; | ||
| 123 | __u8 chbw_int; | ||
| 124 | __u8 softmute_int; | ||
| 125 | __u8 smute; | ||
| 126 | __u8 smattn; | ||
| 127 | __u8 chbw; | ||
| 128 | __u8 hicut; | ||
| 129 | __u8 hiblend; | ||
| 130 | __u8 pilot; | ||
| 131 | __u8 stblend; | ||
| 132 | } __packed; | ||
| 133 | |||
| 134 | enum si476x_fmagc { | ||
| 135 | SI476X_FMAGC_10K_OHM = 0, | ||
| 136 | SI476X_FMAGC_800_OHM = 1, | ||
| 137 | SI476X_FMAGC_400_OHM = 2, | ||
| 138 | SI476X_FMAGC_200_OHM = 4, | ||
| 139 | SI476X_FMAGC_100_OHM = 8, | ||
| 140 | SI476X_FMAGC_50_OHM = 16, | ||
| 141 | SI476X_FMAGC_25_OHM = 32, | ||
| 142 | SI476X_FMAGC_12P5_OHM = 64, | ||
| 143 | SI476X_FMAGC_6P25_OHM = 128, | ||
| 144 | }; | ||
| 145 | |||
| 146 | struct si476x_agc_status_report { | ||
| 147 | __u8 mxhi; | ||
| 148 | __u8 mxlo; | ||
| 149 | __u8 lnahi; | ||
| 150 | __u8 lnalo; | ||
| 151 | __u8 fmagc1; | ||
| 152 | __u8 fmagc2; | ||
| 153 | __u8 pgagain; | ||
| 154 | __u8 fmwblang; | ||
| 155 | } __packed; | ||
| 156 | |||
| 157 | struct si476x_rds_blockcount_report { | ||
| 158 | __u16 expected; | ||
| 159 | __u16 received; | ||
| 160 | __u16 uncorrectable; | ||
| 161 | } __packed; | ||
| 162 | |||
| 163 | #endif /* __SI476X_REPORTS_H__ */ | ||
diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index 383ac1512a39..48395a69a7e9 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h | |||
| @@ -26,6 +26,7 @@ enum stmpe_partnum { | |||
| 26 | STMPE801, | 26 | STMPE801, |
| 27 | STMPE811, | 27 | STMPE811, |
| 28 | STMPE1601, | 28 | STMPE1601, |
| 29 | STMPE1801, | ||
| 29 | STMPE2401, | 30 | STMPE2401, |
| 30 | STMPE2403, | 31 | STMPE2403, |
| 31 | STMPE_NBR_PARTS | 32 | STMPE_NBR_PARTS |
| @@ -39,6 +40,7 @@ enum { | |||
| 39 | STMPE_IDX_CHIP_ID, | 40 | STMPE_IDX_CHIP_ID, |
| 40 | STMPE_IDX_ICR_LSB, | 41 | STMPE_IDX_ICR_LSB, |
| 41 | STMPE_IDX_IER_LSB, | 42 | STMPE_IDX_IER_LSB, |
| 43 | STMPE_IDX_ISR_LSB, | ||
| 42 | STMPE_IDX_ISR_MSB, | 44 | STMPE_IDX_ISR_MSB, |
| 43 | STMPE_IDX_GPMR_LSB, | 45 | STMPE_IDX_GPMR_LSB, |
| 44 | STMPE_IDX_GPSR_LSB, | 46 | STMPE_IDX_GPSR_LSB, |
| @@ -49,6 +51,7 @@ enum { | |||
| 49 | STMPE_IDX_GPFER_LSB, | 51 | STMPE_IDX_GPFER_LSB, |
| 50 | STMPE_IDX_GPAFR_U_MSB, | 52 | STMPE_IDX_GPAFR_U_MSB, |
| 51 | STMPE_IDX_IEGPIOR_LSB, | 53 | STMPE_IDX_IEGPIOR_LSB, |
| 54 | STMPE_IDX_ISGPIOR_LSB, | ||
| 52 | STMPE_IDX_ISGPIOR_MSB, | 55 | STMPE_IDX_ISGPIOR_MSB, |
| 53 | STMPE_IDX_MAX, | 56 | STMPE_IDX_MAX, |
| 54 | }; | 57 | }; |
diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 6aeb6b8da64d..b473577f36db 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h | |||
| @@ -15,8 +15,11 @@ | |||
| 15 | #ifndef __LINUX_MFD_SYSCON_H__ | 15 | #ifndef __LINUX_MFD_SYSCON_H__ |
| 16 | #define __LINUX_MFD_SYSCON_H__ | 16 | #define __LINUX_MFD_SYSCON_H__ |
| 17 | 17 | ||
| 18 | struct device_node; | ||
| 19 | |||
| 18 | extern struct regmap *syscon_node_to_regmap(struct device_node *np); | 20 | extern struct regmap *syscon_node_to_regmap(struct device_node *np); |
| 19 | extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); | 21 | extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); |
| 22 | extern struct regmap *syscon_regmap_lookup_by_pdevname(const char *s); | ||
| 20 | extern struct regmap *syscon_regmap_lookup_by_phandle( | 23 | extern struct regmap *syscon_regmap_lookup_by_phandle( |
| 21 | struct device_node *np, | 24 | struct device_node *np, |
| 22 | const char *property); | 25 | const char *property); |
diff --git a/include/linux/mfd/tps65090.h b/include/linux/mfd/tps65090.h index 998628a2b08b..3f43069413e7 100644 --- a/include/linux/mfd/tps65090.h +++ b/include/linux/mfd/tps65090.h | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | /* TPS65090 IRQs */ | 28 | /* TPS65090 IRQs */ |
| 29 | enum { | 29 | enum { |
| 30 | TPS65090_IRQ_INTERRUPT, | ||
| 30 | TPS65090_IRQ_VAC_STATUS_CHANGE, | 31 | TPS65090_IRQ_VAC_STATUS_CHANGE, |
| 31 | TPS65090_IRQ_VSYS_STATUS_CHANGE, | 32 | TPS65090_IRQ_VSYS_STATUS_CHANGE, |
| 32 | TPS65090_IRQ_BAT_STATUS_CHANGE, | 33 | TPS65090_IRQ_BAT_STATUS_CHANGE, |
diff --git a/include/linux/of.h b/include/linux/of.h index fb2002f3c7dc..1b671c3809b8 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -356,6 +356,11 @@ static inline struct device_node *of_find_node_by_name(struct device_node *from, | |||
| 356 | return NULL; | 356 | return NULL; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static inline struct device_node *of_get_parent(const struct device_node *node) | ||
| 360 | { | ||
| 361 | return NULL; | ||
| 362 | } | ||
| 363 | |||
| 359 | static inline bool of_have_populated_dt(void) | 364 | static inline bool of_have_populated_dt(void) |
| 360 | { | 365 | { |
| 361 | return false; | 366 | return false; |
diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h index d21b33c4c6ca..2e9ee4d1c676 100644 --- a/include/linux/ucb1400.h +++ b/include/linux/ucb1400.h | |||
| @@ -83,15 +83,12 @@ | |||
| 83 | #define UCB_ID 0x7e | 83 | #define UCB_ID 0x7e |
| 84 | #define UCB_ID_1400 0x4304 | 84 | #define UCB_ID_1400 0x4304 |
| 85 | 85 | ||
| 86 | struct ucb1400_gpio_data { | ||
| 87 | int gpio_offset; | ||
| 88 | int (*gpio_setup)(struct device *dev, int ngpio); | ||
| 89 | int (*gpio_teardown)(struct device *dev, int ngpio); | ||
| 90 | }; | ||
| 91 | |||
| 92 | struct ucb1400_gpio { | 86 | struct ucb1400_gpio { |
| 93 | struct gpio_chip gc; | 87 | struct gpio_chip gc; |
| 94 | struct snd_ac97 *ac97; | 88 | struct snd_ac97 *ac97; |
| 89 | int gpio_offset; | ||
| 90 | int (*gpio_setup)(struct device *dev, int ngpio); | ||
| 91 | int (*gpio_teardown)(struct device *dev, int ngpio); | ||
| 95 | }; | 92 | }; |
| 96 | 93 | ||
| 97 | struct ucb1400_ts { | 94 | struct ucb1400_ts { |
| @@ -110,6 +107,9 @@ struct ucb1400 { | |||
| 110 | 107 | ||
| 111 | struct ucb1400_pdata { | 108 | struct ucb1400_pdata { |
| 112 | int irq; | 109 | int irq; |
| 110 | int gpio_offset; | ||
| 111 | int (*gpio_setup)(struct device *dev, int ngpio); | ||
| 112 | int (*gpio_teardown)(struct device *dev, int ngpio); | ||
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| 115 | static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg) | 115 | static inline u16 ucb1400_reg_read(struct snd_ac97 *ac97, u16 reg) |
| @@ -162,10 +162,4 @@ static inline void ucb1400_adc_disable(struct snd_ac97 *ac97) | |||
| 162 | unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, | 162 | unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, |
| 163 | int adcsync); | 163 | int adcsync); |
| 164 | 164 | ||
| 165 | #ifdef CONFIG_GPIO_UCB1400 | ||
| 166 | void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data); | ||
| 167 | #else | ||
| 168 | static inline void ucb1400_gpio_set_data(struct ucb1400_gpio_data *data) {} | ||
| 169 | #endif | ||
| 170 | |||
| 171 | #endif | 165 | #endif |
