diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-05 20:36:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-05 20:36:20 -0400 |
commit | d7ab7302f970a254997687a1cdede421a5635c68 (patch) | |
tree | 71341b72e81c8e031b98e8115c51682427192798 | |
parent | 01227a889ed56ae53aeebb9f93be9d54dd8b2de8 (diff) | |
parent | 99f4c6b66a9ae362d21e6df95d04bc74e04d285e (diff) |
Merge tag 'mfd-3.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next
Pull MFD update from Samuel Ortiz:
"For 3.10 we have a few new MFD drivers for:
- The ChromeOS embedded controller which provides keyboard, battery
and power management services. This controller is accessible
through i2c or SPI.
- Silicon Laboratories 476x controller, providing access to their FM
chipset and their audio codec.
- Realtek's RTS5249, a memory stick, MMC and SD/SDIO PCI based
reader.
- Nokia's Tahvo power button and watchdog device. This device is
very similar to Retu and is thus supported by the same code base.
- STMicroelectronics STMPE1801, a keyboard and GPIO controller
supported by the stmpe driver.
- ST-Ericsson AB8540 and AB8505 power management and voltage
converter controllers through the existing ab8500 code.
Some other drivers got cleaned up or improved. In particular:
- The Linaro/STE guys got the ab8500 driver in sync with their
internal code through a series of optimizations, fixes and
improvements.
- The AS3711 and OMAP USB drivers now have DT support.
- The arizona clock and interrupt handling code got improved.
- The wm5102 register patch and boot mechanism also got improved."
* tag 'mfd-3.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next: (104 commits)
mfd: si476x: Don't use 0bNNN
mfd: vexpress: Handle pending config transactions
mfd: ab8500: Export ab8500_gpadc_sw_hw_convert properly
mfd: si476x: Fix i2c warning
mfd: si476x: Add header files and Kbuild plumbing
mfd: si476x: Add chip properties handling code
mfd: si476x: Add the bulk of the core driver
mfd: si476x: Add commands abstraction layer
mfd: rtsx: Support RTS5249
mfd: retu: Add Tahvo support
mfd: ucb1400: Pass ucb1400-gpio data through ac97 bus
mfd: wm8994: Add some OF properties
mfd: wm8994: Add device ID data to WM8994 OF device IDs
input: Export matrix_keypad_parse_of_params()
mfd: tps65090: Add compatible string for charger subnode
mfd: db8500-prcmu: Support platform dependant device selection
mfd: syscon: Fix warnings when printing resource_size_t
of: Add stub of_get_parent for non-OF builds
mfd: omap-usb-tll: Convert to devm_ioremap_resource()
mfd: omap-usb-host: Convert to devm_ioremap_resource()
...
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 |