diff options
154 files changed, 11162 insertions, 4184 deletions
diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt index 1ac8ea8ade1d..bfeabb843941 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt @@ -8,6 +8,12 @@ the standard I2C multi-master rules. Using GPIOs is generally useful in the case where there is a device on the bus that has errata and/or bugs that makes standard multimaster mode not feasible. +Note that this scheme works well enough but has some downsides: +* It is nonstandard (not using standard I2C multimaster) +* Having two masters on a bus in general makes it relatively hard to debug + problems (hard to tell if i2c issues were caused by one master, another, or + some device on the bus). + Algorithm: diff --git a/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt b/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt new file mode 100644 index 000000000000..898f030eba62 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-cros-ec-tunnel.txt @@ -0,0 +1,39 @@ +I2C bus that tunnels through the ChromeOS EC (cros-ec) +====================================================== +On some ChromeOS board designs we've got a connection to the EC (embedded +controller) but no direct connection to some devices on the other side of +the EC (like a battery and PMIC). To get access to those devices we need +to tunnel our i2c commands through the EC. + +The node for this device should be under a cros-ec node like google,cros-ec-spi +or google,cros-ec-i2c. + + +Required properties: +- compatible: google,cros-ec-i2c-tunnel +- google,remote-bus: The EC bus we'd like to talk to. + +Optional child nodes: +- One node per I2C device connected to the tunnelled I2C bus. + + +Example: + cros-ec@0 { + compatible = "google,cros-ec-spi"; + + ... + + i2c-tunnel { + compatible = "google,cros-ec-i2c-tunnel"; + #address-cells = <1>; + #size-cells = <0>; + + google,remote-bus = <0>; + + battery: sbs-battery@b { + compatible = "sbs,sbs-battery"; + reg = <0xb>; + sbs,poll-retry-count = <1>; + }; + }; + } diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt index 056732cfdcee..d4745e31f5c6 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.txt @@ -5,7 +5,14 @@ at various speeds ranging from 100khz to 3.4Mhz. Required properties: - compatible: value should be. - -> "samsung,exynos5-hsi2c", for i2c compatible with exynos5 hsi2c. + -> "samsung,exynos5-hsi2c", (DEPRECATED) + for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5250-hsi2c", for i2c compatible with HSI2C available + on Exynos5250 and Exynos5420 SoCs. + -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available + on Exynos5260 SoCs. + - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt number to the cpu. @@ -26,7 +33,7 @@ Optional properties: Example: hsi2c@12ca0000 { - compatible = "samsung,exynos5-hsi2c"; + compatible = "samsung,exynos5250-hsi2c"; reg = <0x12ca0000 0x100>; interrupts = <56>; clock-frequency = <100000>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index befd4fb4764f..5c30026921ae 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -5,7 +5,7 @@ Required properties : - reg : Offset and length of the register set for the device - compatible : Should be either: - - "allwinner,sun4i-i2c" + - "allwinner,sun4i-a10-i2c" - "allwinner,sun6i-a31-i2c" - "marvell,mv64xxx-i2c" - "marvell,mv78230-i2c" diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index dd8b2dd1edeb..16b3e07aa98f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -7,6 +7,9 @@ Required properties: "renesas,i2c-r8a7779" "renesas,i2c-r8a7790" "renesas,i2c-r8a7791" + "renesas,i2c-r8a7792" + "renesas,i2c-r8a7793" + "renesas,i2c-r8a7794" - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier. diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt new file mode 100644 index 000000000000..d2153ce36fa8 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -0,0 +1,26 @@ +Device tree configuration for Renesas IIC (sh_mobile) driver + +Required properties: +- compatible : "renesas,iic-<soctype>". "renesas,rmobile-iic" as fallback +- reg : address start and address range size of device +- interrupts : interrupt of device +- clocks : clock for device +- #address-cells : should be <1> +- #size-cells : should be <0> + +Optional properties: +- clock-frequency : frequency of bus clock in Hz. Default 100kHz if unset. + +Pinctrl properties might be needed, too. See there. + +Example: + + iic0: i2c@e6500000 { + compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + reg = <0 0xe6500000 0 0x425>; + interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp3_clks R8A7790_CLK_IIC0>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt new file mode 100644 index 000000000000..6fa4c737af23 --- /dev/null +++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt @@ -0,0 +1,70 @@ +Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit) + +Samsung's Exynos architecture contains System MMUs that enables scattered +physical memory chunks visible as a contiguous region to DMA-capable peripheral +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth. + +System MMU is an IOMMU and supports identical translation table format to +ARMv7 translation tables with minimum set of page properties including access +permissions, shareability and security protection. In addition, System MMU has +another capabilities like L2 TLB or block-fetch buffers to minimize translation +latency. + +System MMUs are in many to one relation with peripheral devices, i.e. single +peripheral device might have multiple System MMUs (usually one for each bus +master), but one System MMU can handle transactions from only one peripheral +device. The relation between a System MMU and the peripheral device needs to be +defined in device node of the peripheral device. + +MFC in all Exynos SoCs and FIMD, M2M Scalers and G2D in Exynos5420 has 2 System +MMUs. +* MFC has one System MMU on its left and right bus. +* FIMD in Exynos5420 has one System MMU for window 0 and 4, the other system MMU + for window 1, 2 and 3. +* M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and + the other System MMU on the write channel. +The drivers must consider how to handle those System MMUs. One of the idea is +to implement child devices or sub-devices which are the client devices of the +System MMU. + +Note: +The current DT binding for the Exynos System MMU is incomplete. +The following properties can be removed or changed, if found incompatible with +the "Generic IOMMU Binding" support for attaching devices to the IOMMU. + +Required properties: +- compatible: Should be "samsung,exynos-sysmmu" +- reg: A tuple of base address and size of System MMU registers. +- interrupt-parent: The phandle of the interrupt controller of System MMU +- interrupts: An interrupt specifier for interrupt signal of System MMU, + according to the format defined by a particular interrupt + controller. +- clock-names: Should be "sysmmu" if the System MMU is needed to gate its clock. + Optional "master" if the clock to the System MMU is gated by + another gate clock other than "sysmmu". + Exynos4 SoCs, there needs no "master" clock. + Exynos5 SoCs, some System MMUs must have "master" clocks. +- clocks: Required if the System MMU is needed to gate its clock. +- samsung,power-domain: Required if the System MMU is needed to gate its power. + Please refer to the following document: + Documentation/devicetree/bindings/arm/exynos/power_domain.txt + +Examples: + gsc_0: gsc@13e00000 { + compatible = "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <0 85 0>; + samsung,power-domain = <&pd_gsc>; + clocks = <&clock CLK_GSCL0>; + clock-names = "gscl"; + }; + + sysmmu_gsc0: sysmmu@13E80000 { + compatible = "samsung,exynos-sysmmu"; + reg = <0x13E80000 0x1000>; + interrupt-parent = <&combiner>; + interrupts = <2 0>; + clock-names = "sysmmu", "master"; + clocks = <&clock CLK_SMMU_GSCL0>, <&clock CLK_GSCL0>; + samsung,power-domain = <&pd_gsc>; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt new file mode 100644 index 000000000000..c27cede3bd68 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -0,0 +1,70 @@ +* Analog Devices ADV7604/11 video decoder with HDMI receiver + +The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI +receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input, +and the ADV7611 has one HDMI input and no analog input. + +These device tree bindings support the ADV7611 only at the moment. + +Required Properties: + + - compatible: Must contain one of the following + - "adi,adv7611" for the ADV7611 + + - reg: I2C slave address + + - hpd-gpios: References to the GPIOs that control the HDMI hot-plug + detection pins, one per HDMI input. The active flag indicates the GPIO + level that enables hot-plug detection. + +The device node must contain one 'port' child node per device input and output +port, in accordance with the video interface bindings defined in +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes +are numbered as follows. + + Port ADV7611 +------------------------------------------------------------ + HDMI 0 + Digital output 1 + +The digital output port node must contain at least one endpoint. + +Optional Properties: + + - reset-gpios: Reference to the GPIO connected to the device's reset pin. + +Optional Endpoint Properties: + + The following three properties are defined in video-interfaces.txt and are + valid for source endpoints only. + + - hsync-active: Horizontal synchronization polarity. Defaults to active low. + - vsync-active: Vertical synchronization polarity. Defaults to active low. + - pclk-sample: Pixel clock polarity. Defaults to output on the falling edge. + + If none of hsync-active, vsync-active and pclk-sample is specified the + endpoint will use embedded BT.656 synchronization. + + +Example: + + hdmi_receiver@4c { + compatible = "adi,adv7611"; + reg = <0x4c>; + + reset-gpios = <&ioexp 0 GPIO_ACTIVE_LOW>; + hpd-gpios = <&ioexp 2 GPIO_ACTIVE_HIGH>; + + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + }; + port@1 { + reg = <1>; + hdmi_in: endpoint { + remote-endpoint = <&ccdc_in>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.txt b/Documentation/devicetree/bindings/media/renesas,vsp1.txt new file mode 100644 index 000000000000..87fe08abf36d --- /dev/null +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.txt @@ -0,0 +1,43 @@ +* Renesas VSP1 Video Processing Engine + +The VSP1 is a video processing engine that supports up-/down-scaling, alpha +blending, color space conversion and various other image processing features. +It can be found in the Renesas R-Car second generation SoCs. + +Required properties: + + - compatible: Must contain "renesas,vsp1" + + - reg: Base address and length of the registers block for the VSP1. + - interrupts: VSP1 interrupt specifier. + - clocks: A phandle + clock-specifier pair for the VSP1 functional clock. + + - renesas,#rpf: Number of Read Pixel Formatter (RPF) modules in the VSP1. + - renesas,#uds: Number of Up Down Scaler (UDS) modules in the VSP1. + - renesas,#wpf: Number of Write Pixel Formatter (WPF) modules in the VSP1. + + +Optional properties: + + - renesas,has-lif: Boolean, indicates that the LCD Interface (LIF) module is + available. + - renesas,has-lut: Boolean, indicates that the Look Up Table (LUT) module is + available. + - renesas,has-sru: Boolean, indicates that the Super Resolution Unit (SRU) + module is available. + + +Example: R8A7790 (R-Car H2) VSP1-S node + + vsp1@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; + + renesas,has-lut; + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <3>; + renesas,#wpf = <4>; + }; diff --git a/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt new file mode 100644 index 000000000000..1f5a31fef907 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/sun6i-prcm.txt @@ -0,0 +1,59 @@ +* Allwinner PRCM (Power/Reset/Clock Management) Multi-Functional Device + +PRCM is an MFD device exposing several Power Management related devices +(like clks and reset controllers). + +Required properties: + - compatible: "allwinner,sun6i-a31-prcm" + - reg: The PRCM registers range + +The prcm node may contain several subdevices definitions: + - see Documentation/devicetree/clk/sunxi.txt for clock devices + - see Documentation/devicetree/reset/allwinner,sunxi-clock-reset.txt for reset + controller devices + + +Example: + + prcm: prcm@01f01400 { + compatible = "allwinner,sun6i-a31-prcm"; + reg = <0x01f01400 0x200>; + + /* Put subdevices here */ + ar100: ar100_clk { + compatible = "allwinner,sun6i-a31-ar100-clk"; + #clock-cells = <0>; + clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>; + }; + + ahb0: ahb0_clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + clock-div = <1>; + clock-mult = <1>; + clocks = <&ar100_div>; + clock-output-names = "ahb0"; + }; + + apb0: apb0_clk { + compatible = "allwinner,sun6i-a31-apb0-clk"; + #clock-cells = <0>; + clocks = <&ahb0>; + clock-output-names = "apb0"; + }; + + apb0_gates: apb0_gates_clk { + compatible = "allwinner,sun6i-a31-apb0-gates-clk"; + #clock-cells = <1>; + clocks = <&apb0>; + clock-output-names = "apb0_pio", "apb0_ir", + "apb0_timer01", "apb0_p2wi", + "apb0_uart", "apb0_1wire", + "apb0_i2c"; + }; + + apb0_rst: apb0_rst { + compatible = "allwinner,sun6i-a31-clock-reset"; + #reset-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/ti-keystone-devctrl.txt b/Documentation/devicetree/bindings/mfd/ti-keystone-devctrl.txt new file mode 100644 index 000000000000..20963c76b4bc --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ti-keystone-devctrl.txt @@ -0,0 +1,19 @@ +* Device tree bindings for Texas Instruments keystone device state control + +The Keystone II devices have a set of registers that are used to control +the status of its peripherals. This node is intended to allow access to +this functionality. + +Required properties: + +- compatible: "ti,keystone-devctrl", "syscon" + +- reg: contains offset/length value for device state control + registers space. + +Example: + +devctrl: device-state-control@0x02620000 { + compatible = "ti,keystone-devctrl", "syscon"; + reg = <0x02620000 0x1000>; +}; diff --git a/Documentation/devicetree/bindings/mfd/twl6040.txt b/Documentation/devicetree/bindings/mfd/twl6040.txt index 0f5dd709d752..a41157b5d930 100644 --- a/Documentation/devicetree/bindings/mfd/twl6040.txt +++ b/Documentation/devicetree/bindings/mfd/twl6040.txt @@ -19,6 +19,8 @@ Required properties: Optional properties, nodes: - enable-active-high: To power on the twl6040 during boot. +- clocks: phandle to the clk32k clock provider +- clock-names: Must be "clk32k" Vibra functionality Required properties: diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi index c7b794ed337d..d96e179490ce 100644 --- a/arch/arm/boot/dts/sun4i-a10.dtsi +++ b/arch/arm/boot/dts/sun4i-a10.dtsi @@ -713,7 +713,7 @@ }; i2c0: i2c@01c2ac00 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun4i-a10-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <7>; clocks = <&apb1_gates 0>; @@ -724,7 +724,7 @@ }; i2c1: i2c@01c2b000 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun4i-a10-i2c"; reg = <0x01c2b000 0x400>; interrupts = <8>; clocks = <&apb1_gates 1>; @@ -735,7 +735,7 @@ }; i2c2: i2c@01c2b400 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun4i-a10-i2c"; reg = <0x01c2b400 0x400>; interrupts = <9>; clocks = <&apb1_gates 2>; diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi index aa1dd59dc34a..b64f705d9008 100644 --- a/arch/arm/boot/dts/sun5i-a10s.dtsi +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi @@ -560,7 +560,7 @@ i2c0: i2c@01c2ac00 { #address-cells = <1>; #size-cells = <0>; - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <7>; clocks = <&apb1_gates 0>; @@ -571,7 +571,7 @@ i2c1: i2c@01c2b000 { #address-cells = <1>; #size-cells = <0>; - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b000 0x400>; interrupts = <8>; clocks = <&apb1_gates 1>; @@ -582,7 +582,7 @@ i2c2: i2c@01c2b400 { #address-cells = <1>; #size-cells = <0>; - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a10s-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b400 0x400>; interrupts = <9>; clocks = <&apb1_gates 2>; diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi index c9fdb7b3ecd9..3b2a94c40f6e 100644 --- a/arch/arm/boot/dts/sun5i-a13.dtsi +++ b/arch/arm/boot/dts/sun5i-a13.dtsi @@ -486,7 +486,7 @@ }; i2c0: i2c@01c2ac00 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <7>; clocks = <&apb1_gates 0>; @@ -497,7 +497,7 @@ }; i2c1: i2c@01c2b000 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b000 0x400>; interrupts = <8>; clocks = <&apb1_gates 1>; @@ -508,7 +508,7 @@ }; i2c2: i2c@01c2b400 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun5i-a13-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b400 0x400>; interrupts = <9>; clocks = <&apb1_gates 2>; diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi index 385933bac114..01e94664232a 100644 --- a/arch/arm/boot/dts/sun7i-a20.dtsi +++ b/arch/arm/boot/dts/sun7i-a20.dtsi @@ -863,7 +863,7 @@ }; i2c0: i2c@01c2ac00 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2ac00 0x400>; interrupts = <0 7 4>; clocks = <&apb1_gates 0>; @@ -874,7 +874,7 @@ }; i2c1: i2c@01c2b000 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b000 0x400>; interrupts = <0 8 4>; clocks = <&apb1_gates 1>; @@ -885,7 +885,7 @@ }; i2c2: i2c@01c2b400 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b400 0x400>; interrupts = <0 9 4>; clocks = <&apb1_gates 2>; @@ -896,7 +896,7 @@ }; i2c3: i2c@01c2b800 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2b800 0x400>; interrupts = <0 88 4>; clocks = <&apb1_gates 3>; @@ -907,7 +907,7 @@ }; i2c4: i2c@01c2c000 { - compatible = "allwinner,sun4i-i2c"; + compatible = "allwinner,sun7i-a20-i2c", "allwinner,sun4i-a10-i2c"; reg = <0x01c2c000 0x400>; interrupts = <0 89 4>; clocks = <&apb1_gates 15>; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 2776a09bee58..628b58494294 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -23,7 +23,8 @@ enum { REG_RE, REG_FE, REG_IE }; #define CACHE_NR_REGS 3 -#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8) +/* No variant has more than 24 GPIOs */ +#define CACHE_NR_BANKS (24 / 8) struct stmpe_gpio { struct gpio_chip chip; @@ -31,8 +32,6 @@ struct stmpe_gpio { struct device *dev; struct mutex irq_lock; struct irq_domain *domain; - - int irq_base; unsigned norequest_mask; /* Caches of interrupt control registers for bus_lock */ @@ -311,13 +310,8 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, struct device_node *np) { - int base = 0; - - if (!np) - base = stmpe_gpio->irq_base; - stmpe_gpio->domain = irq_domain_add_simple(np, - stmpe_gpio->chip.ngpio, base, + stmpe_gpio->chip.ngpio, 0, &stmpe_gpio_irq_simple_ops, stmpe_gpio); if (!stmpe_gpio->domain) { dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); @@ -354,7 +348,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; #endif - stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; + stmpe_gpio->chip.base = -1; if (pdata) stmpe_gpio->norequest_mask = pdata->norequest_mask; @@ -362,9 +356,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev) of_property_read_u32(np, "st,norequest-mask", &stmpe_gpio->norequest_mask); - if (irq >= 0) - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); - else + if (irq < 0) dev_info(&pdev->dev, "device configured in no-irq mode; " "irqs are not available\n"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c94db1c5e353..620d1004a1e7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -449,7 +449,7 @@ config I2C_EFM32 config I2C_EG20T tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" - depends on PCI + depends on PCI && (X86_32 || COMPILE_TEST) help This driver is for PCH(Platform controller Hub) I2C of EG20T which is an IOH(Input/Output Hub) for x86 embedded processor. @@ -570,13 +570,6 @@ config I2C_NOMADIK I2C interface from ST-Ericsson's Nomadik and Ux500 architectures, as well as the STA2X11 PCIe I/O HUB. -config I2C_NUC900 - tristate "NUC900 I2C Driver" - depends on ARCH_W90X900 - help - Say Y here to include support for I2C controller in the - Winbond/Nuvoton NUC900 based System-on-Chip devices. - config I2C_OCORES tristate "OpenCores I2C Controller" help @@ -993,6 +986,15 @@ config I2C_SIBYTE help Supports the SiByte SOC on-chip I2C interfaces (2 channels). +config I2C_CROS_EC_TUNNEL + tristate "ChromeOS EC tunnel I2C bus" + depends on MFD_CROS_EC + help + If you say yes here you get an I2C bus that will tunnel i2c commands + through to the other side of the ChromeOS EC to the i2c bus + connected there. This will work whatever the interface used to + talk to the EC (SPI, I2C or LPC). + config SCx200_I2C tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" depends on SCx200_GPIO diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 18d18ff9db93..298692cc6000 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o -obj-$(CONFIG_I2C_NUC900) += i2c-nuc900.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o @@ -95,6 +94,7 @@ obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o # Other I2C/SMBus bus drivers obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o +obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 98a1c97739ba..15517d78d5ff 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -63,7 +63,7 @@ static struct pci_driver ali1563_pci_driver; static unsigned short ali1563_smba; -static int ali1563_transaction(struct i2c_adapter * a, int size) +static int ali1563_transaction(struct i2c_adapter *a, int size) { u32 data; int timeout; @@ -78,7 +78,7 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) { dev_err(&a->dev, "ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); + outb_p(data | HST_STS_BAD, SMB_HST_STS); data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) return -EBUSY; @@ -102,10 +102,10 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) if (!timeout) { dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n"); /* Issue 'kill' to host controller */ - outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); + outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2); data = inb_p(SMB_HST_STS); status = -ETIMEDOUT; - } + } /* device error - no response, ignore the autodetection case */ if (data & HST_STS_DEVERR) { @@ -117,18 +117,18 @@ static int ali1563_transaction(struct i2c_adapter * a, int size) if (data & HST_STS_BUSERR) { dev_err(&a->dev, "Bus collision!\n"); /* Issue timeout, hoping it helps */ - outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); + outb_p(HST_CNTL1_TIMEOUT, SMB_HST_CNTL1); } if (data & HST_STS_FAIL) { dev_err(&a->dev, "Cleaning fail after KILL!\n"); - outb_p(0x0,SMB_HST_CNTL2); + outb_p(0x0, SMB_HST_CNTL2); } return status; } -static int ali1563_block_start(struct i2c_adapter * a) +static int ali1563_block_start(struct i2c_adapter *a) { u32 data; int timeout; @@ -142,8 +142,8 @@ static int ali1563_block_start(struct i2c_adapter * a) data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) { - dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); - outb_p(data | HST_STS_BAD,SMB_HST_STS); + dev_warn(&a->dev, "ali1563: Trying to reset busy device\n"); + outb_p(data | HST_STS_BAD, SMB_HST_STS); data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) return -EBUSY; @@ -184,13 +184,14 @@ static int ali1563_block_start(struct i2c_adapter * a) return status; } -static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 rw) +static int ali1563_block(struct i2c_adapter *a, + union i2c_smbus_data *data, u8 rw) { int i, len; int error = 0; /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); if (rw == I2C_SMBUS_WRITE) { len = data->block[0]; @@ -198,8 +199,8 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 len = 1; else if (len > 32) len = 32; - outb_p(len,SMB_HST_DAT0); - outb_p(data->block[1],SMB_BLK_DAT); + outb_p(len, SMB_HST_DAT0); + outb_p(data->block[1], SMB_BLK_DAT); } else len = 32; @@ -208,10 +209,12 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 for (i = 0; i < len; i++) { if (rw == I2C_SMBUS_WRITE) { outb_p(data->block[i + 1], SMB_BLK_DAT); - if ((error = ali1563_block_start(a))) + error = ali1563_block_start(a); + if (error) break; } else { - if ((error = ali1563_block_start(a))) + error = ali1563_block_start(a); + if (error) break; if (i == 0) { len = inb_p(SMB_HST_DAT0); @@ -224,25 +227,26 @@ static int ali1563_block(struct i2c_adapter * a, union i2c_smbus_data * data, u8 } } /* Do we need this? */ - outb_p(HST_CNTL1_LAST,SMB_HST_CNTL1); + outb_p(HST_CNTL1_LAST, SMB_HST_CNTL1); return error; } -static s32 ali1563_access(struct i2c_adapter * a, u16 addr, +static s32 ali1563_access(struct i2c_adapter *a, u16 addr, unsigned short flags, char rw, u8 cmd, - int size, union i2c_smbus_data * data) + int size, union i2c_smbus_data *data) { int error = 0; int timeout; u32 reg; for (timeout = ALI1563_MAX_TIMEOUT; timeout; timeout--) { - if (!(reg = inb_p(SMB_HST_STS) & HST_STS_BUSY)) + reg = inb_p(SMB_HST_STS); + if (!(reg & HST_STS_BUSY)) break; } if (!timeout) - dev_warn(&a->dev,"SMBus not idle. HST_STS = %02x\n",reg); - outb_p(0xff,SMB_HST_STS); + dev_warn(&a->dev, "SMBus not idle. HST_STS = %02x\n", reg); + outb_p(0xff, SMB_HST_STS); /* Map the size to what the chip understands */ switch (size) { @@ -268,13 +272,14 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, } outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); - outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2); + outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | + (size << 3), SMB_HST_CNTL2); /* Write the command register */ - switch(size) { + switch (size) { case HST_CNTL2_BYTE: - if (rw== I2C_SMBUS_WRITE) + if (rw == I2C_SMBUS_WRITE) /* Beware it uses DAT0 register and not CMD! */ outb_p(cmd, SMB_HST_DAT0); break; @@ -292,11 +297,12 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, break; case HST_CNTL2_BLOCK: outb_p(cmd, SMB_HST_CMD); - error = ali1563_block(a,data,rw); + error = ali1563_block(a, data, rw); goto Done; } - if ((error = ali1563_transaction(a, size))) + error = ali1563_transaction(a, size); + if (error) goto Done; if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) @@ -317,7 +323,7 @@ Done: return error; } -static u32 ali1563_func(struct i2c_adapter * a) +static u32 ali1563_func(struct i2c_adapter *a) { return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | @@ -329,13 +335,13 @@ static int ali1563_setup(struct pci_dev *dev) { u16 ctrl; - pci_read_config_word(dev,ALI1563_SMBBA,&ctrl); + pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); /* SMB I/O Base in high 12 bits and must be aligned with the * size of the I/O space. */ ali1563_smba = ctrl & ~(ALI1563_SMB_IOSIZE - 1); if (!ali1563_smba) { - dev_warn(&dev->dev,"ali1563_smba Uninitialized\n"); + dev_warn(&dev->dev, "ali1563_smba Uninitialized\n"); goto Err; } @@ -350,8 +356,8 @@ static int ali1563_setup(struct pci_dev *dev) ctrl | ALI1563_SMB_IOEN); pci_read_config_word(dev, ALI1563_SMBBA, &ctrl); if (!(ctrl & ALI1563_SMB_IOEN)) { - dev_err(&dev->dev, "I/O space still not enabled, " - "giving up\n"); + dev_err(&dev->dev, + "I/O space still not enabled, giving up\n"); goto Err; } } @@ -375,7 +381,7 @@ Err: static void ali1563_shutdown(struct pci_dev *dev) { - release_region(ali1563_smba,ALI1563_SMB_IOSIZE); + release_region(ali1563_smba, ALI1563_SMB_IOSIZE); } static const struct i2c_algorithm ali1563_algorithm = { @@ -394,12 +400,14 @@ static int ali1563_probe(struct pci_dev *dev, { int error; - if ((error = ali1563_setup(dev))) + error = ali1563_setup(dev); + if (error) goto exit; ali1563_adapter.dev.parent = &dev->dev; snprintf(ali1563_adapter.name, sizeof(ali1563_adapter.name), "SMBus ALi 1563 Adapter @ %04x", ali1563_smba); - if ((error = i2c_add_adapter(&ali1563_adapter))) + error = i2c_add_adapter(&ali1563_adapter); + if (error) goto exit_shutdown; return 0; @@ -421,12 +429,12 @@ static const struct pci_device_id ali1563_id_table[] = { {}, }; -MODULE_DEVICE_TABLE (pci, ali1563_id_table); +MODULE_DEVICE_TABLE(pci, ali1563_id_table); static struct pci_driver ali1563_pci_driver = { - .name = "ali1563_smbus", + .name = "ali1563_smbus", .id_table = ali1563_id_table, - .probe = ali1563_probe, + .probe = ali1563_probe, .remove = ali1563_remove, }; diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index c60719577fc3..214ff9700efe 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -225,10 +225,8 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) struct i2c_adapter *adap; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "Cannot allocate i2c_dev\n"); + if (!i2c_dev) return -ENOMEM; - } platform_set_drvdata(pdev, i2c_dev); i2c_dev->dev = &pdev->dev; init_completion(&i2c_dev->completion); diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index e6d5162b6379..3e271e7558d3 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -620,35 +620,27 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) int rc; unsigned int clkhilow; - iface = kzalloc(sizeof(struct bfin_twi_iface), GFP_KERNEL); + iface = devm_kzalloc(&pdev->dev, sizeof(struct bfin_twi_iface), + GFP_KERNEL); if (!iface) { dev_err(&pdev->dev, "Cannot allocate memory\n"); - rc = -ENOMEM; - goto out_error_nomem; + return -ENOMEM; } spin_lock_init(&(iface->lock)); /* Find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n"); - rc = -ENOENT; - goto out_error_get_res; - } - - iface->regs_base = ioremap(res->start, resource_size(res)); - if (iface->regs_base == NULL) { + iface->regs_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(iface->regs_base)) { dev_err(&pdev->dev, "Cannot map IO\n"); - rc = -ENXIO; - goto out_error_ioremap; + return PTR_ERR(iface->regs_base); } iface->irq = platform_get_irq(pdev, 0); if (iface->irq < 0) { dev_err(&pdev->dev, "No IRQ specified\n"); - rc = -ENOENT; - goto out_error_no_irq; + return -ENOENT; } p_adap = &iface->adap; @@ -666,15 +658,15 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) "i2c-bfin-twi"); if (rc) { dev_err(&pdev->dev, "Can't setup pin mux!\n"); - goto out_error_pin_mux; + return -EBUSY; } - rc = request_irq(iface->irq, bfin_twi_interrupt_entry, + rc = devm_request_irq(&pdev->dev, iface->irq, bfin_twi_interrupt_entry, 0, pdev->name, iface); if (rc) { dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); rc = -ENODEV; - goto out_error_req_irq; + goto out_error; } /* Set TWI internal clock as 10MHz */ @@ -695,7 +687,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) rc = i2c_add_numbered_adapter(p_adap); if (rc < 0) { dev_err(&pdev->dev, "Can't add i2c adapter!\n"); - goto out_error_add_adapter; + goto out_error; } platform_set_drvdata(pdev, iface); @@ -705,17 +697,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) return 0; -out_error_add_adapter: - free_irq(iface->irq, iface); -out_error_req_irq: -out_error_no_irq: +out_error: peripheral_free_list(dev_get_platdata(&pdev->dev)); -out_error_pin_mux: - iounmap(iface->regs_base); -out_error_ioremap: -out_error_get_res: - kfree(iface); -out_error_nomem: return rc; } @@ -724,10 +707,7 @@ static int i2c_bfin_twi_remove(struct platform_device *pdev) struct bfin_twi_iface *iface = platform_get_drvdata(pdev); i2c_del_adapter(&(iface->adap)); - free_irq(iface->irq, iface); peripheral_free_list(dev_get_platdata(&pdev->dev)); - iounmap(iface->regs_base); - kfree(iface); return 0; } diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c new file mode 100644 index 000000000000..8e7a71487bb1 --- /dev/null +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Expose an I2C passthrough to the ChromeOS EC. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/mfd/cros_ec.h> +#include <linux/mfd/cros_ec_commands.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/** + * struct ec_i2c_device - Driver data for I2C tunnel + * + * @dev: Device node + * @adap: I2C adapter + * @ec: Pointer to EC device + * @remote_bus: The EC bus number we tunnel to on the other side. + * @request_buf: Buffer for transmitting data; we expect most transfers to fit. + * @response_buf: Buffer for receiving data; we expect most transfers to fit. + */ + +struct ec_i2c_device { + struct device *dev; + struct i2c_adapter adap; + struct cros_ec_device *ec; + + u16 remote_bus; + + u8 request_buf[256]; + u8 response_buf[256]; +}; + +/** + * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message + * + * @i2c_msgs: The i2c messages to read + * @num: The number of i2c messages. + * + * Returns the number of bytes the messages will take up. + */ +static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num) +{ + int i; + int size; + + size = sizeof(struct ec_params_i2c_passthru); + size += num * sizeof(struct ec_params_i2c_passthru_msg); + for (i = 0; i < num; i++) + if (!(i2c_msgs[i].flags & I2C_M_RD)) + size += i2c_msgs[i].len; + + return size; +} + +/** + * ec_i2c_construct_message - construct a message to go to the EC + * + * This function effectively stuffs the standard i2c_msg format of Linux into + * a format that the EC understands. + * + * @buf: The buffer to fill. We assume that the buffer is big enough. + * @i2c_msgs: The i2c messages to read. + * @num: The number of i2c messages. + * @bus_num: The remote bus number we want to talk to. + * + * Returns 0 or a negative error number. + */ +static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[], + int num, u16 bus_num) +{ + struct ec_params_i2c_passthru *params; + u8 *out_data; + int i; + + out_data = buf + sizeof(struct ec_params_i2c_passthru) + + num * sizeof(struct ec_params_i2c_passthru_msg); + + params = (struct ec_params_i2c_passthru *)buf; + params->port = bus_num; + params->num_msgs = num; + for (i = 0; i < num; i++) { + const struct i2c_msg *i2c_msg = &i2c_msgs[i]; + struct ec_params_i2c_passthru_msg *msg = ¶ms->msg[i]; + + msg->len = i2c_msg->len; + msg->addr_flags = i2c_msg->addr; + + if (i2c_msg->flags & I2C_M_TEN) + msg->addr_flags |= EC_I2C_FLAG_10BIT; + + if (i2c_msg->flags & I2C_M_RD) { + msg->addr_flags |= EC_I2C_FLAG_READ; + } else { + memcpy(out_data, i2c_msg->buf, msg->len); + out_data += msg->len; + } + } + + return 0; +} + +/** + * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response + * + * @i2c_msgs: The i2c messages to to fill up. + * @num: The number of i2c messages expected. + * + * Returns the number of response bytes expeced. + */ +static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num) +{ + int size; + int i; + + size = sizeof(struct ec_response_i2c_passthru); + for (i = 0; i < num; i++) + if (i2c_msgs[i].flags & I2C_M_RD) + size += i2c_msgs[i].len; + + return size; +} + +/** + * ec_i2c_parse_response - Parse a response from the EC + * + * We'll take the EC's response and copy it back into msgs. + * + * @buf: The buffer to parse. + * @i2c_msgs: The i2c messages to to fill up. + * @num: The number of i2c messages; will be modified to include the actual + * number received. + * + * Returns 0 or a negative error number. + */ +static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[], + int *num) +{ + const struct ec_response_i2c_passthru *resp; + const u8 *in_data; + int i; + + in_data = buf + sizeof(struct ec_response_i2c_passthru); + + resp = (const struct ec_response_i2c_passthru *)buf; + if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT) + return -ETIMEDOUT; + else if (resp->i2c_status & EC_I2C_STATUS_ERROR) + return -EREMOTEIO; + + /* Other side could send us back fewer messages, but not more */ + if (resp->num_msgs > *num) + return -EPROTO; + *num = resp->num_msgs; + + for (i = 0; i < *num; i++) { + struct i2c_msg *i2c_msg = &i2c_msgs[i]; + + if (i2c_msgs[i].flags & I2C_M_RD) { + memcpy(i2c_msg->buf, in_data, i2c_msg->len); + in_data += i2c_msg->len; + } + } + + return 0; +} + +static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], + int num) +{ + struct ec_i2c_device *bus = adap->algo_data; + struct device *dev = bus->dev; + const u16 bus_num = bus->remote_bus; + int request_len; + int response_len; + u8 *request = NULL; + u8 *response = NULL; + int result; + + request_len = ec_i2c_count_message(i2c_msgs, num); + if (request_len < 0) { + dev_warn(dev, "Error constructing message %d\n", request_len); + result = request_len; + goto exit; + } + response_len = ec_i2c_count_response(i2c_msgs, num); + if (response_len < 0) { + /* Unexpected; no errors should come when NULL response */ + dev_warn(dev, "Error preparing response %d\n", response_len); + result = response_len; + goto exit; + } + + if (request_len <= ARRAY_SIZE(bus->request_buf)) { + request = bus->request_buf; + } else { + request = kzalloc(request_len, GFP_KERNEL); + if (request == NULL) { + result = -ENOMEM; + goto exit; + } + } + if (response_len <= ARRAY_SIZE(bus->response_buf)) { + response = bus->response_buf; + } else { + response = kzalloc(response_len, GFP_KERNEL); + if (response == NULL) { + result = -ENOMEM; + goto exit; + } + } + + ec_i2c_construct_message(request, i2c_msgs, num, bus_num); + result = bus->ec->command_sendrecv(bus->ec, EC_CMD_I2C_PASSTHRU, + request, request_len, + response, response_len); + if (result) + goto exit; + + result = ec_i2c_parse_response(response, i2c_msgs, &num); + if (result < 0) + goto exit; + + /* Indicate success by saying how many messages were sent */ + result = num; +exit: + if (request != bus->request_buf) + kfree(request); + if (response != bus->response_buf) + kfree(response); + + return result; +} + +static u32 ec_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ec_i2c_algorithm = { + .master_xfer = ec_i2c_xfer, + .functionality = ec_i2c_functionality, +}; + +static int ec_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct ec_i2c_device *bus = NULL; + u32 remote_bus; + int err; + + if (!ec->command_sendrecv) { + dev_err(dev, "Missing sendrecv\n"); + return -EINVAL; + } + + bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL); + if (bus == NULL) + return -ENOMEM; + + err = of_property_read_u32(np, "google,remote-bus", &remote_bus); + if (err) { + dev_err(dev, "Couldn't read remote-bus property\n"); + return err; + } + bus->remote_bus = remote_bus; + + bus->ec = ec; + bus->dev = dev; + + bus->adap.owner = THIS_MODULE; + strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name)); + bus->adap.algo = &ec_i2c_algorithm; + bus->adap.algo_data = bus; + bus->adap.dev.parent = &pdev->dev; + bus->adap.dev.of_node = np; + + err = i2c_add_adapter(&bus->adap); + if (err) { + dev_err(dev, "cannot register i2c adapter\n"); + return err; + } + platform_set_drvdata(pdev, bus); + + return err; +} + +static int ec_i2c_remove(struct platform_device *dev) +{ + struct ec_i2c_device *bus = platform_get_drvdata(dev); + + i2c_del_adapter(&bus->adap); + + return 0; +} + +static struct platform_driver ec_i2c_tunnel_driver = { + .probe = ec_i2c_probe, + .remove = ec_i2c_remove, + .driver = { + .name = "cros-ec-i2c-tunnel", + }, +}; + +module_platform_driver(ec_i2c_tunnel_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EC I2C tunnel driver"); +MODULE_ALIAS("platform:cros-ec-i2c-tunnel"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 85056c22d21e..3356f7ab9f79 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -56,6 +56,7 @@ enum dw_pci_ctl_id_t { medfield_5, baytrail, + haswell, }; struct dw_scl_sda_cfg { @@ -95,6 +96,15 @@ static struct dw_scl_sda_cfg byt_config = { .sda_hold = 0x6, }; +/* Haswell HCNT/LCNT/SDA hold time */ +static struct dw_scl_sda_cfg hsw_config = { + .ss_hcnt = 0x01b0, + .fs_hcnt = 0x48, + .ss_lcnt = 0x01fb, + .fs_lcnt = 0xa0, + .sda_hold = 0x9, +}; + static struct dw_pci_controller dw_pci_controllers[] = { [moorestown_0] = { .bus_num = 0, @@ -168,6 +178,15 @@ static struct dw_pci_controller dw_pci_controllers[] = { .functionality = I2C_FUNC_10BIT_ADDR, .scl_sda_cfg = &byt_config, }, + [haswell] = { + .bus_num = -1, + .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, + .tx_fifo_depth = 32, + .rx_fifo_depth = 32, + .clk_khz = 100000, + .functionality = I2C_FUNC_10BIT_ADDR, + .scl_sda_cfg = &hsw_config, + }, }; static struct i2c_algorithm i2c_dw_algo = { .master_xfer = i2c_dw_xfer, @@ -328,6 +347,9 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0F45), baytrail }, { PCI_VDEVICE(INTEL, 0x0F46), baytrail }, { PCI_VDEVICE(INTEL, 0x0F47), baytrail }, + /* Haswell */ + { PCI_VDEVICE(INTEL, 0x9c61), haswell }, + { PCI_VDEVICE(INTEL, 0x9c62), haswell }, { 0,} }; MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 9c7802614342..402ec3970fed 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -247,12 +247,13 @@ static const struct of_device_id dw_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #endif -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM static int dw_i2c_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev); + i2c_dw_disable(i_dev); clk_disable_unprepare(i_dev->clk); return 0; @@ -268,13 +269,11 @@ static int dw_i2c_resume(struct device *dev) return 0; } - -static SIMPLE_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, dw_i2c_resume); -#define DW_I2C_DEV_PM_OPS (&dw_i2c_dev_pm_ops) -#else -#define DW_I2C_DEV_PM_OPS NULL #endif +static UNIVERSAL_DEV_PM_OPS(dw_i2c_dev_pm_ops, dw_i2c_suspend, + dw_i2c_resume, NULL); + /* work with hotplug and coldplug */ MODULE_ALIAS("platform:i2c_designware"); @@ -286,7 +285,7 @@ static struct platform_driver dw_i2c_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(dw_i2c_of_match), .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), - .pm = DW_I2C_DEV_PM_OPS, + .pm = &dw_i2c_dev_pm_ops, }, }; diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index 721f7ebf9a3b..b19a310bf9b3 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -455,7 +455,6 @@ static int diolan_u2c_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - dev_err(&interface->dev, "no memory for device state\n"); ret = -ENOMEM; goto error; } diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index 777ed409a24a..f7eccd682de9 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -320,10 +320,8 @@ static int efm32_i2c_probe(struct platform_device *pdev) return -EINVAL; ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) { - dev_dbg(&pdev->dev, "failed to allocate private data\n"); + if (!ddata) return -ENOMEM; - } platform_set_drvdata(pdev, ddata); init_completion(&ddata->done); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index ff775ac29e49..a44ea13d1434 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -751,10 +751,8 @@ static int pch_i2c_probe(struct pci_dev *pdev, pch_pci_dbg(pdev, "Entered.\n"); adap_info = kzalloc((sizeof(struct adapter_info)), GFP_KERNEL); - if (adap_info == NULL) { - pch_pci_err(pdev, "Memory allocation FAILED\n"); + if (adap_info == NULL) return -ENOMEM; - } ret = pci_enable_device(pdev); if (ret) { diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 00af0a0a3361..63d229202854 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -76,12 +76,6 @@ #define HSI2C_RXFIFO_TRIGGER_LEVEL(x) ((x) << 4) #define HSI2C_TXFIFO_TRIGGER_LEVEL(x) ((x) << 16) -/* As per user manual FIFO max depth is 64bytes */ -#define HSI2C_FIFO_MAX 0x40 -/* default trigger levels for Tx and Rx FIFOs */ -#define HSI2C_DEF_TXFIFO_LVL (HSI2C_FIFO_MAX - 0x30) -#define HSI2C_DEF_RXFIFO_LVL (HSI2C_FIFO_MAX - 0x10) - /* I2C_TRAILING_CTL Register bits */ #define HSI2C_TRAILING_COUNT (0xf) @@ -183,14 +177,54 @@ struct exynos5_i2c { * 2. Fast speed upto 1Mbps */ int speed_mode; + + /* Version of HS-I2C Hardware */ + struct exynos_hsi2c_variant *variant; +}; + +/** + * struct exynos_hsi2c_variant - platform specific HSI2C driver data + * @fifo_depth: the fifo depth supported by the HSI2C module + * + * Specifies platform specific configuration of HSI2C module. + * Note: A structure for driver specific platform data is used for future + * expansion of its usage. + */ +struct exynos_hsi2c_variant { + unsigned int fifo_depth; +}; + +static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { + .fifo_depth = 64, +}; + +static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { + .fifo_depth = 16, }; static const struct of_device_id exynos5_i2c_match[] = { - { .compatible = "samsung,exynos5-hsi2c" }, - {}, + { + .compatible = "samsung,exynos5-hsi2c", + .data = &exynos5250_hsi2c_data + }, { + .compatible = "samsung,exynos5250-hsi2c", + .data = &exynos5250_hsi2c_data + }, { + .compatible = "samsung,exynos5260-hsi2c", + .data = &exynos5260_hsi2c_data + }, {}, }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); +static inline struct exynos_hsi2c_variant *exynos5_i2c_get_variant + (struct platform_device *pdev) +{ + const struct of_device_id *match; + + match = of_match_node(exynos5_i2c_match, pdev->dev.of_node); + return (struct exynos_hsi2c_variant *)match->data; +} + static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) { writel(readl(i2c->regs + HSI2C_INT_STATUS), @@ -415,7 +449,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) fifo_status = readl(i2c->regs + HSI2C_FIFO_STATUS); fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); - len = HSI2C_FIFO_MAX - fifo_level; + len = i2c->variant->fifo_depth - fifo_level; if (len > (i2c->msg->len - i2c->msg_ptr)) len = i2c->msg->len - i2c->msg_ptr; @@ -483,6 +517,7 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) u32 i2c_auto_conf = 0; u32 fifo_ctl; unsigned long flags; + unsigned short trig_lvl; i2c_ctl = readl(i2c->regs + HSI2C_CTL); i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); @@ -493,13 +528,19 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) i2c_auto_conf = HSI2C_READ_WRITE; - fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(HSI2C_DEF_TXFIFO_LVL); + trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? + (i2c->variant->fifo_depth * 3 / 4) : i2c->msg->len; + fifo_ctl |= HSI2C_RXFIFO_TRIGGER_LEVEL(trig_lvl); + int_en |= (HSI2C_INT_RX_ALMOSTFULL_EN | HSI2C_INT_TRAILING_EN); } else { i2c_ctl |= HSI2C_TXCHON; - fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(HSI2C_DEF_RXFIFO_LVL); + trig_lvl = (i2c->msg->len > i2c->variant->fifo_depth) ? + (i2c->variant->fifo_depth * 1 / 4) : i2c->msg->len; + fifo_ctl |= HSI2C_TXFIFO_TRIGGER_LEVEL(trig_lvl); + int_en |= HSI2C_INT_TX_ALMOSTEMPTY_EN; } @@ -621,10 +662,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev) int ret; i2c = devm_kzalloc(&pdev->dev, sizeof(struct exynos5_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); + if (!i2c) return -ENOMEM; - } if (of_property_read_u32(np, "clock-frequency", &op_clock)) { i2c->speed_mode = HSI2C_FAST_SPD; @@ -691,7 +730,9 @@ static int exynos5_i2c_probe(struct platform_device *pdev) if (ret) goto err_clk; - exynos5_i2c_init(i2c); + i2c->variant = exynos5_i2c_get_variant(pdev); + + exynos5_i2c_reset(i2c); ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 02d2d4abb9dd..71a45b210a24 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -147,24 +147,22 @@ static int i2c_gpio_probe(struct platform_device *pdev) scl_pin = pdata->scl_pin; } - ret = gpio_request(sda_pin, "sda"); + ret = devm_gpio_request(&pdev->dev, sda_pin, "sda"); if (ret) { if (ret == -EINVAL) ret = -EPROBE_DEFER; /* Try again later */ - goto err_request_sda; + return ret; } - ret = gpio_request(scl_pin, "scl"); + ret = devm_gpio_request(&pdev->dev, scl_pin, "scl"); if (ret) { if (ret == -EINVAL) ret = -EPROBE_DEFER; /* Try again later */ - goto err_request_scl; + return ret; } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_add_bus; - } + if (!priv) + return -ENOMEM; adap = &priv->adap; bit_data = &priv->bit_data; pdata = &priv->pdata; @@ -225,7 +223,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); if (ret) - goto err_add_bus; + return ret; platform_set_drvdata(pdev, priv); @@ -235,13 +233,6 @@ static int i2c_gpio_probe(struct platform_device *pdev) ? ", no clock stretching" : ""); return 0; - -err_add_bus: - gpio_free(scl_pin); -err_request_scl: - gpio_free(sda_pin); -err_request_sda: - return ret; } static int i2c_gpio_remove(struct platform_device *pdev) @@ -255,8 +246,6 @@ static int i2c_gpio_remove(struct platform_device *pdev) pdata = &priv->pdata; i2c_del_adapter(adap); - gpio_free(pdata->scl_pin); - gpio_free(pdata->sda_pin); return 0; } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index db895fb22e65..aa8bc146718b 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -183,6 +183,8 @@ struct imx_i2c_struct { unsigned int disable_delay; int stopped; unsigned int ifdr; /* IMX_I2C_IFDR */ + unsigned int cur_clk; + unsigned int bitrate; const struct imx_i2c_hwdata *hwdata; }; @@ -305,6 +307,48 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) return 0; } +static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx) +{ + struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; + unsigned int i2c_clk_rate; + unsigned int div; + int i; + + /* Divider value calculation */ + i2c_clk_rate = clk_get_rate(i2c_imx->clk); + if (i2c_imx->cur_clk == i2c_clk_rate) + return; + else + i2c_imx->cur_clk = i2c_clk_rate; + + div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate; + if (div < i2c_clk_div[0].div) + i = 0; + else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) + i = i2c_imx->hwdata->ndivs - 1; + else + for (i = 0; i2c_clk_div[i].div < div; i++); + + /* Store divider value */ + i2c_imx->ifdr = i2c_clk_div[i].val; + + /* + * There dummy delay is calculated. + * It should be about one I2C clock period long. + * This delay is used in I2C bus disable function + * to fix chip hardware bug. + */ + i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div + + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); + +#ifdef CONFIG_I2C_DEBUG_BUS + dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n", + i2c_clk_rate, div); + dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n", + i2c_clk_div[i].val, i2c_clk_div[i].div); +#endif +} + static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) { unsigned int temp = 0; @@ -312,6 +356,8 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx) dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); + i2c_imx_set_clk(i2c_imx); + result = clk_prepare_enable(i2c_imx->clk); if (result) return result; @@ -367,45 +413,6 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx) clk_disable_unprepare(i2c_imx->clk); } -static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, - unsigned int rate) -{ - struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; - unsigned int i2c_clk_rate; - unsigned int div; - int i; - - /* Divider value calculation */ - i2c_clk_rate = clk_get_rate(i2c_imx->clk); - div = (i2c_clk_rate + rate - 1) / rate; - if (div < i2c_clk_div[0].div) - i = 0; - else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) - i = i2c_imx->hwdata->ndivs - 1; - else - for (i = 0; i2c_clk_div[i].div < div; i++); - - /* Store divider value */ - i2c_imx->ifdr = i2c_clk_div[i].val; - - /* - * There dummy delay is calculated. - * It should be about one I2C clock period long. - * This delay is used in I2C bus disable function - * to fix chip hardware bug. - */ - i2c_imx->disable_delay = (500000U * i2c_clk_div[i].div - + (i2c_clk_rate / 2) - 1) / (i2c_clk_rate / 2); - - /* dev_dbg() can't be used, because adapter is not yet registered */ -#ifdef CONFIG_I2C_DEBUG_BUS - dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n", - __func__, i2c_clk_rate, div); - dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n", - __func__, i2c_clk_div[i].val, i2c_clk_div[i].div); -#endif -} - static irqreturn_t i2c_imx_isr(int irq, void *dev_id) { struct imx_i2c_struct *i2c_imx = dev_id; @@ -458,10 +465,11 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { int i, result; unsigned int temp; + int block_data = msgs->flags & I2C_M_RECV_LEN; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", @@ -481,7 +489,12 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) /* setup bus to read data */ temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp &= ~I2CR_MTX; - if (msgs->len - 1) + + /* + * Reset the I2CR_TXAK flag initially for SMBus block read since the + * length is unknown + */ + if ((msgs->len - 1) || block_data) temp &= ~I2CR_TXAK; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ @@ -490,19 +503,49 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) /* read data */ for (i = 0; i < msgs->len; i++) { + u8 len = 0; result = i2c_imx_trx_complete(i2c_imx); if (result) return result; - if (i == (msgs->len - 1)) { - /* It must generate STOP before read I2DR to prevent - controller from generating another clock cycle */ + /* + * First byte is the length of remaining packet + * in the SMBus block data read. Add it to + * msgs->len. + */ + if ((!i) && block_data) { + len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) + return -EPROTO; dev_dbg(&i2c_imx->adapter.dev, - "<%s> clear MSTA\n", __func__); - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp &= ~(I2CR_MSTA | I2CR_MTX); - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - i2c_imx_bus_busy(i2c_imx, 0); - i2c_imx->stopped = 1; + "<%s> read length: 0x%X\n", + __func__, len); + msgs->len += len; + } + if (i == (msgs->len - 1)) { + if (is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + dev_dbg(&i2c_imx->adapter.dev, + "<%s> clear MSTA\n", __func__); + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + i2c_imx_bus_busy(i2c_imx, 0); + i2c_imx->stopped = 1; + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = readb(i2c_imx->base + IMX_I2C_I2CR); + temp |= I2CR_MTX; + writeb(temp, i2c_imx->base + IMX_I2C_I2CR); + } } else if (i == (msgs->len - 2)) { dev_dbg(&i2c_imx->adapter.dev, "<%s> set TXAK\n", __func__); @@ -510,7 +553,10 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) temp |= I2CR_TXAK; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); } - msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + if ((!i) && block_data) + msgs->buf[0] = len; + else + msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); dev_dbg(&i2c_imx->adapter.dev, "<%s> read byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); @@ -523,6 +569,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, { unsigned int i, temp; int result; + bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__); @@ -534,6 +581,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, /* read/write data */ for (i = 0; i < num; i++) { + if (i == num - 1) + is_lastmsg = true; + if (i) { dev_dbg(&i2c_imx->adapter.dev, "<%s> repeated start\n", __func__); @@ -564,7 +614,7 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, (temp & I2SR_RXAK ? 1 : 0)); #endif if (msgs[i].flags & I2C_M_RD) - result = i2c_imx_read(i2c_imx, &msgs[i]); + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); else result = i2c_imx_write(i2c_imx, &msgs[i]); if (result) @@ -583,7 +633,8 @@ fail0: static u32 i2c_imx_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL + | I2C_FUNC_SMBUS_READ_BLOCK_DATA; } static struct i2c_algorithm i2c_imx_algo = { @@ -600,7 +651,6 @@ static int i2c_imx_probe(struct platform_device *pdev) struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev); void __iomem *base; int irq, ret; - u32 bitrate; dev_dbg(&pdev->dev, "<%s>\n", __func__); @@ -617,10 +667,8 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx = devm_kzalloc(&pdev->dev, sizeof(struct imx_i2c_struct), GFP_KERNEL); - if (!i2c_imx) { - dev_err(&pdev->dev, "can't allocate interface\n"); + if (!i2c_imx) return -ENOMEM; - } if (of_id) i2c_imx->hwdata = of_id->data; @@ -664,12 +712,11 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); /* Set up clock divider */ - bitrate = IMX_I2C_BIT_RATE; + i2c_imx->bitrate = IMX_I2C_BIT_RATE; ret = of_property_read_u32(pdev->dev.of_node, - "clock-frequency", &bitrate); + "clock-frequency", &i2c_imx->bitrate); if (ret < 0 && pdata && pdata->bitrate) - bitrate = pdata->bitrate; - i2c_imx_set_clk(i2c_imx, bitrate); + i2c_imx->bitrate = pdata->bitrate; /* Set up chip registers to defaults */ imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index f5391633b53a..6a32aa095f83 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -115,7 +115,7 @@ static void mpc_i2c_fixup(struct mpc_i2c *i2c) for (k = 9; k; k--) { writeccr(i2c, 0); writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); - udelay(delay_val); + readb(i2c->base + MPC_I2C_DR); writeccr(i2c, CCR_MEN); udelay(delay_val << 1); } diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 540ea692bf79..9f4b775e2e39 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -681,7 +681,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { ***************************************************************************** */ static const struct of_device_id mv64xxx_i2c_of_match_table[] = { - { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, + { .compatible = "allwinner,sun4i-a10-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 32c85e9ecdae..0e55d85fd4ed 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -879,19 +879,19 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) #ifdef CONFIG_PM_SLEEP static int nmk_i2c_suspend_late(struct device *dev) { - pinctrl_pm_select_sleep_state(dev); + int ret; + ret = pm_runtime_force_suspend(dev); + if (ret) + return ret; + + pinctrl_pm_select_sleep_state(dev); return 0; } static int nmk_i2c_resume_early(struct device *dev) { - /* First go to the default state */ - pinctrl_pm_select_default_state(dev); - /* Then let's idle the pins until the next transfer happens */ - pinctrl_pm_select_idle_state(dev); - - return 0; + return pm_runtime_force_resume(dev); } #endif diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c deleted file mode 100644 index 36394d737faf..000000000000 --- a/drivers/i2c/busses/i2c-nuc900.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * linux/drivers/i2c/busses/i2c-nuc900.c - * - * Copyright (c) 2010 Nuvoton technology corporation. - * - * This driver based on S3C2410 I2C driver of Ben Dooks <ben-Y5A6D6n0/KfQXOPxS62xeg@public.gmane.org>. - * Written by Wan ZongShun <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation;version 2 of the License. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/cpufreq.h> -#include <linux/slab.h> -#include <linux/io.h> - -#include <mach/mfp.h> -#include <linux/platform_data/i2c-nuc900.h> - -/* nuc900 i2c registers offset */ - -#define CSR 0x00 -#define DIVIDER 0x04 -#define CMDR 0x08 -#define SWR 0x0C -#define RXR 0x10 -#define TXR 0x14 - -/* nuc900 i2c CSR register bits */ - -#define IRQEN 0x003 -#define I2CBUSY 0x400 -#define I2CSTART 0x018 -#define IRQFLAG 0x004 -#define ARBIT_LOST 0x200 -#define SLAVE_ACK 0x800 - -/* nuc900 i2c CMDR register bits */ - -#define I2C_CMD_START 0x10 -#define I2C_CMD_STOP 0x08 -#define I2C_CMD_READ 0x04 -#define I2C_CMD_WRITE 0x02 -#define I2C_CMD_NACK 0x01 - -/* i2c controller state */ - -enum nuc900_i2c_state { - STATE_IDLE, - STATE_START, - STATE_READ, - STATE_WRITE, - STATE_STOP -}; - -/* i2c controller private data */ - -struct nuc900_i2c { - spinlock_t lock; - wait_queue_head_t wait; - - struct i2c_msg *msg; - unsigned int msg_num; - unsigned int msg_idx; - unsigned int msg_ptr; - unsigned int irq; - - enum nuc900_i2c_state state; - - void __iomem *regs; - struct clk *clk; - struct device *dev; - struct resource *ioarea; - struct i2c_adapter adap; -}; - -/* nuc900_i2c_master_complete - * - * complete the message and wake up the caller, using the given return code, - * or zero to mean ok. -*/ - -static inline void nuc900_i2c_master_complete(struct nuc900_i2c *i2c, int ret) -{ - dev_dbg(i2c->dev, "master_complete %d\n", ret); - - i2c->msg_ptr = 0; - i2c->msg = NULL; - i2c->msg_idx++; - i2c->msg_num = 0; - if (ret) - i2c->msg_idx = ret; - - wake_up(&i2c->wait); -} - -/* irq enable/disable functions */ - -static inline void nuc900_i2c_disable_irq(struct nuc900_i2c *i2c) -{ - unsigned long tmp; - - tmp = readl(i2c->regs + CSR); - writel(tmp & ~IRQEN, i2c->regs + CSR); -} - -static inline void nuc900_i2c_enable_irq(struct nuc900_i2c *i2c) -{ - unsigned long tmp; - - tmp = readl(i2c->regs + CSR); - writel(tmp | IRQEN, i2c->regs + CSR); -} - - -/* nuc900_i2c_message_start - * - * put the start of a message onto the bus -*/ - -static void nuc900_i2c_message_start(struct nuc900_i2c *i2c, - struct i2c_msg *msg) -{ - unsigned int addr = (msg->addr & 0x7f) << 1; - - if (msg->flags & I2C_M_RD) - addr |= 0x1; - writel(addr & 0xff, i2c->regs + TXR); - writel(I2C_CMD_START | I2C_CMD_WRITE, i2c->regs + CMDR); -} - -static inline void nuc900_i2c_stop(struct nuc900_i2c *i2c, int ret) -{ - - dev_dbg(i2c->dev, "STOP\n"); - - /* stop the transfer */ - i2c->state = STATE_STOP; - writel(I2C_CMD_STOP, i2c->regs + CMDR); - - nuc900_i2c_master_complete(i2c, ret); - nuc900_i2c_disable_irq(i2c); -} - -/* helper functions to determine the current state in the set of - * messages we are sending -*/ - -/* is_lastmsg() - * - * returns TRUE if the current message is the last in the set -*/ - -static inline int is_lastmsg(struct nuc900_i2c *i2c) -{ - return i2c->msg_idx >= (i2c->msg_num - 1); -} - -/* is_msglast - * - * returns TRUE if we this is the last byte in the current message -*/ - -static inline int is_msglast(struct nuc900_i2c *i2c) -{ - return i2c->msg_ptr == i2c->msg->len-1; -} - -/* is_msgend - * - * returns TRUE if we reached the end of the current message -*/ - -static inline int is_msgend(struct nuc900_i2c *i2c) -{ - return i2c->msg_ptr >= i2c->msg->len; -} - -/* i2c_nuc900_irq_nextbyte - * - * process an interrupt and work out what to do - */ - -static void i2c_nuc900_irq_nextbyte(struct nuc900_i2c *i2c, - unsigned long iicstat) -{ - unsigned char byte; - - switch (i2c->state) { - - case STATE_IDLE: - dev_err(i2c->dev, "%s: called in STATE_IDLE\n", __func__); - break; - - case STATE_STOP: - dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__); - nuc900_i2c_disable_irq(i2c); - break; - - case STATE_START: - /* last thing we did was send a start condition on the - * bus, or started a new i2c message - */ - - if (iicstat & SLAVE_ACK && - !(i2c->msg->flags & I2C_M_IGNORE_NAK)) { - /* ack was not received... */ - - dev_dbg(i2c->dev, "ack was not received\n"); - nuc900_i2c_stop(i2c, -ENXIO); - break; - } - - if (i2c->msg->flags & I2C_M_RD) - i2c->state = STATE_READ; - else - i2c->state = STATE_WRITE; - - /* terminate the transfer if there is nothing to do - * as this is used by the i2c probe to find devices. - */ - - if (is_lastmsg(i2c) && i2c->msg->len == 0) { - nuc900_i2c_stop(i2c, 0); - break; - } - - if (i2c->state == STATE_READ) - goto prepare_read; - - /* fall through to the write state, as we will need to - * send a byte as well - */ - - case STATE_WRITE: - /* we are writing data to the device... check for the - * end of the message, and if so, work out what to do - */ - - if (!(i2c->msg->flags & I2C_M_IGNORE_NAK)) { - if (iicstat & SLAVE_ACK) { - dev_dbg(i2c->dev, "WRITE: No Ack\n"); - - nuc900_i2c_stop(i2c, -ECONNREFUSED); - break; - } - } - -retry_write: - - if (!is_msgend(i2c)) { - byte = i2c->msg->buf[i2c->msg_ptr++]; - writeb(byte, i2c->regs + TXR); - writel(I2C_CMD_WRITE, i2c->regs + CMDR); - - } else if (!is_lastmsg(i2c)) { - /* we need to go to the next i2c message */ - - dev_dbg(i2c->dev, "WRITE: Next Message\n"); - - i2c->msg_ptr = 0; - i2c->msg_idx++; - i2c->msg++; - - /* check to see if we need to do another message */ - if (i2c->msg->flags & I2C_M_NOSTART) { - - if (i2c->msg->flags & I2C_M_RD) { - /* cannot do this, the controller - * forces us to send a new START - * when we change direction - */ - - nuc900_i2c_stop(i2c, -EINVAL); - } - - goto retry_write; - } else { - /* send the new start */ - nuc900_i2c_message_start(i2c, i2c->msg); - i2c->state = STATE_START; - } - - } else { - /* send stop */ - - nuc900_i2c_stop(i2c, 0); - } - break; - - case STATE_READ: - /* we have a byte of data in the data register, do - * something with it, and then work out whether we are - * going to do any more read/write - */ - - byte = readb(i2c->regs + RXR); - i2c->msg->buf[i2c->msg_ptr++] = byte; - -prepare_read: - if (is_msglast(i2c)) { - /* last byte of buffer */ - - if (is_lastmsg(i2c)) - writel(I2C_CMD_READ | I2C_CMD_NACK, - i2c->regs + CMDR); - - } else if (is_msgend(i2c)) { - /* ok, we've read the entire buffer, see if there - * is anything else we need to do - */ - - if (is_lastmsg(i2c)) { - /* last message, send stop and complete */ - dev_dbg(i2c->dev, "READ: Send Stop\n"); - - nuc900_i2c_stop(i2c, 0); - } else { - /* go to the next transfer */ - dev_dbg(i2c->dev, "READ: Next Transfer\n"); - - i2c->msg_ptr = 0; - i2c->msg_idx++; - i2c->msg++; - - writel(I2C_CMD_READ, i2c->regs + CMDR); - } - - } else { - writel(I2C_CMD_READ, i2c->regs + CMDR); - } - - break; - } -} - -/* nuc900_i2c_irq - * - * top level IRQ servicing routine -*/ - -static irqreturn_t nuc900_i2c_irq(int irqno, void *dev_id) -{ - struct nuc900_i2c *i2c = dev_id; - unsigned long status; - - status = readl(i2c->regs + CSR); - writel(status | IRQFLAG, i2c->regs + CSR); - - if (status & ARBIT_LOST) { - /* deal with arbitration loss */ - dev_err(i2c->dev, "deal with arbitration loss\n"); - goto out; - } - - if (i2c->state == STATE_IDLE) { - dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n"); - goto out; - } - - /* pretty much this leaves us with the fact that we've - * transmitted or received whatever byte we last sent - */ - - i2c_nuc900_irq_nextbyte(i2c, status); - - out: - return IRQ_HANDLED; -} - - -/* nuc900_i2c_set_master - * - * get the i2c bus for a master transaction -*/ - -static int nuc900_i2c_set_master(struct nuc900_i2c *i2c) -{ - int timeout = 400; - - while (timeout-- > 0) { - if (((readl(i2c->regs + SWR) & I2CSTART) == I2CSTART) && - ((readl(i2c->regs + CSR) & I2CBUSY) == 0)) { - return 0; - } - - msleep(1); - } - - return -ETIMEDOUT; -} - -/* nuc900_i2c_doxfer - * - * this starts an i2c transfer -*/ - -static int nuc900_i2c_doxfer(struct nuc900_i2c *i2c, - struct i2c_msg *msgs, int num) -{ - unsigned long iicstat, timeout; - int spins = 20; - int ret; - - ret = nuc900_i2c_set_master(i2c); - if (ret != 0) { - dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); - ret = -EAGAIN; - goto out; - } - - spin_lock_irq(&i2c->lock); - - i2c->msg = msgs; - i2c->msg_num = num; - i2c->msg_ptr = 0; - i2c->msg_idx = 0; - i2c->state = STATE_START; - - nuc900_i2c_message_start(i2c, msgs); - spin_unlock_irq(&i2c->lock); - - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - - ret = i2c->msg_idx; - - /* having these next two as dev_err() makes life very - * noisy when doing an i2cdetect - */ - - if (timeout == 0) - dev_dbg(i2c->dev, "timeout\n"); - else if (ret != num) - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); - - /* ensure the stop has been through the bus */ - - dev_dbg(i2c->dev, "waiting for bus idle\n"); - - /* first, try busy waiting briefly */ - do { - iicstat = readl(i2c->regs + CSR); - } while ((iicstat & I2CBUSY) && --spins); - - /* if that timed out sleep */ - if (!spins) { - msleep(1); - iicstat = readl(i2c->regs + CSR); - } - - if (iicstat & I2CBUSY) - dev_warn(i2c->dev, "timeout waiting for bus idle\n"); - - out: - return ret; -} - -/* nuc900_i2c_xfer - * - * first port of call from the i2c bus code when an message needs - * transferring across the i2c bus. -*/ - -static int nuc900_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct nuc900_i2c *i2c = (struct nuc900_i2c *)adap->algo_data; - int retry; - int ret; - - nuc900_i2c_enable_irq(i2c); - - for (retry = 0; retry < adap->retries; retry++) { - - ret = nuc900_i2c_doxfer(i2c, msgs, num); - - if (ret != -EAGAIN) - return ret; - - dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry); - - udelay(100); - } - - return -EREMOTEIO; -} - -/* declare our i2c functionality */ -static u32 nuc900_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART | - I2C_FUNC_PROTOCOL_MANGLING; -} - -/* i2c bus registration info */ - -static const struct i2c_algorithm nuc900_i2c_algorithm = { - .master_xfer = nuc900_i2c_xfer, - .functionality = nuc900_i2c_func, -}; - -/* nuc900_i2c_probe - * - * called by the bus driver when a suitable device is found -*/ - -static int nuc900_i2c_probe(struct platform_device *pdev) -{ - struct nuc900_i2c *i2c; - struct nuc900_platform_i2c *pdata; - struct resource *res; - int ret; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "no platform data\n"); - return -EINVAL; - } - - i2c = kzalloc(sizeof(struct nuc900_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); - return -ENOMEM; - } - - strlcpy(i2c->adap.name, "nuc900-i2c0", sizeof(i2c->adap.name)); - i2c->adap.owner = THIS_MODULE; - i2c->adap.algo = &nuc900_i2c_algorithm; - i2c->adap.retries = 2; - i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - - spin_lock_init(&i2c->lock); - init_waitqueue_head(&i2c->wait); - - /* find the clock and enable it */ - - i2c->dev = &pdev->dev; - i2c->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "cannot get clock\n"); - ret = -ENOENT; - goto err_noclk; - } - - dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); - - clk_enable(i2c->clk); - - /* map the registers */ - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err_clk; - } - - i2c->ioarea = request_mem_region(res->start, resource_size(res), - pdev->name); - - if (i2c->ioarea == NULL) { - dev_err(&pdev->dev, "cannot request IO\n"); - ret = -ENXIO; - goto err_clk; - } - - i2c->regs = ioremap(res->start, resource_size(res)); - - if (i2c->regs == NULL) { - dev_err(&pdev->dev, "cannot map IO\n"); - ret = -ENXIO; - goto err_ioarea; - } - - dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", - i2c->regs, i2c->ioarea, res); - - /* setup info block for the i2c core */ - - i2c->adap.algo_data = i2c; - i2c->adap.dev.parent = &pdev->dev; - - mfp_set_groupg(&pdev->dev, NULL); - - clk_get_rate(i2c->clk); - - ret = (i2c->clk.apbfreq)/(pdata->bus_freq * 5) - 1; - writel(ret & 0xffff, i2c->regs + DIVIDER); - - /* find the IRQ for this unit (note, this relies on the init call to - * ensure no current IRQs pending - */ - - i2c->irq = ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); - goto err_iomap; - } - - ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED, - dev_name(&pdev->dev), i2c); - - if (ret != 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - goto err_iomap; - } - - /* Note, previous versions of the driver used i2c_add_adapter() - * to add the bus at any number. We now pass the bus number via - * the platform data, so if unset it will now default to always - * being bus 0. - */ - - i2c->adap.nr = pdata->bus_num; - - ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto err_irq; - } - - platform_set_drvdata(pdev, i2c); - - dev_info(&pdev->dev, "%s: NUC900 I2C adapter\n", - dev_name(&i2c->adap.dev)); - return 0; - - err_irq: - free_irq(i2c->irq, i2c); - - err_iomap: - iounmap(i2c->regs); - - err_ioarea: - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - - err_clk: - clk_disable(i2c->clk); - clk_put(i2c->clk); - - err_noclk: - kfree(i2c); - return ret; -} - -/* nuc900_i2c_remove - * - * called when device is removed from the bus -*/ - -static int nuc900_i2c_remove(struct platform_device *pdev) -{ - struct nuc900_i2c *i2c = platform_get_drvdata(pdev); - - i2c_del_adapter(&i2c->adap); - free_irq(i2c->irq, i2c); - - clk_disable(i2c->clk); - clk_put(i2c->clk); - - iounmap(i2c->regs); - - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - kfree(i2c); - - return 0; -} - -static struct platform_driver nuc900_i2c_driver = { - .probe = nuc900_i2c_probe, - .remove = nuc900_i2c_remove, - .driver = { - .owner = THIS_MODULE, - .name = "nuc900-i2c0", - }, -}; - -static int __init i2c_adap_nuc900_init(void) -{ - return platform_driver_register(&nuc900_i2c_driver); -} - -static void __exit i2c_adap_nuc900_exit(void) -{ - platform_driver_unregister(&nuc900_i2c_driver); -} -subsys_initcall(i2c_adap_nuc900_init); -module_exit(i2c_adap_nuc900_exit); - -MODULE_DESCRIPTION("NUC900 I2C Bus driver"); -MODULE_AUTHOR("Wan ZongShun, <mcuos.com-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-i2c0"); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 1f6369f14fb6..0e10cc6182f0 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -250,7 +250,7 @@ static struct i2c_adapter ocores_adapter = { .algo = &ocores_algorithm, }; -static struct of_device_id ocores_i2c_match[] = { +static const struct of_device_id ocores_i2c_match[] = { { .compatible = "opencores,i2c-ocores", .data = (void *)TYPE_OCORES, diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 85f8eac9ba18..b182793a4051 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1114,10 +1114,8 @@ omap_i2c_probe(struct platform_device *pdev) } dev = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Menory allocation failed\n"); + if (!dev) return -ENOMEM; - } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index bbe6dfbc5c05..be671f7a0e06 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1084,7 +1084,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = { .functionality = i2c_pxa_functionality, }; -static struct of_device_id i2c_pxa_dt_ids[] = { +static const struct of_device_id i2c_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX }, diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 06d47aafbb79..899405923678 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1,7 +1,9 @@ /* - * drivers/i2c/busses/i2c-rcar.c + * Driver for the Renesas RCar I2C unit * - * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com> + * + * Copyright (C) 2012-14 Renesas Solutions Corp. * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> * * This file is based on the drivers/i2c/busses/i2c-sh7760.c @@ -12,16 +14,12 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License + * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/clk.h> #include <linux/delay.h> @@ -36,7 +34,6 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> -#include <linux/spinlock.h> /* register offsets */ #define ICSCR 0x00 /* slave ctrl */ @@ -60,7 +57,7 @@ #define FSB (1 << 1) /* force stop bit */ #define ESG (1 << 0) /* en startbit gen */ -/* ICMSR */ +/* ICMSR (also for ICMIE) */ #define MNR (1 << 6) /* nack received */ #define MAL (1 << 5) /* arbitration lost */ #define MST (1 << 4) /* sent a stop */ @@ -69,32 +66,18 @@ #define MDR (1 << 1) #define MAT (1 << 0) /* slave addr xfer done */ -/* ICMIE */ -#define MNRE (1 << 6) /* nack irq en */ -#define MALE (1 << 5) /* arblos irq en */ -#define MSTE (1 << 4) /* stop irq en */ -#define MDEE (1 << 3) -#define MDTE (1 << 2) -#define MDRE (1 << 1) -#define MATE (1 << 0) /* address sent irq en */ +#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) +#define RCAR_BUS_PHASE_DATA (MDBS | MIE) +#define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) -enum { - RCAR_BUS_PHASE_ADDR, - RCAR_BUS_PHASE_DATA, - RCAR_BUS_PHASE_STOP, -}; +#define RCAR_IRQ_SEND (MNR | MAL | MST | MAT | MDE) +#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR) +#define RCAR_IRQ_STOP (MST) -enum { - RCAR_IRQ_CLOSE, - RCAR_IRQ_OPEN_FOR_SEND, - RCAR_IRQ_OPEN_FOR_RECV, - RCAR_IRQ_OPEN_FOR_STOP, -}; +#define RCAR_IRQ_ACK_SEND (~(MAT | MDE)) +#define RCAR_IRQ_ACK_RECV (~(MAT | MDR)) -/* - * flags - */ #define ID_LAST_MSG (1 << 0) #define ID_IOERROR (1 << 1) #define ID_DONE (1 << 2) @@ -112,14 +95,12 @@ struct rcar_i2c_priv { struct i2c_msg *msg; struct clk *clk; - spinlock_t lock; wait_queue_head_t wait; int pos; - int irq; u32 icccr; u32 flags; - enum rcar_i2c_type devtype; + enum rcar_i2c_type devtype; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -130,9 +111,7 @@ struct rcar_i2c_priv { #define LOOP_TIMEOUT 1024 -/* - * basic functions - */ + static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val) { writel(val, priv->io + reg); @@ -161,36 +140,6 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMAR, 0); } -static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open) -{ - u32 val = MNRE | MALE | MSTE | MATE; /* default */ - - switch (open) { - case RCAR_IRQ_OPEN_FOR_SEND: - val |= MDEE; /* default + send */ - break; - case RCAR_IRQ_OPEN_FOR_RECV: - val |= MDRE; /* default + read */ - break; - case RCAR_IRQ_OPEN_FOR_STOP: - val = MSTE; /* stop irq only */ - break; - case RCAR_IRQ_CLOSE: - default: - val = 0; /* all close */ - break; - } - rcar_i2c_write(priv, ICMIER, val); -} - -static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv) -{ - rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv); -} - -/* - * bus control functions - */ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) { int i; @@ -205,24 +154,6 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) return -EBUSY; } -static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase) -{ - switch (phase) { - case RCAR_BUS_PHASE_ADDR: - rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG); - break; - case RCAR_BUS_PHASE_DATA: - rcar_i2c_write(priv, ICMCR, MDBS | MIE); - break; - case RCAR_BUS_PHASE_STOP: - rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB); - break; - } -} - -/* - * clock function - */ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, u32 bus_speed, struct device *dev) @@ -312,60 +243,18 @@ scgd_find: return 0; } -static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv) -{ - rcar_i2c_write(priv, ICCCR, priv->icccr); -} - -/* - * status functions - */ -static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv) -{ - return rcar_i2c_read(priv, ICMSR); -} - -#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff) -static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) -{ - rcar_i2c_write(priv, ICMSR, ~bit); -} - -/* - * recv/send functions - */ -static int rcar_i2c_recv(struct rcar_i2c_priv *priv) -{ - rcar_i2c_set_addr(priv, 1); - rcar_i2c_status_clear(priv); - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV); - - return 0; -} - -static int rcar_i2c_send(struct rcar_i2c_priv *priv) +static int rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) { - int ret; + int read = !!rcar_i2c_is_recv(priv); - /* - * It should check bus status when send case - */ - ret = rcar_i2c_bus_barrier(priv); - if (ret < 0) - return ret; - - rcar_i2c_set_addr(priv, 0); - rcar_i2c_status_clear(priv); - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND); + rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | read); + rcar_i2c_write(priv, ICMSR, 0); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); + rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); return 0; } -#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE)) -#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR)) - /* * interrupt functions */ @@ -386,7 +275,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) * goto data phase. */ if (msr & MAT) - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); if (priv->pos < msg->len) { /* @@ -414,7 +303,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) * prepare stop condition here. * ID_DONE will be set on STOP irq. */ - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); else /* * If current msg is _NOT_ last msg, @@ -425,7 +314,7 @@ static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) return ID_DONE; } - rcar_i2c_send_restart(priv); + rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND); return 0; } @@ -462,11 +351,11 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) * otherwise, go to DATA phase. */ if (priv->pos + 1 >= msg->len) - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); else - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); - rcar_i2c_recv_restart(priv); + rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV); return 0; } @@ -474,53 +363,31 @@ static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) static irqreturn_t rcar_i2c_irq(int irq, void *ptr) { struct rcar_i2c_priv *priv = ptr; - struct device *dev = rcar_i2c_priv_to_dev(priv); u32 msr; - /*-------------- spin lock -----------------*/ - spin_lock(&priv->lock); - - msr = rcar_i2c_status_get(priv); + msr = rcar_i2c_read(priv, ICMSR); - /* - * Arbitration lost - */ + /* Arbitration lost */ if (msr & MAL) { - /* - * CAUTION - * - * When arbitration lost, device become _slave_ mode. - */ - dev_dbg(dev, "Arbitration Lost\n"); rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); goto out; } - /* - * Stop - */ + /* Stop */ if (msr & MST) { - dev_dbg(dev, "Stop\n"); rcar_i2c_flags_set(priv, ID_DONE); goto out; } - /* - * Nack - */ + /* Nack */ if (msr & MNR) { - dev_dbg(dev, "Nack\n"); - /* go to stop phase */ - rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); - rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); + rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); + rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP); rcar_i2c_flags_set(priv, ID_NACK); goto out; } - /* - * recv/send - */ if (rcar_i2c_is_recv(priv)) rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); else @@ -528,14 +395,11 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) out: if (rcar_i2c_flags_has(priv, ID_DONE)) { - rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE); - rcar_i2c_status_clear(priv); + rcar_i2c_write(priv, ICMIER, 0); + rcar_i2c_write(priv, ICMSR, 0); wake_up(&priv->wait); } - spin_unlock(&priv->lock); - /*-------------- spin unlock -----------------*/ - return IRQ_HANDLED; } @@ -545,21 +409,18 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, { struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); struct device *dev = rcar_i2c_priv_to_dev(priv); - unsigned long flags; int i, ret, timeout; pm_runtime_get_sync(dev); - /*-------------- spin lock -----------------*/ - spin_lock_irqsave(&priv->lock, flags); - rcar_i2c_init(priv); - rcar_i2c_clock_start(priv); + /* start clock */ + rcar_i2c_write(priv, ICCCR, priv->icccr); - spin_unlock_irqrestore(&priv->lock, flags); - /*-------------- spin unlock -----------------*/ + ret = rcar_i2c_bus_barrier(priv); + if (ret < 0) + goto out; - ret = -EINVAL; for (i = 0; i < num; i++) { /* This HW can't send STOP after address phase */ if (msgs[i].len == 0) { @@ -567,9 +428,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, break; } - /*-------------- spin lock -----------------*/ - spin_lock_irqsave(&priv->lock, flags); - /* init each data */ priv->msg = &msgs[i]; priv->pos = 0; @@ -577,21 +435,11 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (priv->msg == &msgs[num - 1]) rcar_i2c_flags_set(priv, ID_LAST_MSG); - /* start send/recv */ - if (rcar_i2c_is_recv(priv)) - ret = rcar_i2c_recv(priv); - else - ret = rcar_i2c_send(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - /*-------------- spin unlock -----------------*/ + ret = rcar_i2c_prepare_msg(priv); if (ret < 0) break; - /* - * wait result - */ timeout = wait_event_timeout(priv->wait, rcar_i2c_flags_has(priv, ID_DONE), 5 * HZ); @@ -600,9 +448,6 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, break; } - /* - * error handling - */ if (rcar_i2c_flags_has(priv, ID_NACK)) { ret = -ENXIO; break; @@ -620,7 +465,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ret = i + 1; /* The number of transfer */ } - +out: pm_runtime_put(dev); if (ret < 0 && ret != -ENXIO) @@ -646,6 +491,9 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -658,13 +506,11 @@ static int rcar_i2c_probe(struct platform_device *pdev) struct resource *res; struct device *dev = &pdev->dev; u32 bus_speed; - int ret; + int irq, ret; priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "no mem for private data\n"); + if (!priv) return -ENOMEM; - } priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { @@ -692,9 +538,8 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (IS_ERR(priv->io)) return PTR_ERR(priv->io); - priv->irq = platform_get_irq(pdev, 0); + irq = platform_get_irq(pdev, 0); init_waitqueue_head(&priv->wait); - spin_lock_init(&priv->lock); adap = &priv->adap; adap->nr = pdev->id; @@ -706,10 +551,10 @@ static int rcar_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, priv); strlcpy(adap->name, pdev->name, sizeof(adap->name)); - ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, + ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv); if (ret < 0) { - dev_err(dev, "cannot get irq %d\n", priv->irq); + dev_err(dev, "cannot get irq %d\n", irq); return ret; } @@ -759,6 +604,6 @@ static struct platform_driver rcar_i2c_driver = { module_platform_driver(rcar_i2c_driver); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 9e1f8bacfb39..af3b3d032a9f 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -404,7 +404,7 @@ static int riic_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id riic_i2c_dt_ids[] = { +static const struct of_device_id riic_i2c_dt_ids[] = { { .compatible = "renesas,riic-rz" }, { /* Sentinel */ }, }; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index bb3a9964f7e0..e828a1dba0e5 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1114,16 +1114,12 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) } i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL); - if (!i2c) { - dev_err(&pdev->dev, "no memory for state\n"); + if (!i2c) return -ENOMEM; - } i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!i2c->pdata) { - dev_err(&pdev->dev, "no memory for platform data\n"); + if (!i2c->pdata) return -ENOMEM; - } i2c->quirks = s3c24xx_get_device_quirks(pdev); if (pdata) diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 1d79585ba4b3..8b5e79cb4468 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -32,6 +32,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/slab.h> +#include <linux/of_device.h> #include <linux/i2c/i2c-sh_mobile.h> /* Transmit operation: */ @@ -139,6 +140,10 @@ struct sh_mobile_i2c_data { bool send_stop; }; +struct sh_mobile_dt_config { + int clks_per_count; +}; + #define IIC_FLAG_HAS_ICIC67 (1 << 0) #define STANDARD_MODE 100000 @@ -194,7 +199,7 @@ static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs, iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr); } -static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int offset) +static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf) { /* * Conditional expression: @@ -206,10 +211,10 @@ static u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf, int off * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return (((count_khz * (tLOW + tf)) + 5000) / 10000) + offset; + return (((count_khz * (tLOW + tf)) + 5000) / 10000); } -static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int offset) +static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf) { /* * Conditional expression: @@ -225,52 +230,58 @@ static u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf, int of * to take into account the fall time of SDA signal (tf) at START * condition, in order to meet both tHIGH and tHD;STA specs. */ - return (((count_khz * (tHIGH + tf)) + 5000) / 10000) + offset; + return (((count_khz * (tHIGH + tf)) + 5000) / 10000); } -static void sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) +static int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd) { unsigned long i2c_clk_khz; u32 tHIGH, tLOW, tf; - int offset; + uint16_t max_val; /* Get clock rate after clock is enabled */ clk_prepare_enable(pd->clk); i2c_clk_khz = clk_get_rate(pd->clk) / 1000; + clk_disable_unprepare(pd->clk); i2c_clk_khz /= pd->clks_per_count; if (pd->bus_speed == STANDARD_MODE) { tLOW = 47; /* tLOW = 4.7 us */ tHIGH = 40; /* tHD;STA = tHIGH = 4.0 us */ tf = 3; /* tf = 0.3 us */ - offset = 0; /* No offset */ } else if (pd->bus_speed == FAST_MODE) { tLOW = 13; /* tLOW = 1.3 us */ tHIGH = 6; /* tHD;STA = tHIGH = 0.6 us */ tf = 3; /* tf = 0.3 us */ - offset = 0; /* No offset */ } else { dev_err(pd->dev, "unrecognized bus speed %lu Hz\n", pd->bus_speed); - goto out; + return -EINVAL; + } + + pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf); + pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf); + + max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff; + if (pd->iccl > max_val || pd->icch > max_val) { + dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n", + pd->iccl, pd->icch); + return -EINVAL; } - pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf, offset); /* one more bit of ICCL in ICIC */ - if ((pd->iccl > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + if (pd->iccl & 0x100) pd->icic |= ICIC_ICCLB8; else pd->icic &= ~ICIC_ICCLB8; - pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf, offset); /* one more bit of ICCH in ICIC */ - if ((pd->icch > 0xff) && (pd->flags & IIC_FLAG_HAS_ICIC67)) + if (pd->icch & 0x100) pd->icic |= ICIC_ICCHB8; else pd->icic &= ~ICIC_ICCHB8; -out: - clk_disable_unprepare(pd->clk); + return 0; } static void activate_ch(struct sh_mobile_i2c_data *pd) @@ -316,7 +327,7 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, switch (op) { case OP_START: /* issue start and trigger DTE interrupt */ - iic_wr(pd, ICCR, 0x94); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; case OP_TX_FIRST: /* disable DTE interrupt and write data */ iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE); @@ -327,10 +338,11 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, break; case OP_TX_STOP: /* write data and issue a stop afterwards */ iic_wr(pd, ICDR, data); - iic_wr(pd, ICCR, pd->send_stop ? 0x90 : 0x94); + iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS + : ICCR_ICE | ICCR_TRS | ICCR_BBSY); break; case OP_TX_TO_RX: /* select read mode */ - iic_wr(pd, ICCR, 0x81); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP); break; case OP_RX: /* just read data */ ret = iic_rd(pd, ICDR); @@ -338,13 +350,13 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, case OP_RX_STOP: /* enable DTE interrupt, issue stop */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); - iic_wr(pd, ICCR, 0xc0); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); break; case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE); ret = iic_rd(pd, ICDR); - iic_wr(pd, ICCR, 0xc0); + iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK); break; } @@ -479,7 +491,7 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg, { if (usr_msg->len == 0 && (usr_msg->flags & I2C_M_RD)) { dev_err(pd->dev, "Unsupported zero length i2c read\n"); - return -EIO; + return -EOPNOTSUPP; } if (do_init) { @@ -514,17 +526,12 @@ static int poll_dte(struct sh_mobile_i2c_data *pd) break; if (val & ICSR_TACK) - return -EIO; + return -ENXIO; udelay(10); } - if (!i) { - dev_warn(pd->dev, "Timeout polling for DTE!\n"); - return -ETIMEDOUT; - } - - return 0; + return i ? 0 : -ETIMEDOUT; } static int poll_busy(struct sh_mobile_i2c_data *pd) @@ -542,20 +549,18 @@ static int poll_busy(struct sh_mobile_i2c_data *pd) */ if (!(val & ICSR_BUSY)) { /* handle missing acknowledge and arbitration lost */ - if ((val | pd->sr) & (ICSR_TACK | ICSR_AL)) - return -EIO; + val |= pd->sr; + if (val & ICSR_TACK) + return -ENXIO; + if (val & ICSR_AL) + return -EAGAIN; break; } udelay(10); } - if (!i) { - dev_err(pd->dev, "Polling timed out\n"); - return -ETIMEDOUT; - } - - return 0; + return i ? 0 : -ETIMEDOUT; } static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter, @@ -617,42 +622,44 @@ static struct i2c_algorithm sh_mobile_i2c_algorithm = { .master_xfer = sh_mobile_i2c_xfer, }; -static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) +static const struct sh_mobile_dt_config default_dt_config = { + .clks_per_count = 1, +}; + +static const struct sh_mobile_dt_config rcar_gen2_dt_config = { + .clks_per_count = 2, +}; + +static const struct of_device_id sh_mobile_i2c_dt_ids[] = { + { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7791", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7792", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7793", .data = &rcar_gen2_dt_config }, + { .compatible = "renesas,iic-r8a7794", .data = &rcar_gen2_dt_config }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); + +static int sh_mobile_i2c_hook_irqs(struct platform_device *dev) { struct resource *res; - int ret = -ENXIO; - int n, k = 0; + resource_size_t n; + int k = 0, ret; while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { - for (n = res->start; hook && n <= res->end; n++) { - if (request_irq(n, sh_mobile_i2c_isr, 0, - dev_name(&dev->dev), dev)) { - for (n--; n >= res->start; n--) - free_irq(n, dev); - - goto rollback; + for (n = res->start; n <= res->end; n++) { + ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), dev); + if (ret) { + dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + return ret; } } k++; } - if (hook) - return k > 0 ? 0 : -ENOENT; - - ret = 0; - - rollback: - k--; - - while (k >= 0) { - res = platform_get_resource(dev, IORESOURCE_IRQ, k); - for (n = res->start; n <= res->end; n++) - free_irq(n, dev); - - k--; - } - - return ret; + return k > 0 ? 0 : -ENOENT; } static int sh_mobile_i2c_probe(struct platform_device *dev) @@ -661,62 +668,64 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; struct resource *res; - int size; int ret; + u32 bus_speed; - pd = kzalloc(sizeof(struct sh_mobile_i2c_data), GFP_KERNEL); - if (pd == NULL) { - dev_err(&dev->dev, "cannot allocate private data\n"); + pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL); + if (!pd) return -ENOMEM; - } - pd->clk = clk_get(&dev->dev, NULL); + pd->clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(pd->clk)) { dev_err(&dev->dev, "cannot get clock\n"); - ret = PTR_ERR(pd->clk); - goto err; + return PTR_ERR(pd->clk); } - ret = sh_mobile_i2c_hook_irqs(dev, 1); - if (ret) { - dev_err(&dev->dev, "cannot request IRQ\n"); - goto err_clk; - } + ret = sh_mobile_i2c_hook_irqs(dev); + if (ret) + return ret; pd->dev = &dev->dev; platform_set_drvdata(dev, pd); res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&dev->dev, "cannot find IO resource\n"); - ret = -ENOENT; - goto err_irq; - } - - size = resource_size(res); - pd->reg = ioremap(res->start, size); - if (pd->reg == NULL) { - dev_err(&dev->dev, "cannot map IO\n"); - ret = -ENXIO; - goto err_irq; - } + pd->reg = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(pd->reg)) + return PTR_ERR(pd->reg); /* Use platform data bus speed or STANDARD_MODE */ - pd->bus_speed = STANDARD_MODE; - if (pdata && pdata->bus_speed) - pd->bus_speed = pdata->bus_speed; + ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed); + pd->bus_speed = ret ? STANDARD_MODE : bus_speed; + pd->clks_per_count = 1; - if (pdata && pdata->clks_per_count) - pd->clks_per_count = pdata->clks_per_count; + + if (dev->dev.of_node) { + const struct of_device_id *match; + + match = of_match_device(sh_mobile_i2c_dt_ids, &dev->dev); + if (match) { + const struct sh_mobile_dt_config *config; + + config = match->data; + pd->clks_per_count = config->clks_per_count; + } + } else { + if (pdata && pdata->bus_speed) + pd->bus_speed = pdata->bus_speed; + if (pdata && pdata->clks_per_count) + pd->clks_per_count = pdata->clks_per_count; + } /* The IIC blocks on SH-Mobile ARM processors * come with two new bits in ICIC. */ - if (size > 0x17) + if (resource_size(res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; - sh_mobile_i2c_init(pd); + ret = sh_mobile_i2c_init(pd); + if (ret) + return ret; /* Enable Runtime PM for this device. * @@ -750,24 +759,14 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { dev_err(&dev->dev, "cannot add numbered adapter\n"); - goto err_all; + return ret; } dev_info(&dev->dev, - "I2C adapter %d with bus speed %lu Hz (L/H=%x/%x)\n", + "I2C adapter %d with bus speed %lu Hz (L/H=0x%x/0x%x)\n", adap->nr, pd->bus_speed, pd->iccl, pd->icch); return 0; - - err_all: - iounmap(pd->reg); - err_irq: - sh_mobile_i2c_hook_irqs(dev, 0); - err_clk: - clk_put(pd->clk); - err: - kfree(pd); - return ret; } static int sh_mobile_i2c_remove(struct platform_device *dev) @@ -775,11 +774,7 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); - iounmap(pd->reg); - sh_mobile_i2c_hook_irqs(dev, 0); - clk_put(pd->clk); pm_runtime_disable(&dev->dev); - kfree(pd); return 0; } @@ -800,12 +795,6 @@ static const struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = { .runtime_resume = sh_mobile_i2c_runtime_nop, }; -static const struct of_device_id sh_mobile_i2c_dt_ids[] = { - { .compatible = "renesas,rmobile-iic", }, - {}, -}; -MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); - static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 294c80f21d65..964e5c6f84ab 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -77,10 +77,8 @@ static int simtec_i2c_probe(struct platform_device *dev) int ret; pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL); - if (pd == NULL) { - dev_err(&dev->dev, "cannot allocate private data\n"); + if (pd == NULL) return -ENOMEM; - } platform_set_drvdata(dev, pd); diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 8e3be7ed0586..a3216defc1d3 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -307,7 +307,6 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) siic = devm_kzalloc(&pdev->dev, sizeof(*siic), GFP_KERNEL); if (!siic) { - dev_err(&pdev->dev, "Can't allocate driver data\n"); err = -ENOMEM; goto out; } diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 872016196ef3..95b947670386 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -847,7 +847,7 @@ static int st_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id st_i2c_match[] = { +static const struct of_device_id st_i2c_match[] = { { .compatible = "st,comms-ssc-i2c", }, { .compatible = "st,comms-ssc4-i2c", }, {}, diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 29b1fb778943..fefb1c19ec1d 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -868,10 +868,8 @@ static int stu300_probe(struct platform_device *pdev) int ret = 0; dev = devm_kzalloc(&pdev->dev, sizeof(struct stu300_dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "could not allocate device struct\n"); + if (!dev) return -ENOMEM; - } bus_nr = pdev->id; dev->clk = devm_clk_get(&pdev->dev, NULL); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 00f04cb5b4eb..f1bb2fc06791 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -732,10 +732,8 @@ static int tegra_i2c_probe(struct platform_device *pdev) } i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "Could not allocate struct tegra_i2c_dev"); + if (!i2c_dev) return -ENOMEM; - } i2c_dev->base = base; i2c_dev->div_clk = div_clk; diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index 2c8a3e4f9008..f80a38c2072c 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -379,10 +379,8 @@ static int wmt_i2c_probe(struct platform_device *pdev) u32 clk_rate; i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) { - dev_err(&pdev->dev, "device memory allocation failed\n"); + if (!i2c_dev) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); @@ -454,7 +452,7 @@ static int wmt_i2c_remove(struct platform_device *pdev) return 0; } -static struct of_device_id wmt_i2c_dt_ids[] = { +static const struct of_device_id wmt_i2c_dt_ids[] = { { .compatible = "wm,wm8505-i2c" }, { /* Sentinel */ }, }; diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index cb66f9586f76..ff3f5747e43b 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -431,10 +431,8 @@ static struct scx200_acb_iface *scx200_create_iface(const char *text, struct i2c_adapter *adapter; iface = kzalloc(sizeof(*iface), GFP_KERNEL); - if (!iface) { - pr_err("can't allocate memory\n"); + if (!iface) return NULL; - } adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 550bd36aa5d6..9bd4212782ab 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -36,12 +36,11 @@ */ #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/i2c-mux.h> #include <linux/i2c/pca954x.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/slab.h> #define PCA954X_MAX_NCHANS 8 @@ -186,7 +185,7 @@ static int pca954x_probe(struct i2c_client *client, { struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); - struct device_node *np = client->dev.of_node; + struct gpio_desc *gpio; int num, force, class; struct pca954x *data; int ret; @@ -200,21 +199,10 @@ static int pca954x_probe(struct i2c_client *client, i2c_set_clientdata(client, data); - if (IS_ENABLED(CONFIG_OF) && np) { - enum of_gpio_flags flags; - int gpio; - - /* Get the mux out of reset if a reset GPIO is specified. */ - gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); - if (gpio_is_valid(gpio)) { - ret = devm_gpio_request_one(&client->dev, gpio, - flags & OF_GPIO_ACTIVE_LOW ? - GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - "pca954x reset"); - if (ret < 0) - return ret; - } - } + /* Get the mux out of reset if a reset GPIO is specified. */ + gpio = devm_gpiod_get(&client->dev, "reset"); + if (!IS_ERR(gpio)) + gpiod_direction_output(gpio, 0); /* Write the mux register at addr to verify * that the mux is in fact present. This also diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index df56e4c74a7e..d260605e6d5f 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -178,13 +178,13 @@ config TEGRA_IOMMU_SMMU config EXYNOS_IOMMU bool "Exynos IOMMU Support" - depends on ARCH_EXYNOS && EXYNOS_DEV_SYSMMU + depends on ARCH_EXYNOS select IOMMU_API help - Support for the IOMMU(System MMU) of Samsung Exynos application - processor family. This enables H/W multimedia accellerators to see - non-linear physical memory chunks as a linear memory in their - address spaces + Support for the IOMMU (System MMU) of Samsung Exynos application + processor family. This enables H/W multimedia accelerators to see + non-linear physical memory chunks as linear memory in their + address space. If unsure, say N here. @@ -193,9 +193,9 @@ config EXYNOS_IOMMU_DEBUG depends on EXYNOS_IOMMU help Select this to see the detailed log message that shows what - happens in the IOMMU driver + happens in the IOMMU driver. - Say N unless you need kernel log message for IOMMU debugging + Say N unless you need kernel log message for IOMMU debugging. config SHMOBILE_IPMMU bool @@ -272,6 +272,18 @@ config SHMOBILE_IOMMU_L1SIZE default 256 if SHMOBILE_IOMMU_ADDRSIZE_64MB default 128 if SHMOBILE_IOMMU_ADDRSIZE_32MB +config IPMMU_VMSA + bool "Renesas VMSA-compatible IPMMU" + depends on ARM_LPAE + depends on ARCH_SHMOBILE || COMPILE_TEST + select IOMMU_API + select ARM_DMA_USE_IOMMU + help + Support for the Renesas VMSA-compatible IPMMU Renesas found in the + R-Mobile APE6 and R-Car H2/M2 SoCs. + + If unsure, say N. + config SPAPR_TCE_IOMMU bool "sPAPR TCE IOMMU Support" depends on PPC_POWERNV || PPC_PSERIES diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 5d58bf16e9e3..8893bad048e0 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm-smmu.o obj-$(CONFIG_DMAR_TABLE) += dmar.o obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o +obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o obj-$(CONFIG_OMAP_IOMMU) += omap-iommu2.o diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 57068e8035b5..4aec6a29e316 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3499,8 +3499,6 @@ int __init amd_iommu_init_passthrough(void) { struct iommu_dev_data *dev_data; struct pci_dev *dev = NULL; - struct amd_iommu *iommu; - u16 devid; int ret; ret = alloc_passthrough_domain(); @@ -3514,12 +3512,6 @@ int __init amd_iommu_init_passthrough(void) dev_data = get_dev_data(&dev->dev); dev_data->passthrough = true; - devid = get_device_id(&dev->dev); - - iommu = amd_iommu_rlookup_table[devid]; - if (!iommu) - continue; - attach_device(&dev->dev, pt_domain); } diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 203b2e6a91cf..d4daa05efe60 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -45,6 +45,8 @@ struct pri_queue { struct pasid_state { struct list_head list; /* For global state-list */ atomic_t count; /* Reference count */ + atomic_t mmu_notifier_count; /* Counting nested mmu_notifier + calls */ struct task_struct *task; /* Task bound to this PASID */ struct mm_struct *mm; /* mm_struct for the faults */ struct mmu_notifier mn; /* mmu_otifier handle */ @@ -56,6 +58,8 @@ struct pasid_state { }; struct device_state { + struct list_head list; + u16 devid; atomic_t count; struct pci_dev *pdev; struct pasid_state **states; @@ -81,13 +85,9 @@ struct fault { u16 flags; }; -static struct device_state **state_table; +static LIST_HEAD(state_list); static spinlock_t state_lock; -/* List and lock for all pasid_states */ -static LIST_HEAD(pasid_state_list); -static DEFINE_SPINLOCK(ps_lock); - static struct workqueue_struct *iommu_wq; /* @@ -99,7 +99,6 @@ static u64 *empty_page_table; static void free_pasid_states(struct device_state *dev_state); static void unbind_pasid(struct device_state *dev_state, int pasid); -static int task_exit(struct notifier_block *nb, unsigned long e, void *data); static u16 device_id(struct pci_dev *pdev) { @@ -111,13 +110,25 @@ static u16 device_id(struct pci_dev *pdev) return devid; } +static struct device_state *__get_device_state(u16 devid) +{ + struct device_state *dev_state; + + list_for_each_entry(dev_state, &state_list, list) { + if (dev_state->devid == devid) + return dev_state; + } + + return NULL; +} + static struct device_state *get_device_state(u16 devid) { struct device_state *dev_state; unsigned long flags; spin_lock_irqsave(&state_lock, flags); - dev_state = state_table[devid]; + dev_state = __get_device_state(devid); if (dev_state != NULL) atomic_inc(&dev_state->count); spin_unlock_irqrestore(&state_lock, flags); @@ -158,29 +169,6 @@ static void put_device_state_wait(struct device_state *dev_state) free_device_state(dev_state); } -static struct notifier_block profile_nb = { - .notifier_call = task_exit, -}; - -static void link_pasid_state(struct pasid_state *pasid_state) -{ - spin_lock(&ps_lock); - list_add_tail(&pasid_state->list, &pasid_state_list); - spin_unlock(&ps_lock); -} - -static void __unlink_pasid_state(struct pasid_state *pasid_state) -{ - list_del(&pasid_state->list); -} - -static void unlink_pasid_state(struct pasid_state *pasid_state) -{ - spin_lock(&ps_lock); - __unlink_pasid_state(pasid_state); - spin_unlock(&ps_lock); -} - /* Must be called under dev_state->lock */ static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state, int pasid, bool alloc) @@ -337,7 +325,6 @@ static void unbind_pasid(struct device_state *dev_state, int pasid) if (pasid_state == NULL) return; - unlink_pasid_state(pasid_state); __unbind_pasid(pasid_state); put_pasid_state_wait(pasid_state); /* Reference taken in this function */ } @@ -379,7 +366,12 @@ static void free_pasid_states(struct device_state *dev_state) continue; put_pasid_state(pasid_state); - unbind_pasid(dev_state, i); + + /* + * This will call the mn_release function and + * unbind the PASID + */ + mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm); } if (dev_state->pasid_levels == 2) @@ -443,8 +435,11 @@ static void mn_invalidate_range_start(struct mmu_notifier *mn, pasid_state = mn_to_state(mn); dev_state = pasid_state->device_state; - amd_iommu_domain_set_gcr3(dev_state->domain, pasid_state->pasid, - __pa(empty_page_table)); + if (atomic_add_return(1, &pasid_state->mmu_notifier_count) == 1) { + amd_iommu_domain_set_gcr3(dev_state->domain, + pasid_state->pasid, + __pa(empty_page_table)); + } } static void mn_invalidate_range_end(struct mmu_notifier *mn, @@ -457,11 +452,31 @@ static void mn_invalidate_range_end(struct mmu_notifier *mn, pasid_state = mn_to_state(mn); dev_state = pasid_state->device_state; - amd_iommu_domain_set_gcr3(dev_state->domain, pasid_state->pasid, - __pa(pasid_state->mm->pgd)); + if (atomic_dec_and_test(&pasid_state->mmu_notifier_count)) { + amd_iommu_domain_set_gcr3(dev_state->domain, + pasid_state->pasid, + __pa(pasid_state->mm->pgd)); + } +} + +static void mn_release(struct mmu_notifier *mn, struct mm_struct *mm) +{ + struct pasid_state *pasid_state; + struct device_state *dev_state; + + might_sleep(); + + pasid_state = mn_to_state(mn); + dev_state = pasid_state->device_state; + + if (pasid_state->device_state->inv_ctx_cb) + dev_state->inv_ctx_cb(dev_state->pdev, pasid_state->pasid); + + unbind_pasid(dev_state, pasid_state->pasid); } static struct mmu_notifier_ops iommu_mn = { + .release = mn_release, .clear_flush_young = mn_clear_flush_young, .change_pte = mn_change_pte, .invalidate_page = mn_invalidate_page, @@ -606,53 +621,6 @@ static struct notifier_block ppr_nb = { .notifier_call = ppr_notifier, }; -static int task_exit(struct notifier_block *nb, unsigned long e, void *data) -{ - struct pasid_state *pasid_state; - struct task_struct *task; - - task = data; - - /* - * Using this notifier is a hack - but there is no other choice - * at the moment. What I really want is a sleeping notifier that - * is called when an MM goes down. But such a notifier doesn't - * exist yet. The notifier needs to sleep because it has to make - * sure that the device does not use the PASID and the address - * space anymore before it is destroyed. This includes waiting - * for pending PRI requests to pass the workqueue. The - * MMU-Notifiers would be a good fit, but they use RCU and so - * they are not allowed to sleep. Lets see how we can solve this - * in a more intelligent way in the future. - */ -again: - spin_lock(&ps_lock); - list_for_each_entry(pasid_state, &pasid_state_list, list) { - struct device_state *dev_state; - int pasid; - - if (pasid_state->task != task) - continue; - - /* Drop Lock and unbind */ - spin_unlock(&ps_lock); - - dev_state = pasid_state->device_state; - pasid = pasid_state->pasid; - - if (pasid_state->device_state->inv_ctx_cb) - dev_state->inv_ctx_cb(dev_state->pdev, pasid); - - unbind_pasid(dev_state, pasid); - - /* Task may be in the list multiple times */ - goto again; - } - spin_unlock(&ps_lock); - - return NOTIFY_OK; -} - int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, struct task_struct *task) { @@ -682,6 +650,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, goto out; atomic_set(&pasid_state->count, 1); + atomic_set(&pasid_state->mmu_notifier_count, 0); init_waitqueue_head(&pasid_state->wq); spin_lock_init(&pasid_state->lock); @@ -705,8 +674,6 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, int pasid, if (ret) goto out_clear_state; - link_pasid_state(pasid_state); - return 0; out_clear_state: @@ -727,6 +694,7 @@ EXPORT_SYMBOL(amd_iommu_bind_pasid); void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid) { + struct pasid_state *pasid_state; struct device_state *dev_state; u16 devid; @@ -743,7 +711,17 @@ void amd_iommu_unbind_pasid(struct pci_dev *pdev, int pasid) if (pasid < 0 || pasid >= dev_state->max_pasids) goto out; - unbind_pasid(dev_state, pasid); + pasid_state = get_pasid_state(dev_state, pasid); + if (pasid_state == NULL) + goto out; + /* + * Drop reference taken here. We are safe because we still hold + * the reference taken in the amd_iommu_bind_pasid function. + */ + put_pasid_state(pasid_state); + + /* This will call the mn_release function and unbind the PASID */ + mmu_notifier_unregister(&pasid_state->mn, pasid_state->mm); out: put_device_state(dev_state); @@ -773,7 +751,8 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) spin_lock_init(&dev_state->lock); init_waitqueue_head(&dev_state->wq); - dev_state->pdev = pdev; + dev_state->pdev = pdev; + dev_state->devid = devid; tmp = pasids; for (dev_state->pasid_levels = 0; (tmp - 1) & ~0x1ff; tmp >>= 9) @@ -803,13 +782,13 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) spin_lock_irqsave(&state_lock, flags); - if (state_table[devid] != NULL) { + if (__get_device_state(devid) != NULL) { spin_unlock_irqrestore(&state_lock, flags); ret = -EBUSY; goto out_free_domain; } - state_table[devid] = dev_state; + list_add_tail(&dev_state->list, &state_list); spin_unlock_irqrestore(&state_lock, flags); @@ -841,13 +820,13 @@ void amd_iommu_free_device(struct pci_dev *pdev) spin_lock_irqsave(&state_lock, flags); - dev_state = state_table[devid]; + dev_state = __get_device_state(devid); if (dev_state == NULL) { spin_unlock_irqrestore(&state_lock, flags); return; } - state_table[devid] = NULL; + list_del(&dev_state->list); spin_unlock_irqrestore(&state_lock, flags); @@ -874,7 +853,7 @@ int amd_iommu_set_invalid_ppr_cb(struct pci_dev *pdev, spin_lock_irqsave(&state_lock, flags); ret = -EINVAL; - dev_state = state_table[devid]; + dev_state = __get_device_state(devid); if (dev_state == NULL) goto out_unlock; @@ -905,7 +884,7 @@ int amd_iommu_set_invalidate_ctx_cb(struct pci_dev *pdev, spin_lock_irqsave(&state_lock, flags); ret = -EINVAL; - dev_state = state_table[devid]; + dev_state = __get_device_state(devid); if (dev_state == NULL) goto out_unlock; @@ -922,7 +901,6 @@ EXPORT_SYMBOL(amd_iommu_set_invalidate_ctx_cb); static int __init amd_iommu_v2_init(void) { - size_t state_table_size; int ret; pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n"); @@ -938,16 +916,10 @@ static int __init amd_iommu_v2_init(void) spin_lock_init(&state_lock); - state_table_size = MAX_DEVICES * sizeof(struct device_state *); - state_table = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(state_table_size)); - if (state_table == NULL) - return -ENOMEM; - ret = -ENOMEM; iommu_wq = create_workqueue("amd_iommu_v2"); if (iommu_wq == NULL) - goto out_free; + goto out; ret = -ENOMEM; empty_page_table = (u64 *)get_zeroed_page(GFP_KERNEL); @@ -955,29 +927,24 @@ static int __init amd_iommu_v2_init(void) goto out_destroy_wq; amd_iommu_register_ppr_notifier(&ppr_nb); - profile_event_register(PROFILE_TASK_EXIT, &profile_nb); return 0; out_destroy_wq: destroy_workqueue(iommu_wq); -out_free: - free_pages((unsigned long)state_table, get_order(state_table_size)); - +out: return ret; } static void __exit amd_iommu_v2_exit(void) { struct device_state *dev_state; - size_t state_table_size; int i; if (!amd_iommu_v2_supported()) return; - profile_event_unregister(PROFILE_TASK_EXIT, &profile_nb); amd_iommu_unregister_ppr_notifier(&ppr_nb); flush_workqueue(iommu_wq); @@ -1000,9 +967,6 @@ static void __exit amd_iommu_v2_exit(void) destroy_workqueue(iommu_wq); - state_table_size = MAX_DEVICES * sizeof(struct device_state *); - free_pages((unsigned long)state_table, get_order(state_table_size)); - free_page((unsigned long)empty_page_table); } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 647c3c7fd742..1599354e974d 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1167,7 +1167,7 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, for (i = 0; i < master->num_streamids; ++i) { u32 idx, s2cr; idx = master->smrs ? master->smrs[i].idx : master->streamids[i]; - s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) | + s2cr = S2CR_TYPE_TRANS | (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT); writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx)); } @@ -1804,7 +1804,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) * allocation (PTRS_PER_PGD). */ #ifdef CONFIG_64BIT - smmu->s1_output_size = min(39UL, size); + smmu->s1_output_size = min((unsigned long)VA_BITS, size); #else smmu->s1_output_size = min(32UL, size); #endif diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 685f9263cfee..99054d2c040d 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -29,7 +29,8 @@ #include <asm/cacheflush.h> #include <asm/pgtable.h> -#include <mach/sysmmu.h> +typedef u32 sysmmu_iova_t; +typedef u32 sysmmu_pte_t; /* We does not consider super section mapping (16MB) */ #define SECT_ORDER 20 @@ -44,28 +45,44 @@ #define LPAGE_MASK (~(LPAGE_SIZE - 1)) #define SPAGE_MASK (~(SPAGE_SIZE - 1)) -#define lv1ent_fault(sent) (((*(sent) & 3) == 0) || ((*(sent) & 3) == 3)) -#define lv1ent_page(sent) ((*(sent) & 3) == 1) +#define lv1ent_fault(sent) ((*(sent) == ZERO_LV2LINK) || \ + ((*(sent) & 3) == 0) || ((*(sent) & 3) == 3)) +#define lv1ent_zero(sent) (*(sent) == ZERO_LV2LINK) +#define lv1ent_page_zero(sent) ((*(sent) & 3) == 1) +#define lv1ent_page(sent) ((*(sent) != ZERO_LV2LINK) && \ + ((*(sent) & 3) == 1)) #define lv1ent_section(sent) ((*(sent) & 3) == 2) #define lv2ent_fault(pent) ((*(pent) & 3) == 0) #define lv2ent_small(pent) ((*(pent) & 2) == 2) #define lv2ent_large(pent) ((*(pent) & 3) == 1) +static u32 sysmmu_page_offset(sysmmu_iova_t iova, u32 size) +{ + return iova & (size - 1); +} + #define section_phys(sent) (*(sent) & SECT_MASK) -#define section_offs(iova) ((iova) & 0xFFFFF) +#define section_offs(iova) sysmmu_page_offset((iova), SECT_SIZE) #define lpage_phys(pent) (*(pent) & LPAGE_MASK) -#define lpage_offs(iova) ((iova) & 0xFFFF) +#define lpage_offs(iova) sysmmu_page_offset((iova), LPAGE_SIZE) #define spage_phys(pent) (*(pent) & SPAGE_MASK) -#define spage_offs(iova) ((iova) & 0xFFF) - -#define lv1ent_offset(iova) ((iova) >> SECT_ORDER) -#define lv2ent_offset(iova) (((iova) & 0xFF000) >> SPAGE_ORDER) +#define spage_offs(iova) sysmmu_page_offset((iova), SPAGE_SIZE) #define NUM_LV1ENTRIES 4096 -#define NUM_LV2ENTRIES 256 +#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE) + +static u32 lv1ent_offset(sysmmu_iova_t iova) +{ + return iova >> SECT_ORDER; +} + +static u32 lv2ent_offset(sysmmu_iova_t iova) +{ + return (iova >> SPAGE_ORDER) & (NUM_LV2ENTRIES - 1); +} -#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long)) +#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t)) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) @@ -80,6 +97,13 @@ #define CTRL_BLOCK 0x7 #define CTRL_DISABLE 0x0 +#define CFG_LRU 0x1 +#define CFG_QOS(n) ((n & 0xF) << 7) +#define CFG_MASK 0x0150FFFF /* Selecting bit 0-15, 20, 22 and 24 */ +#define CFG_ACGEN (1 << 24) /* System MMU 3.3 only */ +#define CFG_SYSSEL (1 << 22) /* System MMU 3.2 only */ +#define CFG_FLPDCACHE (1 << 20) /* System MMU 3.2+ only */ + #define REG_MMU_CTRL 0x000 #define REG_MMU_CFG 0x004 #define REG_MMU_STATUS 0x008 @@ -96,19 +120,32 @@ #define REG_MMU_VERSION 0x034 +#define MMU_MAJ_VER(val) ((val) >> 7) +#define MMU_MIN_VER(val) ((val) & 0x7F) +#define MMU_RAW_VER(reg) (((reg) >> 21) & ((1 << 11) - 1)) /* 11 bits */ + +#define MAKE_MMU_VER(maj, min) ((((maj) & 0xF) << 7) | ((min) & 0x7F)) + #define REG_PB0_SADDR 0x04C #define REG_PB0_EADDR 0x050 #define REG_PB1_SADDR 0x054 #define REG_PB1_EADDR 0x058 -static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova) +#define has_sysmmu(dev) (dev->archdata.iommu != NULL) + +static struct kmem_cache *lv2table_kmem_cache; +static sysmmu_pte_t *zero_lv2_table; +#define ZERO_LV2LINK mk_lv1ent_page(virt_to_phys(zero_lv2_table)) + +static sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable, sysmmu_iova_t iova) { return pgtable + lv1ent_offset(iova); } -static unsigned long *page_entry(unsigned long *sent, unsigned long iova) +static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova) { - return (unsigned long *)__va(lv2table_base(sent)) + lv2ent_offset(iova); + return (sysmmu_pte_t *)phys_to_virt( + lv2table_base(sent)) + lv2ent_offset(iova); } enum exynos_sysmmu_inttype { @@ -124,16 +161,6 @@ enum exynos_sysmmu_inttype { SYSMMU_FAULTS_NUM }; -/* - * @itype: type of fault. - * @pgtable_base: the physical address of page table base. This is 0 if @itype - * is SYSMMU_BUSERROR. - * @fault_addr: the device (virtual) address that the System MMU tried to - * translated. This is 0 if @itype is SYSMMU_BUSERROR. - */ -typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype, - unsigned long pgtable_base, unsigned long fault_addr); - static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = { REG_PAGE_FAULT_ADDR, REG_AR_FAULT_ADDR, @@ -157,27 +184,34 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = { "UNKNOWN FAULT" }; +/* attached to dev.archdata.iommu of the master device */ +struct exynos_iommu_owner { + struct list_head client; /* entry of exynos_iommu_domain.clients */ + struct device *dev; + struct device *sysmmu; + struct iommu_domain *domain; + void *vmm_data; /* IO virtual memory manager's data */ + spinlock_t lock; /* Lock to preserve consistency of System MMU */ +}; + struct exynos_iommu_domain { struct list_head clients; /* list of sysmmu_drvdata.node */ - unsigned long *pgtable; /* lv1 page table, 16KB */ + sysmmu_pte_t *pgtable; /* lv1 page table, 16KB */ short *lv2entcnt; /* free lv2 entry counter for each section */ spinlock_t lock; /* lock for this structure */ spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */ }; struct sysmmu_drvdata { - struct list_head node; /* entry of exynos_iommu_domain.clients */ struct device *sysmmu; /* System MMU's device descriptor */ - struct device *dev; /* Owner of system MMU */ - char *dbgname; - int nsfrs; - void __iomem **sfrbases; - struct clk *clk[2]; + struct device *master; /* Owner of system MMU */ + void __iomem *sfrbase; + struct clk *clk; + struct clk *clk_master; int activations; - rwlock_t lock; + spinlock_t lock; struct iommu_domain *domain; - sysmmu_fault_handler_t fault_handler; - unsigned long pgtable; + phys_addr_t pgtable; }; static bool set_sysmmu_active(struct sysmmu_drvdata *data) @@ -204,6 +238,11 @@ static void sysmmu_unblock(void __iomem *sfrbase) __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL); } +static unsigned int __raw_sysmmu_version(struct sysmmu_drvdata *data) +{ + return MMU_RAW_VER(__raw_readl(data->sfrbase + REG_MMU_VERSION)); +} + static bool sysmmu_block(void __iomem *sfrbase) { int i = 120; @@ -226,429 +265,428 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase) } static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase, - unsigned long iova) + sysmmu_iova_t iova, unsigned int num_inv) { - __raw_writel((iova & SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY); + unsigned int i; + + for (i = 0; i < num_inv; i++) { + __raw_writel((iova & SPAGE_MASK) | 1, + sfrbase + REG_MMU_FLUSH_ENTRY); + iova += SPAGE_SIZE; + } } static void __sysmmu_set_ptbase(void __iomem *sfrbase, - unsigned long pgd) + phys_addr_t pgd) { - __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */ __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR); __sysmmu_tlb_invalidate(sfrbase); } -static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base, - unsigned long size, int idx) +static void show_fault_information(const char *name, + enum exynos_sysmmu_inttype itype, + phys_addr_t pgtable_base, sysmmu_iova_t fault_addr) { - __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8); - __raw_writel(size - 1 + base, sfrbase + REG_PB0_EADDR + idx * 8); -} - -static void __set_fault_handler(struct sysmmu_drvdata *data, - sysmmu_fault_handler_t handler) -{ - unsigned long flags; - - write_lock_irqsave(&data->lock, flags); - data->fault_handler = handler; - write_unlock_irqrestore(&data->lock, flags); -} - -void exynos_sysmmu_set_fault_handler(struct device *dev, - sysmmu_fault_handler_t handler) -{ - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); - - __set_fault_handler(data, handler); -} - -static int default_fault_handler(enum exynos_sysmmu_inttype itype, - unsigned long pgtable_base, unsigned long fault_addr) -{ - unsigned long *ent; + sysmmu_pte_t *ent; if ((itype >= SYSMMU_FAULTS_NUM) || (itype < SYSMMU_PAGEFAULT)) itype = SYSMMU_FAULT_UNKNOWN; - pr_err("%s occurred at 0x%lx(Page table base: 0x%lx)\n", - sysmmu_fault_name[itype], fault_addr, pgtable_base); + pr_err("%s occurred at %#x by %s(Page table base: %pa)\n", + sysmmu_fault_name[itype], fault_addr, name, &pgtable_base); - ent = section_entry(__va(pgtable_base), fault_addr); - pr_err("\tLv1 entry: 0x%lx\n", *ent); + ent = section_entry(phys_to_virt(pgtable_base), fault_addr); + pr_err("\tLv1 entry: %#x\n", *ent); if (lv1ent_page(ent)) { ent = page_entry(ent, fault_addr); - pr_err("\t Lv2 entry: 0x%lx\n", *ent); + pr_err("\t Lv2 entry: %#x\n", *ent); } - - pr_err("Generating Kernel OOPS... because it is unrecoverable.\n"); - - BUG(); - - return 0; } static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) { /* SYSMMU is in blocked when interrupt occurred. */ struct sysmmu_drvdata *data = dev_id; - struct resource *irqres; - struct platform_device *pdev; enum exynos_sysmmu_inttype itype; - unsigned long addr = -1; - - int i, ret = -ENOSYS; - - read_lock(&data->lock); + sysmmu_iova_t addr = -1; + int ret = -ENOSYS; WARN_ON(!is_sysmmu_active(data)); - pdev = to_platform_device(data->sysmmu); - for (i = 0; i < (pdev->num_resources / 2); i++) { - irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i); - if (irqres && ((int)irqres->start == irq)) - break; - } + spin_lock(&data->lock); + + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); - if (i == pdev->num_resources) { + itype = (enum exynos_sysmmu_inttype) + __ffs(__raw_readl(data->sfrbase + REG_INT_STATUS)); + if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN)))) itype = SYSMMU_FAULT_UNKNOWN; + else + addr = __raw_readl(data->sfrbase + fault_reg_offset[itype]); + + if (itype == SYSMMU_FAULT_UNKNOWN) { + pr_err("%s: Fault is not occurred by System MMU '%s'!\n", + __func__, dev_name(data->sysmmu)); + pr_err("%s: Please check if IRQ is correctly configured.\n", + __func__); + BUG(); } else { - itype = (enum exynos_sysmmu_inttype) - __ffs(__raw_readl(data->sfrbases[i] + REG_INT_STATUS)); - if (WARN_ON(!((itype >= 0) && (itype < SYSMMU_FAULT_UNKNOWN)))) - itype = SYSMMU_FAULT_UNKNOWN; - else - addr = __raw_readl( - data->sfrbases[i] + fault_reg_offset[itype]); + unsigned int base = + __raw_readl(data->sfrbase + REG_PT_BASE_ADDR); + show_fault_information(dev_name(data->sysmmu), + itype, base, addr); + if (data->domain) + ret = report_iommu_fault(data->domain, + data->master, addr, itype); } - if (data->domain) - ret = report_iommu_fault(data->domain, data->dev, - addr, itype); + /* fault is not recovered by fault handler */ + BUG_ON(ret != 0); - if ((ret == -ENOSYS) && data->fault_handler) { - unsigned long base = data->pgtable; - if (itype != SYSMMU_FAULT_UNKNOWN) - base = __raw_readl( - data->sfrbases[i] + REG_PT_BASE_ADDR); - ret = data->fault_handler(itype, base, addr); - } + __raw_writel(1 << itype, data->sfrbase + REG_INT_CLEAR); - if (!ret && (itype != SYSMMU_FAULT_UNKNOWN)) - __raw_writel(1 << itype, data->sfrbases[i] + REG_INT_CLEAR); - else - dev_dbg(data->sysmmu, "(%s) %s is not handled.\n", - data->dbgname, sysmmu_fault_name[itype]); + sysmmu_unblock(data->sfrbase); - if (itype != SYSMMU_FAULT_UNKNOWN) - sysmmu_unblock(data->sfrbases[i]); + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); - read_unlock(&data->lock); + spin_unlock(&data->lock); return IRQ_HANDLED; } -static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data) +static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data) { + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); + + __raw_writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL); + __raw_writel(0, data->sfrbase + REG_MMU_CFG); + + clk_disable(data->clk); + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); +} + +static bool __sysmmu_disable(struct sysmmu_drvdata *data) +{ + bool disabled; unsigned long flags; - bool disabled = false; - int i; - write_lock_irqsave(&data->lock, flags); + spin_lock_irqsave(&data->lock, flags); - if (!set_sysmmu_inactive(data)) - goto finish; + disabled = set_sysmmu_inactive(data); - for (i = 0; i < data->nsfrs; i++) - __raw_writel(CTRL_DISABLE, data->sfrbases[i] + REG_MMU_CTRL); + if (disabled) { + data->pgtable = 0; + data->domain = NULL; - if (data->clk[1]) - clk_disable(data->clk[1]); - if (data->clk[0]) - clk_disable(data->clk[0]); + __sysmmu_disable_nocount(data); - disabled = true; - data->pgtable = 0; - data->domain = NULL; -finish: - write_unlock_irqrestore(&data->lock, flags); + dev_dbg(data->sysmmu, "Disabled\n"); + } else { + dev_dbg(data->sysmmu, "%d times left to disable\n", + data->activations); + } - if (disabled) - dev_dbg(data->sysmmu, "(%s) Disabled\n", data->dbgname); - else - dev_dbg(data->sysmmu, "(%s) %d times left to be disabled\n", - data->dbgname, data->activations); + spin_unlock_irqrestore(&data->lock, flags); return disabled; } -/* __exynos_sysmmu_enable: Enables System MMU - * - * returns -error if an error occurred and System MMU is not enabled, - * 0 if the System MMU has been just enabled and 1 if System MMU was already - * enabled before. - */ -static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data, - unsigned long pgtable, struct iommu_domain *domain) +static void __sysmmu_init_config(struct sysmmu_drvdata *data) { - int i, ret = 0; - unsigned long flags; + unsigned int cfg = CFG_LRU | CFG_QOS(15); + unsigned int ver; + + ver = __raw_sysmmu_version(data); + if (MMU_MAJ_VER(ver) == 3) { + if (MMU_MIN_VER(ver) >= 2) { + cfg |= CFG_FLPDCACHE; + if (MMU_MIN_VER(ver) == 3) { + cfg |= CFG_ACGEN; + cfg &= ~CFG_LRU; + } else { + cfg |= CFG_SYSSEL; + } + } + } - write_lock_irqsave(&data->lock, flags); + __raw_writel(cfg, data->sfrbase + REG_MMU_CFG); +} - if (!set_sysmmu_active(data)) { - if (WARN_ON(pgtable != data->pgtable)) { - ret = -EBUSY; - set_sysmmu_inactive(data); - } else { - ret = 1; - } +static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) +{ + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); + clk_enable(data->clk); - dev_dbg(data->sysmmu, "(%s) Already enabled\n", data->dbgname); - goto finish; - } + __raw_writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL); - if (data->clk[0]) - clk_enable(data->clk[0]); - if (data->clk[1]) - clk_enable(data->clk[1]); + __sysmmu_init_config(data); - data->pgtable = pgtable; + __sysmmu_set_ptbase(data->sfrbase, data->pgtable); - for (i = 0; i < data->nsfrs; i++) { - __sysmmu_set_ptbase(data->sfrbases[i], pgtable); + __raw_writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); - if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) { - /* System MMU version is 3.x */ - __raw_writel((1 << 12) | (2 << 28), - data->sfrbases[i] + REG_MMU_CFG); - __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 0); - __sysmmu_set_prefbuf(data->sfrbases[i], 0, -1, 1); - } + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); +} + +static int __sysmmu_enable(struct sysmmu_drvdata *data, + phys_addr_t pgtable, struct iommu_domain *domain) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&data->lock, flags); + if (set_sysmmu_active(data)) { + data->pgtable = pgtable; + data->domain = domain; + + __sysmmu_enable_nocount(data); + + dev_dbg(data->sysmmu, "Enabled\n"); + } else { + ret = (pgtable == data->pgtable) ? 1 : -EBUSY; - __raw_writel(CTRL_ENABLE, data->sfrbases[i] + REG_MMU_CTRL); + dev_dbg(data->sysmmu, "already enabled\n"); } - data->domain = domain; + if (WARN_ON(ret < 0)) + set_sysmmu_inactive(data); /* decrement count */ - dev_dbg(data->sysmmu, "(%s) Enabled\n", data->dbgname); -finish: - write_unlock_irqrestore(&data->lock, flags); + spin_unlock_irqrestore(&data->lock, flags); return ret; } -int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable) +/* __exynos_sysmmu_enable: Enables System MMU + * + * returns -error if an error occurred and System MMU is not enabled, + * 0 if the System MMU has been just enabled and 1 if System MMU was already + * enabled before. + */ +static int __exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable, + struct iommu_domain *domain) { - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); - int ret; + int ret = 0; + unsigned long flags; + struct exynos_iommu_owner *owner = dev->archdata.iommu; + struct sysmmu_drvdata *data; - BUG_ON(!memblock_is_memory(pgtable)); + BUG_ON(!has_sysmmu(dev)); - ret = pm_runtime_get_sync(data->sysmmu); - if (ret < 0) { - dev_dbg(data->sysmmu, "(%s) Failed to enable\n", data->dbgname); - return ret; - } + spin_lock_irqsave(&owner->lock, flags); - ret = __exynos_sysmmu_enable(data, pgtable, NULL); - if (WARN_ON(ret < 0)) { - pm_runtime_put(data->sysmmu); - dev_err(data->sysmmu, - "(%s) Already enabled with page table %#lx\n", - data->dbgname, data->pgtable); - } else { - data->dev = dev; - } + data = dev_get_drvdata(owner->sysmmu); + + ret = __sysmmu_enable(data, pgtable, domain); + if (ret >= 0) + data->master = dev; + + spin_unlock_irqrestore(&owner->lock, flags); return ret; } +int exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable) +{ + BUG_ON(!memblock_is_memory(pgtable)); + + return __exynos_sysmmu_enable(dev, pgtable, NULL); +} + static bool exynos_sysmmu_disable(struct device *dev) { - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); - bool disabled; + unsigned long flags; + bool disabled = true; + struct exynos_iommu_owner *owner = dev->archdata.iommu; + struct sysmmu_drvdata *data; + + BUG_ON(!has_sysmmu(dev)); + + spin_lock_irqsave(&owner->lock, flags); + + data = dev_get_drvdata(owner->sysmmu); + + disabled = __sysmmu_disable(data); + if (disabled) + data->master = NULL; - disabled = __exynos_sysmmu_disable(data); - pm_runtime_put(data->sysmmu); + spin_unlock_irqrestore(&owner->lock, flags); return disabled; } -static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova) +static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, + sysmmu_iova_t iova) +{ + if (__raw_sysmmu_version(data) == MAKE_MMU_VER(3, 3)) + __raw_writel(iova | 0x1, data->sfrbase + REG_MMU_FLUSH_ENTRY); +} + +static void sysmmu_tlb_invalidate_flpdcache(struct device *dev, + sysmmu_iova_t iova) { unsigned long flags; - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct exynos_iommu_owner *owner = dev->archdata.iommu; + struct sysmmu_drvdata *data = dev_get_drvdata(owner->sysmmu); + + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); - read_lock_irqsave(&data->lock, flags); + spin_lock_irqsave(&data->lock, flags); + if (is_sysmmu_active(data)) + __sysmmu_tlb_invalidate_flpdcache(data, iova); + spin_unlock_irqrestore(&data->lock, flags); + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); +} + +static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t iova, + size_t size) +{ + struct exynos_iommu_owner *owner = dev->archdata.iommu; + unsigned long flags; + struct sysmmu_drvdata *data; + + data = dev_get_drvdata(owner->sysmmu); + + spin_lock_irqsave(&data->lock, flags); if (is_sysmmu_active(data)) { - int i; - for (i = 0; i < data->nsfrs; i++) { - if (sysmmu_block(data->sfrbases[i])) { - __sysmmu_tlb_invalidate_entry( - data->sfrbases[i], iova); - sysmmu_unblock(data->sfrbases[i]); - } + unsigned int num_inv = 1; + + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); + + /* + * L2TLB invalidation required + * 4KB page: 1 invalidation + * 64KB page: 16 invalidation + * 1MB page: 64 invalidation + * because it is set-associative TLB + * with 8-way and 64 sets. + * 1MB page can be cached in one of all sets. + * 64KB page can be one of 16 consecutive sets. + */ + if (MMU_MAJ_VER(__raw_sysmmu_version(data)) == 2) + num_inv = min_t(unsigned int, size / PAGE_SIZE, 64); + + if (sysmmu_block(data->sfrbase)) { + __sysmmu_tlb_invalidate_entry( + data->sfrbase, iova, num_inv); + sysmmu_unblock(data->sfrbase); } + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); } else { - dev_dbg(data->sysmmu, - "(%s) Disabled. Skipping invalidating TLB.\n", - data->dbgname); + dev_dbg(dev, "disabled. Skipping TLB invalidation @ %#x\n", + iova); } - - read_unlock_irqrestore(&data->lock, flags); + spin_unlock_irqrestore(&data->lock, flags); } void exynos_sysmmu_tlb_invalidate(struct device *dev) { + struct exynos_iommu_owner *owner = dev->archdata.iommu; unsigned long flags; - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct sysmmu_drvdata *data; - read_lock_irqsave(&data->lock, flags); + data = dev_get_drvdata(owner->sysmmu); + spin_lock_irqsave(&data->lock, flags); if (is_sysmmu_active(data)) { - int i; - for (i = 0; i < data->nsfrs; i++) { - if (sysmmu_block(data->sfrbases[i])) { - __sysmmu_tlb_invalidate(data->sfrbases[i]); - sysmmu_unblock(data->sfrbases[i]); - } + if (!IS_ERR(data->clk_master)) + clk_enable(data->clk_master); + if (sysmmu_block(data->sfrbase)) { + __sysmmu_tlb_invalidate(data->sfrbase); + sysmmu_unblock(data->sfrbase); } + if (!IS_ERR(data->clk_master)) + clk_disable(data->clk_master); } else { - dev_dbg(data->sysmmu, - "(%s) Disabled. Skipping invalidating TLB.\n", - data->dbgname); + dev_dbg(dev, "disabled. Skipping TLB invalidation\n"); } - - read_unlock_irqrestore(&data->lock, flags); + spin_unlock_irqrestore(&data->lock, flags); } -static int exynos_sysmmu_probe(struct platform_device *pdev) +static int __init exynos_sysmmu_probe(struct platform_device *pdev) { - int i, ret; - struct device *dev; + int irq, ret; + struct device *dev = &pdev->dev; struct sysmmu_drvdata *data; + struct resource *res; - dev = &pdev->dev; + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) { - dev_dbg(dev, "Not enough memory\n"); - ret = -ENOMEM; - goto err_alloc; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->sfrbase = devm_ioremap_resource(dev, res); + if (IS_ERR(data->sfrbase)) + return PTR_ERR(data->sfrbase); - dev_set_drvdata(dev, data); - data->nsfrs = pdev->num_resources / 2; - data->sfrbases = kmalloc(sizeof(*data->sfrbases) * data->nsfrs, - GFP_KERNEL); - if (data->sfrbases == NULL) { - dev_dbg(dev, "Not enough memory\n"); - ret = -ENOMEM; - goto err_init; + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev, "Unable to find IRQ resource\n"); + return irq; } - for (i = 0; i < data->nsfrs; i++) { - struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (!res) { - dev_dbg(dev, "Unable to find IOMEM region\n"); - ret = -ENOENT; - goto err_res; - } - - data->sfrbases[i] = ioremap(res->start, resource_size(res)); - if (!data->sfrbases[i]) { - dev_dbg(dev, "Unable to map IOMEM @ PA:%#x\n", - res->start); - ret = -ENOENT; - goto err_res; - } + ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0, + dev_name(dev), data); + if (ret) { + dev_err(dev, "Unabled to register handler of irq %d\n", irq); + return ret; } - for (i = 0; i < data->nsfrs; i++) { - ret = platform_get_irq(pdev, i); - if (ret <= 0) { - dev_dbg(dev, "Unable to find IRQ resource\n"); - goto err_irq; - } - - ret = request_irq(ret, exynos_sysmmu_irq, 0, - dev_name(dev), data); + data->clk = devm_clk_get(dev, "sysmmu"); + if (IS_ERR(data->clk)) { + dev_err(dev, "Failed to get clock!\n"); + return PTR_ERR(data->clk); + } else { + ret = clk_prepare(data->clk); if (ret) { - dev_dbg(dev, "Unabled to register interrupt handler\n"); - goto err_irq; + dev_err(dev, "Failed to prepare clk\n"); + return ret; } } - if (dev_get_platdata(dev)) { - char *deli, *beg; - struct sysmmu_platform_data *platdata = dev_get_platdata(dev); - - beg = platdata->clockname; - - for (deli = beg; (*deli != '\0') && (*deli != ','); deli++) - /* NOTHING */; - - if (*deli == '\0') - deli = NULL; - else - *deli = '\0'; - - data->clk[0] = clk_get(dev, beg); - if (IS_ERR(data->clk[0])) { - data->clk[0] = NULL; - dev_dbg(dev, "No clock descriptor registered\n"); - } - - if (data->clk[0] && deli) { - *deli = ','; - data->clk[1] = clk_get(dev, deli + 1); - if (IS_ERR(data->clk[1])) - data->clk[1] = NULL; + data->clk_master = devm_clk_get(dev, "master"); + if (!IS_ERR(data->clk_master)) { + ret = clk_prepare(data->clk_master); + if (ret) { + clk_unprepare(data->clk); + dev_err(dev, "Failed to prepare master's clk\n"); + return ret; } - - data->dbgname = platdata->dbgname; } data->sysmmu = dev; - rwlock_init(&data->lock); - INIT_LIST_HEAD(&data->node); + spin_lock_init(&data->lock); - __set_fault_handler(data, &default_fault_handler); + platform_set_drvdata(pdev, data); - if (dev->parent) - pm_runtime_enable(dev); + pm_runtime_enable(dev); - dev_dbg(dev, "(%s) Initialized\n", data->dbgname); return 0; -err_irq: - while (i-- > 0) { - int irq; - - irq = platform_get_irq(pdev, i); - free_irq(irq, data); - } -err_res: - while (data->nsfrs-- > 0) - iounmap(data->sfrbases[data->nsfrs]); - kfree(data->sfrbases); -err_init: - kfree(data); -err_alloc: - dev_err(dev, "Failed to initialize\n"); - return ret; } -static struct platform_driver exynos_sysmmu_driver = { - .probe = exynos_sysmmu_probe, - .driver = { +static const struct of_device_id sysmmu_of_match[] __initconst = { + { .compatible = "samsung,exynos-sysmmu", }, + { }, +}; + +static struct platform_driver exynos_sysmmu_driver __refdata = { + .probe = exynos_sysmmu_probe, + .driver = { .owner = THIS_MODULE, .name = "exynos-sysmmu", + .of_match_table = sysmmu_of_match, } }; @@ -662,21 +700,32 @@ static inline void pgtable_flush(void *vastart, void *vaend) static int exynos_iommu_domain_init(struct iommu_domain *domain) { struct exynos_iommu_domain *priv; + int i; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->pgtable = (unsigned long *)__get_free_pages( - GFP_KERNEL | __GFP_ZERO, 2); + priv->pgtable = (sysmmu_pte_t *)__get_free_pages(GFP_KERNEL, 2); if (!priv->pgtable) goto err_pgtable; - priv->lv2entcnt = (short *)__get_free_pages( - GFP_KERNEL | __GFP_ZERO, 1); + priv->lv2entcnt = (short *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1); if (!priv->lv2entcnt) goto err_counter; + /* w/a of System MMU v3.3 to prevent caching 1MiB mapping */ + for (i = 0; i < NUM_LV1ENTRIES; i += 8) { + priv->pgtable[i + 0] = ZERO_LV2LINK; + priv->pgtable[i + 1] = ZERO_LV2LINK; + priv->pgtable[i + 2] = ZERO_LV2LINK; + priv->pgtable[i + 3] = ZERO_LV2LINK; + priv->pgtable[i + 4] = ZERO_LV2LINK; + priv->pgtable[i + 5] = ZERO_LV2LINK; + priv->pgtable[i + 6] = ZERO_LV2LINK; + priv->pgtable[i + 7] = ZERO_LV2LINK; + } + pgtable_flush(priv->pgtable, priv->pgtable + NUM_LV1ENTRIES); spin_lock_init(&priv->lock); @@ -700,7 +749,7 @@ err_pgtable: static void exynos_iommu_domain_destroy(struct iommu_domain *domain) { struct exynos_iommu_domain *priv = domain->priv; - struct sysmmu_drvdata *data; + struct exynos_iommu_owner *owner; unsigned long flags; int i; @@ -708,16 +757,20 @@ static void exynos_iommu_domain_destroy(struct iommu_domain *domain) spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(data, &priv->clients, node) { - while (!exynos_sysmmu_disable(data->dev)) + list_for_each_entry(owner, &priv->clients, client) { + while (!exynos_sysmmu_disable(owner->dev)) ; /* until System MMU is actually disabled */ } + while (!list_empty(&priv->clients)) + list_del_init(priv->clients.next); + spin_unlock_irqrestore(&priv->lock, flags); for (i = 0; i < NUM_LV1ENTRIES; i++) if (lv1ent_page(priv->pgtable + i)) - kfree(__va(lv2table_base(priv->pgtable + i))); + kmem_cache_free(lv2table_kmem_cache, + phys_to_virt(lv2table_base(priv->pgtable + i))); free_pages((unsigned long)priv->pgtable, 2); free_pages((unsigned long)priv->lv2entcnt, 1); @@ -728,114 +781,134 @@ static void exynos_iommu_domain_destroy(struct iommu_domain *domain) static int exynos_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct exynos_iommu_owner *owner = dev->archdata.iommu; struct exynos_iommu_domain *priv = domain->priv; + phys_addr_t pagetable = virt_to_phys(priv->pgtable); unsigned long flags; int ret; - ret = pm_runtime_get_sync(data->sysmmu); - if (ret < 0) - return ret; - - ret = 0; - spin_lock_irqsave(&priv->lock, flags); - ret = __exynos_sysmmu_enable(data, __pa(priv->pgtable), domain); - + ret = __exynos_sysmmu_enable(dev, pagetable, domain); if (ret == 0) { - /* 'data->node' must not be appeared in priv->clients */ - BUG_ON(!list_empty(&data->node)); - data->dev = dev; - list_add_tail(&data->node, &priv->clients); + list_add_tail(&owner->client, &priv->clients); + owner->domain = domain; } spin_unlock_irqrestore(&priv->lock, flags); if (ret < 0) { - dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n", - __func__, __pa(priv->pgtable)); - pm_runtime_put(data->sysmmu); - } else if (ret > 0) { - dev_dbg(dev, "%s: IOMMU with pgtable 0x%lx already attached\n", - __func__, __pa(priv->pgtable)); - } else { - dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n", - __func__, __pa(priv->pgtable)); + dev_err(dev, "%s: Failed to attach IOMMU with pgtable %pa\n", + __func__, &pagetable); + return ret; } + dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa %s\n", + __func__, &pagetable, (ret == 0) ? "" : ", again"); + return ret; } static void exynos_iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu); + struct exynos_iommu_owner *owner; struct exynos_iommu_domain *priv = domain->priv; - struct list_head *pos; + phys_addr_t pagetable = virt_to_phys(priv->pgtable); unsigned long flags; - bool found = false; spin_lock_irqsave(&priv->lock, flags); - list_for_each(pos, &priv->clients) { - if (list_entry(pos, struct sysmmu_drvdata, node) == data) { - found = true; + list_for_each_entry(owner, &priv->clients, client) { + if (owner == dev->archdata.iommu) { + if (exynos_sysmmu_disable(dev)) { + list_del_init(&owner->client); + owner->domain = NULL; + } break; } } - if (!found) - goto finish; - - if (__exynos_sysmmu_disable(data)) { - dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n", - __func__, __pa(priv->pgtable)); - list_del_init(&data->node); - - } else { - dev_dbg(dev, "%s: Detaching IOMMU with pgtable %#lx delayed", - __func__, __pa(priv->pgtable)); - } - -finish: spin_unlock_irqrestore(&priv->lock, flags); - if (found) - pm_runtime_put(data->sysmmu); + if (owner == dev->archdata.iommu) + dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", + __func__, &pagetable); + else + dev_err(dev, "%s: No IOMMU is attached\n", __func__); } -static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova, - short *pgcounter) +static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *priv, + sysmmu_pte_t *sent, sysmmu_iova_t iova, short *pgcounter) { + if (lv1ent_section(sent)) { + WARN(1, "Trying mapping on %#08x mapped with 1MiB page", iova); + return ERR_PTR(-EADDRINUSE); + } + if (lv1ent_fault(sent)) { - unsigned long *pent; + sysmmu_pte_t *pent; + bool need_flush_flpd_cache = lv1ent_zero(sent); - pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC); - BUG_ON((unsigned long)pent & (LV2TABLE_SIZE - 1)); + pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC); + BUG_ON((unsigned int)pent & (LV2TABLE_SIZE - 1)); if (!pent) - return NULL; + return ERR_PTR(-ENOMEM); - *sent = mk_lv1ent_page(__pa(pent)); + *sent = mk_lv1ent_page(virt_to_phys(pent)); *pgcounter = NUM_LV2ENTRIES; pgtable_flush(pent, pent + NUM_LV2ENTRIES); pgtable_flush(sent, sent + 1); + + /* + * If pretched SLPD is a fault SLPD in zero_l2_table, FLPD cache + * may caches the address of zero_l2_table. This function + * replaces the zero_l2_table with new L2 page table to write + * valid mappings. + * Accessing the valid area may cause page fault since FLPD + * cache may still caches zero_l2_table for the valid area + * instead of new L2 page table that have the mapping + * information of the valid area + * Thus any replacement of zero_l2_table with other valid L2 + * page table must involve FLPD cache invalidation for System + * MMU v3.3. + * FLPD cache invalidation is performed with TLB invalidation + * by VPN without blocking. It is safe to invalidate TLB without + * blocking because the target address of TLB invalidation is + * not currently mapped. + */ + if (need_flush_flpd_cache) { + struct exynos_iommu_owner *owner; + + spin_lock(&priv->lock); + list_for_each_entry(owner, &priv->clients, client) + sysmmu_tlb_invalidate_flpdcache( + owner->dev, iova); + spin_unlock(&priv->lock); + } } return page_entry(sent, iova); } -static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt) +static int lv1set_section(struct exynos_iommu_domain *priv, + sysmmu_pte_t *sent, sysmmu_iova_t iova, + phys_addr_t paddr, short *pgcnt) { - if (lv1ent_section(sent)) + if (lv1ent_section(sent)) { + WARN(1, "Trying mapping on 1MiB@%#08x that is mapped", + iova); return -EADDRINUSE; + } if (lv1ent_page(sent)) { - if (*pgcnt != NUM_LV2ENTRIES) + if (*pgcnt != NUM_LV2ENTRIES) { + WARN(1, "Trying mapping on 1MiB@%#08x that is mapped", + iova); return -EADDRINUSE; + } - kfree(page_entry(sent, 0)); - + kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0)); *pgcnt = 0; } @@ -843,14 +916,26 @@ static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt) pgtable_flush(sent, sent + 1); + spin_lock(&priv->lock); + if (lv1ent_page_zero(sent)) { + struct exynos_iommu_owner *owner; + /* + * Flushing FLPD cache in System MMU v3.3 that may cache a FLPD + * entry by speculative prefetch of SLPD which has no mapping. + */ + list_for_each_entry(owner, &priv->clients, client) + sysmmu_tlb_invalidate_flpdcache(owner->dev, iova); + } + spin_unlock(&priv->lock); + return 0; } -static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, +static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, short *pgcnt) { if (size == SPAGE_SIZE) { - if (!lv2ent_fault(pent)) + if (WARN_ON(!lv2ent_fault(pent))) return -EADDRINUSE; *pent = mk_lv2ent_spage(paddr); @@ -858,9 +943,11 @@ static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, *pgcnt -= 1; } else { /* size == LPAGE_SIZE */ int i; + for (i = 0; i < SPAGES_PER_LPAGE; i++, pent++) { - if (!lv2ent_fault(pent)) { - memset(pent, 0, sizeof(*pent) * i); + if (WARN_ON(!lv2ent_fault(pent))) { + if (i > 0) + memset(pent - i, 0, sizeof(*pent) * i); return -EADDRINUSE; } @@ -873,11 +960,38 @@ static int lv2set_page(unsigned long *pent, phys_addr_t paddr, size_t size, return 0; } -static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, +/* + * *CAUTION* to the I/O virtual memory managers that support exynos-iommu: + * + * System MMU v3.x have an advanced logic to improve address translation + * performance with caching more page table entries by a page table walk. + * However, the logic has a bug that caching fault page table entries and System + * MMU reports page fault if the cached fault entry is hit even though the fault + * entry is updated to a valid entry after the entry is cached. + * To prevent caching fault page table entries which may be updated to valid + * entries later, the virtual memory manager should care about the w/a about the + * problem. The followings describe w/a. + * + * Any two consecutive I/O virtual address regions must have a hole of 128KiB + * in maximum to prevent misbehavior of System MMU 3.x. (w/a of h/w bug) + * + * Precisely, any start address of I/O virtual region must be aligned by + * the following sizes for System MMU v3.1 and v3.2. + * System MMU v3.1: 128KiB + * System MMU v3.2: 256KiB + * + * Because System MMU v3.3 caches page table entries more aggressively, it needs + * more w/a. + * - Any two consecutive I/O virtual regions must be have a hole of larger size + * than or equal size to 128KiB. + * - Start address of an I/O virtual region must be aligned by 128KiB. + */ +static int exynos_iommu_map(struct iommu_domain *domain, unsigned long l_iova, phys_addr_t paddr, size_t size, int prot) { struct exynos_iommu_domain *priv = domain->priv; - unsigned long *entry; + sysmmu_pte_t *entry; + sysmmu_iova_t iova = (sysmmu_iova_t)l_iova; unsigned long flags; int ret = -ENOMEM; @@ -888,38 +1002,52 @@ static int exynos_iommu_map(struct iommu_domain *domain, unsigned long iova, entry = section_entry(priv->pgtable, iova); if (size == SECT_SIZE) { - ret = lv1set_section(entry, paddr, + ret = lv1set_section(priv, entry, iova, paddr, &priv->lv2entcnt[lv1ent_offset(iova)]); } else { - unsigned long *pent; + sysmmu_pte_t *pent; - pent = alloc_lv2entry(entry, iova, + pent = alloc_lv2entry(priv, entry, iova, &priv->lv2entcnt[lv1ent_offset(iova)]); - if (!pent) - ret = -ENOMEM; + if (IS_ERR(pent)) + ret = PTR_ERR(pent); else ret = lv2set_page(pent, paddr, size, &priv->lv2entcnt[lv1ent_offset(iova)]); } - if (ret) { - pr_debug("%s: Failed to map iova 0x%lx/0x%x bytes\n", - __func__, iova, size); - } + if (ret) + pr_err("%s: Failed(%d) to map %#zx bytes @ %#x\n", + __func__, ret, size, iova); spin_unlock_irqrestore(&priv->pgtablelock, flags); return ret; } +static void exynos_iommu_tlb_invalidate_entry(struct exynos_iommu_domain *priv, + sysmmu_iova_t iova, size_t size) +{ + struct exynos_iommu_owner *owner; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + list_for_each_entry(owner, &priv->clients, client) + sysmmu_tlb_invalidate_entry(owner->dev, iova, size); + + spin_unlock_irqrestore(&priv->lock, flags); +} + static size_t exynos_iommu_unmap(struct iommu_domain *domain, - unsigned long iova, size_t size) + unsigned long l_iova, size_t size) { struct exynos_iommu_domain *priv = domain->priv; - struct sysmmu_drvdata *data; + sysmmu_iova_t iova = (sysmmu_iova_t)l_iova; + sysmmu_pte_t *ent; + size_t err_pgsize; unsigned long flags; - unsigned long *ent; BUG_ON(priv->pgtable == NULL); @@ -928,9 +1056,12 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, ent = section_entry(priv->pgtable, iova); if (lv1ent_section(ent)) { - BUG_ON(size < SECT_SIZE); + if (WARN_ON(size < SECT_SIZE)) { + err_pgsize = SECT_SIZE; + goto err; + } - *ent = 0; + *ent = ZERO_LV2LINK; /* w/a for h/w bug in Sysmem MMU v3.3 */ pgtable_flush(ent, ent + 1); size = SECT_SIZE; goto done; @@ -954,34 +1085,42 @@ static size_t exynos_iommu_unmap(struct iommu_domain *domain, if (lv2ent_small(ent)) { *ent = 0; size = SPAGE_SIZE; + pgtable_flush(ent, ent + 1); priv->lv2entcnt[lv1ent_offset(iova)] += 1; goto done; } /* lv1ent_large(ent) == true here */ - BUG_ON(size < LPAGE_SIZE); + if (WARN_ON(size < LPAGE_SIZE)) { + err_pgsize = LPAGE_SIZE; + goto err; + } memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE); + pgtable_flush(ent, ent + SPAGES_PER_LPAGE); size = LPAGE_SIZE; priv->lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE; done: spin_unlock_irqrestore(&priv->pgtablelock, flags); - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry(data, &priv->clients, node) - sysmmu_tlb_invalidate_entry(data->dev, iova); - spin_unlock_irqrestore(&priv->lock, flags); - + exynos_iommu_tlb_invalidate_entry(priv, iova, size); return size; +err: + spin_unlock_irqrestore(&priv->pgtablelock, flags); + + pr_err("%s: Failed: size(%#zx) @ %#x is smaller than page size %#zx\n", + __func__, size, iova, err_pgsize); + + return 0; } static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova) { struct exynos_iommu_domain *priv = domain->priv; - unsigned long *entry; + sysmmu_pte_t *entry; unsigned long flags; phys_addr_t phys = 0; @@ -1005,6 +1144,32 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct iommu_domain *domain, return phys; } +static int exynos_iommu_add_device(struct device *dev) +{ + struct iommu_group *group; + int ret; + + group = iommu_group_get(dev); + + if (!group) { + group = iommu_group_alloc(); + if (IS_ERR(group)) { + dev_err(dev, "Failed to allocate IOMMU group\n"); + return PTR_ERR(group); + } + } + + ret = iommu_group_add_device(group, dev); + iommu_group_put(group); + + return ret; +} + +static void exynos_iommu_remove_device(struct device *dev) +{ + iommu_group_remove_device(dev); +} + static struct iommu_ops exynos_iommu_ops = { .domain_init = exynos_iommu_domain_init, .domain_destroy = exynos_iommu_domain_destroy, @@ -1013,6 +1178,8 @@ static struct iommu_ops exynos_iommu_ops = { .map = exynos_iommu_map, .unmap = exynos_iommu_unmap, .iova_to_phys = exynos_iommu_iova_to_phys, + .add_device = exynos_iommu_add_device, + .remove_device = exynos_iommu_remove_device, .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE, }; @@ -1020,11 +1187,41 @@ static int __init exynos_iommu_init(void) { int ret; + lv2table_kmem_cache = kmem_cache_create("exynos-iommu-lv2table", + LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL); + if (!lv2table_kmem_cache) { + pr_err("%s: Failed to create kmem cache\n", __func__); + return -ENOMEM; + } + ret = platform_driver_register(&exynos_sysmmu_driver); + if (ret) { + pr_err("%s: Failed to register driver\n", __func__); + goto err_reg_driver; + } - if (ret == 0) - bus_set_iommu(&platform_bus_type, &exynos_iommu_ops); + zero_lv2_table = kmem_cache_zalloc(lv2table_kmem_cache, GFP_KERNEL); + if (zero_lv2_table == NULL) { + pr_err("%s: Failed to allocate zero level2 page table\n", + __func__); + ret = -ENOMEM; + goto err_zero_lv2; + } + ret = bus_set_iommu(&platform_bus_type, &exynos_iommu_ops); + if (ret) { + pr_err("%s: Failed to register exynos-iommu driver.\n", + __func__); + goto err_set_iommu; + } + + return 0; +err_set_iommu: + kmem_cache_free(lv2table_kmem_cache, zero_lv2_table); +err_zero_lv2: + platform_driver_unregister(&exynos_sysmmu_driver); +err_reg_driver: + kmem_cache_destroy(lv2table_kmem_cache); return ret; } subsys_initcall(exynos_iommu_init); diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c index cba0498eb011..b99dd88e31b9 100644 --- a/drivers/iommu/fsl_pamu.c +++ b/drivers/iommu/fsl_pamu.c @@ -592,8 +592,7 @@ found_cpu_node: /* advance to next node in cache hierarchy */ node = of_find_node_by_phandle(*prop); if (!node) { - pr_debug("Invalid node for cache hierarchy %s\n", - node->full_name); + pr_debug("Invalid node for cache hierarchy\n"); return ~(u32)0; } } diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c new file mode 100644 index 000000000000..53cde086e83b --- /dev/null +++ b/drivers/iommu/ipmmu-vmsa.c @@ -0,0 +1,1255 @@ +/* + * IPMMU VMSA + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iommu.h> +#include <linux/module.h> +#include <linux/platform_data/ipmmu-vmsa.h> +#include <linux/platform_device.h> +#include <linux/sizes.h> +#include <linux/slab.h> + +#include <asm/dma-iommu.h> +#include <asm/pgalloc.h> + +struct ipmmu_vmsa_device { + struct device *dev; + void __iomem *base; + struct list_head list; + + const struct ipmmu_vmsa_platform_data *pdata; + unsigned int num_utlbs; + + struct dma_iommu_mapping *mapping; +}; + +struct ipmmu_vmsa_domain { + struct ipmmu_vmsa_device *mmu; + struct iommu_domain *io_domain; + + unsigned int context_id; + spinlock_t lock; /* Protects mappings */ + pgd_t *pgd; +}; + +struct ipmmu_vmsa_archdata { + struct ipmmu_vmsa_device *mmu; + unsigned int utlb; +}; + +static DEFINE_SPINLOCK(ipmmu_devices_lock); +static LIST_HEAD(ipmmu_devices); + +#define TLB_LOOP_TIMEOUT 100 /* 100us */ + +/* ----------------------------------------------------------------------------- + * Registers Definition + */ + +#define IM_CTX_SIZE 0x40 + +#define IMCTR 0x0000 +#define IMCTR_TRE (1 << 17) +#define IMCTR_AFE (1 << 16) +#define IMCTR_RTSEL_MASK (3 << 4) +#define IMCTR_RTSEL_SHIFT 4 +#define IMCTR_TREN (1 << 3) +#define IMCTR_INTEN (1 << 2) +#define IMCTR_FLUSH (1 << 1) +#define IMCTR_MMUEN (1 << 0) + +#define IMCAAR 0x0004 + +#define IMTTBCR 0x0008 +#define IMTTBCR_EAE (1 << 31) +#define IMTTBCR_PMB (1 << 30) +#define IMTTBCR_SH1_NON_SHAREABLE (0 << 28) +#define IMTTBCR_SH1_OUTER_SHAREABLE (2 << 28) +#define IMTTBCR_SH1_INNER_SHAREABLE (3 << 28) +#define IMTTBCR_SH1_MASK (3 << 28) +#define IMTTBCR_ORGN1_NC (0 << 26) +#define IMTTBCR_ORGN1_WB_WA (1 << 26) +#define IMTTBCR_ORGN1_WT (2 << 26) +#define IMTTBCR_ORGN1_WB (3 << 26) +#define IMTTBCR_ORGN1_MASK (3 << 26) +#define IMTTBCR_IRGN1_NC (0 << 24) +#define IMTTBCR_IRGN1_WB_WA (1 << 24) +#define IMTTBCR_IRGN1_WT (2 << 24) +#define IMTTBCR_IRGN1_WB (3 << 24) +#define IMTTBCR_IRGN1_MASK (3 << 24) +#define IMTTBCR_TSZ1_MASK (7 << 16) +#define IMTTBCR_TSZ1_SHIFT 16 +#define IMTTBCR_SH0_NON_SHAREABLE (0 << 12) +#define IMTTBCR_SH0_OUTER_SHAREABLE (2 << 12) +#define IMTTBCR_SH0_INNER_SHAREABLE (3 << 12) +#define IMTTBCR_SH0_MASK (3 << 12) +#define IMTTBCR_ORGN0_NC (0 << 10) +#define IMTTBCR_ORGN0_WB_WA (1 << 10) +#define IMTTBCR_ORGN0_WT (2 << 10) +#define IMTTBCR_ORGN0_WB (3 << 10) +#define IMTTBCR_ORGN0_MASK (3 << 10) +#define IMTTBCR_IRGN0_NC (0 << 8) +#define IMTTBCR_IRGN0_WB_WA (1 << 8) +#define IMTTBCR_IRGN0_WT (2 << 8) +#define IMTTBCR_IRGN0_WB (3 << 8) +#define IMTTBCR_IRGN0_MASK (3 << 8) +#define IMTTBCR_SL0_LVL_2 (0 << 4) +#define IMTTBCR_SL0_LVL_1 (1 << 4) +#define IMTTBCR_TSZ0_MASK (7 << 0) +#define IMTTBCR_TSZ0_SHIFT O + +#define IMBUSCR 0x000c +#define IMBUSCR_DVM (1 << 2) +#define IMBUSCR_BUSSEL_SYS (0 << 0) +#define IMBUSCR_BUSSEL_CCI (1 << 0) +#define IMBUSCR_BUSSEL_IMCAAR (2 << 0) +#define IMBUSCR_BUSSEL_CCI_IMCAAR (3 << 0) +#define IMBUSCR_BUSSEL_MASK (3 << 0) + +#define IMTTLBR0 0x0010 +#define IMTTUBR0 0x0014 +#define IMTTLBR1 0x0018 +#define IMTTUBR1 0x001c + +#define IMSTR 0x0020 +#define IMSTR_ERRLVL_MASK (3 << 12) +#define IMSTR_ERRLVL_SHIFT 12 +#define IMSTR_ERRCODE_TLB_FORMAT (1 << 8) +#define IMSTR_ERRCODE_ACCESS_PERM (4 << 8) +#define IMSTR_ERRCODE_SECURE_ACCESS (5 << 8) +#define IMSTR_ERRCODE_MASK (7 << 8) +#define IMSTR_MHIT (1 << 4) +#define IMSTR_ABORT (1 << 2) +#define IMSTR_PF (1 << 1) +#define IMSTR_TF (1 << 0) + +#define IMMAIR0 0x0028 +#define IMMAIR1 0x002c +#define IMMAIR_ATTR_MASK 0xff +#define IMMAIR_ATTR_DEVICE 0x04 +#define IMMAIR_ATTR_NC 0x44 +#define IMMAIR_ATTR_WBRWA 0xff +#define IMMAIR_ATTR_SHIFT(n) ((n) << 3) +#define IMMAIR_ATTR_IDX_NC 0 +#define IMMAIR_ATTR_IDX_WBRWA 1 +#define IMMAIR_ATTR_IDX_DEV 2 + +#define IMEAR 0x0030 + +#define IMPCTR 0x0200 +#define IMPSTR 0x0208 +#define IMPEAR 0x020c +#define IMPMBA(n) (0x0280 + ((n) * 4)) +#define IMPMBD(n) (0x02c0 + ((n) * 4)) + +#define IMUCTR(n) (0x0300 + ((n) * 16)) +#define IMUCTR_FIXADDEN (1 << 31) +#define IMUCTR_FIXADD_MASK (0xff << 16) +#define IMUCTR_FIXADD_SHIFT 16 +#define IMUCTR_TTSEL_MMU(n) ((n) << 4) +#define IMUCTR_TTSEL_PMB (8 << 4) +#define IMUCTR_TTSEL_MASK (15 << 4) +#define IMUCTR_FLUSH (1 << 1) +#define IMUCTR_MMUEN (1 << 0) + +#define IMUASID(n) (0x0308 + ((n) * 16)) +#define IMUASID_ASID8_MASK (0xff << 8) +#define IMUASID_ASID8_SHIFT 8 +#define IMUASID_ASID0_MASK (0xff << 0) +#define IMUASID_ASID0_SHIFT 0 + +/* ----------------------------------------------------------------------------- + * Page Table Bits + */ + +/* + * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory access, + * Long-descriptor format" that the NStable bit being set in a table descriptor + * will result in the NStable and NS bits of all child entries being ignored and + * considered as being set. The IPMMU seems not to comply with this, as it + * generates a secure access page fault if any of the NStable and NS bits isn't + * set when running in non-secure mode. + */ +#ifndef PMD_NSTABLE +#define PMD_NSTABLE (_AT(pmdval_t, 1) << 63) +#endif + +#define ARM_VMSA_PTE_XN (((pteval_t)3) << 53) +#define ARM_VMSA_PTE_CONT (((pteval_t)1) << 52) +#define ARM_VMSA_PTE_AF (((pteval_t)1) << 10) +#define ARM_VMSA_PTE_SH_NS (((pteval_t)0) << 8) +#define ARM_VMSA_PTE_SH_OS (((pteval_t)2) << 8) +#define ARM_VMSA_PTE_SH_IS (((pteval_t)3) << 8) +#define ARM_VMSA_PTE_SH_MASK (((pteval_t)3) << 8) +#define ARM_VMSA_PTE_NS (((pteval_t)1) << 5) +#define ARM_VMSA_PTE_PAGE (((pteval_t)3) << 0) + +/* Stage-1 PTE */ +#define ARM_VMSA_PTE_nG (((pteval_t)1) << 11) +#define ARM_VMSA_PTE_AP_UNPRIV (((pteval_t)1) << 6) +#define ARM_VMSA_PTE_AP_RDONLY (((pteval_t)2) << 6) +#define ARM_VMSA_PTE_AP_MASK (((pteval_t)3) << 6) +#define ARM_VMSA_PTE_ATTRINDX_MASK (((pteval_t)3) << 2) +#define ARM_VMSA_PTE_ATTRINDX_SHIFT 2 + +#define ARM_VMSA_PTE_ATTRS_MASK \ + (ARM_VMSA_PTE_XN | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_nG | \ + ARM_VMSA_PTE_AF | ARM_VMSA_PTE_SH_MASK | ARM_VMSA_PTE_AP_MASK | \ + ARM_VMSA_PTE_NS | ARM_VMSA_PTE_ATTRINDX_MASK) + +#define ARM_VMSA_PTE_CONT_ENTRIES 16 +#define ARM_VMSA_PTE_CONT_SIZE (PAGE_SIZE * ARM_VMSA_PTE_CONT_ENTRIES) + +#define IPMMU_PTRS_PER_PTE 512 +#define IPMMU_PTRS_PER_PMD 512 +#define IPMMU_PTRS_PER_PGD 4 + +/* ----------------------------------------------------------------------------- + * Read/Write Access + */ + +static u32 ipmmu_read(struct ipmmu_vmsa_device *mmu, unsigned int offset) +{ + return ioread32(mmu->base + offset); +} + +static void ipmmu_write(struct ipmmu_vmsa_device *mmu, unsigned int offset, + u32 data) +{ + iowrite32(data, mmu->base + offset); +} + +static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) +{ + return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg); +} + +static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, + u32 data) +{ + ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data); +} + +/* ----------------------------------------------------------------------------- + * TLB and microTLB Management + */ + +/* Wait for any pending TLB invalidations to complete */ +static void ipmmu_tlb_sync(struct ipmmu_vmsa_domain *domain) +{ + unsigned int count = 0; + + while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) { + cpu_relax(); + if (++count == TLB_LOOP_TIMEOUT) { + dev_err_ratelimited(domain->mmu->dev, + "TLB sync timed out -- MMU may be deadlocked\n"); + return; + } + udelay(1); + } +} + +static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain) +{ + u32 reg; + + reg = ipmmu_ctx_read(domain, IMCTR); + reg |= IMCTR_FLUSH; + ipmmu_ctx_write(domain, IMCTR, reg); + + ipmmu_tlb_sync(domain); +} + +/* + * Enable MMU translation for the microTLB. + */ +static void ipmmu_utlb_enable(struct ipmmu_vmsa_domain *domain, + unsigned int utlb) +{ + struct ipmmu_vmsa_device *mmu = domain->mmu; + + /* + * TODO: Reference-count the microTLB as several bus masters can be + * connected to the same microTLB. + */ + + /* TODO: What should we set the ASID to ? */ + ipmmu_write(mmu, IMUASID(utlb), 0); + /* TODO: Do we need to flush the microTLB ? */ + ipmmu_write(mmu, IMUCTR(utlb), + IMUCTR_TTSEL_MMU(domain->context_id) | IMUCTR_FLUSH | + IMUCTR_MMUEN); +} + +/* + * Disable MMU translation for the microTLB. + */ +static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain, + unsigned int utlb) +{ + struct ipmmu_vmsa_device *mmu = domain->mmu; + + ipmmu_write(mmu, IMUCTR(utlb), 0); +} + +static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr, + size_t size) +{ + unsigned long offset = (unsigned long)addr & ~PAGE_MASK; + + /* + * TODO: Add support for coherent walk through CCI with DVM and remove + * cache handling. + */ + dma_map_page(mmu->dev, virt_to_page(addr), offset, size, DMA_TO_DEVICE); +} + +/* ----------------------------------------------------------------------------- + * Domain/Context Management + */ + +static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) +{ + phys_addr_t ttbr; + u32 reg; + + /* + * TODO: When adding support for multiple contexts, find an unused + * context. + */ + domain->context_id = 0; + + /* TTBR0 */ + ipmmu_flush_pgtable(domain->mmu, domain->pgd, + IPMMU_PTRS_PER_PGD * sizeof(*domain->pgd)); + ttbr = __pa(domain->pgd); + ipmmu_ctx_write(domain, IMTTLBR0, ttbr); + ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32); + + /* + * TTBCR + * We use long descriptors with inner-shareable WBWA tables and allocate + * the whole 32-bit VA space to TTBR0. + */ + ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | + IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | + IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); + + /* + * MAIR0 + * We need three attributes only, non-cacheable, write-back read/write + * allocate and device memory. + */ + reg = (IMMAIR_ATTR_NC << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_NC)) + | (IMMAIR_ATTR_WBRWA << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_WBRWA)) + | (IMMAIR_ATTR_DEVICE << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_DEV)); + ipmmu_ctx_write(domain, IMMAIR0, reg); + + /* IMBUSCR */ + ipmmu_ctx_write(domain, IMBUSCR, + ipmmu_ctx_read(domain, IMBUSCR) & + ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); + + /* + * IMSTR + * Clear all interrupt flags. + */ + ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR)); + + /* + * IMCTR + * Enable the MMU and interrupt generation. The long-descriptor + * translation table format doesn't use TEX remapping. Don't enable AF + * software management as we have no use for it. Flush the TLB as + * required when modifying the context registers. + */ + ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); + + return 0; +} + +static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain) +{ + /* + * Disable the context. Flush the TLB as required when modifying the + * context registers. + * + * TODO: Is TLB flush really needed ? + */ + ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH); + ipmmu_tlb_sync(domain); +} + +/* ----------------------------------------------------------------------------- + * Fault Handling + */ + +static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) +{ + const u32 err_mask = IMSTR_MHIT | IMSTR_ABORT | IMSTR_PF | IMSTR_TF; + struct ipmmu_vmsa_device *mmu = domain->mmu; + u32 status; + u32 iova; + + status = ipmmu_ctx_read(domain, IMSTR); + if (!(status & err_mask)) + return IRQ_NONE; + + iova = ipmmu_ctx_read(domain, IMEAR); + + /* + * Clear the error status flags. Unlike traditional interrupt flag + * registers that must be cleared by writing 1, this status register + * seems to require 0. The error address register must be read before, + * otherwise its value will be 0. + */ + ipmmu_ctx_write(domain, IMSTR, 0); + + /* Log fatal errors. */ + if (status & IMSTR_MHIT) + dev_err_ratelimited(mmu->dev, "Multiple TLB hits @0x%08x\n", + iova); + if (status & IMSTR_ABORT) + dev_err_ratelimited(mmu->dev, "Page Table Walk Abort @0x%08x\n", + iova); + + if (!(status & (IMSTR_PF | IMSTR_TF))) + return IRQ_NONE; + + /* + * Try to handle page faults and translation faults. + * + * TODO: We need to look up the faulty device based on the I/O VA. Use + * the IOMMU device for now. + */ + if (!report_iommu_fault(domain->io_domain, mmu->dev, iova, 0)) + return IRQ_HANDLED; + + dev_err_ratelimited(mmu->dev, + "Unhandled fault: status 0x%08x iova 0x%08x\n", + status, iova); + + return IRQ_HANDLED; +} + +static irqreturn_t ipmmu_irq(int irq, void *dev) +{ + struct ipmmu_vmsa_device *mmu = dev; + struct iommu_domain *io_domain; + struct ipmmu_vmsa_domain *domain; + + if (!mmu->mapping) + return IRQ_NONE; + + io_domain = mmu->mapping->domain; + domain = io_domain->priv; + + return ipmmu_domain_irq(domain); +} + +/* ----------------------------------------------------------------------------- + * Page Table Management + */ + +#define pud_pgtable(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK)) + +static void ipmmu_free_ptes(pmd_t *pmd) +{ + pgtable_t table = pmd_pgtable(*pmd); + __free_page(table); +} + +static void ipmmu_free_pmds(pud_t *pud) +{ + pmd_t *pmd = pmd_offset(pud, 0); + pgtable_t table; + unsigned int i; + + for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) { + if (!pmd_table(*pmd)) + continue; + + ipmmu_free_ptes(pmd); + pmd++; + } + + table = pud_pgtable(*pud); + __free_page(table); +} + +static void ipmmu_free_pgtables(struct ipmmu_vmsa_domain *domain) +{ + pgd_t *pgd, *pgd_base = domain->pgd; + unsigned int i; + + /* + * Recursively free the page tables for this domain. We don't care about + * speculative TLB filling, because the TLB will be nuked next time this + * context bank is re-allocated and no devices currently map to these + * tables. + */ + pgd = pgd_base; + for (i = 0; i < IPMMU_PTRS_PER_PGD; ++i) { + if (pgd_none(*pgd)) + continue; + ipmmu_free_pmds((pud_t *)pgd); + pgd++; + } + + kfree(pgd_base); +} + +/* + * We can't use the (pgd|pud|pmd|pte)_populate or the set_(pgd|pud|pmd|pte) + * functions as they would flush the CPU TLB. + */ + +static pte_t *ipmmu_alloc_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, + unsigned long iova) +{ + pte_t *pte; + + if (!pmd_none(*pmd)) + return pte_offset_kernel(pmd, iova); + + pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); + if (!pte) + return NULL; + + ipmmu_flush_pgtable(mmu, pte, PAGE_SIZE); + *pmd = __pmd(__pa(pte) | PMD_NSTABLE | PMD_TYPE_TABLE); + ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); + + return pte + pte_index(iova); +} + +static pmd_t *ipmmu_alloc_pmd(struct ipmmu_vmsa_device *mmu, pgd_t *pgd, + unsigned long iova) +{ + pud_t *pud = (pud_t *)pgd; + pmd_t *pmd; + + if (!pud_none(*pud)) + return pmd_offset(pud, iova); + + pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); + if (!pmd) + return NULL; + + ipmmu_flush_pgtable(mmu, pmd, PAGE_SIZE); + *pud = __pud(__pa(pmd) | PMD_NSTABLE | PMD_TYPE_TABLE); + ipmmu_flush_pgtable(mmu, pud, sizeof(*pud)); + + return pmd + pmd_index(iova); +} + +static u64 ipmmu_page_prot(unsigned int prot, u64 type) +{ + u64 pgprot = ARM_VMSA_PTE_XN | ARM_VMSA_PTE_nG | ARM_VMSA_PTE_AF + | ARM_VMSA_PTE_SH_IS | ARM_VMSA_PTE_AP_UNPRIV + | ARM_VMSA_PTE_NS | type; + + if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) + pgprot |= ARM_VMSA_PTE_AP_RDONLY; + + if (prot & IOMMU_CACHE) + pgprot |= IMMAIR_ATTR_IDX_WBRWA << ARM_VMSA_PTE_ATTRINDX_SHIFT; + + if (prot & IOMMU_EXEC) + pgprot &= ~ARM_VMSA_PTE_XN; + else if (!(prot & (IOMMU_READ | IOMMU_WRITE))) + /* If no access create a faulting entry to avoid TLB fills. */ + pgprot &= ~ARM_VMSA_PTE_PAGE; + + return pgprot; +} + +static int ipmmu_alloc_init_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, + unsigned long iova, unsigned long pfn, + size_t size, int prot) +{ + pteval_t pteval = ipmmu_page_prot(prot, ARM_VMSA_PTE_PAGE); + unsigned int num_ptes = 1; + pte_t *pte, *start; + unsigned int i; + + pte = ipmmu_alloc_pte(mmu, pmd, iova); + if (!pte) + return -ENOMEM; + + start = pte; + + /* + * Install the page table entries. We can be called both for a single + * page or for a block of 16 physically contiguous pages. In the latter + * case set the PTE contiguous hint. + */ + if (size == SZ_64K) { + pteval |= ARM_VMSA_PTE_CONT; + num_ptes = ARM_VMSA_PTE_CONT_ENTRIES; + } + + for (i = num_ptes; i; --i) + *pte++ = pfn_pte(pfn++, __pgprot(pteval)); + + ipmmu_flush_pgtable(mmu, start, sizeof(*pte) * num_ptes); + + return 0; +} + +static int ipmmu_alloc_init_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd, + unsigned long iova, unsigned long pfn, + int prot) +{ + pmdval_t pmdval = ipmmu_page_prot(prot, PMD_TYPE_SECT); + + *pmd = pfn_pmd(pfn, __pgprot(pmdval)); + ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); + + return 0; +} + +static int ipmmu_create_mapping(struct ipmmu_vmsa_domain *domain, + unsigned long iova, phys_addr_t paddr, + size_t size, int prot) +{ + struct ipmmu_vmsa_device *mmu = domain->mmu; + pgd_t *pgd = domain->pgd; + unsigned long flags; + unsigned long pfn; + pmd_t *pmd; + int ret; + + if (!pgd) + return -EINVAL; + + if (size & ~PAGE_MASK) + return -EINVAL; + + if (paddr & ~((1ULL << 40) - 1)) + return -ERANGE; + + pfn = __phys_to_pfn(paddr); + pgd += pgd_index(iova); + + /* Update the page tables. */ + spin_lock_irqsave(&domain->lock, flags); + + pmd = ipmmu_alloc_pmd(mmu, pgd, iova); + if (!pmd) { + ret = -ENOMEM; + goto done; + } + + switch (size) { + case SZ_2M: + ret = ipmmu_alloc_init_pmd(mmu, pmd, iova, pfn, prot); + break; + case SZ_64K: + case SZ_4K: + ret = ipmmu_alloc_init_pte(mmu, pmd, iova, pfn, size, prot); + break; + default: + ret = -EINVAL; + break; + } + +done: + spin_unlock_irqrestore(&domain->lock, flags); + + if (!ret) + ipmmu_tlb_invalidate(domain); + + return ret; +} + +static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud) +{ + /* Free the page table. */ + pgtable_t table = pud_pgtable(*pud); + __free_page(table); + + /* Clear the PUD. */ + *pud = __pud(0); + ipmmu_flush_pgtable(mmu, pud, sizeof(*pud)); +} + +static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud, + pmd_t *pmd) +{ + unsigned int i; + + /* Free the page table. */ + if (pmd_table(*pmd)) { + pgtable_t table = pmd_pgtable(*pmd); + __free_page(table); + } + + /* Clear the PMD. */ + *pmd = __pmd(0); + ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); + + /* Check whether the PUD is still needed. */ + pmd = pmd_offset(pud, 0); + for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) { + if (!pmd_none(pmd[i])) + return; + } + + /* Clear the parent PUD. */ + ipmmu_clear_pud(mmu, pud); +} + +static void ipmmu_clear_pte(struct ipmmu_vmsa_device *mmu, pud_t *pud, + pmd_t *pmd, pte_t *pte, unsigned int num_ptes) +{ + unsigned int i; + + /* Clear the PTE. */ + for (i = num_ptes; i; --i) + pte[i-1] = __pte(0); + + ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * num_ptes); + + /* Check whether the PMD is still needed. */ + pte = pte_offset_kernel(pmd, 0); + for (i = 0; i < IPMMU_PTRS_PER_PTE; ++i) { + if (!pte_none(pte[i])) + return; + } + + /* Clear the parent PMD. */ + ipmmu_clear_pmd(mmu, pud, pmd); +} + +static int ipmmu_split_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd) +{ + pte_t *pte, *start; + pteval_t pteval; + unsigned long pfn; + unsigned int i; + + pte = (pte_t *)get_zeroed_page(GFP_ATOMIC); + if (!pte) + return -ENOMEM; + + /* Copy the PMD attributes. */ + pteval = (pmd_val(*pmd) & ARM_VMSA_PTE_ATTRS_MASK) + | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_PAGE; + + pfn = pmd_pfn(*pmd); + start = pte; + + for (i = IPMMU_PTRS_PER_PTE; i; --i) + *pte++ = pfn_pte(pfn++, __pgprot(pteval)); + + ipmmu_flush_pgtable(mmu, start, PAGE_SIZE); + *pmd = __pmd(__pa(start) | PMD_NSTABLE | PMD_TYPE_TABLE); + ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd)); + + return 0; +} + +static void ipmmu_split_pte(struct ipmmu_vmsa_device *mmu, pte_t *pte) +{ + unsigned int i; + + for (i = ARM_VMSA_PTE_CONT_ENTRIES; i; --i) + pte[i-1] = __pte(pte_val(*pte) & ~ARM_VMSA_PTE_CONT); + + ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * ARM_VMSA_PTE_CONT_ENTRIES); +} + +static int ipmmu_clear_mapping(struct ipmmu_vmsa_domain *domain, + unsigned long iova, size_t size) +{ + struct ipmmu_vmsa_device *mmu = domain->mmu; + unsigned long flags; + pgd_t *pgd = domain->pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + int ret = 0; + + if (!pgd) + return -EINVAL; + + if (size & ~PAGE_MASK) + return -EINVAL; + + pgd += pgd_index(iova); + pud = (pud_t *)pgd; + + spin_lock_irqsave(&domain->lock, flags); + + /* If there's no PUD or PMD we're done. */ + if (pud_none(*pud)) + goto done; + + pmd = pmd_offset(pud, iova); + if (pmd_none(*pmd)) + goto done; + + /* + * When freeing a 2MB block just clear the PMD. In the unlikely case the + * block is mapped as individual pages this will free the corresponding + * PTE page table. + */ + if (size == SZ_2M) { + ipmmu_clear_pmd(mmu, pud, pmd); + goto done; + } + + /* + * If the PMD has been mapped as a section remap it as pages to allow + * freeing individual pages. + */ + if (pmd_sect(*pmd)) + ipmmu_split_pmd(mmu, pmd); + + pte = pte_offset_kernel(pmd, iova); + + /* + * When freeing a 64kB block just clear the PTE entries. We don't have + * to care about the contiguous hint of the surrounding entries. + */ + if (size == SZ_64K) { + ipmmu_clear_pte(mmu, pud, pmd, pte, ARM_VMSA_PTE_CONT_ENTRIES); + goto done; + } + + /* + * If the PTE has been mapped with the contiguous hint set remap it and + * its surrounding PTEs to allow unmapping a single page. + */ + if (pte_val(*pte) & ARM_VMSA_PTE_CONT) + ipmmu_split_pte(mmu, pte); + + /* Clear the PTE. */ + ipmmu_clear_pte(mmu, pud, pmd, pte, 1); + +done: + spin_unlock_irqrestore(&domain->lock, flags); + + if (ret) + ipmmu_tlb_invalidate(domain); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * IOMMU Operations + */ + +static int ipmmu_domain_init(struct iommu_domain *io_domain) +{ + struct ipmmu_vmsa_domain *domain; + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) + return -ENOMEM; + + spin_lock_init(&domain->lock); + + domain->pgd = kzalloc(IPMMU_PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL); + if (!domain->pgd) { + kfree(domain); + return -ENOMEM; + } + + io_domain->priv = domain; + domain->io_domain = io_domain; + + return 0; +} + +static void ipmmu_domain_destroy(struct iommu_domain *io_domain) +{ + struct ipmmu_vmsa_domain *domain = io_domain->priv; + + /* + * Free the domain resources. We assume that all devices have already + * been detached. + */ + ipmmu_domain_destroy_context(domain); + ipmmu_free_pgtables(domain); + kfree(domain); +} + +static int ipmmu_attach_device(struct iommu_domain *io_domain, + struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_device *mmu = archdata->mmu; + struct ipmmu_vmsa_domain *domain = io_domain->priv; + unsigned long flags; + int ret = 0; + + if (!mmu) { + dev_err(dev, "Cannot attach to IPMMU\n"); + return -ENXIO; + } + + spin_lock_irqsave(&domain->lock, flags); + + if (!domain->mmu) { + /* The domain hasn't been used yet, initialize it. */ + domain->mmu = mmu; + ret = ipmmu_domain_init_context(domain); + } else if (domain->mmu != mmu) { + /* + * Something is wrong, we can't attach two devices using + * different IOMMUs to the same domain. + */ + dev_err(dev, "Can't attach IPMMU %s to domain on IPMMU %s\n", + dev_name(mmu->dev), dev_name(domain->mmu->dev)); + ret = -EINVAL; + } + + spin_unlock_irqrestore(&domain->lock, flags); + + if (ret < 0) + return ret; + + ipmmu_utlb_enable(domain, archdata->utlb); + + return 0; +} + +static void ipmmu_detach_device(struct iommu_domain *io_domain, + struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu; + struct ipmmu_vmsa_domain *domain = io_domain->priv; + + ipmmu_utlb_disable(domain, archdata->utlb); + + /* + * TODO: Optimize by disabling the context when no device is attached. + */ +} + +static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova, + phys_addr_t paddr, size_t size, int prot) +{ + struct ipmmu_vmsa_domain *domain = io_domain->priv; + + if (!domain) + return -ENODEV; + + return ipmmu_create_mapping(domain, iova, paddr, size, prot); +} + +static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova, + size_t size) +{ + struct ipmmu_vmsa_domain *domain = io_domain->priv; + int ret; + + ret = ipmmu_clear_mapping(domain, iova, size); + return ret ? 0 : size; +} + +static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain, + dma_addr_t iova) +{ + struct ipmmu_vmsa_domain *domain = io_domain->priv; + pgd_t pgd; + pud_t pud; + pmd_t pmd; + pte_t pte; + + /* TODO: Is locking needed ? */ + + if (!domain->pgd) + return 0; + + pgd = *(domain->pgd + pgd_index(iova)); + if (pgd_none(pgd)) + return 0; + + pud = *pud_offset(&pgd, iova); + if (pud_none(pud)) + return 0; + + pmd = *pmd_offset(&pud, iova); + if (pmd_none(pmd)) + return 0; + + if (pmd_sect(pmd)) + return __pfn_to_phys(pmd_pfn(pmd)) | (iova & ~PMD_MASK); + + pte = *(pmd_page_vaddr(pmd) + pte_index(iova)); + if (pte_none(pte)) + return 0; + + return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK); +} + +static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev) +{ + const struct ipmmu_vmsa_master *master = mmu->pdata->masters; + const char *devname = dev_name(dev); + unsigned int i; + + for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) { + if (strcmp(master->name, devname) == 0) + return master->utlb; + } + + return -1; +} + +static int ipmmu_add_device(struct device *dev) +{ + struct ipmmu_vmsa_archdata *archdata; + struct ipmmu_vmsa_device *mmu; + struct iommu_group *group; + int utlb = -1; + int ret; + + if (dev->archdata.iommu) { + dev_warn(dev, "IOMMU driver already assigned to device %s\n", + dev_name(dev)); + return -EINVAL; + } + + /* Find the master corresponding to the device. */ + spin_lock(&ipmmu_devices_lock); + + list_for_each_entry(mmu, &ipmmu_devices, list) { + utlb = ipmmu_find_utlb(mmu, dev); + if (utlb >= 0) { + /* + * TODO Take a reference to the MMU to protect + * against device removal. + */ + break; + } + } + + spin_unlock(&ipmmu_devices_lock); + + if (utlb < 0) + return -ENODEV; + + if (utlb >= mmu->num_utlbs) + return -EINVAL; + + /* Create a device group and add the device to it. */ + group = iommu_group_alloc(); + if (IS_ERR(group)) { + dev_err(dev, "Failed to allocate IOMMU group\n"); + return PTR_ERR(group); + } + + ret = iommu_group_add_device(group, dev); + iommu_group_put(group); + + if (ret < 0) { + dev_err(dev, "Failed to add device to IPMMU group\n"); + return ret; + } + + archdata = kzalloc(sizeof(*archdata), GFP_KERNEL); + if (!archdata) { + ret = -ENOMEM; + goto error; + } + + archdata->mmu = mmu; + archdata->utlb = utlb; + dev->archdata.iommu = archdata; + + /* + * Create the ARM mapping, used by the ARM DMA mapping core to allocate + * VAs. This will allocate a corresponding IOMMU domain. + * + * TODO: + * - Create one mapping per context (TLB). + * - Make the mapping size configurable ? We currently use a 2GB mapping + * at a 1GB offset to ensure that NULL VAs will fault. + */ + if (!mmu->mapping) { + struct dma_iommu_mapping *mapping; + + mapping = arm_iommu_create_mapping(&platform_bus_type, + SZ_1G, SZ_2G); + if (IS_ERR(mapping)) { + dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n"); + return PTR_ERR(mapping); + } + + mmu->mapping = mapping; + } + + /* Attach the ARM VA mapping to the device. */ + ret = arm_iommu_attach_device(dev, mmu->mapping); + if (ret < 0) { + dev_err(dev, "Failed to attach device to VA mapping\n"); + goto error; + } + + return 0; + +error: + kfree(dev->archdata.iommu); + dev->archdata.iommu = NULL; + iommu_group_remove_device(dev); + return ret; +} + +static void ipmmu_remove_device(struct device *dev) +{ + arm_iommu_detach_device(dev); + iommu_group_remove_device(dev); + kfree(dev->archdata.iommu); + dev->archdata.iommu = NULL; +} + +static struct iommu_ops ipmmu_ops = { + .domain_init = ipmmu_domain_init, + .domain_destroy = ipmmu_domain_destroy, + .attach_dev = ipmmu_attach_device, + .detach_dev = ipmmu_detach_device, + .map = ipmmu_map, + .unmap = ipmmu_unmap, + .iova_to_phys = ipmmu_iova_to_phys, + .add_device = ipmmu_add_device, + .remove_device = ipmmu_remove_device, + .pgsize_bitmap = SZ_2M | SZ_64K | SZ_4K, +}; + +/* ----------------------------------------------------------------------------- + * Probe/remove and init + */ + +static void ipmmu_device_reset(struct ipmmu_vmsa_device *mmu) +{ + unsigned int i; + + /* Disable all contexts. */ + for (i = 0; i < 4; ++i) + ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0); +} + +static int ipmmu_probe(struct platform_device *pdev) +{ + struct ipmmu_vmsa_device *mmu; + struct resource *res; + int irq; + int ret; + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "missing platform data\n"); + return -EINVAL; + } + + mmu = devm_kzalloc(&pdev->dev, sizeof(*mmu), GFP_KERNEL); + if (!mmu) { + dev_err(&pdev->dev, "cannot allocate device data\n"); + return -ENOMEM; + } + + mmu->dev = &pdev->dev; + mmu->pdata = pdev->dev.platform_data; + mmu->num_utlbs = 32; + + /* Map I/O memory and request IRQ. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mmu->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mmu->base)) + return PTR_ERR(mmu->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no IRQ found\n"); + return irq; + } + + ret = devm_request_irq(&pdev->dev, irq, ipmmu_irq, 0, + dev_name(&pdev->dev), mmu); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request IRQ %d\n", irq); + return irq; + } + + ipmmu_device_reset(mmu); + + /* + * We can't create the ARM mapping here as it requires the bus to have + * an IOMMU, which only happens when bus_set_iommu() is called in + * ipmmu_init() after the probe function returns. + */ + + spin_lock(&ipmmu_devices_lock); + list_add(&mmu->list, &ipmmu_devices); + spin_unlock(&ipmmu_devices_lock); + + platform_set_drvdata(pdev, mmu); + + return 0; +} + +static int ipmmu_remove(struct platform_device *pdev) +{ + struct ipmmu_vmsa_device *mmu = platform_get_drvdata(pdev); + + spin_lock(&ipmmu_devices_lock); + list_del(&mmu->list); + spin_unlock(&ipmmu_devices_lock); + + arm_iommu_release_mapping(mmu->mapping); + + ipmmu_device_reset(mmu); + + return 0; +} + +static struct platform_driver ipmmu_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ipmmu-vmsa", + }, + .probe = ipmmu_probe, + .remove = ipmmu_remove, +}; + +static int __init ipmmu_init(void) +{ + int ret; + + ret = platform_driver_register(&ipmmu_driver); + if (ret < 0) + return ret; + + if (!iommu_present(&platform_bus_type)) + bus_set_iommu(&platform_bus_type, &ipmmu_ops); + + return 0; +} + +static void __exit ipmmu_exit(void) +{ + return platform_driver_unregister(&ipmmu_driver); +} + +subsys_initcall(ipmmu_init); +module_exit(ipmmu_exit); + +MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU"); +MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c index 08ba4972da9d..61def7cb5263 100644 --- a/drivers/iommu/msm_iommu_dev.c +++ b/drivers/iommu/msm_iommu_dev.c @@ -127,13 +127,12 @@ static void msm_iommu_reset(void __iomem *base, int ncb) static int msm_iommu_probe(struct platform_device *pdev) { - struct resource *r, *r2; + struct resource *r; struct clk *iommu_clk; struct clk *iommu_pclk; struct msm_iommu_drvdata *drvdata; struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data; void __iomem *regs_base; - resource_size_t len; int ret, irq, par; if (pdev->id == -1) { @@ -178,35 +177,16 @@ static int msm_iommu_probe(struct platform_device *pdev) iommu_clk = NULL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase"); - - if (!r) { - ret = -ENODEV; - goto fail_clk; - } - - len = resource_size(r); - - r2 = request_mem_region(r->start, len, r->name); - if (!r2) { - pr_err("Could not request memory region: start=%p, len=%d\n", - (void *) r->start, len); - ret = -EBUSY; + regs_base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(regs_base)) { + ret = PTR_ERR(regs_base); goto fail_clk; } - regs_base = ioremap(r2->start, len); - - if (!regs_base) { - pr_err("Could not ioremap: start=%p, len=%d\n", - (void *) r2->start, len); - ret = -EBUSY; - goto fail_mem; - } - irq = platform_get_irq_byname(pdev, "secure_irq"); if (irq < 0) { ret = -ENODEV; - goto fail_io; + goto fail_clk; } msm_iommu_reset(regs_base, iommu_dev->ncb); @@ -222,14 +202,14 @@ static int msm_iommu_probe(struct platform_device *pdev) if (!par) { pr_err("%s: Invalid PAR value detected\n", iommu_dev->name); ret = -ENODEV; - goto fail_io; + goto fail_clk; } ret = request_irq(irq, msm_iommu_fault_handler, 0, "msm_iommu_secure_irpt_handler", drvdata); if (ret) { pr_err("Request IRQ %d failed with ret=%d\n", irq, ret); - goto fail_io; + goto fail_clk; } @@ -250,10 +230,6 @@ static int msm_iommu_probe(struct platform_device *pdev) clk_disable(iommu_pclk); return 0; -fail_io: - iounmap(regs_base); -fail_mem: - release_mem_region(r->start, len); fail_clk: if (iommu_clk) { clk_disable(iommu_clk); diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 7fcbfc498fa9..895af06a667f 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -34,6 +34,9 @@ #include "omap-iopgtable.h" #include "omap-iommu.h" +#define to_iommu(dev) \ + ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))) + #define for_each_iotlb_cr(obj, n, __i, cr) \ for (__i = 0; \ (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ @@ -391,6 +394,7 @@ static void flush_iotlb_page(struct omap_iommu *obj, u32 da) __func__, start, da, bytes); iotlb_load_cr(obj, &cr); iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); + break; } } pm_runtime_put_sync(obj->dev); @@ -1037,19 +1041,18 @@ static void iopte_cachep_ctor(void *iopte) clean_dcache_area(iopte, IOPTE_TABLE_SIZE); } -static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, - u32 flags) +static u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, int pgsz) { memset(e, 0, sizeof(*e)); e->da = da; e->pa = pa; - e->valid = 1; + e->valid = MMU_CAM_V; /* FIXME: add OMAP1 support */ - e->pgsz = flags & MMU_CAM_PGSZ_MASK; - e->endian = flags & MMU_RAM_ENDIAN_MASK; - e->elsz = flags & MMU_RAM_ELSZ_MASK; - e->mixed = flags & MMU_RAM_MIXED_MASK; + e->pgsz = pgsz; + e->endian = MMU_RAM_ENDIAN_LITTLE; + e->elsz = MMU_RAM_ELSZ_8; + e->mixed = 0; return iopgsz_to_bytes(e->pgsz); } @@ -1062,9 +1065,8 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, struct device *dev = oiommu->dev; struct iotlb_entry e; int omap_pgsz; - u32 ret, flags; + u32 ret; - /* we only support mapping a single iommu page for now */ omap_pgsz = bytes_to_iopgsz(bytes); if (omap_pgsz < 0) { dev_err(dev, "invalid size to map: %d\n", bytes); @@ -1073,9 +1075,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da, dev_dbg(dev, "mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes); - flags = omap_pgsz | prot; - - iotlb_init_entry(&e, da, pa, flags); + iotlb_init_entry(&e, da, pa, omap_pgsz); ret = omap_iopgtable_store_entry(oiommu, &e); if (ret) @@ -1248,12 +1248,6 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain, return ret; } -static int omap_iommu_domain_has_cap(struct iommu_domain *domain, - unsigned long cap) -{ - return 0; -} - static int omap_iommu_add_device(struct device *dev) { struct omap_iommu_arch_data *arch_data; @@ -1305,7 +1299,6 @@ static struct iommu_ops omap_iommu_ops = { .map = omap_iommu_map, .unmap = omap_iommu_unmap, .iova_to_phys = omap_iommu_iova_to_phys, - .domain_has_cap = omap_iommu_domain_has_cap, .add_device = omap_iommu_add_device, .remove_device = omap_iommu_remove_device, .pgsize_bitmap = OMAP_IOMMU_PGSIZES, diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h index b6f9a51746ca..f891683e3f05 100644 --- a/drivers/iommu/omap-iopgtable.h +++ b/drivers/iommu/omap-iopgtable.h @@ -93,6 +93,3 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask) /* to find an entry in the second-level page table. */ #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) - -#define to_iommu(dev) \ - (platform_get_drvdata(to_platform_device(dev))) diff --git a/drivers/iommu/shmobile-ipmmu.c b/drivers/iommu/shmobile-ipmmu.c index e3bc2e19b6dd..bd97adecb1fd 100644 --- a/drivers/iommu/shmobile-ipmmu.c +++ b/drivers/iommu/shmobile-ipmmu.c @@ -94,11 +94,6 @@ static int ipmmu_probe(struct platform_device *pdev) struct resource *res; struct shmobile_ipmmu_platform_data *pdata = pdev->dev.platform_data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "cannot get platform resources\n"); - return -ENOENT; - } ipmmu = devm_kzalloc(&pdev->dev, sizeof(*ipmmu), GFP_KERNEL); if (!ipmmu) { dev_err(&pdev->dev, "cannot allocate device data\n"); @@ -106,19 +101,18 @@ static int ipmmu_probe(struct platform_device *pdev) } spin_lock_init(&ipmmu->flush_lock); ipmmu->dev = &pdev->dev; - ipmmu->ipmmu_base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!ipmmu->ipmmu_base) { - dev_err(&pdev->dev, "ioremap_nocache failed\n"); - return -ENOMEM; - } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ipmmu->ipmmu_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ipmmu->ipmmu_base)) + return PTR_ERR(ipmmu->ipmmu_base); + ipmmu->dev_names = pdata->dev_names; ipmmu->num_dev_names = pdata->num_dev_names; platform_set_drvdata(pdev, ipmmu); ipmmu_reg_write(ipmmu, IMCTR1, 0x0); /* disable TLB */ ipmmu_reg_write(ipmmu, IMCTR2, 0x0); /* disable PMB */ - ipmmu_iommu_init(ipmmu); - return 0; + return ipmmu_iommu_init(ipmmu); } static struct platform_driver ipmmu_driver = { diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 338baa4c23ef..1778d320272e 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -27,19 +27,21 @@ * REF_03 - Analog devices, ADV7604, Hardware Manual, Rev. F, August 2010 */ - +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/delay.h> +#include <linux/v4l2-dv-timings.h> #include <linux/videodev2.h> #include <linux/workqueue.h> -#include <linux/v4l2-dv-timings.h> -#include <media/v4l2-device.h> + +#include <media/adv7604.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> #include <media/v4l2-dv-timings.h> -#include <media/adv7604.h> +#include <media/v4l2-of.h> static int debug; module_param(debug, int, 0644); @@ -53,6 +55,76 @@ MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ #define ADV7604_fsc (28636360) +#define ADV7604_RGB_OUT (1 << 1) + +#define ADV7604_OP_FORMAT_SEL_8BIT (0 << 0) +#define ADV7604_OP_FORMAT_SEL_10BIT (1 << 0) +#define ADV7604_OP_FORMAT_SEL_12BIT (2 << 0) + +#define ADV7604_OP_MODE_SEL_SDR_422 (0 << 5) +#define ADV7604_OP_MODE_SEL_DDR_422 (1 << 5) +#define ADV7604_OP_MODE_SEL_SDR_444 (2 << 5) +#define ADV7604_OP_MODE_SEL_DDR_444 (3 << 5) +#define ADV7604_OP_MODE_SEL_SDR_422_2X (4 << 5) +#define ADV7604_OP_MODE_SEL_ADI_CM (5 << 5) + +#define ADV7604_OP_CH_SEL_GBR (0 << 5) +#define ADV7604_OP_CH_SEL_GRB (1 << 5) +#define ADV7604_OP_CH_SEL_BGR (2 << 5) +#define ADV7604_OP_CH_SEL_RGB (3 << 5) +#define ADV7604_OP_CH_SEL_BRG (4 << 5) +#define ADV7604_OP_CH_SEL_RBG (5 << 5) + +#define ADV7604_OP_SWAP_CB_CR (1 << 0) + +enum adv7604_type { + ADV7604, + ADV7611, +}; + +struct adv7604_reg_seq { + unsigned int reg; + u8 val; +}; + +struct adv7604_format_info { + enum v4l2_mbus_pixelcode code; + u8 op_ch_sel; + bool rgb_out; + bool swap_cb_cr; + u8 op_format_sel; +}; + +struct adv7604_chip_info { + enum adv7604_type type; + + bool has_afe; + unsigned int max_port; + unsigned int num_dv_ports; + + unsigned int edid_enable_reg; + unsigned int edid_status_reg; + unsigned int lcf_reg; + + unsigned int cable_det_mask; + unsigned int tdms_lock_mask; + unsigned int fmt_change_digital_mask; + + const struct adv7604_format_info *formats; + unsigned int nformats; + + void (*set_termination)(struct v4l2_subdev *sd, bool enable); + void (*setup_irqs)(struct v4l2_subdev *sd); + unsigned int (*read_hdmi_pixelclock)(struct v4l2_subdev *sd); + unsigned int (*read_cable_det)(struct v4l2_subdev *sd); + + /* 0 = AFE, 1 = HDMI */ + const struct adv7604_reg_seq *recommended_settings[2]; + unsigned int num_recommended_settings[2]; + + unsigned long page_mask; +}; + /* ********************************************************************** * @@ -60,13 +132,24 @@ MODULE_LICENSE("GPL"); * ********************************************************************** */ + struct adv7604_state { + const struct adv7604_chip_info *info; struct adv7604_platform_data pdata; + + struct gpio_desc *hpd_gpio[4]; + struct v4l2_subdev sd; - struct media_pad pad; + struct media_pad pads[ADV7604_PAD_MAX]; + unsigned int source_pad; + struct v4l2_ctrl_handler hdl; - enum adv7604_input_port selected_input; + + enum adv7604_pad selected_input; + struct v4l2_dv_timings timings; + const struct adv7604_format_info *format; + struct { u8 edid[256]; u32 present; @@ -80,18 +163,7 @@ struct adv7604_state { bool restart_stdi_once; /* i2c clients */ - struct i2c_client *i2c_avlink; - struct i2c_client *i2c_cec; - struct i2c_client *i2c_infoframe; - struct i2c_client *i2c_esdp; - struct i2c_client *i2c_dpp; - struct i2c_client *i2c_afe; - struct i2c_client *i2c_repeater; - struct i2c_client *i2c_edid; - struct i2c_client *i2c_hdmi; - struct i2c_client *i2c_test; - struct i2c_client *i2c_cp; - struct i2c_client *i2c_vdp; + struct i2c_client *i2c_clients[ADV7604_PAGE_MAX]; /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; @@ -101,6 +173,11 @@ struct adv7604_state { struct v4l2_ctrl *rgb_quantization_range_ctrl; }; +static bool adv7604_has_afe(struct adv7604_state *state) +{ + return state->info->has_afe; +} + /* Supported CEA and DMT timings */ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_CEA_720X480P59_94, @@ -256,11 +333,6 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) return container_of(sd, struct adv7604_state, sd); } -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; -} - static inline unsigned hblanking(const struct v4l2_bt_timings *t) { return V4L2_DV_BT_BLANKING_WIDTH(t); @@ -298,14 +370,18 @@ static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, return -EIO; } -static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) +static s32 adv_smbus_read_byte_data(struct adv7604_state *state, + enum adv7604_page page, u8 command) { - return adv_smbus_read_byte_data_check(client, command, true); + return adv_smbus_read_byte_data_check(state->i2c_clients[page], + command, true); } -static s32 adv_smbus_write_byte_data(struct i2c_client *client, - u8 command, u8 value) +static s32 adv_smbus_write_byte_data(struct adv7604_state *state, + enum adv7604_page page, u8 command, + u8 value) { + struct i2c_client *client = state->i2c_clients[page]; union i2c_smbus_data data; int err; int i; @@ -325,9 +401,11 @@ static s32 adv_smbus_write_byte_data(struct i2c_client *client, return err; } -static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, - u8 command, unsigned length, const u8 *values) +static s32 adv_smbus_write_i2c_block_data(struct adv7604_state *state, + enum adv7604_page page, u8 command, + unsigned length, const u8 *values) { + struct i2c_client *client = state->i2c_clients[page]; union i2c_smbus_data data; if (length > I2C_SMBUS_BLOCK_MAX) @@ -343,149 +421,150 @@ static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, static inline int io_read(struct v4l2_subdev *sd, u8 reg) { - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(client, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(client, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_IO, reg, val); } -static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) { - return io_write(sd, reg, (io_read(sd, reg) & mask) | val); + return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val); } static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_avlink, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_avlink, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_cec, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_cec, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val); } -static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) { - return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val); + return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_infoframe, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_infoframe, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_INFOFRAME, + reg, val); } static inline int esdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_esdp, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg); } static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_esdp, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val); } static inline int dpp_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_dpp, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg); } static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_dpp, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_afe, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_afe, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_AFE, reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_repeater, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_repeater, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_REP, reg, val); } -static inline int rep_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) { - return rep_write(sd, reg, (rep_read(sd, reg) & mask) | val); + return rep_write(sd, reg, (rep_read(sd, reg) & ~mask) | val); } static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_edid, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_edid, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val); } static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) { struct adv7604_state *state = to_state(sd); - struct i2c_client *client = state->i2c_edid; + struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID]; u8 msgbuf0[1] = { 0 }; u8 msgbuf1[256]; struct i2c_msg msg[2] = { @@ -518,11 +597,25 @@ static inline int edid_write_block(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, - I2C_SMBUS_BLOCK_MAX, val + i); + err = adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_EDID, + i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } +static void adv7604_set_hpd(struct adv7604_state *state, unsigned int hpd) +{ + unsigned int i; + + for (i = 0; i < state->info->num_dv_ports; ++i) { + if (IS_ERR(state->hpd_gpio[i])) + continue; + + gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); + } + + v4l2_subdev_notify(&state->sd, ADV7604_HOTPLUG, &hpd); +} + static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -532,73 +625,210 @@ static void adv7604_delayed_work_enable_hotplug(struct work_struct *work) v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); + adv7604_set_hpd(state, state->edid.present); } static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_hdmi, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_HDMI, reg); +} + +static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) +{ + return ((hdmi_read(sd, reg) << 8) | hdmi_read(sd, reg + 1)) & mask; } static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_HDMI, reg, val); } -static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) { - return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val); + return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val); } static inline int test_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_test, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg); } static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_test, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_TEST, reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_cp, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_CP, reg); +} + +static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) +{ + return ((cp_read(sd, reg) << 8) | cp_read(sd, reg + 1)) & mask; } static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_cp, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_CP, reg, val); } -static inline int cp_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) { - return cp_write(sd, reg, (cp_read(sd, reg) & mask) | val); + return cp_write(sd, reg, (cp_read(sd, reg) & ~mask) | val); } static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv7604_state *state = to_state(sd); - return adv_smbus_read_byte_data(state->i2c_vdp, reg); + return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv7604_state *state = to_state(sd); - return adv_smbus_write_byte_data(state->i2c_vdp, reg, val); + return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); +} + +#define ADV7604_REG(page, offset) (((page) << 8) | (offset)) +#define ADV7604_REG_SEQ_TERM 0xffff + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int adv7604_read_reg(struct v4l2_subdev *sd, unsigned int reg) +{ + struct adv7604_state *state = to_state(sd); + unsigned int page = reg >> 8; + + if (!(BIT(page) & state->info->page_mask)) + return -EINVAL; + + reg &= 0xff; + + return adv_smbus_read_byte_data(state, page, reg); +} +#endif + +static int adv7604_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) +{ + struct adv7604_state *state = to_state(sd); + unsigned int page = reg >> 8; + + if (!(BIT(page) & state->info->page_mask)) + return -EINVAL; + + reg &= 0xff; + + return adv_smbus_write_byte_data(state, page, reg, val); +} + +static void adv7604_write_reg_seq(struct v4l2_subdev *sd, + const struct adv7604_reg_seq *reg_seq) +{ + unsigned int i; + + for (i = 0; reg_seq[i].reg != ADV7604_REG_SEQ_TERM; i++) + adv7604_write_reg(sd, reg_seq[i].reg, reg_seq[i].val); +} + +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +static const struct adv7604_format_info adv7604_formats[] = { + { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, + ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT }, + { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +}; + +static const struct adv7604_format_info adv7611_formats[] = { + { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false, + ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT }, + { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, + { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true, + ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT }, +}; + +static const struct adv7604_format_info * +adv7604_format_info(struct adv7604_state *state, enum v4l2_mbus_pixelcode code) +{ + unsigned int i; + + for (i = 0; i < state->info->nformats; ++i) { + if (state->info->formats[i].code == code) + return &state->info->formats[i]; + } + + return NULL; } /* ----------------------------------------------------------------------- */ @@ -607,18 +837,18 @@ static inline bool is_analog_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); - return state->selected_input == ADV7604_INPUT_VGA_RGB || - state->selected_input == ADV7604_INPUT_VGA_COMP; + return state->selected_input == ADV7604_PAD_VGA_RGB || + state->selected_input == ADV7604_PAD_VGA_COMP; } static inline bool is_digital_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); - return state->selected_input == ADV7604_INPUT_HDMI_PORT_A || - state->selected_input == ADV7604_INPUT_HDMI_PORT_B || - state->selected_input == ADV7604_INPUT_HDMI_PORT_C || - state->selected_input == ADV7604_INPUT_HDMI_PORT_D; + return state->selected_input == ADV7604_PAD_HDMI_PORT_A || + state->selected_input == ADV7604_PAD_HDMI_PORT_B || + state->selected_input == ADV7604_PAD_HDMI_PORT_C || + state->selected_input == ADV7604_PAD_HDMI_PORT_D; } /* ----------------------------------------------------------------------- */ @@ -644,119 +874,61 @@ static void adv7604_inv_register(struct v4l2_subdev *sd) static int adv7604_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) { - reg->size = 1; - switch (reg->reg >> 8) { - case 0: - reg->val = io_read(sd, reg->reg & 0xff); - break; - case 1: - reg->val = avlink_read(sd, reg->reg & 0xff); - break; - case 2: - reg->val = cec_read(sd, reg->reg & 0xff); - break; - case 3: - reg->val = infoframe_read(sd, reg->reg & 0xff); - break; - case 4: - reg->val = esdp_read(sd, reg->reg & 0xff); - break; - case 5: - reg->val = dpp_read(sd, reg->reg & 0xff); - break; - case 6: - reg->val = afe_read(sd, reg->reg & 0xff); - break; - case 7: - reg->val = rep_read(sd, reg->reg & 0xff); - break; - case 8: - reg->val = edid_read(sd, reg->reg & 0xff); - break; - case 9: - reg->val = hdmi_read(sd, reg->reg & 0xff); - break; - case 0xa: - reg->val = test_read(sd, reg->reg & 0xff); - break; - case 0xb: - reg->val = cp_read(sd, reg->reg & 0xff); - break; - case 0xc: - reg->val = vdp_read(sd, reg->reg & 0xff); - break; - default: + int ret; + + ret = adv7604_read_reg(sd, reg->reg); + if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); adv7604_inv_register(sd); - break; + return ret; } + + reg->size = 1; + reg->val = ret; + return 0; } static int adv7604_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { - u8 val = reg->val & 0xff; + int ret; - switch (reg->reg >> 8) { - case 0: - io_write(sd, reg->reg & 0xff, val); - break; - case 1: - avlink_write(sd, reg->reg & 0xff, val); - break; - case 2: - cec_write(sd, reg->reg & 0xff, val); - break; - case 3: - infoframe_write(sd, reg->reg & 0xff, val); - break; - case 4: - esdp_write(sd, reg->reg & 0xff, val); - break; - case 5: - dpp_write(sd, reg->reg & 0xff, val); - break; - case 6: - afe_write(sd, reg->reg & 0xff, val); - break; - case 7: - rep_write(sd, reg->reg & 0xff, val); - break; - case 8: - edid_write(sd, reg->reg & 0xff, val); - break; - case 9: - hdmi_write(sd, reg->reg & 0xff, val); - break; - case 0xa: - test_write(sd, reg->reg & 0xff, val); - break; - case 0xb: - cp_write(sd, reg->reg & 0xff, val); - break; - case 0xc: - vdp_write(sd, reg->reg & 0xff, val); - break; - default: + ret = adv7604_write_reg(sd, reg->reg, reg->val); + if (ret < 0) { v4l2_info(sd, "Register %03llx not supported\n", reg->reg); adv7604_inv_register(sd); - break; + return ret; } + return 0; } #endif +static unsigned int adv7604_read_cable_det(struct v4l2_subdev *sd) +{ + u8 value = io_read(sd, 0x6f); + + return ((value & 0x10) >> 4) + | ((value & 0x08) >> 2) + | ((value & 0x04) << 0) + | ((value & 0x02) << 2); +} + +static unsigned int adv7611_read_cable_det(struct v4l2_subdev *sd) +{ + u8 value = io_read(sd, 0x6f); + + return value & 1; +} + static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); - u8 reg_io_6f = io_read(sd, 0x6f); + const struct adv7604_chip_info *info = state->info; return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, - ((reg_io_6f & 0x10) >> 4) | - ((reg_io_6f & 0x08) >> 2) | - (reg_io_6f & 0x04) | - ((reg_io_6f & 0x02) << 2)); + info->read_cable_det(sd)); } static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, @@ -787,11 +959,13 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s", __func__); - /* reset to default values */ - io_write(sd, 0x16, 0x43); - io_write(sd, 0x17, 0x5a); + if (adv7604_has_afe(state)) { + /* reset to default values */ + io_write(sd, 0x16, 0x43); + io_write(sd, 0x17, 0x5a); + } /* disable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x00); + cp_write_clr_set(sd, 0x81, 0x10, 0x00); cp_write(sd, 0x8f, 0x00); cp_write(sd, 0x90, 0x00); cp_write(sd, 0xa2, 0x00); @@ -829,7 +1003,6 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, const struct v4l2_bt_timings *bt) { struct adv7604_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); u32 width = htotal(bt); u32 height = vtotal(bt); u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; @@ -850,12 +1023,13 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, io_write(sd, 0x00, 0x07); /* video std */ io_write(sd, 0x01, 0x02); /* prim mode */ /* enable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x10); + cp_write_clr_set(sd, 0x81, 0x10, 0x10); /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) + if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_IO, + 0x16, 2, pll)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); /* active video - horizontal timing */ @@ -906,7 +1080,8 @@ static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) + if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + 0x77, 4, offset_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } @@ -935,7 +1110,8 @@ static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) + if (adv_smbus_write_i2c_block_data(state, ADV7604_PAGE_CP, + 0x73, 4, gain_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } @@ -954,24 +1130,24 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: - if (state->selected_input == ADV7604_INPUT_VGA_RGB) { + if (state->selected_input == ADV7604_PAD_VGA_RGB) { /* Receiving analog RGB signal * Set RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + io_write_clr_set(sd, 0x02, 0xf0, 0x10); break; } - if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + if (state->selected_input == ADV7604_PAD_VGA_COMP) { /* Receiving analog YPbPr signal * Set automode */ - io_write_and_or(sd, 0x02, 0x0f, 0xf0); + io_write_clr_set(sd, 0x02, 0xf0, 0xf0); break; } if (hdmi_signal) { /* Receiving HDMI signal * Set automode */ - io_write_and_or(sd, 0x02, 0x0f, 0xf0); + io_write_clr_set(sd, 0x02, 0xf0, 0xf0); break; } @@ -980,10 +1156,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) * input format (CE/IT) in automatic mode */ if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); + io_write_clr_set(sd, 0x02, 0xf0, 0x00); } else { /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + io_write_clr_set(sd, 0x02, 0xf0, 0x10); if (is_digital_input(sd) && rgb_output) { adv7604_set_offset(sd, false, 0x40, 0x40, 0x40); @@ -994,25 +1170,25 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) } break; case V4L2_DV_RGB_RANGE_LIMITED: - if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + if (state->selected_input == ADV7604_PAD_VGA_COMP) { /* YCrCb limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x20); + io_write_clr_set(sd, 0x02, 0xf0, 0x20); break; } /* RGB limited range (16-235) */ - io_write_and_or(sd, 0x02, 0x0f, 0x00); + io_write_clr_set(sd, 0x02, 0xf0, 0x00); break; case V4L2_DV_RGB_RANGE_FULL: - if (state->selected_input == ADV7604_INPUT_VGA_COMP) { + if (state->selected_input == ADV7604_PAD_VGA_COMP) { /* YCrCb full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x60); + io_write_clr_set(sd, 0x02, 0xf0, 0x60); break; } /* RGB full range (0-255) */ - io_write_and_or(sd, 0x02, 0x0f, 0x10); + io_write_clr_set(sd, 0x02, 0xf0, 0x10); if (is_analog_input(sd) || hdmi_signal) break; @@ -1030,7 +1206,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) { - struct v4l2_subdev *sd = to_sd(ctrl); + struct v4l2_subdev *sd = + &container_of(ctrl->handler, struct adv7604_state, hdl)->sd; + struct adv7604_state *state = to_state(sd); switch (ctrl->id) { @@ -1051,6 +1229,8 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) set_rgb_quantization_range(sd); return 0; case V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE: + if (!adv7604_has_afe(state)) + return -EINVAL; /* Set the analog sampling phase. This is needed to find the best sampling phase for analog video: an application or driver has to try a number of phases and analyze the picture @@ -1060,7 +1240,7 @@ static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL: /* Use the default blue color for free running mode, or supply your own. */ - cp_write_and_or(sd, 0xbf, ~0x04, (ctrl->val << 2)); + cp_write_clr_set(sd, 0xbf, 0x04, ctrl->val << 2); return 0; case V4L2_CID_ADV_RX_FREE_RUN_COLOR: cp_write(sd, 0xc0, (ctrl->val & 0xff0000) >> 16); @@ -1088,7 +1268,10 @@ static inline bool no_signal_tmds(struct v4l2_subdev *sd) static inline bool no_lock_tmds(struct v4l2_subdev *sd) { - return (io_read(sd, 0x6a) & 0xe0) != 0xe0; + struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; + + return (io_read(sd, 0x6a) & info->tdms_lock_mask) != info->tdms_lock_mask; } static inline bool is_hdmi(struct v4l2_subdev *sd) @@ -1098,6 +1281,15 @@ static inline bool is_hdmi(struct v4l2_subdev *sd) static inline bool no_lock_sspd(struct v4l2_subdev *sd) { + struct adv7604_state *state = to_state(sd); + + /* + * Chips without a AFE don't expose registers for the SSPD, so just assume + * that we have a lock. + */ + if (adv7604_has_afe(state)) + return false; + /* TODO channel 2 */ return ((cp_read(sd, 0xb5) & 0xd0) != 0xd0); } @@ -1127,6 +1319,11 @@ static inline bool no_signal(struct v4l2_subdev *sd) static inline bool no_lock_cp(struct v4l2_subdev *sd) { + struct adv7604_state *state = to_state(sd); + + if (!adv7604_has_afe(state)) + return false; + /* CP has detected a non standard number of lines on the incoming video compared to what it is configured to receive by s_dv_timings */ return io_read(sd, 0x12) & 0x01; @@ -1195,28 +1392,40 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, return -1; } + static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) { + struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; + u8 polarity; + if (no_lock_stdi(sd) || no_lock_sspd(sd)) { v4l2_dbg(2, debug, sd, "%s: STDI and/or SSPD not locked\n", __func__); return -1; } /* read STDI */ - stdi->bl = ((cp_read(sd, 0xb1) & 0x3f) << 8) | cp_read(sd, 0xb2); - stdi->lcf = ((cp_read(sd, 0xb3) & 0x7) << 8) | cp_read(sd, 0xb4); + stdi->bl = cp_read16(sd, 0xb1, 0x3fff); + stdi->lcf = cp_read16(sd, info->lcf_reg, 0x7ff); stdi->lcvs = cp_read(sd, 0xb3) >> 3; stdi->interlaced = io_read(sd, 0x12) & 0x10; - /* read SSPD */ - if ((cp_read(sd, 0xb5) & 0x03) == 0x01) { - stdi->hs_pol = ((cp_read(sd, 0xb5) & 0x10) ? - ((cp_read(sd, 0xb5) & 0x08) ? '+' : '-') : 'x'); - stdi->vs_pol = ((cp_read(sd, 0xb5) & 0x40) ? - ((cp_read(sd, 0xb5) & 0x20) ? '+' : '-') : 'x'); + if (adv7604_has_afe(state)) { + /* read SSPD */ + polarity = cp_read(sd, 0xb5); + if ((polarity & 0x03) == 0x01) { + stdi->hs_pol = polarity & 0x10 + ? (polarity & 0x08 ? '+' : '-') : 'x'; + stdi->vs_pol = polarity & 0x40 + ? (polarity & 0x20 ? '+' : '-') : 'x'; + } else { + stdi->hs_pol = 'x'; + stdi->vs_pol = 'x'; + } } else { - stdi->hs_pol = 'x'; - stdi->vs_pol = 'x'; + polarity = hdmi_read(sd, 0x05); + stdi->hs_pol = polarity & 0x20 ? '+' : '-'; + stdi->vs_pol = polarity & 0x10 ? '+' : '-'; } if (no_lock_stdi(sd) || no_lock_sspd(sd)) { @@ -1243,8 +1452,14 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi) static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { + struct adv7604_state *state = to_state(sd); + if (timings->index >= ARRAY_SIZE(adv7604_timings) - 1) return -EINVAL; + + if (timings->pad >= state->source_pad) + return -EINVAL; + memset(timings->reserved, 0, sizeof(timings->reserved)); timings->timings = adv7604_timings[timings->index]; return 0; @@ -1253,14 +1468,30 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd, static int adv7604_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { + struct adv7604_state *state = to_state(sd); + + if (cap->pad >= state->source_pad) + return -EINVAL; + cap->type = V4L2_DV_BT_656_1120; cap->bt.max_width = 1920; cap->bt.max_height = 1200; cap->bt.min_pixelclock = 25000000; - if (is_digital_input(sd)) + + switch (cap->pad) { + case ADV7604_PAD_HDMI_PORT_A: + case ADV7604_PAD_HDMI_PORT_B: + case ADV7604_PAD_HDMI_PORT_C: + case ADV7604_PAD_HDMI_PORT_D: cap->bt.max_pixelclock = 225000000; - else + break; + case ADV7604_PAD_VGA_RGB: + case ADV7604_PAD_VGA_COMP: + default: cap->bt.max_pixelclock = 170000000; + break; + } + cap->bt.standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT; cap->bt.capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | @@ -1284,10 +1515,43 @@ static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd, } } +static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd) +{ + unsigned int freq; + int a, b; + + a = hdmi_read(sd, 0x06); + b = hdmi_read(sd, 0x3b); + if (a < 0 || b < 0) + return 0; + freq = a * 1000000 + ((b & 0x30) >> 4) * 250000; + + if (is_hdmi(sd)) { + /* adjust for deep color mode */ + unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8; + + freq = freq * 8 / bits_per_channel; + } + + return freq; +} + +static unsigned int adv7611_read_hdmi_pixelclock(struct v4l2_subdev *sd) +{ + int a, b; + + a = hdmi_read(sd, 0x51); + b = hdmi_read(sd, 0x52); + if (a < 0 || b < 0) + return 0; + return ((a << 1) | (b >> 7)) * 1000000 + (b & 0x7f) * 1000000 / 128; +} + static int adv7604_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; struct v4l2_bt_timings *bt = &timings->bt; struct stdi_readback stdi; @@ -1311,44 +1575,25 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; if (is_digital_input(sd)) { - uint32_t freq; - timings->type = V4L2_DV_BT_656_1120; - bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08); - bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a); - freq = (hdmi_read(sd, 0x06) * 1000000) + - ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000; - if (is_hdmi(sd)) { - /* adjust for deep color mode */ - unsigned bits_per_channel = ((hdmi_read(sd, 0x0b) & 0x60) >> 4) + 8; - - freq = freq * 8 / bits_per_channel; - } - bt->pixelclock = freq; - bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 + - hdmi_read(sd, 0x21); - bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 + - hdmi_read(sd, 0x23); - bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 + - hdmi_read(sd, 0x25); - bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 + - hdmi_read(sd, 0x2b)) / 2; - bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 + - hdmi_read(sd, 0x2f)) / 2; - bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 + - hdmi_read(sd, 0x33)) / 2; + /* FIXME: All masks are incorrect for ADV7611 */ + bt->width = hdmi_read16(sd, 0x07, 0xfff); + bt->height = hdmi_read16(sd, 0x09, 0xfff); + bt->pixelclock = info->read_hdmi_pixelclock(sd); + bt->hfrontporch = hdmi_read16(sd, 0x20, 0x3ff); + bt->hsync = hdmi_read16(sd, 0x22, 0x3ff); + bt->hbackporch = hdmi_read16(sd, 0x24, 0x3ff); + bt->vfrontporch = hdmi_read16(sd, 0x2a, 0x1fff) / 2; + bt->vsync = hdmi_read16(sd, 0x2e, 0x1fff) / 2; + bt->vbackporch = hdmi_read16(sd, 0x32, 0x1fff) / 2; bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) | ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0); if (bt->interlaced == V4L2_DV_INTERLACED) { - bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 + - hdmi_read(sd, 0x0c); - bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 + - hdmi_read(sd, 0x2d)) / 2; - bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + - hdmi_read(sd, 0x31)) / 2; - bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + - hdmi_read(sd, 0x35)) / 2; + bt->height += hdmi_read16(sd, 0x0b, 0xfff); + bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2; + bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; + bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; } adv7604_fill_optional_dv_timings_fields(sd, timings); } else { @@ -1378,11 +1623,11 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); /* TODO restart STDI for Sync Channel 2 */ /* enter one-shot mode */ - cp_write_and_or(sd, 0x86, 0xf9, 0x00); + cp_write_clr_set(sd, 0x86, 0x06, 0x00); /* trigger STDI restart */ - cp_write_and_or(sd, 0x86, 0xf9, 0x04); + cp_write_clr_set(sd, 0x86, 0x06, 0x04); /* reset to continuous mode */ - cp_write_and_or(sd, 0x86, 0xf9, 0x02); + cp_write_clr_set(sd, 0x86, 0x06, 0x02); state->restart_stdi_once = false; return -ENOLINK; } @@ -1441,7 +1686,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, state->timings = *timings; - cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); + cp_write_clr_set(sd, 0x91, 0x40, bt->interlaced ? 0x40 : 0x00); /* Use prim_mode and vid_std when available */ err = configure_predefined_video_timings(sd, timings); @@ -1468,6 +1713,16 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd, return 0; } +static void adv7604_set_termination(struct v4l2_subdev *sd, bool enable) +{ + hdmi_write(sd, 0x01, enable ? 0x00 : 0x78); +} + +static void adv7611_set_termination(struct v4l2_subdev *sd, bool enable) +{ + hdmi_write(sd, 0x83, enable ? 0xfe : 0xff); +} + static void enable_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); @@ -1475,10 +1730,10 @@ static void enable_input(struct v4l2_subdev *sd) if (is_analog_input(sd)) { io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ } else if (is_digital_input(sd)) { - hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input); - hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ + hdmi_write_clr_set(sd, 0x00, 0x03, state->selected_input); + state->info->set_termination(sd, true); io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ - hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */ + hdmi_write_clr_set(sd, 0x1a, 0x10, 0x00); /* Unmute audio */ } else { v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n", __func__, state->selected_input); @@ -1487,67 +1742,36 @@ static void enable_input(struct v4l2_subdev *sd) static void disable_input(struct v4l2_subdev *sd) { - hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */ + struct adv7604_state *state = to_state(sd); + + hdmi_write_clr_set(sd, 0x1a, 0x10, 0x10); /* Mute audio */ msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */ io_write(sd, 0x15, 0xbe); /* Tristate all outputs from video core */ - hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ + state->info->set_termination(sd, false); } static void select_input(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; if (is_analog_input(sd)) { - /* reset ADI recommended settings for HDMI: */ - /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ - hdmi_write(sd, 0x3d, 0x00); /* DDC bus active pull-up control */ - hdmi_write(sd, 0x3e, 0x74); /* TMDS PLL optimization */ - hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */ - hdmi_write(sd, 0x57, 0x74); /* TMDS PLL optimization */ - hdmi_write(sd, 0x58, 0x63); /* TMDS PLL optimization */ - hdmi_write(sd, 0x8d, 0x18); /* equaliser */ - hdmi_write(sd, 0x8e, 0x34); /* equaliser */ - hdmi_write(sd, 0x93, 0x88); /* equaliser */ - hdmi_write(sd, 0x94, 0x2e); /* equaliser */ - hdmi_write(sd, 0x96, 0x00); /* enable automatic EQ changing */ + adv7604_write_reg_seq(sd, info->recommended_settings[0]); afe_write(sd, 0x00, 0x08); /* power up ADC */ afe_write(sd, 0x01, 0x06); /* power up Analog Front End */ afe_write(sd, 0xc8, 0x00); /* phase control */ - - /* set ADI recommended settings for digitizer */ - /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - afe_write(sd, 0x12, 0x7b); /* ADC noise shaping filter controls */ - afe_write(sd, 0x0c, 0x1f); /* CP core gain controls */ - cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */ - cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ - cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ } else if (is_digital_input(sd)) { hdmi_write(sd, 0x00, state->selected_input & 0x03); - /* set ADI recommended settings for HDMI: */ - /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ - hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ - hdmi_write(sd, 0x3d, 0x10); /* DDC bus active pull-up control */ - hdmi_write(sd, 0x3e, 0x39); /* TMDS PLL optimization */ - hdmi_write(sd, 0x4e, 0x3b); /* TMDS PLL optimization */ - hdmi_write(sd, 0x57, 0xb6); /* TMDS PLL optimization */ - hdmi_write(sd, 0x58, 0x03); /* TMDS PLL optimization */ - hdmi_write(sd, 0x8d, 0x18); /* equaliser */ - hdmi_write(sd, 0x8e, 0x34); /* equaliser */ - hdmi_write(sd, 0x93, 0x8b); /* equaliser */ - hdmi_write(sd, 0x94, 0x2d); /* equaliser */ - hdmi_write(sd, 0x96, 0x01); /* enable automatic EQ changing */ - - afe_write(sd, 0x00, 0xff); /* power down ADC */ - afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ - afe_write(sd, 0xc8, 0x40); /* phase control */ - - /* reset ADI recommended settings for digitizer */ - /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ - afe_write(sd, 0x12, 0xfb); /* ADC noise shaping filter controls */ - afe_write(sd, 0x0c, 0x0d); /* CP core gain controls */ + adv7604_write_reg_seq(sd, info->recommended_settings[1]); + + if (adv7604_has_afe(state)) { + afe_write(sd, 0x00, 0xff); /* power down ADC */ + afe_write(sd, 0x01, 0xfe); /* power down Analog Front End */ + afe_write(sd, 0xc8, 0x40); /* phase control */ + } + cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */ cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */ cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */ @@ -1568,6 +1792,9 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, if (input == state->selected_input) return 0; + if (input > state->info->max_port) + return -EINVAL; + state->selected_input = input; disable_input(sd); @@ -1579,34 +1806,139 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7604_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) +static int adv7604_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct adv7604_state *state = to_state(sd); + + if (code->index >= state->info->nformats) + return -EINVAL; + + code->code = state->info->formats[code->index].code; + + return 0; +} + +static void adv7604_fill_format(struct adv7604_state *state, + struct v4l2_mbus_framefmt *format) +{ + memset(format, 0, sizeof(*format)); + + format->width = state->timings.bt.width; + format->height = state->timings.bt.height; + format->field = V4L2_FIELD_NONE; + + if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) + format->colorspace = (state->timings.bt.height <= 576) ? + V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; +} + +/* + * Compute the op_ch_sel value required to obtain on the bus the component order + * corresponding to the selected format taking into account bus reordering + * applied by the board at the output of the device. + * + * The following table gives the op_ch_value from the format component order + * (expressed as op_ch_sel value in column) and the bus reordering (expressed as + * adv7604_bus_order value in row). + * + * | GBR(0) GRB(1) BGR(2) RGB(3) BRG(4) RBG(5) + * ----------+------------------------------------------------- + * RGB (NOP) | GBR GRB BGR RGB BRG RBG + * GRB (1-2) | BGR RGB GBR GRB RBG BRG + * RBG (2-3) | GRB GBR BRG RBG BGR RGB + * BGR (1-3) | RBG BRG RGB BGR GRB GBR + * BRG (ROR) | BRG RBG GRB GBR RGB BGR + * GBR (ROL) | RGB BGR RBG BRG GBR GRB + */ +static unsigned int adv7604_op_ch_sel(struct adv7604_state *state) +{ +#define _SEL(a,b,c,d,e,f) { \ + ADV7604_OP_CH_SEL_##a, ADV7604_OP_CH_SEL_##b, ADV7604_OP_CH_SEL_##c, \ + ADV7604_OP_CH_SEL_##d, ADV7604_OP_CH_SEL_##e, ADV7604_OP_CH_SEL_##f } +#define _BUS(x) [ADV7604_BUS_ORDER_##x] + + static const unsigned int op_ch_sel[6][6] = { + _BUS(RGB) /* NOP */ = _SEL(GBR, GRB, BGR, RGB, BRG, RBG), + _BUS(GRB) /* 1-2 */ = _SEL(BGR, RGB, GBR, GRB, RBG, BRG), + _BUS(RBG) /* 2-3 */ = _SEL(GRB, GBR, BRG, RBG, BGR, RGB), + _BUS(BGR) /* 1-3 */ = _SEL(RBG, BRG, RGB, BGR, GRB, GBR), + _BUS(BRG) /* ROR */ = _SEL(BRG, RBG, GRB, GBR, RGB, BGR), + _BUS(GBR) /* ROL */ = _SEL(RGB, BGR, RBG, BRG, GBR, GRB), + }; + + return op_ch_sel[state->pdata.bus_order][state->format->op_ch_sel >> 5]; +} + +static void adv7604_setup_format(struct adv7604_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + io_write_clr_set(sd, 0x02, 0x02, + state->format->rgb_out ? ADV7604_RGB_OUT : 0); + io_write(sd, 0x03, state->format->op_format_sel | + state->pdata.op_format_mode_sel); + io_write_clr_set(sd, 0x04, 0xe0, adv7604_op_ch_sel(state)); + io_write_clr_set(sd, 0x05, 0x01, + state->format->swap_cb_cr ? ADV7604_OP_SWAP_CB_CR : 0); +} + +static int adv7604_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) { - if (index) + struct adv7604_state *state = to_state(sd); + + if (format->pad != state->source_pad) return -EINVAL; - /* Good enough for now */ - *code = V4L2_MBUS_FMT_FIXED; + + adv7604_fill_format(state, &format->format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(fh, format->pad); + format->format.code = fmt->code; + } else { + format->format.code = state->format->code; + } + return 0; } -static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) { struct adv7604_state *state = to_state(sd); + const struct adv7604_format_info *info; - fmt->width = state->timings.bt.width; - fmt->height = state->timings.bt.height; - fmt->code = V4L2_MBUS_FMT_FIXED; - fmt->field = V4L2_FIELD_NONE; - if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) { - fmt->colorspace = (state->timings.bt.height <= 576) ? - V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709; + if (format->pad != state->source_pad) + return -EINVAL; + + info = adv7604_format_info(state, format->format.code); + if (info == NULL) + info = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8); + + adv7604_fill_format(state, &format->format); + format->format.code = info->code; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(fh, format->pad); + fmt->code = format->format.code; + } else { + state->format = info; + adv7604_setup_format(state); } + return 0; } static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) { + struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; const u8 irq_reg_0x43 = io_read(sd, 0x43); const u8 irq_reg_0x6b = io_read(sd, 0x6b); const u8 irq_reg_0x70 = io_read(sd, 0x70); @@ -1625,7 +1957,9 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) /* format change */ fmt_change = irq_reg_0x43 & 0x98; - fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0; + fmt_change_digital = is_digital_input(sd) + ? irq_reg_0x6b & info->fmt_change_digital_mask + : 0; if (fmt_change || fmt_change_digital) { v4l2_dbg(1, debug, sd, @@ -1647,7 +1981,7 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled) } /* tx 5v detect */ - tx_5v = io_read(sd, 0x70) & 0x1e; + tx_5v = io_read(sd, 0x70) & info->cable_det_mask; if (tx_5v) { v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v); io_write(sd, 0x71, tx_5v); @@ -1663,7 +1997,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) struct adv7604_state *state = to_state(sd); u8 *data = NULL; - if (edid->pad > ADV7604_EDID_PORT_D) + if (edid->pad > ADV7604_PAD_HDMI_PORT_D) return -EINVAL; if (edid->blocks == 0) return -EINVAL; @@ -1678,10 +2012,10 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) edid->blocks = state->edid.blocks; switch (edid->pad) { - case ADV7604_EDID_PORT_A: - case ADV7604_EDID_PORT_B: - case ADV7604_EDID_PORT_C: - case ADV7604_EDID_PORT_D: + case ADV7604_PAD_HDMI_PORT_A: + case ADV7604_PAD_HDMI_PORT_B: + case ADV7604_PAD_HDMI_PORT_C: + case ADV7604_PAD_HDMI_PORT_D: if (state->edid.present & (1 << edid->pad)) data = state->edid.edid; break; @@ -1729,20 +2063,20 @@ static int get_edid_spa_location(const u8 *edid) static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; int spa_loc; - int tmp = 0; int err; int i; - if (edid->pad > ADV7604_EDID_PORT_D) + if (edid->pad > ADV7604_PAD_HDMI_PORT_D) return -EINVAL; if (edid->start_block != 0) return -EINVAL; if (edid->blocks == 0) { /* Disable hotplug and I2C access to EDID RAM from DDC port */ state->edid.present &= ~(1 << edid->pad); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present); - rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); + adv7604_set_hpd(state, state->edid.present); + rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); /* Fall back to a 16:9 aspect ratio */ state->aspect_ratio.numerator = 16; @@ -1765,35 +2099,41 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) /* Disable hotplug and I2C access to EDID RAM from DDC port */ cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); - v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp); - rep_write_and_or(sd, 0x77, 0xf0, 0x00); + adv7604_set_hpd(state, 0); + rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); spa_loc = get_edid_spa_location(edid->edid); if (spa_loc < 0) spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ switch (edid->pad) { - case ADV7604_EDID_PORT_A: + case ADV7604_PAD_HDMI_PORT_A: state->spa_port_a[0] = edid->edid[spa_loc]; state->spa_port_a[1] = edid->edid[spa_loc + 1]; break; - case ADV7604_EDID_PORT_B: + case ADV7604_PAD_HDMI_PORT_B: rep_write(sd, 0x70, edid->edid[spa_loc]); rep_write(sd, 0x71, edid->edid[spa_loc + 1]); break; - case ADV7604_EDID_PORT_C: + case ADV7604_PAD_HDMI_PORT_C: rep_write(sd, 0x72, edid->edid[spa_loc]); rep_write(sd, 0x73, edid->edid[spa_loc + 1]); break; - case ADV7604_EDID_PORT_D: + case ADV7604_PAD_HDMI_PORT_D: rep_write(sd, 0x74, edid->edid[spa_loc]); rep_write(sd, 0x75, edid->edid[spa_loc + 1]); break; default: return -EINVAL; } - rep_write(sd, 0x76, spa_loc & 0xff); - rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); + + if (info->type == ADV7604) { + rep_write(sd, 0x76, spa_loc & 0xff); + rep_write_clr_set(sd, 0x77, 0x40, (spa_loc & 0x100) >> 2); + } else { + /* FIXME: Where is the SPA location LSB register ? */ + rep_write_clr_set(sd, 0x71, 0x01, (spa_loc & 0x100) >> 8); + } edid->edid[spa_loc] = state->spa_port_a[0]; edid->edid[spa_loc + 1] = state->spa_port_a[1]; @@ -1812,10 +2152,10 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) /* adv7604 calculates the checksums and enables I2C access to internal EDID RAM from DDC port. */ - rep_write_and_or(sd, 0x77, 0xf0, state->edid.present); + rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, state->edid.present); for (i = 0; i < 1000; i++) { - if (rep_read(sd, 0x7d) & state->edid.present) + if (rep_read(sd, info->edid_status_reg) & state->edid.present) break; mdelay(1); } @@ -1878,17 +2218,20 @@ static void print_avi_infoframe(struct v4l2_subdev *sd) static int adv7604_log_status(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; struct v4l2_dv_timings timings; struct stdi_readback stdi; u8 reg_io_0x02 = io_read(sd, 0x02); + u8 edid_enabled; + u8 cable_det; - char *csc_coeff_sel_rb[16] = { + static const char * const csc_coeff_sel_rb[16] = { "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", "reserved", "YPbPr709 -> YPbPr601", "YPbPr601 -> YPbPr709", "reserved", "reserved", "reserved", "reserved", "manual" }; - char *input_color_space_txt[16] = { + static const char * const input_color_space_txt[16] = { "RGB limited range (16-235)", "RGB full range (0-255)", "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)", "xvYCC Bt.601", "xvYCC Bt.709", @@ -1896,12 +2239,12 @@ static int adv7604_log_status(struct v4l2_subdev *sd) "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "invalid", "automatic" }; - char *rgb_quantization_range_txt[] = { + static const char * const rgb_quantization_range_txt[] = { "Automatic", "RGB limited range (16-235)", "RGB full range (0-255)", }; - char *deep_color_mode_txt[4] = { + static const char * const deep_color_mode_txt[4] = { "8-bits per channel", "10-bits per channel", "12-bits per channel", @@ -1910,20 +2253,22 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "-----Chip status-----\n"); v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on"); + edid_enabled = rep_read(sd, info->edid_status_reg); v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n", - ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"), - ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"), - ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"), - ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No")); + ((edid_enabled & 0x01) ? "Yes" : "No"), + ((edid_enabled & 0x02) ? "Yes" : "No"), + ((edid_enabled & 0x04) ? "Yes" : "No"), + ((edid_enabled & 0x08) ? "Yes" : "No")); v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? "enabled" : "disabled"); v4l2_info(sd, "-----Signal status-----\n"); + cable_det = info->read_cable_det(sd); v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n", - ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"), - ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"), - ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"), - ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No")); + ((cable_det & 0x01) ? "Yes" : "No"), + ((cable_det & 0x02) ? "Yes" : "No"), + ((cable_det & 0x04) ? "Yes" : "No"), + ((cable_det & 0x08) ? "Yes" : "No")); v4l2_info(sd, "TMDS signal detected: %s\n", no_signal_tmds(sd) ? "false" : "true"); v4l2_info(sd, "TMDS signal locked: %s\n", @@ -2017,13 +2362,6 @@ static const struct v4l2_ctrl_ops adv7604_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7604_core_ops = { .log_status = adv7604_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, .interrupt_service_routine = adv7604_isr, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7604_g_register, @@ -2037,17 +2375,16 @@ static const struct v4l2_subdev_video_ops adv7604_video_ops = { .s_dv_timings = adv7604_s_dv_timings, .g_dv_timings = adv7604_g_dv_timings, .query_dv_timings = adv7604_query_dv_timings, - .enum_dv_timings = adv7604_enum_dv_timings, - .dv_timings_cap = adv7604_dv_timings_cap, - .enum_mbus_fmt = adv7604_enum_mbus_fmt, - .g_mbus_fmt = adv7604_g_mbus_fmt, - .try_mbus_fmt = adv7604_g_mbus_fmt, - .s_mbus_fmt = adv7604_g_mbus_fmt, }; static const struct v4l2_subdev_pad_ops adv7604_pad_ops = { + .enum_mbus_code = adv7604_enum_mbus_code, + .get_fmt = adv7604_get_format, + .set_fmt = adv7604_set_format, .get_edid = adv7604_get_edid, .set_edid = adv7604_set_edid, + .dv_timings_cap = adv7604_dv_timings_cap, + .enum_dv_timings = adv7604_enum_dv_timings, }; static const struct v4l2_subdev_ops adv7604_ops = { @@ -2096,6 +2433,7 @@ static const struct v4l2_ctrl_config adv7604_ctrl_free_run_color = { static int adv7604_core_init(struct v4l2_subdev *sd) { struct adv7604_state *state = to_state(sd); + const struct adv7604_chip_info *info = state->info; struct adv7604_platform_data *pdata = &state->pdata; hdmi_write(sd, 0x48, @@ -2104,28 +2442,33 @@ static int adv7604_core_init(struct v4l2_subdev *sd) disable_input(sd); + if (pdata->default_input >= 0 && + pdata->default_input < state->source_pad) { + state->selected_input = pdata->default_input; + select_input(sd); + enable_input(sd); + } + /* power */ io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */ io_write(sd, 0x0b, 0x44); /* Power down ESDP block */ cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ /* video format */ - io_write_and_or(sd, 0x02, 0xf0, + io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3 | pdata->op_656_range << 2 | - pdata->rgb_out << 1 | pdata->alt_data_sat << 0); - io_write(sd, 0x03, pdata->op_format_sel); - io_write_and_or(sd, 0x04, 0x1f, pdata->op_ch_sel << 5); - io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 | - pdata->insert_av_codes << 2 | - pdata->replicate_av_codes << 1 | - pdata->invert_cbcr << 0); + io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | + pdata->insert_av_codes << 2 | + pdata->replicate_av_codes << 1); + adv7604_setup_format(state); cp_write(sd, 0x69, 0x30); /* Enable CP CSC */ /* VS, HS polarities */ - io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1); + io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | + pdata->inv_hs_pol << 1 | pdata->inv_llc_pol); /* Adjust drive strength */ io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 | @@ -2142,52 +2485,46 @@ static int adv7604_core_init(struct v4l2_subdev *sd) for digital formats */ /* HDMI audio */ - hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ - hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */ - hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ + hdmi_write_clr_set(sd, 0x15, 0x03, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */ + hdmi_write_clr_set(sd, 0x1a, 0x0e, 0x08); /* Wait 1 s before unmute */ + hdmi_write_clr_set(sd, 0x68, 0x06, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */ /* TODO from platform data */ afe_write(sd, 0xb5, 0x01); /* Setting MCLK to 256Fs */ - afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ - io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); + if (adv7604_has_afe(state)) { + afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ + io_write_clr_set(sd, 0x30, 1 << 4, pdata->output_bus_lsb_to_msb << 4); + } /* interrupts */ - io_write(sd, 0x40, 0xc2); /* Configure INT1 */ - io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ + io_write(sd, 0x40, 0xc0 | pdata->int1_config); /* Configure INT1 */ io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */ - io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */ - io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */ + io_write(sd, 0x6e, info->fmt_change_digital_mask); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */ + io_write(sd, 0x73, info->cable_det_mask); /* Enable cable detection (+5v) interrupts */ + info->setup_irqs(sd); return v4l2_ctrl_handler_setup(sd->ctrl_handler); } +static void adv7604_setup_irqs(struct v4l2_subdev *sd) +{ + io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ +} + +static void adv7611_setup_irqs(struct v4l2_subdev *sd) +{ + io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ +} + static void adv7604_unregister_clients(struct adv7604_state *state) { - if (state->i2c_avlink) - i2c_unregister_device(state->i2c_avlink); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); - if (state->i2c_infoframe) - i2c_unregister_device(state->i2c_infoframe); - if (state->i2c_esdp) - i2c_unregister_device(state->i2c_esdp); - if (state->i2c_dpp) - i2c_unregister_device(state->i2c_dpp); - if (state->i2c_afe) - i2c_unregister_device(state->i2c_afe); - if (state->i2c_repeater) - i2c_unregister_device(state->i2c_repeater); - if (state->i2c_edid) - i2c_unregister_device(state->i2c_edid); - if (state->i2c_hdmi) - i2c_unregister_device(state->i2c_hdmi); - if (state->i2c_test) - i2c_unregister_device(state->i2c_test); - if (state->i2c_cp) - i2c_unregister_device(state->i2c_cp); - if (state->i2c_vdp) - i2c_unregister_device(state->i2c_vdp); + unsigned int i; + + for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) { + if (state->i2c_clients[i]) + i2c_unregister_device(state->i2c_clients[i]); + } } static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, @@ -2200,15 +2537,219 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd, return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1); } +static const struct adv7604_reg_seq adv7604_recommended_settings_afe[] = { + /* reset ADI recommended settings for HDMI: */ + /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x04 }, /* HDMI filter optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x00 }, /* DDC bus active pull-up control */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x74 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0x74 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x63 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x88 }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2e }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x00 }, /* enable automatic EQ changing */ + + /* set ADI recommended settings for digitizer */ + /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ + { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0x7b }, /* ADC noise shaping filter controls */ + { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x1f }, /* CP core gain controls */ + { ADV7604_REG(ADV7604_PAGE_CP, 0x3e), 0x04 }, /* CP core pre-gain control */ + { ADV7604_REG(ADV7604_PAGE_CP, 0xc3), 0x39 }, /* CP coast control. Graphics mode */ + { ADV7604_REG(ADV7604_PAGE_CP, 0x40), 0x5c }, /* CP core pre-gain control. Graphics mode */ + + { ADV7604_REG_SEQ_TERM, 0 }, +}; + +static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = { + /* set ADI recommended settings for HDMI: */ + /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x0d), 0x84 }, /* HDMI filter optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3d), 0x10 }, /* DDC bus active pull-up control */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x3e), 0x39 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4e), 0x3b }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xb6 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x03 }, /* TMDS PLL optimization */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x18 }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x34 }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x93), 0x8b }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x94), 0x2d }, /* equaliser */ + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x96), 0x01 }, /* enable automatic EQ changing */ + + /* reset ADI recommended settings for digitizer */ + /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 17. */ + { ADV7604_REG(ADV7604_PAGE_AFE, 0x12), 0xfb }, /* ADC noise shaping filter controls */ + { ADV7604_REG(ADV7604_PAGE_AFE, 0x0c), 0x0d }, /* CP core gain controls */ + + { ADV7604_REG_SEQ_TERM, 0 }, +}; + +static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = { + { ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x0c }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x03), 0x98 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x4c), 0x44 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8d), 0x04 }, + { ADV7604_REG(ADV7604_PAGE_HDMI, 0x8e), 0x1e }, + + { ADV7604_REG_SEQ_TERM, 0 }, +}; + +static const struct adv7604_chip_info adv7604_chip_info[] = { + [ADV7604] = { + .type = ADV7604, + .has_afe = true, + .max_port = ADV7604_PAD_VGA_COMP, + .num_dv_ports = 4, + .edid_enable_reg = 0x77, + .edid_status_reg = 0x7d, + .lcf_reg = 0xb3, + .tdms_lock_mask = 0xe0, + .cable_det_mask = 0x1e, + .fmt_change_digital_mask = 0xc1, + .formats = adv7604_formats, + .nformats = ARRAY_SIZE(adv7604_formats), + .set_termination = adv7604_set_termination, + .setup_irqs = adv7604_setup_irqs, + .read_hdmi_pixelclock = adv7604_read_hdmi_pixelclock, + .read_cable_det = adv7604_read_cable_det, + .recommended_settings = { + [0] = adv7604_recommended_settings_afe, + [1] = adv7604_recommended_settings_hdmi, + }, + .num_recommended_settings = { + [0] = ARRAY_SIZE(adv7604_recommended_settings_afe), + [1] = ARRAY_SIZE(adv7604_recommended_settings_hdmi), + }, + .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_AVLINK) | + BIT(ADV7604_PAGE_CEC) | BIT(ADV7604_PAGE_INFOFRAME) | + BIT(ADV7604_PAGE_ESDP) | BIT(ADV7604_PAGE_DPP) | + BIT(ADV7604_PAGE_AFE) | BIT(ADV7604_PAGE_REP) | + BIT(ADV7604_PAGE_EDID) | BIT(ADV7604_PAGE_HDMI) | + BIT(ADV7604_PAGE_TEST) | BIT(ADV7604_PAGE_CP) | + BIT(ADV7604_PAGE_VDP), + }, + [ADV7611] = { + .type = ADV7611, + .has_afe = false, + .max_port = ADV7604_PAD_HDMI_PORT_A, + .num_dv_ports = 1, + .edid_enable_reg = 0x74, + .edid_status_reg = 0x76, + .lcf_reg = 0xa3, + .tdms_lock_mask = 0x43, + .cable_det_mask = 0x01, + .fmt_change_digital_mask = 0x03, + .formats = adv7611_formats, + .nformats = ARRAY_SIZE(adv7611_formats), + .set_termination = adv7611_set_termination, + .setup_irqs = adv7611_setup_irqs, + .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock, + .read_cable_det = adv7611_read_cable_det, + .recommended_settings = { + [1] = adv7611_recommended_settings_hdmi, + }, + .num_recommended_settings = { + [1] = ARRAY_SIZE(adv7611_recommended_settings_hdmi), + }, + .page_mask = BIT(ADV7604_PAGE_IO) | BIT(ADV7604_PAGE_CEC) | + BIT(ADV7604_PAGE_INFOFRAME) | BIT(ADV7604_PAGE_AFE) | + BIT(ADV7604_PAGE_REP) | BIT(ADV7604_PAGE_EDID) | + BIT(ADV7604_PAGE_HDMI) | BIT(ADV7604_PAGE_CP), + }, +}; + +static struct i2c_device_id adv7604_i2c_id[] = { + { "adv7604", (kernel_ulong_t)&adv7604_chip_info[ADV7604] }, + { "adv7611", (kernel_ulong_t)&adv7604_chip_info[ADV7611] }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7604_i2c_id); + +static struct of_device_id adv7604_of_id[] __maybe_unused = { + { .compatible = "adi,adv7611", .data = &adv7604_chip_info[ADV7611] }, + { } +}; +MODULE_DEVICE_TABLE(of, adv7604_of_id); + +static int adv7604_parse_dt(struct adv7604_state *state) +{ + struct v4l2_of_endpoint bus_cfg; + struct device_node *endpoint; + struct device_node *np; + unsigned int flags; + + np = state->i2c_clients[ADV7604_PAGE_IO]->dev.of_node; + + /* Parse the endpoint. */ + endpoint = of_graph_get_next_endpoint(np, NULL); + if (!endpoint) + return -EINVAL; + + v4l2_of_parse_endpoint(endpoint, &bus_cfg); + of_node_put(endpoint); + + flags = bus_cfg.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + state->pdata.inv_hs_pol = 1; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + state->pdata.inv_vs_pol = 1; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + state->pdata.inv_llc_pol = 1; + + if (bus_cfg.bus_type == V4L2_MBUS_BT656) { + state->pdata.insert_av_codes = 1; + state->pdata.op_656_range = 1; + } + + /* Disable the interrupt for now as no DT-based board uses it. */ + state->pdata.int1_config = ADV7604_INT1_CONFIG_DISABLED; + + /* Use the default I2C addresses. */ + state->pdata.i2c_addresses[ADV7604_PAGE_AVLINK] = 0x42; + state->pdata.i2c_addresses[ADV7604_PAGE_CEC] = 0x40; + state->pdata.i2c_addresses[ADV7604_PAGE_INFOFRAME] = 0x3e; + state->pdata.i2c_addresses[ADV7604_PAGE_ESDP] = 0x38; + state->pdata.i2c_addresses[ADV7604_PAGE_DPP] = 0x3c; + state->pdata.i2c_addresses[ADV7604_PAGE_AFE] = 0x26; + state->pdata.i2c_addresses[ADV7604_PAGE_REP] = 0x32; + state->pdata.i2c_addresses[ADV7604_PAGE_EDID] = 0x36; + state->pdata.i2c_addresses[ADV7604_PAGE_HDMI] = 0x34; + state->pdata.i2c_addresses[ADV7604_PAGE_TEST] = 0x30; + state->pdata.i2c_addresses[ADV7604_PAGE_CP] = 0x22; + state->pdata.i2c_addresses[ADV7604_PAGE_VDP] = 0x24; + + /* Hardcode the remaining platform data fields. */ + state->pdata.disable_pwrdnb = 0; + state->pdata.disable_cable_det_rst = 0; + state->pdata.default_input = -1; + state->pdata.blank_data = 1; + state->pdata.alt_data_sat = 1; + state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; + state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; + + return 0; +} + static int adv7604_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const struct v4l2_dv_timings cea640x480 = V4L2_DV_BT_CEA_640X480P59_94; struct adv7604_state *state; - struct adv7604_platform_data *pdata = client->dev.platform_data; struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; + unsigned int i; + u16 val; int err; /* Check if the adapter supports the needed features */ @@ -2223,32 +2764,80 @@ static int adv7604_probe(struct i2c_client *client, return -ENOMEM; } + state->i2c_clients[ADV7604_PAGE_IO] = client; + /* initialize variables */ state->restart_stdi_once = true; state->selected_input = ~0; - /* platform data */ - if (!pdata) { + if (IS_ENABLED(CONFIG_OF) && client->dev.of_node) { + const struct of_device_id *oid; + + oid = of_match_node(adv7604_of_id, client->dev.of_node); + state->info = oid->data; + + err = adv7604_parse_dt(state); + if (err < 0) { + v4l_err(client, "DT parsing error\n"); + return err; + } + } else if (client->dev.platform_data) { + struct adv7604_platform_data *pdata = client->dev.platform_data; + + state->info = (const struct adv7604_chip_info *)id->driver_data; + state->pdata = *pdata; + } else { v4l_err(client, "No platform data!\n"); return -ENODEV; } - state->pdata = *pdata; + + /* Request GPIOs. */ + for (i = 0; i < state->info->num_dv_ports; ++i) { + state->hpd_gpio[i] = + devm_gpiod_get_index(&client->dev, "hpd", i); + if (IS_ERR(state->hpd_gpio[i])) + continue; + + gpiod_direction_output(state->hpd_gpio[i], 0); + + v4l_info(client, "Handling HPD %u GPIO\n", i); + } + state->timings = cea640x480; + state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8); sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7604_ops); + snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", + id->name, i2c_adapter_id(client->adapter), + client->addr); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - /* i2c access to adv7604? */ - if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) { - v4l2_info(sd, "not an adv7604 on address 0x%x\n", - client->addr << 1); - return -ENODEV; + /* + * Verify that the chip is present. On ADV7604 the RD_INFO register only + * identifies the revision, while on ADV7611 it identifies the model as + * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. + */ + if (state->info->type == ADV7604) { + val = adv_smbus_read_byte_data_check(client, 0xfb, false); + if (val != 0x68) { + v4l2_info(sd, "not an adv7604 on address 0x%x\n", + client->addr << 1); + return -ENODEV; + } + } else { + val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8) + | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0); + if (val != 0x2051) { + v4l2_info(sd, "not an adv7611 on address 0x%x\n", + client->addr << 1); + return -ENODEV; + } } /* control handlers */ hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, 9); + v4l2_ctrl_handler_init(hdl, adv7604_has_afe(state) ? 9 : 8); v4l2_ctrl_new_std(hdl, &adv7604_ctrl_ops, V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); @@ -2261,15 +2850,17 @@ static int adv7604_probe(struct i2c_client *client, /* private controls */ state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0); + V4L2_CID_DV_RX_POWER_PRESENT, 0, + (1 << state->info->num_dv_ports) - 1, 0, 0); state->rgb_quantization_range_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); /* custom controls */ - state->analog_sampling_phase_ctrl = - v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); + if (adv7604_has_afe(state)) + state->analog_sampling_phase_ctrl = + v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_analog_sampling_phase, NULL); state->free_run_color_manual_ctrl = v4l2_ctrl_new_custom(hdl, &adv7604_ctrl_free_run_color_manual, NULL); state->free_run_color_ctrl = @@ -2282,7 +2873,8 @@ static int adv7604_probe(struct i2c_client *client, } state->detect_tx_5v_ctrl->is_private = true; state->rgb_quantization_range_ctrl->is_private = true; - state->analog_sampling_phase_ctrl->is_private = true; + if (adv7604_has_afe(state)) + state->analog_sampling_phase_ctrl->is_private = true; state->free_run_color_manual_ctrl->is_private = true; state->free_run_color_ctrl->is_private = true; @@ -2291,25 +2883,18 @@ static int adv7604_probe(struct i2c_client *client, goto err_hdl; } - state->i2c_avlink = adv7604_dummy_client(sd, pdata->i2c_avlink, 0xf3); - state->i2c_cec = adv7604_dummy_client(sd, pdata->i2c_cec, 0xf4); - state->i2c_infoframe = adv7604_dummy_client(sd, pdata->i2c_infoframe, 0xf5); - state->i2c_esdp = adv7604_dummy_client(sd, pdata->i2c_esdp, 0xf6); - state->i2c_dpp = adv7604_dummy_client(sd, pdata->i2c_dpp, 0xf7); - state->i2c_afe = adv7604_dummy_client(sd, pdata->i2c_afe, 0xf8); - state->i2c_repeater = adv7604_dummy_client(sd, pdata->i2c_repeater, 0xf9); - state->i2c_edid = adv7604_dummy_client(sd, pdata->i2c_edid, 0xfa); - state->i2c_hdmi = adv7604_dummy_client(sd, pdata->i2c_hdmi, 0xfb); - state->i2c_test = adv7604_dummy_client(sd, pdata->i2c_test, 0xfc); - state->i2c_cp = adv7604_dummy_client(sd, pdata->i2c_cp, 0xfd); - state->i2c_vdp = adv7604_dummy_client(sd, pdata->i2c_vdp, 0xfe); - if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe || - !state->i2c_esdp || !state->i2c_dpp || !state->i2c_afe || - !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi || - !state->i2c_test || !state->i2c_cp || !state->i2c_vdp) { - err = -ENOMEM; - v4l2_err(sd, "failed to create all i2c clients\n"); - goto err_i2c; + for (i = 1; i < ADV7604_PAGE_MAX; ++i) { + if (!(BIT(i) & state->info->page_mask)) + continue; + + state->i2c_clients[i] = + adv7604_dummy_client(sd, state->pdata.i2c_addresses[i], + 0xf2 + i); + if (state->i2c_clients[i] == NULL) { + err = -ENOMEM; + v4l2_err(sd, "failed to create i2c client %u\n", i); + goto err_i2c; + } } /* work queues */ @@ -2323,8 +2908,14 @@ static int adv7604_probe(struct i2c_client *client, INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, adv7604_delayed_work_enable_hotplug); - state->pad.flags = MEDIA_PAD_FL_SOURCE; - err = media_entity_init(&sd->entity, 1, &state->pad, 0); + state->source_pad = state->info->num_dv_ports + + (state->info->has_afe ? 2 : 0); + for (i = 0; i < state->source_pad; ++i) + state->pads[i].flags = MEDIA_PAD_FL_SINK; + state->pads[state->source_pad].flags = MEDIA_PAD_FL_SOURCE; + + err = media_entity_init(&sd->entity, state->source_pad + 1, + state->pads, 0); if (err) goto err_work_queues; @@ -2333,6 +2924,11 @@ static int adv7604_probe(struct i2c_client *client, goto err_entity; v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); + + err = v4l2_async_register_subdev(sd); + if (err) + goto err_entity; + return 0; err_entity: @@ -2356,6 +2952,7 @@ static int adv7604_remove(struct i2c_client *client) cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); + v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); adv7604_unregister_clients(to_state(sd)); @@ -2365,20 +2962,15 @@ static int adv7604_remove(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static struct i2c_device_id adv7604_id[] = { - { "adv7604", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adv7604_id); - static struct i2c_driver adv7604_driver = { .driver = { .owner = THIS_MODULE, .name = "adv7604", + .of_match_table = of_match_ptr(adv7604_of_id), }, .probe = adv7604_probe, .remove = adv7604_remove, - .id_table = adv7604_id, + .id_table = adv7604_i2c_id, }; module_i2c_driver(adv7604_driver); diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 151cecd0ea25..6a93f928dfde 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile @@ -1,6 +1,6 @@ vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o -vsp1-y += vsp1_sru.o vsp1_uds.o +vsp1-y += vsp1_bru.o vsp1_sru.o vsp1_uds.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 0313210c6e9e..6ca2cf20d545 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -28,6 +28,7 @@ struct clk; struct device; struct vsp1_platform_data; +struct vsp1_bru; struct vsp1_hsit; struct vsp1_lif; struct vsp1_lut; @@ -45,11 +46,11 @@ struct vsp1_device { void __iomem *mmio; struct clk *clock; - struct clk *rt_clock; struct mutex lock; int ref_count; + struct vsp1_bru *bru; struct vsp1_hsit *hsi; struct vsp1_hsit *hst; struct vsp1_lif *lif; diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c new file mode 100644 index 000000000000..f80695480060 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.c @@ -0,0 +1,395 @@ +/* + * vsp1_bru.c -- R-Car VSP1 Blend ROP Unit + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/device.h> +#include <linux/gfp.h> + +#include <media/v4l2-subdev.h> + +#include "vsp1.h" +#include "vsp1_bru.h" + +#define BRU_MIN_SIZE 4U +#define BRU_MAX_SIZE 8190U + +/* ----------------------------------------------------------------------------- + * Device Access + */ + +static inline u32 vsp1_bru_read(struct vsp1_bru *bru, u32 reg) +{ + return vsp1_read(bru->entity.vsp1, reg); +} + +static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data) +{ + vsp1_write(bru->entity.vsp1, reg, data); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Core Operations + */ + +static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input) +{ + return media_entity_remote_pad(&bru->entity.pads[input]) != NULL; +} + +static int bru_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + unsigned int i; + + if (!enable) + return 0; + + format = &bru->entity.formats[BRU_PAD_SOURCE]; + + /* The hardware is extremely flexible but we have no userspace API to + * expose all the parameters, nor is it clear whether we would have use + * cases for all the supported modes. Let's just harcode the parameters + * to sane default values for now. + */ + + /* Disable both color data normalization and dithering. */ + vsp1_bru_write(bru, VI6_BRU_INCTRL, 0); + + /* Set the background position to cover the whole output image and + * set its color to opaque black. + */ + vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE, + (format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) | + (format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT)); + vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0); + vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, + 0xff << VI6_BRU_VIRRPF_COL_A_SHIFT); + + /* Route BRU input 1 as SRC input to the ROP unit and configure the ROP + * unit with a NOP operation to make BRU input 1 available as the + * Blend/ROP unit B SRC input. + */ + vsp1_bru_write(bru, VI6_BRU_ROP, VI6_BRU_ROP_DSTSEL_BRUIN(1) | + VI6_BRU_ROP_CROP(VI6_ROP_NOP) | + VI6_BRU_ROP_AROP(VI6_ROP_NOP)); + + for (i = 0; i < 4; ++i) { + u32 ctrl = 0; + + /* Configure all Blend/ROP units corresponding to an enabled BRU + * input for alpha blending. Blend/ROP units corresponding to + * disabled BRU inputs are used in ROP NOP mode to ignore the + * SRC input. + */ + if (bru_is_input_enabled(bru, i)) + ctrl |= VI6_BRU_CTRL_RBC; + else + ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP) + | VI6_BRU_CTRL_AROP(VI6_ROP_NOP); + + /* Select the virtual RPF as the Blend/ROP unit A DST input to + * serve as a background color. + */ + if (i == 0) + ctrl |= VI6_BRU_CTRL_DSTSEL_VRPF; + + /* Route BRU inputs 0 to 3 as SRC inputs to Blend/ROP units A to + * D in that order. The Blend/ROP unit B SRC is hardwired to the + * ROP unit output, the corresponding register bits must be set + * to 0. + */ + if (i != 1) + ctrl |= VI6_BRU_CTRL_SRCSEL_BRUIN(i); + + vsp1_bru_write(bru, VI6_BRU_CTRL(i), ctrl); + + /* Harcode the blending formula to + * + * DSTc = DSTc * (1 - SRCa) + SRCc * SRCa + * DSTa = DSTa * (1 - SRCa) + SRCa + */ + vsp1_bru_write(bru, VI6_BRU_BLD(i), + VI6_BRU_BLD_CCMDX_255_SRC_A | + VI6_BRU_BLD_CCMDY_SRC_A | + VI6_BRU_BLD_ACMDX_255_SRC_A | + VI6_BRU_BLD_ACMDY_COEFY | + (0xff << VI6_BRU_BLD_COEFY_SHIFT)); + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +/* + * The BRU can't perform format conversion, all sink and source formats must be + * identical. We pick the format on the first sink pad (pad 0) and propagate it + * to all other pads. + */ + +static int bru_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + static const unsigned int codes[] = { + V4L2_MBUS_FMT_ARGB8888_1X32, + V4L2_MBUS_FMT_AYUV8_1X32, + }; + struct v4l2_mbus_framefmt *format; + + if (code->pad == BRU_PAD_SINK(0)) { + if (code->index >= ARRAY_SIZE(codes)) + return -EINVAL; + + code->code = codes[code->index]; + } else { + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(fh, BRU_PAD_SINK(0)); + code->code = format->code; + } + + return 0; +} + +static int bru_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index) + return -EINVAL; + + if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fse->code != V4L2_MBUS_FMT_AYUV8_1X32) + return -EINVAL; + + fse->min_width = BRU_MIN_SIZE; + fse->max_width = BRU_MAX_SIZE; + fse->min_height = BRU_MIN_SIZE; + fse->max_height = BRU_MAX_SIZE; + + return 0; +} + +static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru, + struct v4l2_subdev_fh *fh, + unsigned int pad, u32 which) +{ + switch (which) { + case V4L2_SUBDEV_FORMAT_TRY: + return v4l2_subdev_get_try_crop(fh, pad); + case V4L2_SUBDEV_FORMAT_ACTIVE: + return &bru->compose[pad]; + default: + return NULL; + } +} + +static int bru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_bru *bru = to_bru(subdev); + + fmt->format = *vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->which); + + return 0; +} + +static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + + switch (pad) { + case BRU_PAD_SINK(0): + /* Default to YUV if the requested format is not supported. */ + if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) + fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + break; + + default: + /* The BRU can't perform format conversion. */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, + BRU_PAD_SINK(0), which); + fmt->code = format->code; + break; + } + + fmt->width = clamp(fmt->width, BRU_MIN_SIZE, BRU_MAX_SIZE); + fmt->height = clamp(fmt->height, BRU_MIN_SIZE, BRU_MAX_SIZE); + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +static int bru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + + bru_try_format(bru, fh, fmt->pad, &fmt->format, fmt->which); + + format = vsp1_entity_get_pad_format(&bru->entity, fh, fmt->pad, + fmt->which); + *format = fmt->format; + + /* Reset the compose rectangle */ + if (fmt->pad != BRU_PAD_SOURCE) { + struct v4l2_rect *compose; + + compose = bru_get_compose(bru, fh, fmt->pad, fmt->which); + compose->left = 0; + compose->top = 0; + compose->width = format->width; + compose->height = format->height; + } + + /* Propagate the format code to all pads */ + if (fmt->pad == BRU_PAD_SINK(0)) { + unsigned int i; + + for (i = 0; i <= BRU_PAD_SOURCE; ++i) { + format = vsp1_entity_get_pad_format(&bru->entity, fh, + i, fmt->which); + format->code = fmt->format.code; + } + } + + return 0; +} + +static int bru_get_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct vsp1_bru *bru = to_bru(subdev); + + if (sel->pad == BRU_PAD_SOURCE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = BRU_MAX_SIZE; + sel->r.height = BRU_MAX_SIZE; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = *bru_get_compose(bru, fh, sel->pad, sel->which); + return 0; + + default: + return -EINVAL; + } +} + +static int bru_set_selection(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct vsp1_bru *bru = to_bru(subdev); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *compose; + + if (sel->pad == BRU_PAD_SOURCE) + return -EINVAL; + + if (sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + /* The compose rectangle top left corner must be inside the output + * frame. + */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, BRU_PAD_SOURCE, + sel->which); + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1); + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1); + + /* Scaling isn't supported, the compose rectangle size must be identical + * to the sink format size. + */ + format = vsp1_entity_get_pad_format(&bru->entity, fh, sel->pad, + sel->which); + sel->r.width = format->width; + sel->r.height = format->height; + + compose = bru_get_compose(bru, fh, sel->pad, sel->which); + *compose = sel->r; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static struct v4l2_subdev_video_ops bru_video_ops = { + .s_stream = bru_s_stream, +}; + +static struct v4l2_subdev_pad_ops bru_pad_ops = { + .enum_mbus_code = bru_enum_mbus_code, + .enum_frame_size = bru_enum_frame_size, + .get_fmt = bru_get_format, + .set_fmt = bru_set_format, + .get_selection = bru_get_selection, + .set_selection = bru_set_selection, +}; + +static struct v4l2_subdev_ops bru_ops = { + .video = &bru_video_ops, + .pad = &bru_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Initialization and Cleanup + */ + +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1) +{ + struct v4l2_subdev *subdev; + struct vsp1_bru *bru; + int ret; + + bru = devm_kzalloc(vsp1->dev, sizeof(*bru), GFP_KERNEL); + if (bru == NULL) + return ERR_PTR(-ENOMEM); + + bru->entity.type = VSP1_ENTITY_BRU; + + ret = vsp1_entity_init(vsp1, &bru->entity, 5); + if (ret < 0) + return ERR_PTR(ret); + + /* Initialize the V4L2 subdev. */ + subdev = &bru->entity.subdev; + v4l2_subdev_init(subdev, &bru_ops); + + subdev->entity.ops = &vsp1_media_ops; + subdev->internal_ops = &vsp1_subdev_internal_ops; + snprintf(subdev->name, sizeof(subdev->name), "%s bru", + dev_name(vsp1->dev)); + v4l2_set_subdevdata(subdev, bru); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + vsp1_entity_init_formats(subdev, NULL); + + return bru; +} diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h new file mode 100644 index 000000000000..37062704dbf6 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_bru.h @@ -0,0 +1,39 @@ +/* + * vsp1_bru.h -- R-Car VSP1 Blend ROP Unit + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VSP1_BRU_H__ +#define __VSP1_BRU_H__ + +#include <media/media-entity.h> +#include <media/v4l2-subdev.h> + +#include "vsp1_entity.h" + +struct vsp1_device; + +#define BRU_PAD_SINK(n) (n) +#define BRU_PAD_SOURCE 4 + +struct vsp1_bru { + struct vsp1_entity entity; + + struct v4l2_rect compose[4]; +}; + +static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct vsp1_bru, entity.subdev); +} + +struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1); + +#endif /* __VSP1_BRU_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 2f74f0e0ddf5..c69ee0657f75 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -16,10 +16,12 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/videodev2.h> #include "vsp1.h" +#include "vsp1_bru.h" #include "vsp1_hsit.h" #include "vsp1_lif.h" #include "vsp1_lut.h" @@ -155,6 +157,14 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) } /* Instantiate all the entities. */ + vsp1->bru = vsp1_bru_create(vsp1); + if (IS_ERR(vsp1->bru)) { + ret = PTR_ERR(vsp1->bru); + goto done; + } + + list_add_tail(&vsp1->bru->entity.list_dev, &vsp1->entities); + vsp1->hsi = vsp1_hsit_create(vsp1, true); if (IS_ERR(vsp1->hsi)) { ret = PTR_ERR(vsp1->hsi); @@ -329,33 +339,6 @@ static int vsp1_device_init(struct vsp1_device *vsp1) return 0; } -static int vsp1_clocks_enable(struct vsp1_device *vsp1) -{ - int ret; - - ret = clk_prepare_enable(vsp1->clock); - if (ret < 0) - return ret; - - if (IS_ERR(vsp1->rt_clock)) - return 0; - - ret = clk_prepare_enable(vsp1->rt_clock); - if (ret < 0) { - clk_disable_unprepare(vsp1->clock); - return ret; - } - - return 0; -} - -static void vsp1_clocks_disable(struct vsp1_device *vsp1) -{ - if (!IS_ERR(vsp1->rt_clock)) - clk_disable_unprepare(vsp1->rt_clock); - clk_disable_unprepare(vsp1->clock); -} - /* * vsp1_device_get - Acquire the VSP1 device * @@ -373,7 +356,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) if (vsp1->ref_count > 0) goto done; - ret = vsp1_clocks_enable(vsp1); + ret = clk_prepare_enable(vsp1->clock); if (ret < 0) { __vsp1 = NULL; goto done; @@ -381,7 +364,7 @@ struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1) ret = vsp1_device_init(vsp1); if (ret < 0) { - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); __vsp1 = NULL; goto done; } @@ -405,7 +388,7 @@ void vsp1_device_put(struct vsp1_device *vsp1) mutex_lock(&vsp1->lock); if (--vsp1->ref_count == 0) - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); mutex_unlock(&vsp1->lock); } @@ -424,7 +407,7 @@ static int vsp1_pm_suspend(struct device *dev) if (vsp1->ref_count == 0) return 0; - vsp1_clocks_disable(vsp1); + clk_disable_unprepare(vsp1->clock); return 0; } @@ -437,7 +420,7 @@ static int vsp1_pm_resume(struct device *dev) if (vsp1->ref_count) return 0; - return vsp1_clocks_enable(vsp1); + return clk_prepare_enable(vsp1->clock); } #endif @@ -449,34 +432,59 @@ static const struct dev_pm_ops vsp1_pm_ops = { * Platform Driver */ -static struct vsp1_platform_data * -vsp1_get_platform_data(struct platform_device *pdev) +static int vsp1_validate_platform_data(struct platform_device *pdev, + struct vsp1_platform_data *pdata) { - struct vsp1_platform_data *pdata = pdev->dev.platform_data; - if (pdata == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - return NULL; + return -EINVAL; } if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) { dev_err(&pdev->dev, "invalid number of RPF (%u)\n", pdata->rpf_count); - return NULL; + return -EINVAL; } if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) { dev_err(&pdev->dev, "invalid number of UDS (%u)\n", pdata->uds_count); - return NULL; + return -EINVAL; } if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) { dev_err(&pdev->dev, "invalid number of WPF (%u)\n", pdata->wpf_count); - return NULL; + return -EINVAL; } + return 0; +} + +static struct vsp1_platform_data * +vsp1_get_platform_data(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct vsp1_platform_data *pdata; + + if (!IS_ENABLED(CONFIG_OF) || np == NULL) + return pdev->dev.platform_data; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) + return NULL; + + if (of_property_read_bool(np, "renesas,has-lif")) + pdata->features |= VSP1_HAS_LIF; + if (of_property_read_bool(np, "renesas,has-lut")) + pdata->features |= VSP1_HAS_LUT; + if (of_property_read_bool(np, "renesas,has-sru")) + pdata->features |= VSP1_HAS_SRU; + + of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count); + of_property_read_u32(np, "renesas,#uds", &pdata->uds_count); + of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count); + return pdata; } @@ -499,6 +507,10 @@ static int vsp1_probe(struct platform_device *pdev) if (vsp1->pdata == NULL) return -ENODEV; + ret = vsp1_validate_platform_data(pdev, vsp1->pdata); + if (ret < 0) + return ret; + /* I/O, IRQ and clock resources */ io = platform_get_resource(pdev, IORESOURCE_MEM, 0); vsp1->mmio = devm_ioremap_resource(&pdev->dev, io); @@ -511,9 +523,6 @@ static int vsp1_probe(struct platform_device *pdev) return PTR_ERR(vsp1->clock); } - /* The RT clock is optional */ - vsp1->rt_clock = devm_clk_get(&pdev->dev, "rt"); - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "missing IRQ\n"); @@ -548,6 +557,11 @@ static int vsp1_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id vsp1_of_match[] = { + { .compatible = "renesas,vsp1" }, + { }, +}; + static struct platform_driver vsp1_platform_driver = { .probe = vsp1_probe, .remove = vsp1_remove, @@ -555,6 +569,7 @@ static struct platform_driver vsp1_platform_driver = { .owner = THIS_MODULE, .name = "vsp1", .pm = &vsp1_pm_ops, + .of_match_table = vsp1_of_match, }, }; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3fc9e4266caf..44167834285d 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -100,8 +100,10 @@ static int vsp1_entity_link_setup(struct media_entity *entity, if (source->sink) return -EBUSY; source->sink = remote->entity; + source->sink_pad = remote->index; } else { source->sink = NULL; + source->sink_pad = 0; } return 0; @@ -116,42 +118,43 @@ const struct media_entity_operations vsp1_media_ops = { * Initialization */ +static const struct vsp1_route vsp1_routes[] = { + { VSP1_ENTITY_BRU, 0, VI6_DPR_BRU_ROUTE, + { VI6_DPR_NODE_BRU_IN(0), VI6_DPR_NODE_BRU_IN(1), + VI6_DPR_NODE_BRU_IN(2), VI6_DPR_NODE_BRU_IN(3), } }, + { VSP1_ENTITY_HSI, 0, VI6_DPR_HSI_ROUTE, { VI6_DPR_NODE_HSI, } }, + { VSP1_ENTITY_HST, 0, VI6_DPR_HST_ROUTE, { VI6_DPR_NODE_HST, } }, + { VSP1_ENTITY_LIF, 0, 0, { VI6_DPR_NODE_LIF, } }, + { VSP1_ENTITY_LUT, 0, VI6_DPR_LUT_ROUTE, { VI6_DPR_NODE_LUT, } }, + { VSP1_ENTITY_RPF, 0, VI6_DPR_RPF_ROUTE(0), { VI6_DPR_NODE_RPF(0), } }, + { VSP1_ENTITY_RPF, 1, VI6_DPR_RPF_ROUTE(1), { VI6_DPR_NODE_RPF(1), } }, + { VSP1_ENTITY_RPF, 2, VI6_DPR_RPF_ROUTE(2), { VI6_DPR_NODE_RPF(2), } }, + { VSP1_ENTITY_RPF, 3, VI6_DPR_RPF_ROUTE(3), { VI6_DPR_NODE_RPF(3), } }, + { VSP1_ENTITY_RPF, 4, VI6_DPR_RPF_ROUTE(4), { VI6_DPR_NODE_RPF(4), } }, + { VSP1_ENTITY_SRU, 0, VI6_DPR_SRU_ROUTE, { VI6_DPR_NODE_SRU, } }, + { VSP1_ENTITY_UDS, 0, VI6_DPR_UDS_ROUTE(0), { VI6_DPR_NODE_UDS(0), } }, + { VSP1_ENTITY_UDS, 1, VI6_DPR_UDS_ROUTE(1), { VI6_DPR_NODE_UDS(1), } }, + { VSP1_ENTITY_UDS, 2, VI6_DPR_UDS_ROUTE(2), { VI6_DPR_NODE_UDS(2), } }, + { VSP1_ENTITY_WPF, 0, 0, { VI6_DPR_NODE_WPF(0), } }, + { VSP1_ENTITY_WPF, 1, 0, { VI6_DPR_NODE_WPF(1), } }, + { VSP1_ENTITY_WPF, 2, 0, { VI6_DPR_NODE_WPF(2), } }, + { VSP1_ENTITY_WPF, 3, 0, { VI6_DPR_NODE_WPF(3), } }, +}; + int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, unsigned int num_pads) { - static const struct { - unsigned int id; - unsigned int reg; - } routes[] = { - { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, - { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, - { VI6_DPR_NODE_LIF, 0 }, - { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE }, - { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, - { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, - { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, - { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, - { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, - { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE }, - { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, - { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, - { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, - { VI6_DPR_NODE_WPF(0), 0 }, - { VI6_DPR_NODE_WPF(1), 0 }, - { VI6_DPR_NODE_WPF(2), 0 }, - { VI6_DPR_NODE_WPF(3), 0 }, - }; - unsigned int i; - for (i = 0; i < ARRAY_SIZE(routes); ++i) { - if (routes[i].id == entity->id) { - entity->route = routes[i].reg; + for (i = 0; i < ARRAY_SIZE(vsp1_routes); ++i) { + if (vsp1_routes[i].type == entity->type && + vsp1_routes[i].index == entity->index) { + entity->route = &vsp1_routes[i]; break; } } - if (i == ARRAY_SIZE(routes)) + if (i == ARRAY_SIZE(vsp1_routes)) return -EINVAL; entity->vsp1 = vsp1; diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index f6fd6988aeb0..7afbd8a7ba66 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -20,6 +20,7 @@ struct vsp1_device; enum vsp1_entity_type { + VSP1_ENTITY_BRU, VSP1_ENTITY_HSI, VSP1_ENTITY_HST, VSP1_ENTITY_LIF, @@ -30,13 +31,31 @@ enum vsp1_entity_type { VSP1_ENTITY_WPF, }; +/* + * struct vsp1_route - Entity routing configuration + * @type: Entity type this routing entry is associated with + * @index: Entity index this routing entry is associated with + * @reg: Output routing configuration register + * @inputs: Target node value for each input + * + * Each $vsp1_route entry describes routing configuration for the entity + * specified by the entry's @type and @index. @reg indicates the register that + * holds output routing configuration for the entity, and the @inputs array + * store the target node value for each input of the entity. + */ +struct vsp1_route { + enum vsp1_entity_type type; + unsigned int index; + unsigned int reg; + unsigned int inputs[4]; +}; + struct vsp1_entity { struct vsp1_device *vsp1; enum vsp1_entity_type type; unsigned int index; - unsigned int id; - unsigned int route; + const struct vsp1_route *route; struct list_head list_dev; struct list_head list_pipe; @@ -45,6 +64,7 @@ struct vsp1_entity { unsigned int source_pad; struct media_entity *sink; + unsigned int sink_pad; struct v4l2_subdev subdev; struct v4l2_mbus_framefmt *formats; diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c index 285485350d82..db2950a73c60 100644 --- a/drivers/media/platform/vsp1/vsp1_hsit.c +++ b/drivers/media/platform/vsp1/vsp1_hsit.c @@ -193,13 +193,10 @@ struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse) hsit->inverse = inverse; - if (inverse) { + if (inverse) hsit->entity.type = VSP1_ENTITY_HSI; - hsit->entity.id = VI6_DPR_NODE_HSI; - } else { + else hsit->entity.type = VSP1_ENTITY_HST; - hsit->entity.id = VI6_DPR_NODE_HST; - } ret = vsp1_entity_init(vsp1, &hsit->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index 135a78957014..d4fb23e9c4a8 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -215,7 +215,6 @@ struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); lif->entity.type = VSP1_ENTITY_LIF; - lif->entity.id = VI6_DPR_NODE_LIF; ret = vsp1_entity_init(vsp1, &lif->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c index 4e9dc7c86ef8..fea36ebe2565 100644 --- a/drivers/media/platform/vsp1/vsp1_lut.c +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -229,7 +229,6 @@ struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); lut->entity.type = VSP1_ENTITY_LUT; - lut->entity.id = VI6_DPR_NODE_LUT; ret = vsp1_entity_init(vsp1, &lut->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 28650806c20f..3e74b44286f6 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -451,13 +451,111 @@ * BRU Control Registers */ +#define VI6_ROP_NOP 0 +#define VI6_ROP_AND 1 +#define VI6_ROP_AND_REV 2 +#define VI6_ROP_COPY 3 +#define VI6_ROP_AND_INV 4 +#define VI6_ROP_CLEAR 5 +#define VI6_ROP_XOR 6 +#define VI6_ROP_OR 7 +#define VI6_ROP_NOR 8 +#define VI6_ROP_EQUIV 9 +#define VI6_ROP_INVERT 10 +#define VI6_ROP_OR_REV 11 +#define VI6_ROP_COPY_INV 12 +#define VI6_ROP_OR_INV 13 +#define VI6_ROP_NAND 14 +#define VI6_ROP_SET 15 + #define VI6_BRU_INCTRL 0x2c00 +#define VI6_BRU_INCTRL_NRM (1 << 28) +#define VI6_BRU_INCTRL_DnON (1 << (16 + (n))) +#define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_16BPP (2 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_15BPP (3 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_12BPP (4 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_8BPP (5 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_MASK (7 << ((n) * 4)) +#define VI6_BRU_INCTRL_DITHn_SHIFT ((n) * 4) + #define VI6_BRU_VIRRPF_SIZE 0x2c04 +#define VI6_BRU_VIRRPF_SIZE_HSIZE_MASK (0x1fff << 16) +#define VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT 16 +#define VI6_BRU_VIRRPF_SIZE_VSIZE_MASK (0x1fff << 0) +#define VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT 0 + #define VI6_BRU_VIRRPF_LOC 0x2c08 +#define VI6_BRU_VIRRPF_LOC_HCOORD_MASK (0x1fff << 16) +#define VI6_BRU_VIRRPF_LOC_HCOORD_SHIFT 16 +#define VI6_BRU_VIRRPF_LOC_VCOORD_MASK (0x1fff << 0) +#define VI6_BRU_VIRRPF_LOC_VCOORD_SHIFT 0 + #define VI6_BRU_VIRRPF_COL 0x2c0c +#define VI6_BRU_VIRRPF_COL_A_MASK (0xff << 24) +#define VI6_BRU_VIRRPF_COL_A_SHIFT 24 +#define VI6_BRU_VIRRPF_COL_RCR_MASK (0xff << 16) +#define VI6_BRU_VIRRPF_COL_RCR_SHIFT 16 +#define VI6_BRU_VIRRPF_COL_GY_MASK (0xff << 8) +#define VI6_BRU_VIRRPF_COL_GY_SHIFT 8 +#define VI6_BRU_VIRRPF_COL_BCB_MASK (0xff << 0) +#define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0 + #define VI6_BRU_CTRL(n) (0x2c10 + (n) * 8) +#define VI6_BRU_CTRL_RBC (1 << 31) +#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) ((n) << 20) +#define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20) +#define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20) +#define VI6_BRU_CTRL_SRCSEL_BRUIN(n) ((n) << 16) +#define VI6_BRU_CTRL_SRCSEL_VRPF (4 << 16) +#define VI6_BRU_CTRL_SRCSEL_MASK (7 << 16) +#define VI6_BRU_CTRL_CROP(rop) ((rop) << 4) +#define VI6_BRU_CTRL_CROP_MASK (0xf << 4) +#define VI6_BRU_CTRL_AROP(rop) ((rop) << 0) +#define VI6_BRU_CTRL_AROP_MASK (0xf << 0) + #define VI6_BRU_BLD(n) (0x2c14 + (n) * 8) +#define VI6_BRU_BLD_CBES (1 << 31) +#define VI6_BRU_BLD_CCMDX_DST_A (0 << 28) +#define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28) +#define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28) +#define VI6_BRU_BLD_CCMDX_255_SRC_A (3 << 28) +#define VI6_BRU_BLD_CCMDX_COEFX (4 << 28) +#define VI6_BRU_BLD_CCMDX_MASK (7 << 28) +#define VI6_BRU_BLD_CCMDY_DST_A (0 << 24) +#define VI6_BRU_BLD_CCMDY_255_DST_A (1 << 24) +#define VI6_BRU_BLD_CCMDY_SRC_A (2 << 24) +#define VI6_BRU_BLD_CCMDY_255_SRC_A (3 << 24) +#define VI6_BRU_BLD_CCMDY_COEFY (4 << 24) +#define VI6_BRU_BLD_CCMDY_MASK (7 << 24) +#define VI6_BRU_BLD_CCMDY_SHIFT 24 +#define VI6_BRU_BLD_ABES (1 << 23) +#define VI6_BRU_BLD_ACMDX_DST_A (0 << 20) +#define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20) +#define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20) +#define VI6_BRU_BLD_ACMDX_255_SRC_A (3 << 20) +#define VI6_BRU_BLD_ACMDX_COEFX (4 << 20) +#define VI6_BRU_BLD_ACMDX_MASK (7 << 20) +#define VI6_BRU_BLD_ACMDY_DST_A (0 << 16) +#define VI6_BRU_BLD_ACMDY_255_DST_A (1 << 16) +#define VI6_BRU_BLD_ACMDY_SRC_A (2 << 16) +#define VI6_BRU_BLD_ACMDY_255_SRC_A (3 << 16) +#define VI6_BRU_BLD_ACMDY_COEFY (4 << 16) +#define VI6_BRU_BLD_ACMDY_MASK (7 << 16) +#define VI6_BRU_BLD_COEFX_MASK (0xff << 8) +#define VI6_BRU_BLD_COEFX_SHIFT 8 +#define VI6_BRU_BLD_COEFY_MASK (0xff << 0) +#define VI6_BRU_BLD_COEFY_SHIFT 0 + #define VI6_BRU_ROP 0x2c30 +#define VI6_BRU_ROP_DSTSEL_BRUIN(n) ((n) << 20) +#define VI6_BRU_ROP_DSTSEL_VRPF (4 << 20) +#define VI6_BRU_ROP_DSTSEL_MASK (7 << 20) +#define VI6_BRU_ROP_CROP(rop) ((rop) << 4) +#define VI6_BRU_ROP_CROP_MASK (0xf << 4) +#define VI6_BRU_ROP_AROP(rop) ((rop) << 0) +#define VI6_BRU_ROP_AROP_MASK (0xf << 0) /* ----------------------------------------------------------------------------- * HGO Control Registers diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c index 2b04d0f95c62..c3d98642a4aa 100644 --- a/drivers/media/platform/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/vsp1/vsp1_rpf.c @@ -96,8 +96,10 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable) vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt); vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap); - /* Output location. Composing isn't supported yet. */ - vsp1_rpf_write(rpf, VI6_RPF_LOC, 0); + /* Output location */ + vsp1_rpf_write(rpf, VI6_RPF_LOC, + (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) | + (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT)); /* Disable alpha, mask and color key. Set the alpha channel to a fixed * value of 255. @@ -176,7 +178,6 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index) rpf->entity.type = VSP1_ENTITY_RPF; rpf->entity.index = index; - rpf->entity.id = VI6_DPR_NODE_RPF(index); ret = vsp1_entity_init(vsp1, &rpf->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h index 5c5ee81bbeae..b4fb65e58770 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.h +++ b/drivers/media/platform/vsp1/vsp1_rwpf.h @@ -30,6 +30,10 @@ struct vsp1_rwpf { unsigned int max_width; unsigned int max_height; + struct { + unsigned int left; + unsigned int top; + } location; struct v4l2_rect crop; unsigned int offsets[2]; diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c index 7ab1a0b2d656..aa0e04c56f3f 100644 --- a/drivers/media/platform/vsp1/vsp1_sru.c +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -327,7 +327,6 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) return ERR_PTR(-ENOMEM); sru->entity.type = VSP1_ENTITY_SRU; - sru->entity.id = VI6_DPR_NODE_SRU; ret = vsp1_entity_init(vsp1, &sru->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c index 622342ac7770..0293bdbb4401 100644 --- a/drivers/media/platform/vsp1/vsp1_uds.c +++ b/drivers/media/platform/vsp1/vsp1_uds.c @@ -131,7 +131,7 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) return 0; /* Enable multi-tap scaling. */ - vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_BC); + vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC); vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH, (uds_passband_width(uds->hscale) @@ -139,7 +139,6 @@ static int uds_s_stream(struct v4l2_subdev *subdev, int enable) (uds_passband_width(uds->vscale) << VI6_UDS_PASS_BWIDTH_V_SHIFT)); - /* Set the scaling ratios and the output size. */ format = &uds->entity.formats[UDS_PAD_SOURCE]; @@ -323,7 +322,6 @@ struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index) uds->entity.type = VSP1_ENTITY_UDS; uds->entity.index = index; - uds->entity.id = VI6_DPR_NODE_UDS(index); ret = vsp1_entity_init(vsp1, &uds->entity, 2); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index a0595c17700f..8a1253e51f04 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -28,6 +28,7 @@ #include <media/videobuf2-dma-contig.h> #include "vsp1.h" +#include "vsp1_bru.h" #include "vsp1_entity.h" #include "vsp1_rwpf.h" #include "vsp1_video.h" @@ -280,6 +281,9 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, struct media_pad *pad; bool uds_found = false; + input->location.left = 0; + input->location.top = 0; + pad = media_entity_remote_pad(&input->entity.pads[RWPF_PAD_SOURCE]); while (1) { @@ -292,6 +296,17 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input, entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity)); + /* A BRU is present in the pipeline, store the compose rectangle + * location in the input RPF for use when configuring the RPF. + */ + if (entity->type == VSP1_ENTITY_BRU) { + struct vsp1_bru *bru = to_bru(&entity->subdev); + struct v4l2_rect *rect = &bru->compose[pad->index]; + + input->location.left = rect->left; + input->location.top = rect->top; + } + /* We've reached the WPF, we're done. */ if (entity->type == VSP1_ENTITY_WPF) break; @@ -363,6 +378,8 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe, rwpf->video.pipe_index = 0; } else if (e->type == VSP1_ENTITY_LIF) { pipe->lif = e; + } else if (e->type == VSP1_ENTITY_BRU) { + pipe->bru = e; } } @@ -392,6 +409,7 @@ error: pipe->num_video = 0; pipe->num_inputs = 0; pipe->output = NULL; + pipe->bru = NULL; pipe->lif = NULL; return ret; } @@ -430,6 +448,7 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe) pipe->num_video = 0; pipe->num_inputs = 0; pipe->output = NULL; + pipe->bru = NULL; pipe->lif = NULL; } @@ -461,7 +480,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) list_for_each_entry(entity, &pipe->entities, list_pipe) { if (entity->route) - vsp1_write(entity->vsp1, entity->route, + vsp1_write(entity->vsp1, entity->route->reg, VI6_DPR_NODE_UNUSED); v4l2_subdev_call(&entity->subdev, video, s_stream, 0); @@ -680,11 +699,12 @@ static void vsp1_entity_route_setup(struct vsp1_entity *source) { struct vsp1_entity *sink; - if (source->route == 0) + if (source->route->reg == 0) return; sink = container_of(source->sink, struct vsp1_entity, subdev.entity); - vsp1_write(source->vsp1, source->route, sink->id); + vsp1_write(source->vsp1, source->route->reg, + sink->route->inputs[source->sink_pad]); } static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index 53e4b3745940..c04d48fa2999 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -75,6 +75,7 @@ struct vsp1_pipeline { unsigned int num_inputs; struct vsp1_rwpf *inputs[VPS1_MAX_RPF]; struct vsp1_rwpf *output; + struct vsp1_entity *bru; struct vsp1_entity *lif; struct list_head entities; diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index 11a61c601da0..1294340dcb36 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -58,13 +58,21 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable) return 0; } - /* Sources */ + /* Sources. If the pipeline has a single input configure it as the + * master layer. Otherwise configure all inputs as sub-layers and + * select the virtual RPF as the master layer. + */ for (i = 0; i < pipe->num_inputs; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; - srcrpf |= VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index); + srcrpf |= pipe->num_inputs == 1 + ? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index) + : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } + if (pipe->num_inputs > 1) + srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST; + vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf); /* Destination stride. */ @@ -181,7 +189,6 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index) wpf->entity.type = VSP1_ENTITY_WPF; wpf->entity.index = index; - wpf->entity.id = VI6_DPR_NODE_WPF(index); ret = vsp1_entity_init(vsp1, &wpf->entity, 2); if (ret < 0) diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index 1b37cf8cd204..7310e32b5991 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -52,3 +52,13 @@ config MEMSTICK_REALTEK_PCI To compile this driver as a module, choose M here: the module will be called rtsx_pci_ms. + +config MEMSTICK_REALTEK_USB + tristate "Realtek USB Memstick Card Interface Driver" + depends on MFD_RTSX_USB + help + Say Y here to include driver code to support Memstick card interface + of Realtek RTS5129/39 series USB card reader + + To compile this driver as a module, choose M here: the module will + be called rts5139_ms. diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index af3459d7686e..491c9557441d 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o obj-$(CONFIG_MEMSTICK_R592) += r592.o obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o +obj-$(CONFIG_MEMSTICK_REALTEK_USB) += rtsx_usb_ms.o diff --git a/drivers/memstick/host/rtsx_usb_ms.c b/drivers/memstick/host/rtsx_usb_ms.c new file mode 100644 index 000000000000..a7282b7d4de8 --- /dev/null +++ b/drivers/memstick/host/rtsx_usb_ms.c @@ -0,0 +1,839 @@ +/* Realtek USB Memstick Card Interface driver + * + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: + * Roger Tseng <rogerable@realtek.com> + */ + +#include <linux/module.h> +#include <linux/highmem.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/workqueue.h> +#include <linux/memstick.h> +#include <linux/kthread.h> +#include <linux/mfd/rtsx_usb.h> +#include <linux/pm_runtime.h> +#include <linux/mutex.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <asm/unaligned.h> + +struct rtsx_usb_ms { + struct platform_device *pdev; + struct rtsx_ucr *ucr; + struct memstick_host *msh; + struct memstick_request *req; + + struct mutex host_mutex; + struct work_struct handle_req; + + struct task_struct *detect_ms; + struct completion detect_ms_exit; + + u8 ssc_depth; + unsigned int clock; + int power_mode; + unsigned char ifmode; + bool eject; +}; + +static inline struct device *ms_dev(struct rtsx_usb_ms *host) +{ + return &(host->pdev->dev); +} + +static inline void ms_clear_error(struct rtsx_usb_ms *host) +{ + struct rtsx_ucr *ucr = host->ucr; + rtsx_usb_ep0_write_register(ucr, CARD_STOP, + MS_STOP | MS_CLR_ERR, + MS_STOP | MS_CLR_ERR); + + rtsx_usb_clear_dma_err(ucr); + rtsx_usb_clear_fsm_err(ucr); +} + +#ifdef DEBUG + +static void ms_print_debug_regs(struct rtsx_usb_ms *host) +{ + struct rtsx_ucr *ucr = host->ucr; + u16 i; + u8 *ptr; + + /* Print MS host internal registers */ + rtsx_usb_init_cmd(ucr); + + /* MS_CFG to MS_INT_REG */ + for (i = 0xFD40; i <= 0xFD44; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); + + /* CARD_SHARE_MODE to CARD_GPIO */ + for (i = 0xFD51; i <= 0xFD56; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); + + /* CARD_PULL_CTLx */ + for (i = 0xFD60; i <= 0xFD65; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, i, 0, 0); + + /* CARD_DATA_SOURCE, CARD_SELECT, CARD_CLK_EN, CARD_PWR_CTL */ + rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_DATA_SOURCE, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_SELECT, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_CLK_EN, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_PWR_CTL, 0, 0); + + rtsx_usb_send_cmd(ucr, MODE_CR, 100); + rtsx_usb_get_rsp(ucr, 21, 100); + + ptr = ucr->rsp_buf; + for (i = 0xFD40; i <= 0xFD44; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD51; i <= 0xFD56; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD60; i <= 0xFD65; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_DATA_SOURCE, *(ptr++)); + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_SELECT, *(ptr++)); + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_CLK_EN, *(ptr++)); + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", CARD_PWR_CTL, *(ptr++)); +} + +#else + +static void ms_print_debug_regs(struct rtsx_usb_ms *host) +{ +} + +#endif + +static int ms_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int ms_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int ms_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int ms_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int ms_power_on(struct rtsx_usb_ms *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(ms_dev(host), "%s\n", __func__); + + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_MS); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, + MS_CLK_EN, MS_CLK_EN); + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err < 0) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + err = ms_pull_ctl_enable_lqfp48(ucr); + else + err = ms_pull_ctl_enable_qfn24(ucr); + if (err < 0) + return err; + + err = rtsx_usb_write_register(ucr, CARD_PWR_CTL, + POWER_MASK, PARTIAL_POWER_ON); + if (err) + return err; + + usleep_range(800, 1000); + + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK, POWER_ON); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, + MS_OUTPUT_EN, MS_OUTPUT_EN); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int ms_power_off(struct rtsx_usb_ms *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(ms_dev(host), "%s\n", __func__); + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err < 0) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + return ms_pull_ctl_disable_lqfp48(ucr); + + return ms_pull_ctl_disable_qfn24(ucr); +} + +static int ms_transfer_data(struct rtsx_usb_ms *host, unsigned char data_dir, + u8 tpc, u8 cfg, struct scatterlist *sg) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + unsigned int length = sg->length; + u16 sec_cnt = (u16)(length / 512); + u8 trans_mode, dma_dir, flag; + unsigned int pipe; + struct memstick_dev *card = host->msh->card; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n", + __func__, tpc, (data_dir == READ) ? "READ" : "WRITE", + length); + + if (data_dir == READ) { + flag = MODE_CDIR; + dma_dir = DMA_DIR_FROM_CARD; + if (card->id.type != MEMSTICK_TYPE_PRO) + trans_mode = MS_TM_NORMAL_READ; + else + trans_mode = MS_TM_AUTO_READ; + pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN); + } else { + flag = MODE_CDOR; + dma_dir = DMA_DIR_TO_CARD; + if (card->id.type != MEMSTICK_TYPE_PRO) + trans_mode = MS_TM_NORMAL_WRITE; + else + trans_mode = MS_TM_AUTO_WRITE; + pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT); + } + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + if (card->id.type == MEMSTICK_TYPE_PRO) { + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_H, + 0xFF, (u8)(sec_cnt >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_SECTOR_CNT_L, + 0xFF, (u8)sec_cnt); + } + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3, + 0xFF, (u8)(length >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2, + 0xFF, (u8)(length >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1, + 0xFF, (u8)(length >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, 0xFF, + (u8)length); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, + 0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | trans_mode); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + + err = rtsx_usb_send_cmd(ucr, flag | STAGE_MS_STATUS, 100); + if (err) + return err; + + err = rtsx_usb_transfer_data(ucr, pipe, sg, length, + 1, NULL, 10000); + if (err) + goto err_out; + + err = rtsx_usb_get_rsp(ucr, 3, 15000); + if (err) + goto err_out; + + if (ucr->rsp_buf[0] & MS_TRANSFER_ERR || + ucr->rsp_buf[1] & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { + err = -EIO; + goto err_out; + } + return 0; +err_out: + ms_clear_error(host); + return err; +} + +static int ms_write_bytes(struct rtsx_usb_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_ucr *ucr = host->ucr; + int err, i; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + rtsx_usb_init_cmd(ucr); + + for (i = 0; i < cnt; i++) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, data[i]); + + if (cnt % 2) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, 0xFF); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); + if (err) + return err; + + err = rtsx_usb_get_rsp(ucr, 2, 5000); + if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) { + u8 val; + + rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + if (int_reg) + *int_reg = ucr->rsp_buf[1] & 0x0F; + + return 0; +} + +static int ms_read_bytes(struct rtsx_usb_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_ucr *ucr = host->ucr; + int err, i; + u8 *ptr; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + for (i = 0; i < cnt - 1; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); + if (cnt % 2) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0); + else + rtsx_usb_add_cmd(ucr, READ_REG_CMD, + PPBUF_BASE2 + cnt - 1, 0, 0); + + rtsx_usb_add_cmd(ucr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); + if (err) + return err; + + err = rtsx_usb_get_rsp(ucr, cnt + 2, 5000); + if (err || (ucr->rsp_buf[0] & MS_TRANSFER_ERR)) { + u8 val; + + rtsx_usb_ep0_read_register(ucr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg && (host->ifmode != MEMSTICK_SERIAL)) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + ptr = ucr->rsp_buf + 1; + for (i = 0; i < cnt; i++) + data[i] = *ptr++; + + + if (int_reg && (host->ifmode != MEMSTICK_SERIAL)) + *int_reg = *ptr & 0x0F; + + return 0; +} + +static int rtsx_usb_ms_issue_cmd(struct rtsx_usb_ms *host) +{ + struct memstick_request *req = host->req; + int err = 0; + u8 cfg = 0, int_reg; + + dev_dbg(ms_dev(host), "%s\n", __func__); + + if (req->need_card_int) { + if (host->ifmode != MEMSTICK_SERIAL) + cfg = WAIT_INT; + } + + if (req->long_data) { + err = ms_transfer_data(host, req->data_dir, + req->tpc, cfg, &(req->sg)); + } else { + if (req->data_dir == READ) + err = ms_read_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + else + err = ms_write_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + } + if (err < 0) + return err; + + if (req->need_card_int) { + if (host->ifmode == MEMSTICK_SERIAL) { + err = ms_read_bytes(host, MS_TPC_GET_INT, + NO_WAIT_INT, 1, &req->int_reg, NULL); + if (err < 0) + return err; + } else { + + if (int_reg & MS_INT_CMDNK) + req->int_reg |= MEMSTICK_INT_CMDNAK; + if (int_reg & MS_INT_BREQ) + req->int_reg |= MEMSTICK_INT_BREQ; + if (int_reg & MS_INT_ERR) + req->int_reg |= MEMSTICK_INT_ERR; + if (int_reg & MS_INT_CED) + req->int_reg |= MEMSTICK_INT_CED; + } + dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", req->int_reg); + } + + return 0; +} + +static void rtsx_usb_ms_handle_req(struct work_struct *work) +{ + struct rtsx_usb_ms *host = container_of(work, + struct rtsx_usb_ms, handle_req); + struct rtsx_ucr *ucr = host->ucr; + struct memstick_host *msh = host->msh; + int rc; + + if (!host->req) { + do { + rc = memstick_next_req(msh, &host->req); + dev_dbg(ms_dev(host), "next req %d\n", rc); + + if (!rc) { + mutex_lock(&ucr->dev_mutex); + + if (rtsx_usb_card_exclusive_check(ucr, + RTSX_USB_MS_CARD)) + host->req->error = -EIO; + else + host->req->error = + rtsx_usb_ms_issue_cmd(host); + + mutex_unlock(&ucr->dev_mutex); + + dev_dbg(ms_dev(host), "req result %d\n", + host->req->error); + } + } while (!rc); + } + +} + +static void rtsx_usb_ms_request(struct memstick_host *msh) +{ + struct rtsx_usb_ms *host = memstick_priv(msh); + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + if (!host->eject) + schedule_work(&host->handle_req); +} + +static int rtsx_usb_ms_set_param(struct memstick_host *msh, + enum memstick_param param, int value) +{ + struct rtsx_usb_ms *host = memstick_priv(msh); + struct rtsx_ucr *ucr = host->ucr; + unsigned int clock = 0; + u8 ssc_depth = 0; + int err; + + dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", + __func__, param, value); + + mutex_lock(&ucr->dev_mutex); + + err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_MS_CARD); + if (err) + goto out; + + switch (param) { + case MEMSTICK_POWER: + if (value == host->power_mode) + break; + + if (value == MEMSTICK_POWER_ON) { + pm_runtime_get_sync(ms_dev(host)); + err = ms_power_on(host); + } else if (value == MEMSTICK_POWER_OFF) { + err = ms_power_off(host); + if (host->msh->card) + pm_runtime_put_noidle(ms_dev(host)); + else + pm_runtime_put(ms_dev(host)); + } else + err = -EINVAL; + if (!err) + host->power_mode = value; + break; + + case MEMSTICK_INTERFACE: + if (value == MEMSTICK_SERIAL) { + clock = 19000000; + ssc_depth = SSC_DEPTH_512K; + err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A, + MS_BUS_WIDTH_1 | PUSH_TIME_DEFAULT); + if (err < 0) + break; + } else if (value == MEMSTICK_PAR4) { + clock = 39000000; + ssc_depth = SSC_DEPTH_1M; + + err = rtsx_usb_write_register(ucr, MS_CFG, 0x5A, + MS_BUS_WIDTH_4 | PUSH_TIME_ODD | + MS_NO_CHECK_INT); + if (err < 0) + break; + } else { + err = -EINVAL; + break; + } + + err = rtsx_usb_switch_clock(ucr, clock, + ssc_depth, false, true, false); + if (err < 0) { + dev_dbg(ms_dev(host), "switch clock failed\n"); + break; + } + + host->ssc_depth = ssc_depth; + host->clock = clock; + host->ifmode = value; + break; + default: + err = -EINVAL; + break; + } +out: + mutex_unlock(&ucr->dev_mutex); + + /* power-on delay */ + if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) + usleep_range(10000, 12000); + + dev_dbg(ms_dev(host), "%s: return = %d\n", __func__, err); + return err; +} + +#ifdef CONFIG_PM_SLEEP +static int rtsx_usb_ms_suspend(struct device *dev) +{ + struct rtsx_usb_ms *host = dev_get_drvdata(dev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_suspend_host(msh); + return 0; +} + +static int rtsx_usb_ms_resume(struct device *dev) +{ + struct rtsx_usb_ms *host = dev_get_drvdata(dev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_resume_host(msh); + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +/* + * Thread function of ms card slot detection. The thread starts right after + * successful host addition. It stops while the driver removal function sets + * host->eject true. + */ +static int rtsx_usb_detect_ms_card(void *__host) +{ + struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host; + struct rtsx_ucr *ucr = host->ucr; + u8 val = 0; + int err; + + for (;;) { + mutex_lock(&ucr->dev_mutex); + + /* Check pending MS card changes */ + err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val); + if (err) { + mutex_unlock(&ucr->dev_mutex); + goto poll_again; + } + + /* Clear the pending */ + rtsx_usb_write_register(ucr, CARD_INT_PEND, + XD_INT | MS_INT | SD_INT, + XD_INT | MS_INT | SD_INT); + + mutex_unlock(&ucr->dev_mutex); + + if (val & MS_INT) { + dev_dbg(ms_dev(host), "MS slot change detected\n"); + memstick_detect_change(host->msh); + } + +poll_again: + if (host->eject) + break; + + msleep(1000); + } + + complete(&host->detect_ms_exit); + return 0; +} + +static int rtsx_usb_ms_drv_probe(struct platform_device *pdev) +{ + struct memstick_host *msh; + struct rtsx_usb_ms *host; + struct rtsx_ucr *ucr; + int err; + + ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); + if (!ucr) + return -ENXIO; + + dev_dbg(&(pdev->dev), + "Realtek USB Memstick controller found\n"); + + msh = memstick_alloc_host(sizeof(*host), &pdev->dev); + if (!msh) + return -ENOMEM; + + host = memstick_priv(msh); + host->ucr = ucr; + host->msh = msh; + host->pdev = pdev; + host->power_mode = MEMSTICK_POWER_OFF; + platform_set_drvdata(pdev, host); + + mutex_init(&host->host_mutex); + INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req); + + init_completion(&host->detect_ms_exit); + host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host, + "rtsx_usb_ms_%d", pdev->id); + if (IS_ERR(host->detect_ms)) { + dev_dbg(&(pdev->dev), + "Unable to create polling thread.\n"); + err = PTR_ERR(host->detect_ms); + goto err_out; + } + + msh->request = rtsx_usb_ms_request; + msh->set_param = rtsx_usb_ms_set_param; + msh->caps = MEMSTICK_CAP_PAR4; + + pm_runtime_enable(&pdev->dev); + err = memstick_add_host(msh); + if (err) + goto err_out; + + wake_up_process(host->detect_ms); + return 0; +err_out: + memstick_free_host(msh); + return err; +} + +static int rtsx_usb_ms_drv_remove(struct platform_device *pdev) +{ + struct rtsx_usb_ms *host = platform_get_drvdata(pdev); + struct memstick_host *msh; + int err; + + msh = host->msh; + host->eject = true; + cancel_work_sync(&host->handle_req); + + mutex_lock(&host->host_mutex); + if (host->req) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + dev_name(&msh->dev)); + host->req->error = -ENOMEDIUM; + do { + err = memstick_next_req(msh, &host->req); + if (!err) + host->req->error = -ENOMEDIUM; + } while (!err); + } + mutex_unlock(&host->host_mutex); + + wait_for_completion(&host->detect_ms_exit); + memstick_remove_host(msh); + memstick_free_host(msh); + + /* Balance possible unbalanced usage count + * e.g. unconditional module removal + */ + if (pm_runtime_active(ms_dev(host))) + pm_runtime_put(ms_dev(host)); + + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek USB Memstick controller has been removed\n"); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops, + rtsx_usb_ms_suspend, rtsx_usb_ms_resume); + +static struct platform_device_id rtsx_usb_ms_ids[] = { + { + .name = "rtsx_usb_ms", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_usb_ms_ids); + +static struct platform_driver rtsx_usb_ms_driver = { + .probe = rtsx_usb_ms_drv_probe, + .remove = rtsx_usb_ms_drv_remove, + .id_table = rtsx_usb_ms_ids, + .driver = { + .owner = THIS_MODULE, + .name = "rtsx_usb_ms", + .pm = &rtsx_usb_ms_pm_ops, + }, +}; +module_platform_driver(rtsx_usb_ms_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>"); +MODULE_DESCRIPTION("Realtek USB Memstick Card Host Driver"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6deb8a11c12f..ee8204cc31e9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -67,6 +67,18 @@ config MFD_BCM590XX help Support for the BCM590xx PMUs from Broadcom +config MFD_AXP20X + bool "X-Powers AXP20X" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C=y + help + If you say Y here you get support for the X-Powers AXP202 and AXP209. + This driver include only the core APIs. You have to select individual + components like regulators or the PEK (Power Enable Key) under the + corresponding menus. + config MFD_CROS_EC tristate "ChromeOS Embedded Controller" select MFD_CORE @@ -250,6 +262,16 @@ config MFD_INTEL_MSIC Passage) chip. This chip embeds audio, battery, GPIO, etc. devices used in Intel Medfield platforms. +config MFD_IPAQ_MICRO + bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" + depends on SA1100_H3100 || SA1100_H3600 + select MFD_CORE + help + Select this to get support for the Microcontroller found in + the Compaq iPAQ handheld computers. This is an Atmel + AT90LS8535 microcontroller flashed with a special iPAQ + firmware using the custom protocol implemented in this driver. + config MFD_JANZ_CMODIO tristate "Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE @@ -675,6 +697,7 @@ config MFD_DB8500_PRCMU config MFD_STMPE bool "STMicroelectronics STMPE" depends on (I2C=y || SPI_MASTER=y) + depends on OF select MFD_CORE help Support for the STMPE family of I/O Expanders from @@ -719,6 +742,14 @@ config MFD_STA2X11 select MFD_CORE select REGMAP_MMIO +config MFD_SUN6I_PRCM + bool "Allwinner A31 PRCM controller" + depends on ARCH_SUNXI + select MFD_CORE + help + Support for the PRCM (Power/Reset/Clock Management) unit available + in A31 SoC. + config MFD_SYSCON bool "System Controller Register R/W Based on Regmap" select REGMAP_MMIO diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index cec3487b539e..8afedba535c7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o +obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o @@ -102,6 +103,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o obj-$(CONFIG_PMIC_DA9052) += da9052-core.o obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o +obj-$(CONFIG_MFD_AXP20X) += axp20x.o obj-$(CONFIG_MFD_LP3943) += lp3943.o obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o @@ -166,3 +168,4 @@ obj-$(CONFIG_MFD_RETU) += retu-mfd.o obj-$(CONFIG_MFD_AS3711) += as3711.o obj-$(CONFIG_MFD_AS3722) += as3722.o obj-$(CONFIG_MFD_STW481X) += stw481x.o +obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index f3a15aa54d7b..fe418995108c 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -151,22 +151,6 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq) } EXPORT_SYMBOL(abx500_startup_irq_enabled); -void abx500_dump_all_banks(void) -{ - struct abx500_ops *ops; - struct device dummy_child = {NULL}; - struct abx500_device_entry *dev_entry; - - list_for_each_entry(dev_entry, &abx500_list, list) { - dummy_child.parent = dev_entry->dev; - ops = &dev_entry->ops; - - if ((ops != NULL) && (ops->dump_all_banks != NULL)) - ops->dump_all_banks(&dummy_child); - } -} -EXPORT_SYMBOL(abx500_dump_all_banks); - MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>"); MODULE_DESCRIPTION("ABX500 core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 07e6e27be23c..cfc191abae4a 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -583,6 +583,7 @@ static const char *wm5102_supplies[] = { "CPVDD", "SPKVDDL", "SPKVDDR", + "MICVDD", }; static const struct mfd_cell wm5102_devs[] = { diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 88758ab9402b..17102f589100 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -285,7 +285,7 @@ int arizona_irq_init(struct arizona *arizona) IRQF_ONESHOT, -1, irq, &arizona->irq_chip); if (ret != 0) { - dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret); + dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret); goto err_aod; } diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index ec684fcedb42..d9706ede8d39 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -114,7 +114,7 @@ static const struct regmap_config as3711_regmap_config = { }; #ifdef CONFIG_OF -static struct of_device_id as3711_of_match[] = { +static const struct of_device_id as3711_of_match[] = { {.compatible = "ams,as3711",}, {} }; diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c new file mode 100644 index 000000000000..dee653989e3a --- /dev/null +++ b/drivers/mfd/axp20x.c @@ -0,0 +1,258 @@ +/* + * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209 + * + * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC + * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature + * as well as 4 configurable GPIOs. + * + * Author: Carlo Caione <carlo@caione.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/regulator/consumer.h> +#include <linux/mfd/axp20x.h> +#include <linux/mfd/core.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> + +#define AXP20X_OFF 0x80 + +static const struct regmap_range axp20x_writeable_ranges[] = { + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), + regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES), +}; + +static const struct regmap_range axp20x_volatile_ranges[] = { + regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), +}; + +static const struct regmap_access_table axp20x_writeable_table = { + .yes_ranges = axp20x_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges), +}; + +static const struct regmap_access_table axp20x_volatile_table = { + .yes_ranges = axp20x_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), +}; + +static struct resource axp20x_pek_resources[] = { + { + .name = "PEK_DBR", + .start = AXP20X_IRQ_PEK_RIS_EDGE, + .end = AXP20X_IRQ_PEK_RIS_EDGE, + .flags = IORESOURCE_IRQ, + }, { + .name = "PEK_DBF", + .start = AXP20X_IRQ_PEK_FAL_EDGE, + .end = AXP20X_IRQ_PEK_FAL_EDGE, + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct regmap_config axp20x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp20x_writeable_table, + .volatile_table = &axp20x_volatile_table, + .max_register = AXP20X_FG_RES, + .cache_type = REGCACHE_RBTREE, +}; + +#define AXP20X_IRQ(_irq, _off, _mask) \ + [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } + +static const struct regmap_irq axp20x_regmap_irqs[] = { + AXP20X_IRQ(ACIN_OVER_V, 0, 7), + AXP20X_IRQ(ACIN_PLUGIN, 0, 6), + AXP20X_IRQ(ACIN_REMOVAL, 0, 5), + AXP20X_IRQ(VBUS_OVER_V, 0, 4), + AXP20X_IRQ(VBUS_PLUGIN, 0, 3), + AXP20X_IRQ(VBUS_REMOVAL, 0, 2), + AXP20X_IRQ(VBUS_V_LOW, 0, 1), + AXP20X_IRQ(BATT_PLUGIN, 1, 7), + AXP20X_IRQ(BATT_REMOVAL, 1, 6), + AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5), + AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4), + AXP20X_IRQ(CHARG, 1, 3), + AXP20X_IRQ(CHARG_DONE, 1, 2), + AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1), + AXP20X_IRQ(BATT_TEMP_LOW, 1, 0), + AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7), + AXP20X_IRQ(CHARG_I_LOW, 2, 6), + AXP20X_IRQ(DCDC1_V_LONG, 2, 5), + AXP20X_IRQ(DCDC2_V_LONG, 2, 4), + AXP20X_IRQ(DCDC3_V_LONG, 2, 3), + AXP20X_IRQ(PEK_SHORT, 2, 1), + AXP20X_IRQ(PEK_LONG, 2, 0), + AXP20X_IRQ(N_OE_PWR_ON, 3, 7), + AXP20X_IRQ(N_OE_PWR_OFF, 3, 6), + AXP20X_IRQ(VBUS_VALID, 3, 5), + AXP20X_IRQ(VBUS_NOT_VALID, 3, 4), + AXP20X_IRQ(VBUS_SESS_VALID, 3, 3), + AXP20X_IRQ(VBUS_SESS_END, 3, 2), + AXP20X_IRQ(LOW_PWR_LVL1, 3, 1), + AXP20X_IRQ(LOW_PWR_LVL2, 3, 0), + AXP20X_IRQ(TIMER, 4, 7), + AXP20X_IRQ(PEK_RIS_EDGE, 4, 6), + AXP20X_IRQ(PEK_FAL_EDGE, 4, 5), + AXP20X_IRQ(GPIO3_INPUT, 4, 3), + AXP20X_IRQ(GPIO2_INPUT, 4, 2), + AXP20X_IRQ(GPIO1_INPUT, 4, 1), + AXP20X_IRQ(GPIO0_INPUT, 4, 0), +}; + +static const struct of_device_id axp20x_of_match[] = { + { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, + { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, + { }, +}; +MODULE_DEVICE_TABLE(of, axp20x_of_match); + +/* + * This is useless for OF-enabled devices, but it is needed by I2C subsystem + */ +static const struct i2c_device_id axp20x_i2c_id[] = { + { }, +}; +MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); + +static const struct regmap_irq_chip axp20x_regmap_irq_chip = { + .name = "axp20x_irq_chip", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, + .mask_base = AXP20X_IRQ1_EN, + .num_regs = 5, + .irqs = axp20x_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), + .mask_invert = true, + .init_ack_masked = true, +}; + +static const char * const axp20x_supplies[] = { + "acin", + "vin2", + "vin3", + "ldo24in", + "ldo3in", + "ldo5in", +}; + +static struct mfd_cell axp20x_cells[] = { + { + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp20x_pek_resources), + .resources = axp20x_pek_resources, + }, { + .name = "axp20x-regulator", + .parent_supplies = axp20x_supplies, + .num_parent_supplies = ARRAY_SIZE(axp20x_supplies), + }, +}; + +static struct axp20x_dev *axp20x_pm_power_off; +static void axp20x_power_off(void) +{ + regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, + AXP20X_OFF); +} + +static int axp20x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct axp20x_dev *axp20x; + const struct of_device_id *of_id; + int ret; + + axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); + if (!axp20x) + return -ENOMEM; + + of_id = of_match_device(axp20x_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "Unable to setup AXP20X data\n"); + return -ENODEV; + } + axp20x->variant = (long) of_id->data; + + axp20x->i2c_client = i2c; + axp20x->dev = &i2c->dev; + dev_set_drvdata(axp20x->dev, axp20x); + + axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config); + if (IS_ERR(axp20x->regmap)) { + ret = PTR_ERR(axp20x->regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + + ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &axp20x_regmap_irq_chip, + &axp20x->regmap_irqc); + if (ret) { + dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); + return ret; + } + + ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells, + ARRAY_SIZE(axp20x_cells), NULL, 0, NULL); + + if (ret) { + dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); + regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc); + return ret; + } + + if (!pm_power_off) { + axp20x_pm_power_off = axp20x; + pm_power_off = axp20x_power_off; + } + + dev_info(&i2c->dev, "AXP20X driver loaded\n"); + + return 0; +} + +static int axp20x_i2c_remove(struct i2c_client *i2c) +{ + struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); + + if (axp20x == axp20x_pm_power_off) { + axp20x_pm_power_off = NULL; + pm_power_off = NULL; + } + + mfd_remove_devices(axp20x->dev); + regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc); + + return 0; +} + +static struct i2c_driver axp20x_i2c_driver = { + .driver = { + .name = "axp20x", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(axp20x_of_match), + }, + .probe = axp20x_i2c_probe, + .remove = axp20x_i2c_remove, + .id_table = axp20x_i2c_id, +}; + +module_i2c_driver(axp20x_i2c_driver); + +MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X"); +MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 43cba1a1973c..e334de000e8c 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -96,6 +96,12 @@ err: return ret; } +static int bcm590xx_i2c_remove(struct i2c_client *i2c) +{ + mfd_remove_devices(&i2c->dev); + return 0; +} + static const struct of_device_id bcm590xx_of_match[] = { { .compatible = "brcm,bcm59056" }, { } @@ -115,6 +121,7 @@ static struct i2c_driver bcm590xx_i2c_driver = { .of_match_table = of_match_ptr(bcm590xx_of_match), }, .probe = bcm590xx_i2c_probe, + .remove = bcm590xx_i2c_remove, .id_table = bcm590xx_i2c_id, }; module_i2c_driver(bcm590xx_i2c_driver); @@ -122,4 +129,4 @@ module_i2c_driver(bcm590xx_i2c_driver); MODULE_AUTHOR("Matt Porter <mporter@linaro.org>"); MODULE_DESCRIPTION("BCM590xx multi-function driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bcm590xx"); +MODULE_ALIAS("i2c:bcm590xx"); diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 783fe2e73e1e..38fe9bf0d169 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -30,7 +30,7 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, uint8_t *out; int csum, i; - BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE); + BUG_ON(msg->out_len > EC_PROTO2_MAX_PARAM_SIZE); out = ec_dev->dout; out[0] = EC_CMD_VERSION0 + msg->version; out[1] = msg->cmd; @@ -90,6 +90,11 @@ static const struct mfd_cell cros_devs[] = { .id = 1, .of_compatible = "google,cros-ec-keyb", }, + { + .name = "cros-ec-i2c-tunnel", + .id = 2, + .of_compatible = "google,cros-ec-i2c-tunnel", + }, }; int cros_ec_register(struct cros_ec_device *ec_dev) @@ -184,3 +189,6 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) EXPORT_SYMBOL(cros_ec_resume); #endif + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC core driver"); diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 84af8d7a4295..0b8d32829166 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -39,14 +39,22 @@ #define EC_MSG_PREAMBLE_COUNT 32 /* - * We must get a response from the EC in 5ms. This is a very long - * time, but the flash write command can take 2-3ms. The EC command - * processing is currently not very fast (about 500us). We could - * look at speeding this up and making the flash write command a - * 'slow' command, requiring a GET_STATUS wait loop, like flash - * erase. - */ -#define EC_MSG_DEADLINE_MS 5 + * Allow for a long time for the EC to respond. We support i2c + * tunneling and support fairly long messages for the tunnel (249 + * bytes long at the moment). If we're talking to a 100 kHz device + * on the other end and need to transfer ~256 bytes, then we need: + * 10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms + * + * We'll wait 4 times that to handle clock stretching and other + * paranoia. + * + * It's pretty unlikely that we'll really see a 249 byte tunnel in + * anything other than testing. If this was more common we might + * consider having slow commands like this require a GET_STATUS + * wait loop. The 'flash write' command would be another candidate + * for this, clocking in at 2-3ms. + */ +#define EC_MSG_DEADLINE_MS 100 /* * Time between raising the SPI chip select (for the end of a @@ -65,11 +73,13 @@ * if no record * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that * is sent when we want to turn off CS at the end of a transaction. + * @lock: mutex to ensure only one user of cros_ec_command_spi_xfer at a time */ struct cros_ec_spi { struct spi_device *spi; s64 last_transfer_ns; unsigned int end_of_msg_delay; + struct mutex lock; }; static void debug_packet(struct device *dev, const char *name, u8 *ptr, @@ -111,7 +121,9 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, /* Receive data until we see the header byte */ deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); - do { + while (true) { + unsigned long start_jiffies = jiffies; + memset(&trans, 0, sizeof(trans)); trans.cs_change = 1; trans.rx_buf = ptr = ec_dev->din; @@ -132,12 +144,19 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, break; } } + if (ptr != end) + break; - if (time_after(jiffies, deadline)) { + /* + * Use the time at the start of the loop as a timeout. This + * gives us one last shot at getting the transfer and is useful + * in case we got context switched out for a while. + */ + if (time_after(start_jiffies, deadline)) { dev_warn(ec_dev->dev, "EC failed to respond in time\n"); return -ETIMEDOUT; } - } while (ptr == end); + } /* * ptr now points to the header byte. Copy any valid data to the @@ -208,6 +227,13 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, int ret = 0, final_ret; struct timespec ts; + /* + * We have the shared ec_dev buffer plus we do lots of separate spi_sync + * calls, so we need to make sure only one person is using this at a + * time. + */ + mutex_lock(&ec_spi->lock); + len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); @@ -219,7 +245,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, ktime_get_ts(&ts); delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; if (delay < EC_SPI_RECOVERY_TIME_NS) - ndelay(delay); + ndelay(EC_SPI_RECOVERY_TIME_NS - delay); } /* Transmit phase - send our message */ @@ -260,7 +286,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, ret = final_ret; if (ret < 0) { dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - return ret; + goto exit; } /* check response error code */ @@ -269,14 +295,16 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", ec_msg->cmd, ptr[0]); debug_packet(ec_dev->dev, "in_err", ptr, len); - return -EINVAL; + ret = -EINVAL; + goto exit; } len = ptr[1]; sum = ptr[0] + ptr[1]; if (len > ec_msg->in_len) { dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", len, ec_msg->in_len); - return -ENOSPC; + ret = -ENOSPC; + goto exit; } /* copy response packet payload and compute checksum */ @@ -293,10 +321,14 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, dev_err(ec_dev->dev, "bad packet checksum, expected %02x, got %02x\n", sum, ptr[len + 2]); - return -EBADMSG; + ret = -EBADMSG; + goto exit; } - return 0; + ret = 0; +exit: + mutex_unlock(&ec_spi->lock); + return ret; } static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) @@ -327,6 +359,7 @@ static int cros_ec_spi_probe(struct spi_device *spi) if (ec_spi == NULL) return -ENOMEM; ec_spi->spi = spi; + mutex_init(&ec_spi->lock); ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); if (!ec_dev) return -ENOMEM; diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index b11fdd63eecd..193cf168ba84 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2300,9 +2300,6 @@ int prcmu_ac_wake_req(void) if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, msecs_to_jiffies(5000))) { -#if defined(CONFIG_DBX500_PRCMU_DEBUG) - db8500_prcmu_debug_dump(__func__, true, true); -#endif pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n", __func__); ret = -EFAULT; @@ -3112,7 +3109,7 @@ static int db8500_prcmu_register_ab8500(struct device *parent, { struct device_node *np; struct resource ab8500_resource; - struct mfd_cell ab8500_cell = { + const struct mfd_cell ab8500_cell = { .name = "ab8500-core", .of_compatible = "stericsson,ab8500", .id = AB8500_VERSION_AB8500, diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c new file mode 100644 index 000000000000..7e50fe0118e3 --- /dev/null +++ b/drivers/mfd/ipaq-micro.c @@ -0,0 +1,482 @@ +/* + * Compaq iPAQ h3xxx Atmel microcontroller companion support + * + * This is an Atmel AT90LS8535 with a special flashed-in firmware that + * implements the special protocol used by this driver. + * + * based on previous kernel 2.4 version by Andrew Christian + * Author : Alessandro Gardich <gremlin@gremlin.it> + * Author : Dmitry Artamonow <mad_soft@inbox.ru> + * Author : Linus Walleij <linus.walleij@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pm.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/mfd/core.h> +#include <linux/mfd/ipaq-micro.h> +#include <linux/string.h> +#include <linux/random.h> +#include <linux/slab.h> +#include <linux/list.h> + +#include <mach/hardware.h> + +static void ipaq_micro_trigger_tx(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + struct ipaq_micro_msg *msg = micro->msg; + int i, bp; + u8 checksum; + u32 val; + + bp = 0; + tx->buf[bp++] = CHAR_SOF; + + checksum = ((msg->id & 0x0f) << 4) | (msg->tx_len & 0x0f); + tx->buf[bp++] = checksum; + + for (i = 0; i < msg->tx_len; i++) { + tx->buf[bp++] = msg->tx_data[i]; + checksum += msg->tx_data[i]; + } + + tx->buf[bp++] = checksum; + tx->len = bp; + tx->index = 0; + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, + tx->buf, tx->len, true); + + /* Enable interrupt */ + val = readl(micro->base + UTCR3); + val |= UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +int ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg) +{ + unsigned long flags; + + dev_dbg(micro->dev, "TX msg: %02x, %d bytes\n", msg->id, msg->tx_len); + + spin_lock_irqsave(µ->lock, flags); + if (micro->msg) { + list_add_tail(&msg->node, µ->queue); + spin_unlock_irqrestore(µ->lock, flags); + return 0; + } + micro->msg = msg; + ipaq_micro_trigger_tx(micro); + spin_unlock_irqrestore(µ->lock, flags); + return 0; +} +EXPORT_SYMBOL(ipaq_micro_tx_msg); + +static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data) +{ + int i; + + dev_dbg(micro->dev, "RX msg: %02x, %d bytes\n", id, len); + + spin_lock(µ->lock); + switch (id) { + case MSG_VERSION: + case MSG_EEPROM_READ: + case MSG_EEPROM_WRITE: + case MSG_BACKLIGHT: + case MSG_NOTIFY_LED: + case MSG_THERMAL_SENSOR: + case MSG_BATTERY: + /* Handle synchronous messages */ + if (micro->msg && micro->msg->id == id) { + struct ipaq_micro_msg *msg = micro->msg; + + memcpy(msg->rx_data, data, len); + msg->rx_len = len; + complete(µ->msg->ack); + if (!list_empty(µ->queue)) { + micro->msg = list_entry(micro->queue.next, + struct ipaq_micro_msg, + node); + list_del_init(µ->msg->node); + ipaq_micro_trigger_tx(micro); + } else + micro->msg = NULL; + dev_dbg(micro->dev, "OK RX message 0x%02x\n", id); + } else { + dev_err(micro->dev, + "out of band RX message 0x%02x\n", id); + if(!micro->msg) + dev_info(micro->dev, "no message queued\n"); + else + dev_info(micro->dev, "expected message %02x\n", + micro->msg->id); + } + break; + case MSG_KEYBOARD: + if (micro->key) + micro->key(micro->key_data, len, data); + else + dev_dbg(micro->dev, "key message ignored, no handle \n"); + break; + case MSG_TOUCHSCREEN: + if (micro->ts) + micro->ts(micro->ts_data, len, data); + else + dev_dbg(micro->dev, "touchscreen message ignored, no handle \n"); + break; + default: + dev_err(micro->dev, + "unknown msg %d [%d] ", id, len); + for (i = 0; i < len; ++i) + pr_cont("0x%02x ", data[i]); + pr_cont("\n"); + } + spin_unlock(µ->lock); +} + +static void micro_process_char(struct ipaq_micro *micro, u8 ch) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + + switch (rx->state) { + case STATE_SOF: /* Looking for SOF */ + if (ch == CHAR_SOF) + rx->state = STATE_ID; /* Next byte is the id and len */ + break; + case STATE_ID: /* Looking for id and len byte */ + rx->id = (ch & 0xf0) >> 4 ; + rx->len = (ch & 0x0f); + rx->index = 0; + rx->chksum = ch; + rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM; + break; + case STATE_DATA: /* Looking for 'len' data bytes */ + rx->chksum += ch; + rx->buf[rx->index] = ch; + if (++rx->index == rx->len) + rx->state = STATE_CHKSUM; + break; + case STATE_CHKSUM: /* Looking for the checksum */ + if (ch == rx->chksum) + micro_rx_msg(micro, rx->id, rx->len, rx->buf); + rx->state = STATE_SOF; + break; + } +} + +static void micro_rx_chars(struct ipaq_micro *micro) +{ + u32 status, ch; + + while ((status = readl(micro->base + UTSR1)) & UTSR1_RNE) { + ch = readl(micro->base + UTDR); + if (status & UTSR1_PRE) + dev_err(micro->dev, "rx: parity error\n"); + else if (status & UTSR1_FRE) + dev_err(micro->dev, "rx: framing error\n"); + else if (status & UTSR1_ROR) + dev_err(micro->dev, "rx: overrun error\n"); + micro_process_char(micro, ch); + } +} + +static void ipaq_micro_get_version(struct ipaq_micro *micro) +{ + struct ipaq_micro_msg msg = { + .id = MSG_VERSION, + }; + + ipaq_micro_tx_msg_sync(micro, &msg); + if (msg.rx_len == 4) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + } else if (msg.rx_len == 9) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + /* Bytes 4-7 are "pack", byte 8 is "boot type" */ + } else { + dev_err(micro->dev, + "illegal version message %d bytes\n", msg.rx_len); + } +} + +static void ipaq_micro_eeprom_read(struct ipaq_micro *micro, + u8 address, u8 len, u8 *data) +{ + struct ipaq_micro_msg msg = { + .id = MSG_EEPROM_READ, + }; + u8 i; + + for (i = 0; i < len; i++) { + msg.tx_data[0] = address + i; + msg.tx_data[1] = 1; + msg.tx_len = 2; + ipaq_micro_tx_msg_sync(micro, &msg); + memcpy(data + (i * 2), msg.rx_data, 2); + } +} + +static char *ipaq_micro_str(u8 *wchar, u8 len) +{ + char retstr[256]; + u8 i; + + for (i = 0; i < len / 2; i++) + retstr[i] = wchar[i * 2]; + return kstrdup(retstr, GFP_KERNEL); +} + +static u16 ipaq_micro_to_u16(u8 *data) +{ + return data[1] << 8 | data[0]; +} + +static void ipaq_micro_eeprom_dump(struct ipaq_micro *micro) +{ + u8 dump[256]; + char *str; + + ipaq_micro_eeprom_read(micro, 0, 128, dump); + str = ipaq_micro_str(dump, 10); + if (str) { + dev_info(micro->dev, "HM version %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+10, 40); + if (str) { + dev_info(micro->dev, "serial number: %s\n", str); + /* Feed the random pool with this */ + add_device_randomness(str, strlen(str)); + kfree(str); + } + str = ipaq_micro_str(dump+50, 20); + if (str) { + dev_info(micro->dev, "module ID: %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+70, 10); + if (str) { + dev_info(micro->dev, "product revision: %s\n", str); + kfree(str); + } + dev_info(micro->dev, "product ID: %u\n", ipaq_micro_to_u16(dump+80)); + dev_info(micro->dev, "frame rate: %u fps\n", + ipaq_micro_to_u16(dump+82)); + dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84)); + dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86)); + dev_info(micro->dev, "color display: %s\n", + ipaq_micro_to_u16(dump+88) ? "yes" : "no"); + dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90)); + dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92)); + dev_info(micro->dev, "screen: %u x %u\n", + ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96)); + print_hex_dump(KERN_DEBUG, "eeprom: ", DUMP_PREFIX_OFFSET, 16, 1, + dump, 256, true); + +} + +static void micro_tx_chars(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + u32 val; + + while ((tx->index < tx->len) && + (readl(micro->base + UTSR1) & UTSR1_TNF)) { + writel(tx->buf[tx->index], micro->base + UTDR); + tx->index++; + } + + /* Stop interrupts */ + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static void micro_reset_comm(struct ipaq_micro *micro) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + u32 val; + + if (micro->msg) + complete(µ->msg->ack); + + /* Initialize Serial channel protocol frame */ + rx->state = STATE_SOF; /* Reset the state machine */ + + /* Set up interrupts */ + writel(0x01, micro->sdlc + 0x0); /* Select UART mode */ + + /* Clean up CR3 */ + writel(0x0, micro->base + UTCR3); + + /* Format: 8N1 */ + writel(UTCR0_8BitData | UTCR0_1StpBit, micro->base + UTCR0); + + /* Baud rate: 115200 */ + writel(0x0, micro->base + UTCR1); + writel(0x1, micro->base + UTCR2); + + /* Clear SR0 */ + writel(0xff, micro->base + UTSR0); + + /* Enable RX int, disable TX int */ + writel(UTCR3_TXE | UTCR3_RXE | UTCR3_RIE, micro->base + UTCR3); + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static irqreturn_t micro_serial_isr(int irq, void *dev_id) +{ + struct ipaq_micro *micro = dev_id; + struct ipaq_micro_txdev *tx = µ->tx; + u32 status; + + status = readl(micro->base + UTSR0); + do { + if (status & (UTSR0_RID | UTSR0_RFS)) { + if (status & UTSR0_RID) + /* Clear the Receiver IDLE bit */ + writel(UTSR0_RID, micro->base + UTSR0); + micro_rx_chars(micro); + } + + /* Clear break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + writel(status & (UTSR0_RBB | UTSR0_REB), + micro->base + UTSR0); + + if (status & UTSR0_TFS) + micro_tx_chars(micro); + + status = readl(micro->base + UTSR0); + + } while (((tx->index < tx->len) && (status & UTSR0_TFS)) || + (status & (UTSR0_RFS | UTSR0_RID))); + + return IRQ_HANDLED; +} + +static const struct mfd_cell micro_cells[] = { + { .name = "ipaq-micro-backlight", }, + { .name = "ipaq-micro-battery", }, + { .name = "ipaq-micro-keys", }, + { .name = "ipaq-micro-ts", }, + { .name = "ipaq-micro-leds", }, +}; + +static int micro_resume(struct device *dev) +{ + struct ipaq_micro *micro = dev_get_drvdata(dev); + + micro_reset_comm(micro); + mdelay(10); + + return 0; +} + +static int micro_probe(struct platform_device *pdev) +{ + struct ipaq_micro *micro; + struct resource *res; + int ret; + int irq; + + micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL); + if (!micro) + return -ENOMEM; + + micro->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + micro->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(micro->base)) + return PTR_ERR(micro->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -EINVAL; + + micro->sdlc = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(micro->sdlc)) + return PTR_ERR(micro->sdlc); + + micro_reset_comm(micro); + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr, + IRQF_SHARED, "ipaq-micro", + micro); + if (ret) { + dev_err(&pdev->dev, "unable to grab serial port IRQ\n"); + return ret; + } else + dev_info(&pdev->dev, "grabbed serial port IRQ\n"); + + spin_lock_init(µ->lock); + INIT_LIST_HEAD(µ->queue); + platform_set_drvdata(pdev, micro); + + ret = mfd_add_devices(&pdev->dev, pdev->id, micro_cells, + ARRAY_SIZE(micro_cells), NULL, 0, NULL); + if (ret) { + dev_err(&pdev->dev, "error adding MFD cells"); + return ret; + } + + /* Check version */ + ipaq_micro_get_version(micro); + dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version); + ipaq_micro_eeprom_dump(micro); + + return 0; +} + +static int micro_remove(struct platform_device *pdev) +{ + struct ipaq_micro *micro = platform_get_drvdata(pdev); + u32 val; + + mfd_remove_devices(&pdev->dev); + + val = readl(micro->base + UTCR3); + val &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */ + val &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */ + writel(val, micro->base + UTCR3); + + return 0; +} + +static const struct dev_pm_ops micro_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, micro_resume) +}; + +static struct platform_driver micro_device_driver = { + .driver = { + .name = "ipaq-h3xxx-micro", + .pm = µ_dev_pm_ops, + }, + .probe = micro_probe, + .remove = micro_remove, + /* .shutdown = micro_suspend, // FIXME */ +}; +module_platform_driver(micro_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight"); diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 07692604e119..f7ff0188603d 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -86,7 +86,7 @@ enum kempld_cells { KEMPLD_UART, }; -static struct mfd_cell kempld_devs[] = { +static const struct mfd_cell kempld_devs[] = { [KEMPLD_I2C] = { .name = "kempld-i2c", }, @@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); */ static int kempld_get_info(struct kempld_device_data *pld) { + int ret; struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + char major, minor; + + ret = pdata->get_info(pld); + if (ret) + return ret; + + /* The Kontron PLD firmware version string has the following format: + * Pwxy.zzzz + * P: Fixed + * w: PLD number - 1 hex digit + * x: Major version - 1 alphanumerical digit (0-9A-V) + * y: Minor version - 1 alphanumerical digit (0-9A-V) + * zzzz: Build number - 4 zero padded hex digits */ - return pdata->get_info(pld); + if (pld->info.major < 10) + major = pld->info.major + '0'; + else + major = (pld->info.major - 10) + 'A'; + if (pld->info.minor < 10) + minor = pld->info.minor + '0'; + else + minor = (pld->info.minor - 10) + 'A'; + + ret = scnprintf(pld->info.version, sizeof(pld->info.version), + "P%X%c%c.%04X", pld->info.number, major, minor, + pld->info.buildnr); + if (ret < 0) + return ret; + + return 0; } /* @@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld) return pdata->register_cells(pld); } +static const char *kempld_get_type_string(struct kempld_device_data *pld) +{ + const char *version_type; + + switch (pld->info.type) { + case 0: + version_type = "release"; + break; + case 1: + version_type = "debug"; + break; + case 2: + version_type = "custom"; + break; + default: + version_type = "unspecified"; + break; + } + + return version_type; +} + +static ssize_t kempld_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version); +} + +static ssize_t kempld_specification_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major, + pld->info.spec_minor); +} + +static ssize_t kempld_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld)); +} + +static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL); +static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show, + NULL); +static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL); + +static struct attribute *pld_attributes[] = { + &dev_attr_pld_version.attr, + &dev_attr_pld_specification.attr, + &dev_attr_pld_type.attr, + NULL +}; + +static const struct attribute_group pld_attr_group = { + .attrs = pld_attributes, +}; + static int kempld_detect_device(struct kempld_device_data *pld) { - char *version_type; u8 index_reg; int ret; @@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld) if (ret) return ret; - switch (pld->info.type) { - case 0: - version_type = "release"; - break; - case 1: - version_type = "debug"; - break; - case 2: - version_type = "custom"; - break; - default: - version_type = "unspecified"; - } + dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n", + pld->info.version, kempld_get_type_string(pld), + pld->info.spec_major, pld->info.spec_minor); + + ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group); + if (ret) + return ret; - dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number); - dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n", - version_type, pld->info.major, pld->info.minor, - pld->info.buildnr, pld->info.spec_major, - pld->info.spec_minor); + ret = kempld_register_cells(pld); + if (ret) + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); - return kempld_register_cells(pld); + return ret; } static int kempld_probe(struct platform_device *pdev) @@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev) struct kempld_device_data *pld = platform_get_drvdata(pdev); struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); + mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index e32226836fb4..335b930112b2 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -62,7 +62,7 @@ static const struct lp3943_reg_cfg lp3943_mux_cfg[] = { { LP3943_REG_MUX3, 0xC0, 6 }, }; -static struct mfd_cell lp3943_devs[] = { +static const struct mfd_cell lp3943_devs[] = { { .name = "lp3943-pwm", .of_compatible = "ti,lp3943-pwm", diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 3f10ea3f45d1..7d8482ff5868 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -488,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_PPT] = { .name = "Panther Point", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_LPT] = { .name = "Lynx Point", diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 484d372a4892..4a5e885383f8 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -26,7 +26,7 @@ #include <linux/mfd/max14577.h> #include <linux/mfd/max14577-private.h> -static struct mfd_cell max14577_devs[] = { +static const struct mfd_cell max14577_devs[] = { { .name = "max14577-muic", .of_compatible = "maxim,max14577-muic", @@ -38,7 +38,7 @@ static struct mfd_cell max14577_devs[] = { { .name = "max14577-charger", }, }; -static struct mfd_cell max77836_devs[] = { +static const struct mfd_cell max77836_devs[] = { { .name = "max77836-muic", .of_compatible = "maxim,max77836-muic", @@ -57,7 +57,7 @@ static struct mfd_cell max77836_devs[] = { }, }; -static struct of_device_id max14577_dt_match[] = { +static const struct of_device_id max14577_dt_match[] = { { .compatible = "maxim,max14577", .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, @@ -292,7 +292,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c, struct device_node *np = i2c->dev.of_node; int ret = 0; const struct regmap_irq_chip *irq_chip; - struct mfd_cell *mfd_devs; + const struct mfd_cell *mfd_devs; unsigned int mfd_devs_size; int irq_flags; @@ -331,7 +331,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c, of_id = of_match_device(max14577_dt_match, &i2c->dev); if (of_id) - max14577->dev_type = (unsigned int)of_id->data; + max14577->dev_type = + (enum maxim_device_type)of_id->data; } else { max14577->dev_type = id->driver_data; } @@ -414,20 +415,18 @@ static int max14577_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max14577 *max14577 = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) enable_irq_wake(max14577->irq); - /* - * MUIC IRQ must be disabled during suspend if this is - * a wake up source because it will be handled before - * resuming I2C. - * - * When device is woken up from suspend (e.g. by ADC change), - * an interrupt occurs before resuming I2C bus controller. - * Interrupt handler tries to read registers but this read - * will fail because I2C is still suspended. - */ - disable_irq(max14577->irq); - } + /* + * MUIC IRQ must be disabled during suspend because if it happens + * while suspended it will be handled before resuming I2C. + * + * When device is woken up from suspend (e.g. by ADC change), + * an interrupt occurs before resuming I2C bus controller. + * Interrupt handler tries to read registers but this read + * will fail because I2C is still suspended. + */ + disable_irq(max14577->irq); return 0; } @@ -437,10 +436,9 @@ static int max14577_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max14577 *max14577 = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) disable_irq_wake(max14577->irq); - enable_irq(max14577->irq); - } + enable_irq(max14577->irq); return 0; } diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index e5fce765accb..ce869acf27ae 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -47,7 +47,7 @@ static struct regmap_config max77686_regmap_config = { }; #ifdef CONFIG_OF -static struct of_device_id max77686_pmic_dt_match[] = { +static const struct of_device_id max77686_pmic_dt_match[] = { {.compatible = "maxim,max77686", .data = NULL}, {}, }; diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index c5535f018466..7e05428c756d 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -243,7 +243,7 @@ static const struct dev_pm_ops max77693_pm = { }; #ifdef CONFIG_OF -static struct of_device_id max77693_dt_match[] = { +static const struct of_device_id max77693_dt_match[] = { { .compatible = "maxim,max77693" }, {}, }; diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 07740314b29d..232749c8813d 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -305,7 +305,7 @@ static int max8907_i2c_remove(struct i2c_client *i2c) } #ifdef CONFIG_OF -static struct of_device_id max8907_of_match[] = { +static const struct of_device_id max8907_of_match[] = { { .compatible = "maxim,max8907" }, { }, }; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 8cf7a015cfe5..595364ee178a 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -51,7 +51,7 @@ static const struct mfd_cell max8997_devs[] = { }; #ifdef CONFIG_OF -static struct of_device_id max8997_pmic_dt_match[] = { +static const struct of_device_id max8997_pmic_dt_match[] = { { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 }, {}, }; diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 592db06098e6..a37cb7444b6e 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -132,7 +132,7 @@ int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) EXPORT_SYMBOL(max8998_update_reg); #ifdef CONFIG_OF -static struct of_device_id max8998_dt_match[] = { +static const struct of_device_id max8998_dt_match[] = { { .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 }, { .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 }, { .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 }, diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 0c6c21c5b1a8..acf5dd712eb2 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -660,34 +660,22 @@ int mc13xxx_common_init(struct device *dev) if (ret) return ret; + mutex_init(&mc13xxx->lock); + ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); if (ret) return ret; - mutex_init(&mc13xxx->lock); - if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) mc13xxx->flags = pdata->flags; if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (mc13xxx->flags & MC13XXX_USE_CODEC) { - if (pdata) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", - pdata->codec, sizeof(*pdata->codec)); - else - mc13xxx_add_subdevice(mc13xxx, "%s-codec"); - } - if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); - if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts", - &pdata->touch, sizeof(pdata->touch)); - if (pdata) { mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", &pdata->regulators, sizeof(pdata->regulators)); @@ -695,10 +683,20 @@ int mc13xxx_common_init(struct device *dev) pdata->leds, sizeof(*pdata->leds)); mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", pdata->buttons, sizeof(*pdata->buttons)); + if (mc13xxx->flags & MC13XXX_USE_CODEC) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", + pdata->codec, sizeof(*pdata->codec)); + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts", + &pdata->touch, sizeof(pdata->touch)); } else { mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); mc13xxx_add_subdevice(mc13xxx, "%s-led"); mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); + if (mc13xxx->flags & MC13XXX_USE_CODEC) + mc13xxx_add_subdevice(mc13xxx, "%s-codec"); + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) + mc13xxx_add_subdevice(mc13xxx, "%s-ts"); } return 0; diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index ad25bfa3fb02..5e2667afe2bc 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1287,29 +1287,8 @@ static struct i2c_driver menelaus_i2c_driver = { .id_table = menelaus_id, }; -static int __init menelaus_init(void) -{ - int res; - - res = i2c_add_driver(&menelaus_i2c_driver); - if (res < 0) { - pr_err(DRIVER_NAME ": driver registration failed\n"); - return res; - } - - return 0; -} - -static void __exit menelaus_exit(void) -{ - i2c_del_driver(&menelaus_i2c_driver); - - /* FIXME: Shutdown menelaus parts that can be shut down */ -} +module_i2c_driver(menelaus_i2c_driver); MODULE_AUTHOR("Texas Instruments, Inc. (and others)"); MODULE_DESCRIPTION("I2C interface for Menelaus."); MODULE_LICENSE("GPL"); - -module_init(menelaus_init); -module_exit(menelaus_exit); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 267649244737..892d343193ad 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -102,7 +102,7 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.dma_mask = parent->dma_mask; pdev->dev.dma_parms = parent->dma_parms; - ret = devm_regulator_bulk_register_supply_alias( + ret = regulator_bulk_register_supply_alias( &pdev->dev, cell->parent_supplies, parent, cell->parent_supplies, cell->num_parent_supplies); @@ -182,9 +182,9 @@ static int mfd_add_device(struct device *parent, int id, return 0; fail_alias: - devm_regulator_bulk_unregister_supply_alias(&pdev->dev, - cell->parent_supplies, - cell->num_parent_supplies); + regulator_bulk_unregister_supply_alias(&pdev->dev, + cell->parent_supplies, + cell->num_parent_supplies); fail_res: kfree(res); fail_device: @@ -238,6 +238,9 @@ static int mfd_remove_devices_fn(struct device *dev, void *c) pdev = to_platform_device(dev); cell = mfd_get_cell(pdev); + regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, + cell->num_parent_supplies); + /* find the base address of usage_count pointers (for freeing) */ if (!*usage_count || (cell->usage_count < *usage_count)) *usage_count = cell->usage_count; diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 651e249287dc..b48d80c367f9 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -557,7 +557,7 @@ static int usbhs_omap_get_dt_pdata(struct device *dev, return 0; } -static struct of_device_id usbhs_child_match_table[] = { +static const struct of_device_id usbhs_child_match_table[] = { { .compatible = "ti,omap-ehci", }, { .compatible = "ti,omap-ohci", }, { } diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index b97a97187ae9..959513803542 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -26,7 +26,6 @@ #include <linux/regmap.h> #include <linux/of_platform.h> #include <linux/mfd/core.h> -#include <linux/mfd/pm8xxx/core.h> #define SSBI_REG_ADDR_IRQ_BASE 0x1BB @@ -57,7 +56,6 @@ #define PM8921_NR_IRQS 256 struct pm_irq_chip { - struct device *dev; struct regmap *regmap; spinlock_t pm_irq_lock; struct irq_domain *irqdomain; @@ -67,11 +65,6 @@ struct pm_irq_chip { u8 config[0]; }; -struct pm8921 { - struct device *dev; - struct pm_irq_chip *irq_chip; -}; - static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int *ip) { @@ -255,55 +248,6 @@ static struct irq_chip pm8xxx_irq_chip = { .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; -/** - * pm8xxx_get_irq_stat - get the status of the irq line - * @chip: pointer to identify a pmic irq controller - * @irq: the irq number - * - * The pm8xxx gpio and mpp rely on the interrupt block to read - * the values on their pins. This function is to facilitate reading - * the status of a gpio or an mpp line. The caller has to convert the - * gpio number to irq number. - * - * RETURNS: - * an int indicating the value read on that line - */ -static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq) -{ - int pmirq, rc; - unsigned int block, bits, bit; - unsigned long flags; - struct irq_data *irq_data = irq_get_irq_data(irq); - - pmirq = irq_data->hwirq; - - block = pmirq / 8; - bit = pmirq % 8; - - spin_lock_irqsave(&chip->pm_irq_lock, flags); - - rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block); - if (rc) { - pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n", - irq, pmirq, block, rc); - goto bail_out; - } - - rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits); - if (rc) { - pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n", - irq, pmirq, block, rc); - goto bail_out; - } - - rc = (bits & (1 << bit)) ? 1 : 0; - -bail_out: - spin_unlock_irqrestore(&chip->pm_irq_lock, flags); - - return rc; -} - static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { @@ -324,56 +268,6 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = { .map = pm8xxx_irq_domain_map, }; -static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_read(pmic->dev->parent, addr, val, 1); -} - -static int pm8921_writeb(const struct device *dev, u16 addr, u8 val) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_write(pmic->dev->parent, addr, &val, 1); -} - -static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf, - int cnt) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_read(pmic->dev->parent, addr, buf, cnt); -} - -static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf, - int cnt) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_write(pmic->dev->parent, addr, buf, cnt); -} - -static int pm8921_read_irq_stat(const struct device *dev, int irq) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return pm8xxx_get_irq_stat(pmic->irq_chip, irq); -} - -static struct pm8xxx_drvdata pm8921_drvdata = { - .pmic_readb = pm8921_readb, - .pmic_writeb = pm8921_writeb, - .pmic_read_buf = pm8921_read_buf, - .pmic_write_buf = pm8921_write_buf, - .pmic_read_irq_stat = pm8921_read_irq_stat, -}; - static const struct regmap_config ssbi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -392,7 +286,6 @@ MODULE_DEVICE_TABLE(of, pm8921_id_table); static int pm8921_probe(struct platform_device *pdev) { - struct pm8921 *pmic; struct regmap *regmap; int irq, rc; unsigned int val; @@ -404,12 +297,6 @@ static int pm8921_probe(struct platform_device *pdev) if (irq < 0) return irq; - pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL); - if (!pmic) { - pr_err("Cannot alloc pm8921 struct\n"); - return -ENOMEM; - } - regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent, &ssbi_regmap_config); if (IS_ERR(regmap)) @@ -434,18 +321,13 @@ static int pm8921_probe(struct platform_device *pdev) pr_info("PMIC revision 2: %02X\n", val); rev |= val << BITS_PER_BYTE; - pmic->dev = &pdev->dev; - pm8921_drvdata.pm_chip_data = pmic; - platform_set_drvdata(pdev, &pm8921_drvdata); - chip = devm_kzalloc(&pdev->dev, sizeof(*chip) + sizeof(chip->config[0]) * nirqs, GFP_KERNEL); if (!chip) return -ENOMEM; - pmic->irq_chip = chip; - chip->dev = &pdev->dev; + platform_set_drvdata(pdev, chip); chip->regmap = regmap; chip->num_irqs = nirqs; chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); @@ -481,8 +363,7 @@ static int pm8921_remove_child(struct device *dev, void *unused) static int pm8921_remove(struct platform_device *pdev) { int irq = platform_get_irq(pdev, 0); - struct pm8921 *pmic = pm8921_drvdata.pm_chip_data; - struct pm_irq_chip *chip = pmic->irq_chip; + struct pm_irq_chip *chip = platform_get_drvdata(pdev); device_for_each_child(&pdev->dev, NULL, pm8921_remove_child); irq_set_chained_handler(irq, NULL); diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index c79569750be9..6575585f1d1f 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -38,7 +38,7 @@ static struct resource rdc321x_wdt_resource[] = { }; static struct rdc321x_gpio_pdata rdc321x_gpio_pdata = { - .max_gpios = RDC321X_MAX_GPIO, + .max_gpios = RDC321X_NUM_GPIO, }; static struct resource rdc321x_gpio_resources[] = { diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index b53b9d46cc45..6352bec8419a 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -29,7 +29,7 @@ static int polling_pipe = 1; module_param(polling_pipe, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)"); -static struct mfd_cell rtsx_usb_cells[] = { +static const struct mfd_cell rtsx_usb_cells[] = { [RTSX_USB_SD_CARD] = { .name = "rtsx_usb_sdmmc", .pdata_size = 0, @@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr, ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout); add_timer(&ucr->sg_timer); usb_sg_wait(&ucr->current_sg); - del_timer(&ucr->sg_timer); + del_timer_sync(&ucr->sg_timer); if (act_len) *act_len = ucr->current_sg.bytes; @@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf, if (ret) goto out_init_fail; + /* initialize USB SG transfer timer */ + setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); + ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells, ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL); if (ret) goto out_init_fail; - /* initialize USB SG transfer timer */ - init_timer(&ucr->sg_timer); - setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); #ifdef CONFIG_PM intf->needs_remote_wakeup = 1; usb_enable_autosuspend(usb_dev); @@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n", __func__, message.event); + /* + * Call to make sure LED is off during suspend to save more power. + * It is NOT a permanent state and could be turned on anytime later. + * Thus no need to call turn_on when resunming. + */ mutex_lock(&ucr->dev_mutex); rtsx_usb_turn_off_led(ucr); mutex_unlock(&ucr->dev_mutex); + return 0; } diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 1cf27521fff4..be06d0abbf19 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -25,7 +25,6 @@ #include <linux/mfd/core.h> #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/irq.h> -#include <linux/mfd/samsung/rtc.h> #include <linux/mfd/samsung/s2mpa01.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps14.h> @@ -91,7 +90,7 @@ static const struct mfd_cell s2mpa01_devs[] = { }; #ifdef CONFIG_OF -static struct of_device_id sec_dt_match[] = { +static const struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, }, { @@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config s5m_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = SEC_RTC_REG_MAX, -}; - -static const struct regmap_config s2mps14_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS_RTC_REG_MAX, -}; - #ifdef CONFIG_OF /* * Only the common platform data elements for s5m8767 are parsed here from the @@ -264,8 +249,9 @@ static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); - const struct regmap_config *regmap, *regmap_rtc; + const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; + unsigned long device_type; int ret; sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), @@ -277,7 +263,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, sec_pmic->dev = &i2c->dev; sec_pmic->i2c = i2c; sec_pmic->irq = i2c->irq; - sec_pmic->type = sec_i2c_get_driver_data(i2c, id); + device_type = sec_i2c_get_driver_data(i2c, id); if (sec_pmic->dev->of_node) { pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); @@ -285,7 +271,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = PTR_ERR(pdata); return ret; } - pdata->device_type = sec_pmic->type; + pdata->device_type = device_type; } if (pdata) { sec_pmic->device_type = pdata->device_type; @@ -298,39 +284,21 @@ static int sec_pmic_probe(struct i2c_client *i2c, switch (sec_pmic->device_type) { case S2MPA01: regmap = &s2mpa01_regmap_config; - /* - * The rtc-s5m driver does not support S2MPA01 and there - * is no mfd_cell for S2MPA01 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS11X: regmap = &s2mps11_regmap_config; - /* - * The rtc-s5m driver does not support S2MPS11 and there - * is no mfd_cell for S2MPS11 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS14X: regmap = &s2mps14_regmap_config; - regmap_rtc = &s2mps14_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; default: regmap = &sec_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; } @@ -342,21 +310,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, return ret; } - sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); - if (!sec_pmic->rtc) { - dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); - return -ENODEV; - } - i2c_set_clientdata(sec_pmic->rtc, sec_pmic); - - sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); - if (IS_ERR(sec_pmic->regmap_rtc)) { - ret = PTR_ERR(sec_pmic->regmap_rtc); - dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", - ret); - goto err_regmap_rtc; - } - if (pdata && pdata->cfg_pmic_irq) pdata->cfg_pmic_irq(); @@ -403,8 +356,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, err_mfd: sec_irq_exit(sec_pmic); -err_regmap_rtc: - i2c_unregister_device(sec_pmic->rtc); return ret; } @@ -414,7 +365,6 @@ static int sec_pmic_remove(struct i2c_client *i2c) mfd_remove_devices(sec_pmic->dev); sec_irq_exit(sec_pmic); - i2c_unregister_device(sec_pmic->rtc); return 0; } @@ -424,19 +374,18 @@ static int sec_pmic_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) enable_irq_wake(sec_pmic->irq); - /* - * PMIC IRQ must be disabled during suspend for RTC alarm - * to work properly. - * When device is woken up from suspend by RTC Alarm, an - * interrupt occurs before resuming I2C bus controller. - * The interrupt is handled by regmap_irq_thread which tries - * to read RTC registers. This read fails (I2C is still - * suspended) and RTC Alarm interrupt is disabled. - */ - disable_irq(sec_pmic->irq); - } + /* + * PMIC IRQ must be disabled during suspend for RTC alarm + * to work properly. + * When device is woken up from suspend, an + * interrupt occurs before resuming I2C bus controller. + * The interrupt is handled by regmap_irq_thread which tries + * to read RTC registers. This read fails (I2C is still + * suspended) and RTC Alarm interrupt is disabled. + */ + disable_irq(sec_pmic->irq); return 0; } @@ -446,10 +395,9 @@ static int sec_pmic_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) disable_irq_wake(sec_pmic->irq); - enable_irq(sec_pmic->irq); - } + enable_irq(sec_pmic->irq); return 0; } diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 64e7913aadc6..654e2c1dbf7a 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -385,7 +385,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) &sec_pmic->irq_data); break; default: - dev_err(sec_pmic->dev, "Unknown device type %d\n", + dev_err(sec_pmic->dev, "Unknown device type %lu\n", sec_pmic->device_type); return -EINVAL; } diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index e7dc441a8f8a..81e6d0932bf0 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1726,7 +1726,7 @@ static struct pci_driver sm501_pci_driver = { MODULE_ALIAS("platform:sm501"); -static struct of_device_id of_sm501_match_tbl[] = { +static const struct of_device_id of_sm501_match_tbl[] = { { .compatible = "smi,sm501", }, { /* end */ } }; diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 0da02e11d58e..a45f9c0a330a 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -14,6 +14,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> +#include <linux/of_device.h> #include "stmpe.h" static int i2c_reg_read(struct stmpe *stmpe, u8 reg) @@ -52,15 +53,41 @@ static struct stmpe_client_info i2c_ci = { .write_block = i2c_block_write, }; +static const struct of_device_id stmpe_of_match[] = { + { .compatible = "st,stmpe610", .data = (void *)STMPE610, }, + { .compatible = "st,stmpe801", .data = (void *)STMPE801, }, + { .compatible = "st,stmpe811", .data = (void *)STMPE811, }, + { .compatible = "st,stmpe1601", .data = (void *)STMPE1601, }, + { .compatible = "st,stmpe1801", .data = (void *)STMPE1801, }, + { .compatible = "st,stmpe2401", .data = (void *)STMPE2401, }, + { .compatible = "st,stmpe2403", .data = (void *)STMPE2403, }, + {}, +}; +MODULE_DEVICE_TABLE(of, stmpe_of_match); + static int stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + int partnum; + const struct of_device_id *of_id; + i2c_ci.data = (void *)id; i2c_ci.irq = i2c->irq; i2c_ci.client = i2c; i2c_ci.dev = &i2c->dev; - return stmpe_probe(&i2c_ci, id->driver_data); + of_id = of_match_device(stmpe_of_match, &i2c->dev); + if (!of_id) { + /* + * This happens when the I2C ID matches the node name + * but no real compatible string has been given. + */ + dev_info(&i2c->dev, "matching on node name, compatible is preferred\n"); + partnum = id->driver_data; + } else + partnum = (int)of_id->data; + + return stmpe_probe(&i2c_ci, partnum); } static int stmpe_i2c_remove(struct i2c_client *i2c) @@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = { #ifdef CONFIG_PM .pm = &stmpe_dev_pm_ops, #endif + .of_match_table = stmpe_of_match, }, .probe = stmpe_i2c_probe, .remove = stmpe_i2c_remove, diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 4a91f6771fb8..3b6bfa7184ad 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -20,6 +20,7 @@ #include <linux/slab.h> #include <linux/mfd/core.h> #include <linux/delay.h> +#include <linux/regulator/consumer.h> #include "stmpe.h" static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) @@ -605,9 +606,18 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks, if (blocks & STMPE_BLOCK_GPIO) mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO; if (blocks & STMPE_BLOCK_KEYPAD) mask |= STMPE1601_SYS_CTRL_ENABLE_KPC; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_KPC; + + if (blocks & STMPE_BLOCK_PWM) + mask |= STMPE1601_SYS_CTRL_ENABLE_SPWM; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM; return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask, enable ? mask : 0); @@ -986,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np) int base = 0; int num_irqs = stmpe->variant->num_irqs; - if (!np) - base = stmpe->irq_base; - stmpe->domain = irq_domain_add_simple(np, num_irqs, base, &stmpe_irq_ops, stmpe); if (!stmpe->domain) { @@ -1067,7 +1074,7 @@ static int stmpe_chip_init(struct stmpe *stmpe) static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell) { return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, - NULL, stmpe->irq_base, stmpe->domain); + NULL, 0, stmpe->domain); } static int stmpe_devices_init(struct stmpe *stmpe) @@ -1171,12 +1178,23 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) stmpe->dev = ci->dev; stmpe->client = ci->client; stmpe->pdata = pdata; - stmpe->irq_base = pdata->irq_base; stmpe->ci = ci; stmpe->partnum = partnum; stmpe->variant = stmpe_variant_info[partnum]; stmpe->regs = stmpe->variant->regs; stmpe->num_gpios = stmpe->variant->num_gpios; + stmpe->vcc = devm_regulator_get_optional(ci->dev, "vcc"); + if (!IS_ERR(stmpe->vcc)) { + ret = regulator_enable(stmpe->vcc); + if (ret) + dev_warn(ci->dev, "failed to enable VCC supply\n"); + } + stmpe->vio = devm_regulator_get_optional(ci->dev, "vio"); + if (!IS_ERR(stmpe->vio)) { + ret = regulator_enable(stmpe->vio); + if (ret) + dev_warn(ci->dev, "failed to enable VIO supply\n"); + } dev_set_drvdata(stmpe->dev, stmpe); if (ci->init) @@ -1243,6 +1261,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) int stmpe_remove(struct stmpe *stmpe) { + if (!IS_ERR(stmpe->vio)) + regulator_disable(stmpe->vio); + if (!IS_ERR(stmpe->vcc)) + regulator_disable(stmpe->vcc); + mfd_remove_devices(stmpe->dev); return 0; diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 6639f1b0fef5..9e4d21d37a11 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -192,7 +192,7 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3) #define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1) -#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0) +#define STMPE1601_SYS_CTRL_ENABLE_SPWM (1 << 0) /* The 1601/2403 share the same masks */ #define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7) diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c new file mode 100644 index 000000000000..718fc4d2adc0 --- /dev/null +++ b/drivers/mfd/sun6i-prcm.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * License Terms: GNU General Public License v2 + * Author: Boris BREZILLON <boris.brezillon@free-electrons.com> + * + * Allwinner PRCM (Power/Reset/Clock Management) driver + * + */ + +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/of.h> + +struct prcm_data { + int nsubdevs; + const struct mfd_cell *subdevs; +}; + +static const struct resource sun6i_a31_ar100_clk_res[] = { + { + .start = 0x0, + .end = 0x3, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_clk_res[] = { + { + .start = 0xc, + .end = 0xf, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_gates_clk_res[] = { + { + .start = 0x28, + .end = 0x2b, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_rstc_res[] = { + { + .start = 0xb0, + .end = 0xb3, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct mfd_cell sun6i_a31_prcm_subdevs[] = { + { + .name = "sun6i-a31-ar100-clk", + .of_compatible = "allwinner,sun6i-a31-ar100-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res), + .resources = sun6i_a31_ar100_clk_res, + }, + { + .name = "sun6i-a31-apb0-clk", + .of_compatible = "allwinner,sun6i-a31-apb0-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res), + .resources = sun6i_a31_apb0_clk_res, + }, + { + .name = "sun6i-a31-apb0-gates-clk", + .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res), + .resources = sun6i_a31_apb0_gates_clk_res, + }, + { + .name = "sun6i-a31-apb0-clock-reset", + .of_compatible = "allwinner,sun6i-a31-clock-reset", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res), + .resources = sun6i_a31_apb0_rstc_res, + }, +}; + +static const struct prcm_data sun6i_a31_prcm_data = { + .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs), + .subdevs = sun6i_a31_prcm_subdevs, +}; + +static const struct of_device_id sun6i_prcm_dt_ids[] = { + { + .compatible = "allwinner,sun6i-a31-prcm", + .data = &sun6i_a31_prcm_data, + }, + { /* sentinel */ }, +}; + +static int sun6i_prcm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct prcm_data *data; + struct resource *res; + int ret; + + match = of_match_node(sun6i_prcm_dt_ids, np); + if (!match) + return -EINVAL; + + data = match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no prcm memory region provided\n"); + return -ENOENT; + } + + ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs, + res, -1, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to add subdevices\n"); + return ret; + } + + return 0; +} + +static struct platform_driver sun6i_prcm_driver = { + .driver = { + .name = "sun6i-prcm", + .owner = THIS_MODULE, + .of_match_table = sun6i_prcm_dt_ids, + }, + .probe = sun6i_prcm_probe, +}; +module_platform_driver(sun6i_prcm_driver); + +MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); +MODULE_DESCRIPTION("Allwinner sun6i PRCM driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index e2a04bb8bc1e..ca15878ce5c0 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -95,7 +95,11 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, struct device_node *syscon_np; struct regmap *regmap; - syscon_np = of_parse_phandle(np, property, 0); + if (property) + syscon_np = of_parse_phandle(np, property, 0); + else + syscon_np = np; + if (!syscon_np) return ERR_PTR(-ENODEV); diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 3b27482a174f..a2e1990c9de7 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -119,7 +119,7 @@ static const struct i2c_device_id tps6507x_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id); #ifdef CONFIG_OF -static struct of_device_id tps6507x_of_match[] = { +static const struct of_device_id tps6507x_of_match[] = { {.compatible = "ti,tps6507x", }, {}, }; diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index a74bfb59f18f..0d256cb002eb 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -197,6 +197,7 @@ static struct regmap_irq_chip tps65218_irq_chip = { static const struct of_device_id of_tps65218_match_table[] = { { .compatible = "ti,tps65218", }, + {} }; static int tps65218_probe(struct i2c_client *client, diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 835e5549ecdd..8e1dbc469580 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -444,7 +444,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien return pdata; } -static struct of_device_id tps6586x_of_match[] = { +static const struct of_device_id tps6586x_of_match[] = { { .compatible = "ti,tps6586x", }, { }, }; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 460a014ca629..f9e42ea1cb1a 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -379,7 +379,7 @@ err_sleep_init: } #ifdef CONFIG_OF -static struct of_device_id tps65910_of_match[] = { +static const struct of_device_id tps65910_of_match[] = { { .compatible = "ti,tps65910", .data = (void *)TPS65910}, { .compatible = "ti,tps65911", .data = (void *)TPS65911}, { }, diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 6e88f25832fb..ae26d84b3a59 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -87,8 +87,13 @@ static struct reg_default twl6040_defaults[] = { }; static struct reg_default twl6040_patch[] = { - /* Select I2C bus access to dual access registers */ - { TWL6040_REG_ACCCTL, 0x09 }, + /* + * Select I2C bus access to dual access registers + * Interrupt register is cleared on read + * Select fast mode for i2c (400KHz) + */ + { TWL6040_REG_ACCCTL, + TWL6040_I2CSEL | TWL6040_INTCLRMODE | TWL6040_I2CMODE(1) }, }; @@ -286,6 +291,8 @@ int twl6040_power(struct twl6040 *twl6040, int on) if (twl6040->power_count++) goto out; + clk_prepare_enable(twl6040->clk32k); + /* Allow writes to the chip */ regcache_cache_only(twl6040->regmap, false); @@ -341,6 +348,8 @@ int twl6040_power(struct twl6040 *twl6040, int on) twl6040->sysclk = 0; twl6040->mclk = 0; + + clk_disable_unprepare(twl6040->clk32k); } out: @@ -432,12 +441,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, TWL6040_HPLLENA; break; case 19200000: - /* - * PLL disabled - * (enable PLL if MCLK jitter quality - * doesn't meet specification) - */ - hppllctl |= TWL6040_MCLK_19200KHZ; + /* PLL enabled, bypass mode */ + hppllctl |= TWL6040_MCLK_19200KHZ | + TWL6040_HPLLBP | TWL6040_HPLLENA; break; case 26000000: /* PLL enabled, active mode */ @@ -445,9 +451,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, TWL6040_HPLLENA; break; case 38400000: - /* PLL enabled, active mode */ + /* PLL enabled, bypass mode */ hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLENA; + TWL6040_HPLLBP | TWL6040_HPLLENA; break; default: dev_err(twl6040->dev, @@ -639,6 +645,12 @@ static int twl6040_probe(struct i2c_client *client, i2c_set_clientdata(client, twl6040); + twl6040->clk32k = devm_clk_get(&client->dev, "clk32k"); + if (IS_ERR(twl6040->clk32k)) { + dev_info(&client->dev, "clk32k is not handled\n"); + twl6040->clk32k = NULL; + } + twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, @@ -660,6 +672,9 @@ static int twl6040_probe(struct i2c_client *client, mutex_init(&twl6040->mutex); init_completion(&twl6040->ready); + regmap_register_patch(twl6040->regmap, twl6040_patch, + ARRAY_SIZE(twl6040_patch)); + twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); if (twl6040->rev < 0) { dev_err(&client->dev, "Failed to read revision register: %d\n", @@ -679,6 +694,9 @@ static int twl6040_probe(struct i2c_client *client, GPIOF_OUT_INIT_LOW, "audpwron"); if (ret) goto gpio_err; + + /* Clear any pending interrupt */ + twl6040_reg_read(twl6040, TWL6040_REG_INTID); } ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT, @@ -707,10 +725,6 @@ static int twl6040_probe(struct i2c_client *client, goto readyirq_err; } - /* dual-access registers controlled by I2C only */ - regmap_register_patch(twl6040->regmap, twl6040_patch, - ARRAY_SIZE(twl6040_patch)); - /* * The main functionality of twl6040 to provide audio on OMAP4+ systems. * We can add the ASoC codec child whenever this driver has been loaded. diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 070f8cfbbd7a..c8a993bd17ae 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -333,7 +333,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ - { 0x00000212, 0x0001 }, /* R530 - LDO1 Control 2 */ + { 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */ { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ @@ -1037,6 +1037,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_7: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_8: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 1942b6f231da..41a7f6fb7802 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -468,10 +468,12 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ - { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */ - { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */ - { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */ - { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */ + { 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */ + { 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */ + { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ + { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ + { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ + { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ @@ -549,6 +551,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ { 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ + { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */ @@ -1498,6 +1501,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: @@ -1580,6 +1585,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_LEVEL_3: case ARIZONA_MIC_DETECT_LEVEL_4: case ARIZONA_MIC_NOISE_MIX_CONTROL_1: + case ARIZONA_ISOLATION_CONTROL: case ARIZONA_JACK_DETECT_ANALOGUE: case ARIZONA_INPUT_ENABLES: case ARIZONA_INPUT_ENABLES_STATUS: diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index e5eae751aa1b..c6fb5d16ca09 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -64,7 +64,7 @@ EXPORT_SYMBOL_GPL(wm8400_block_read); static int wm8400_register_codec(struct wm8400 *wm8400) { - struct mfd_cell cell = { + const struct mfd_cell cell = { .name = "wm8400-codec", .platform_data = wm8400, .pdata_size = sizeof(*wm8400), diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index 5aa807687777..c7a81da64ee1 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -174,10 +174,10 @@ static const struct reg_default wm8997_reg_default[] = { { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ - { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */ - { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */ - { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */ - { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */ + { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ + { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ + { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ + { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ @@ -814,10 +814,10 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4: - case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: - case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: @@ -846,6 +846,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_RATE_ESTIMATOR_3: case ARIZONA_RATE_ESTIMATOR_4: case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_DYNAMIC_FREQUENCY_SCALING_1: case ARIZONA_FLL1_CONTROL_1: case ARIZONA_FLL1_CONTROL_2: case ARIZONA_FLL1_CONTROL_3: @@ -880,6 +881,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: case ARIZONA_LDO1_CONTROL_1: + case ARIZONA_LDO1_CONTROL_2: case ARIZONA_LDO2_CONTROL_1: case ARIZONA_MIC_BIAS_CTRL_1: case ARIZONA_MIC_BIAS_CTRL_2: diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8aaf8c1f3f63..b675882307e4 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -694,3 +694,10 @@ config MMC_REALTEK_PCI help Say Y here to include driver code to support SD/MMC card interface of Realtek PCI-E card reader + +config MMC_REALTEK_USB + tristate "Realtek USB SD/MMC Card Interface Driver" + depends on MFD_RTSX_USB + help + Say Y here to include driver code to support SD/MMC card interface + of Realtek RTS5129/39 series card reader diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 0c8aa5e1e304..3eb48b656f25 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o +obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c new file mode 100644 index 000000000000..e11fafa6fc6b --- /dev/null +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -0,0 +1,1455 @@ +/* Realtek USB SD/MMC Card Interface driver + * + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see <http://www.gnu.org/licenses/>. + * + * Author: + * Roger Tseng <rogerable@realtek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/card.h> +#include <linux/scatterlist.h> +#include <linux/pm_runtime.h> + +#include <linux/mfd/rtsx_usb.h> +#include <asm/unaligned.h> + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#include <linux/leds.h> +#include <linux/workqueue.h> +#define RTSX_USB_USE_LEDS_CLASS +#endif + +struct rtsx_usb_sdmmc { + struct platform_device *pdev; + struct rtsx_ucr *ucr; + struct mmc_host *mmc; + struct mmc_request *mrq; + + struct mutex host_mutex; + + u8 ssc_depth; + unsigned int clock; + bool vpclk; + bool double_clk; + bool host_removal; + bool card_exist; + bool initial_mode; + bool ddr_mode; + + unsigned char power_mode; + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) + struct led_classdev led; + char led_name[32]; + struct work_struct led_work; +#endif +}; + +static inline struct device *sdmmc_dev(struct rtsx_usb_sdmmc *host) +{ + return &(host->pdev->dev); +} + +static inline void sd_clear_error(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + rtsx_usb_ep0_write_register(ucr, CARD_STOP, + SD_STOP | SD_CLR_ERR, + SD_STOP | SD_CLR_ERR); + + rtsx_usb_clear_dma_err(ucr); + rtsx_usb_clear_fsm_err(ucr); +} + +#ifdef DEBUG +static void sd_print_debug_regs(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + u8 val = 0; + + rtsx_usb_ep0_read_register(ucr, SD_STAT1, &val); + dev_dbg(sdmmc_dev(host), "SD_STAT1: 0x%x\n", val); + rtsx_usb_ep0_read_register(ucr, SD_STAT2, &val); + dev_dbg(sdmmc_dev(host), "SD_STAT2: 0x%x\n", val); + rtsx_usb_ep0_read_register(ucr, SD_BUS_STAT, &val); + dev_dbg(sdmmc_dev(host), "SD_BUS_STAT: 0x%x\n", val); +} +#else +#define sd_print_debug_regs(host) +#endif /* DEBUG */ + +static int sd_read_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + rtsx_usb_init_cmd(ucr); + if (cmd != NULL) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__ + , cmd->opcode); + if (cmd->opcode == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD1, 0xFF, (u8)(cmd->arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD2, 0xFF, (u8)(cmd->arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD3, 0xFF, (u8)(cmd->arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD4, 0xFF, (u8)cmd->arg); + } else { + trans_mode = SD_TM_AUTO_READ_3; + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + if (trans_mode != SD_TM_AUTO_TUNING) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + if (cmd != NULL) { + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0); + } + + err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd failed (err = %d)\n", err); + return err; + } + + err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout); + if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) { + sd_print_debug_regs(host); + + if (!err) { + dev_dbg(sdmmc_dev(host), + "Transfer failed (SD_TRANSFER = %02x)\n", + ucr->rsp_buf[0]); + err = -EIO; + } else { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + } + + return err; + } + + if (cmd != NULL) { + cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + + if (buf && buf_len) { + /* 2-byte aligned part */ + err = rtsx_usb_read_ppbuf(ucr, buf, byte_cnt - (byte_cnt % 2)); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_read_ppbuf failed (err = %d)\n", err); + return err; + } + + /* unaligned byte */ + if (byte_cnt % 2) + return rtsx_usb_read_register(ucr, + PPBUF_BASE2 + byte_cnt, + buf + byte_cnt - 1); + } + + return 0; +} + +static int sd_write_data(struct rtsx_usb_sdmmc *host, struct mmc_command *cmd, + u16 byte_cnt, u8 *buf, int buf_len, int timeout) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + if (buf && buf_len) { + err = rtsx_usb_write_ppbuf(ucr, buf, buf_len); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_write_ppbuf failed (err = %d)\n", + err); + return err; + } + } + + trans_mode = (cmd != NULL) ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; + rtsx_usb_init_cmd(ucr); + + if (cmd != NULL) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, + cmd->opcode); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD0, 0xFF, (u8)(cmd->opcode) | 0x40); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD1, 0xFF, (u8)(cmd->arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD2, 0xFF, (u8)(cmd->arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD3, 0xFF, (u8)(cmd->arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CMD4, 0xFF, (u8)cmd->arg); + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + if (cmd != NULL) { + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD1, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD2, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD3, 0, 0); + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_CMD4, 0, 0); + } + + err = rtsx_usb_send_cmd(ucr, MODE_CR, timeout); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd failed (err = %d)\n", err); + return err; + } + + err = rtsx_usb_get_rsp(ucr, !cmd ? 1 : 5, timeout); + if (err) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + return err; + } + + if (cmd != NULL) { + cmd->resp[0] = get_unaligned_be32(ucr->rsp_buf + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + + return 0; +} + +static void sd_send_cmd_get_rsp(struct rtsx_usb_sdmmc *host, + struct mmc_command *cmd) +{ + struct rtsx_ucr *ucr = host->ucr; + u8 cmd_idx = (u8)cmd->opcode; + u32 arg = cmd->arg; + int err = 0; + int timeout = 100; + int i; + u8 *ptr; + int stat_idx = 0; + int len = 2; + u8 rsp_type; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd_idx, arg); + + /* Response type: + * R0 + * R1, R5, R6, R7 + * R1b + * R2 + * R3, R4 + */ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rsp_type = SD_RSP_TYPE_R0; + break; + case MMC_RSP_R1: + rsp_type = SD_RSP_TYPE_R1; + break; + case MMC_RSP_R1 & ~MMC_RSP_CRC: + rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7; + break; + case MMC_RSP_R1B: + rsp_type = SD_RSP_TYPE_R1b; + break; + case MMC_RSP_R2: + rsp_type = SD_RSP_TYPE_R2; + break; + case MMC_RSP_R3: + rsp_type = SD_RSP_TYPE_R3; + break; + default: + dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); + err = -EINVAL; + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R1b) + timeout = 3000; + + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_TOGGLE_EN); + if (err) + goto out; + } + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END | SD_STAT_IDLE, + SD_TRANSFER_END | SD_STAT_IDLE); + + if (rsp_type == SD_RSP_TYPE_R2) { + /* Read data from ping-pong buffer */ + for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 16; + } else if (rsp_type != SD_RSP_TYPE_R0) { + /* Read data from SD_CMDx registers */ + for (i = SD_CMD0; i <= SD_CMD4; i++) + rtsx_usb_add_cmd(ucr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 5; + } + len += stat_idx; + + rtsx_usb_add_cmd(ucr, READ_REG_CMD, SD_STAT1, 0, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_CR, 100); + if (err) { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_send_cmd error (err = %d)\n", err); + goto out; + } + + err = rtsx_usb_get_rsp(ucr, len, timeout); + if (err || (ucr->rsp_buf[0] & SD_TRANSFER_ERR)) { + sd_print_debug_regs(host); + sd_clear_error(host); + + if (!err) { + dev_dbg(sdmmc_dev(host), + "Transfer failed (SD_TRANSFER = %02x)\n", + ucr->rsp_buf[0]); + err = -EIO; + } else { + dev_dbg(sdmmc_dev(host), + "rtsx_usb_get_rsp failed (err = %d)\n", err); + } + + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R0) { + err = 0; + goto out; + } + + /* Skip result of CHECK_REG_CMD */ + ptr = ucr->rsp_buf + 1; + + /* Check (Start,Transmission) bit of Response */ + if ((ptr[0] & 0xC0) != 0) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); + goto out; + } + + /* Check CRC7 */ + if (!(rsp_type & SD_NO_CHECK_CRC7)) { + if (ptr[stat_idx] & SD_CRC7_ERR) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "CRC7 error\n"); + goto out; + } + } + + if (rsp_type == SD_RSP_TYPE_R2) { + for (i = 0; i < 4; i++) { + cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); + dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", + i, cmd->resp[i]); + } + } else { + cmd->resp[0] = get_unaligned_be32(ptr + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + +out: + cmd->error = err; +} + +static int sd_rw_multi(struct rtsx_usb_sdmmc *host, struct mmc_request *mrq) +{ + struct rtsx_ucr *ucr = host->ucr; + struct mmc_data *data = mrq->data; + int read = (data->flags & MMC_DATA_READ) ? 1 : 0; + u8 cfg2, trans_mode; + int err; + u8 flag; + size_t data_len = data->blksz * data->blocks; + unsigned int pipe; + + if (read) { + dev_dbg(sdmmc_dev(host), "%s: read %zu bytes\n", + __func__, data_len); + cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_READ_3; + } else { + dev_dbg(sdmmc_dev(host), "%s: write %zu bytes\n", + __func__, data_len); + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_WRITE_3; + } + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_L, + 0xFF, (u8)data->blocks); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BLOCK_CNT_H, + 0xFF, (u8)(data->blocks >> 8)); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC3, + 0xFF, (u8)(data_len >> 24)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC2, + 0xFF, (u8)(data_len >> 16)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC1, + 0xFF, (u8)(data_len >> 8)); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_TC0, + 0xFF, (u8)data_len); + if (read) { + flag = MODE_CDIR; + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | DMA_512); + } else { + flag = MODE_CDOR; + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, MC_DMA_CTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | DMA_512); + } + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_usb_add_cmd(ucr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_usb_send_cmd(ucr, flag, 100); + if (err) + return err; + + if (read) + pipe = usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN); + else + pipe = usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT); + + err = rtsx_usb_transfer_data(ucr, pipe, data->sg, data_len, + data->sg_len, NULL, 10000); + if (err) { + dev_dbg(sdmmc_dev(host), "rtsx_usb_transfer_data error %d\n" + , err); + sd_clear_error(host); + return err; + } + + return rtsx_usb_get_rsp(ucr, 1, 2000); +} + +static inline void sd_enable_initial_mode(struct rtsx_usb_sdmmc *host) +{ + rtsx_usb_write_register(host->ucr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); +} + +static inline void sd_disable_initial_mode(struct rtsx_usb_sdmmc *host) +{ + rtsx_usb_write_register(host->ucr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); +} + +static void sd_normal_rw(struct rtsx_usb_sdmmc *host, + struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + u8 *buf; + + buf = kzalloc(data->blksz, GFP_NOIO); + if (!buf) { + cmd->error = -ENOMEM; + return; + } + + if (data->flags & MMC_DATA_READ) { + if (host->initial_mode) + sd_disable_initial_mode(host); + + cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf, + data->blksz, 200); + + if (host->initial_mode) + sd_enable_initial_mode(host); + + sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); + } else { + sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); + + cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf, + data->blksz, 200); + } + + kfree(buf); +} + +static int sd_change_phase(struct rtsx_usb_sdmmc *host, u8 sample_point, int tx) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: %s sample_point = %d\n", + __func__, tx ? "TX" : "RX", sample_point); + + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); + + if (tx) + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, + 0x0F, sample_point); + else + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK1_CTL, + 0x0F, sample_point); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_RST, 0); + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + return 0; +} + +static inline u32 get_phase_point(u32 phase_map, unsigned int idx) +{ + idx &= MAX_PHASE; + return phase_map & (1 << idx); +} + +static int get_phase_len(u32 phase_map, unsigned int idx) +{ + int i; + + for (i = 0; i < MAX_PHASE + 1; i++) { + if (get_phase_point(phase_map, idx + i) == 0) + return i; + } + return MAX_PHASE + 1; +} + +static u8 sd_search_final_phase(struct rtsx_usb_sdmmc *host, u32 phase_map) +{ + int start = 0, len = 0; + int start_final = 0, len_final = 0; + u8 final_phase = 0xFF; + + if (phase_map == 0) { + dev_dbg(sdmmc_dev(host), "Phase: [map:%x]\n", phase_map); + return final_phase; + } + + while (start < MAX_PHASE + 1) { + len = get_phase_len(phase_map, start); + if (len_final < len) { + start_final = start; + len_final = len; + } + start += len ? len : 1; + } + + final_phase = (start_final + len_final / 2) & MAX_PHASE; + dev_dbg(sdmmc_dev(host), "Phase: [map:%x] [maxlen:%d] [final:%d]\n", + phase_map, len_final, final_phase); + + return final_phase; +} + +static void sd_wait_data_idle(struct rtsx_usb_sdmmc *host) +{ + int err, i; + u8 val = 0; + + for (i = 0; i < 100; i++) { + err = rtsx_usb_ep0_read_register(host->ucr, + SD_DATA_STATE, &val); + if (val & SD_DATA_IDLE) + return; + + usleep_range(100, 1000); + } +} + +static int sd_tuning_rx_cmd(struct rtsx_usb_sdmmc *host, + u8 opcode, u8 sample_point) +{ + int err; + struct mmc_command cmd = {0}; + + err = sd_change_phase(host, sample_point, 0); + if (err) + return err; + + cmd.opcode = MMC_SEND_TUNING_BLOCK; + err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100); + if (err) { + /* Wait till SD DATA IDLE */ + sd_wait_data_idle(host); + sd_clear_error(host); + return err; + } + + return 0; +} + +static void sd_tuning_phase(struct rtsx_usb_sdmmc *host, + u8 opcode, u16 *phase_map) +{ + int err, i; + u16 raw_phase_map = 0; + + for (i = MAX_PHASE; i >= 0; i--) { + err = sd_tuning_rx_cmd(host, opcode, (u8)i); + if (!err) + raw_phase_map |= 1 << i; + } + + if (phase_map) + *phase_map = raw_phase_map; +} + +static int sd_tuning_rx(struct rtsx_usb_sdmmc *host, u8 opcode) +{ + int err, i; + u16 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; + u8 final_phase; + + /* setting fixed default TX phase */ + err = sd_change_phase(host, 0x01, 1); + if (err) { + dev_dbg(sdmmc_dev(host), "TX phase setting failed\n"); + return err; + } + + /* tuning RX phase */ + for (i = 0; i < RX_TUNING_CNT; i++) { + sd_tuning_phase(host, opcode, &(raw_phase_map[i])); + + if (raw_phase_map[i] == 0) + break; + } + + phase_map = 0xFFFF; + for (i = 0; i < RX_TUNING_CNT; i++) { + dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%04x\n", + i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%04x\n", phase_map); + + if (phase_map) { + final_phase = sd_search_final_phase(host, phase_map); + if (final_phase == 0xFF) + return -EINVAL; + + err = sd_change_phase(host, final_phase, 0); + if (err) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static int sdmmc_get_ro(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u16 val; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + /* Check SD card detect */ + err = rtsx_usb_get_card_status(ucr, &val); + + mutex_unlock(&ucr->dev_mutex); + + + /* Treat failed detection as non-ro */ + if (err) + return 0; + + if (val & SD_WP) + return 1; + + return 0; +} + +static int sdmmc_get_cd(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u16 val; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + /* Check SD card detect */ + err = rtsx_usb_get_card_status(ucr, &val); + + mutex_unlock(&ucr->dev_mutex); + + /* Treat failed detection as non-exist */ + if (err) + goto no_card; + + if (val & SD_CD) { + host->card_exist = true; + return 1; + } + +no_card: + host->card_exist = false; + return 0; +} + +static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + unsigned int data_size = 0; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + + if (host->host_removal) { + cmd->error = -ENOMEDIUM; + goto finish; + } + + if ((!host->card_exist)) { + cmd->error = -ENOMEDIUM; + goto finish_detect_card; + } + + /* + * Reject SDIO CMDs to speed up card identification + * since unsupported + */ + if (cmd->opcode == SD_IO_SEND_OP_COND || + cmd->opcode == SD_IO_RW_DIRECT || + cmd->opcode == SD_IO_RW_EXTENDED) { + cmd->error = -EINVAL; + goto finish; + } + + mutex_lock(&ucr->dev_mutex); + + mutex_lock(&host->host_mutex); + host->mrq = mrq; + mutex_unlock(&host->host_mutex); + + if (mrq->data) + data_size = data->blocks * data->blksz; + + if (!data_size) { + sd_send_cmd_get_rsp(host, cmd); + } else if ((!(data_size % 512) && cmd->opcode != MMC_SEND_EXT_CSD) || + mmc_op_multi(cmd->opcode)) { + sd_send_cmd_get_rsp(host, cmd); + + if (!cmd->error) { + sd_rw_multi(host, mrq); + + if (mmc_op_multi(cmd->opcode) && mrq->stop) { + sd_send_cmd_get_rsp(host, mrq->stop); + rtsx_usb_write_register(ucr, MC_FIFO_CTL, + FIFO_FLUSH, FIFO_FLUSH); + } + } + } else { + sd_normal_rw(host, mrq); + } + + if (mrq->data) { + if (cmd->error || data->error) + data->bytes_xfered = 0; + else + data->bytes_xfered = data->blocks * data->blksz; + } + + mutex_unlock(&ucr->dev_mutex); + +finish_detect_card: + if (cmd->error) { + /* + * detect card when fail to update card existence state and + * speed up card removal when retry + */ + sdmmc_get_cd(mmc); + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + } + +finish: + mutex_lock(&host->host_mutex); + host->mrq = NULL; + mutex_unlock(&host->host_mutex); + + mmc_request_done(mmc, mrq); +} + +static int sd_set_bus_width(struct rtsx_usb_sdmmc *host, + unsigned char bus_width) +{ + int err = 0; + u8 width[] = { + [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, + [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, + [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, + }; + + if (bus_width <= MMC_BUS_WIDTH_8) + err = rtsx_usb_write_register(host->ucr, SD_CFG1, + 0x03, width[bus_width]); + + return err; +} + +static int sd_pull_ctl_disable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_disable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0x95); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x56); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x59); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_enable_lqfp48(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xAA); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0xAA); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA9); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x55); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0xA5); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_pull_ctl_enable_qfn24(struct rtsx_ucr *ucr) +{ + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 0xA5); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 0x9A); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 0xA5); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 0x9A); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 0x65); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 0x5A); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_power_on(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_SD); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, + SD_CLK_EN, SD_CLK_EN); + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + err = sd_pull_ctl_enable_lqfp48(ucr); + else + err = sd_pull_ctl_enable_qfn24(ucr); + if (err) + return err; + + err = rtsx_usb_write_register(ucr, CARD_PWR_CTL, + POWER_MASK, PARTIAL_POWER_ON); + if (err) + return err; + + usleep_range(800, 1000); + + rtsx_usb_init_cmd(ucr); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK|LDO3318_PWR_MASK, POWER_ON|LDO_ON); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, + SD_OUTPUT_EN, SD_OUTPUT_EN); + + return rtsx_usb_send_cmd(ucr, MODE_C, 100); +} + +static int sd_power_off(struct rtsx_usb_sdmmc *host) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + rtsx_usb_init_cmd(ucr); + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK, POWER_OFF); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, + POWER_MASK|LDO3318_PWR_MASK, POWER_OFF|LDO_SUSPEND); + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + if (err) + return err; + + if (CHECK_PKG(ucr, LQFP48)) + return sd_pull_ctl_disable_lqfp48(ucr); + return sd_pull_ctl_disable_qfn24(ucr); +} + +static int sd_set_power_mode(struct rtsx_usb_sdmmc *host, + unsigned char power_mode) +{ + int err; + + if (power_mode != MMC_POWER_OFF) + power_mode = MMC_POWER_ON; + + if (power_mode == host->power_mode) + return 0; + + if (power_mode == MMC_POWER_OFF) { + err = sd_power_off(host); + pm_runtime_put(sdmmc_dev(host)); + } else { + pm_runtime_get_sync(sdmmc_dev(host)); + err = sd_power_on(host); + } + + if (!err) + host->power_mode = power_mode; + + return err; +} + +static int sd_set_timing(struct rtsx_usb_sdmmc *host, + unsigned char timing, bool *ddr_mode) +{ + struct rtsx_ucr *ucr = host->ucr; + int err; + + *ddr_mode = false; + + rtsx_usb_init_cmd(ucr); + + switch (timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_RST, + SD_30_MODE | SD_ASYNC_FIFO_RST); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + break; + + case MMC_TIMING_UHS_DDR50: + *ddr_mode = true; + + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_RST, + SD_DDR_MODE | SD_ASYNC_FIFO_RST); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); + break; + + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_CFG1, + 0x0C, SD_20_MODE); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_14_DELAY); + break; + + default: + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_CFG1, 0x0C, SD_20_MODE); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, + SD_PUSH_POINT_CTL, 0xFF, 0); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); + break; + } + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + + return err; +} + +static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + mutex_lock(&ucr->dev_mutex); + + if (rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD)) { + mutex_unlock(&ucr->dev_mutex); + return; + } + + sd_set_power_mode(host, ios->power_mode); + sd_set_bus_width(host, ios->bus_width); + sd_set_timing(host, ios->timing, &host->ddr_mode); + + host->vpclk = false; + host->double_clk = true; + + switch (ios->timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + host->ssc_depth = SSC_DEPTH_2M; + host->vpclk = true; + host->double_clk = false; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_UHS_SDR25: + host->ssc_depth = SSC_DEPTH_1M; + break; + default: + host->ssc_depth = SSC_DEPTH_512K; + break; + } + + host->initial_mode = (ios->clock <= 1000000) ? true : false; + host->clock = ios->clock; + + rtsx_usb_switch_clock(host->ucr, host->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + + mutex_unlock(&ucr->dev_mutex); + dev_dbg(sdmmc_dev(host), "%s end\n", __func__); +} + +static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err = 0; + + dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", + __func__, ios->signal_voltage); + + if (host->host_removal) + return -ENOMEDIUM; + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) + return -EPERM; + + mutex_lock(&ucr->dev_mutex); + + err = rtsx_usb_card_exclusive_check(ucr, RTSX_USB_SD_CARD); + if (err) { + mutex_unlock(&ucr->dev_mutex); + return err; + } + + /* Let mmc core do the busy checking, simply stop the forced-toggle + * clock(while issuing CMD11) and switch voltage. + */ + rtsx_usb_init_cmd(ucr); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL, + SD_IO_USING_1V8, SD_IO_USING_3V3); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, + TUNE_SD18_MASK, TUNE_SD18_3V3); + } else { + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_FORCE_STOP); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_PAD_CTL, + SD_IO_USING_1V8, SD_IO_USING_1V8); + rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, + TUNE_SD18_MASK, TUNE_SD18_1V8); + } + + err = rtsx_usb_send_cmd(ucr, MODE_C, 100); + mutex_unlock(&ucr->dev_mutex); + + return err; +} + +static int sdmmc_card_busy(struct mmc_host *mmc) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err; + u8 stat; + u8 mask = SD_DAT3_STATUS | SD_DAT2_STATUS | SD_DAT1_STATUS + | SD_DAT0_STATUS; + + dev_dbg(sdmmc_dev(host), "%s\n", __func__); + + mutex_lock(&ucr->dev_mutex); + + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, + SD_CLK_TOGGLE_EN); + if (err) + goto out; + + mdelay(1); + + err = rtsx_usb_read_register(ucr, SD_BUS_STAT, &stat); + if (err) + goto out; + + err = rtsx_usb_write_register(ucr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); +out: + mutex_unlock(&ucr->dev_mutex); + + if (err) + return err; + + /* check if any pin between dat[0:3] is low */ + if ((stat & mask) != mask) + return 1; + else + return 0; +} + +static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct rtsx_usb_sdmmc *host = mmc_priv(mmc); + struct rtsx_ucr *ucr = host->ucr; + int err = 0; + + if (host->host_removal) + return -ENOMEDIUM; + + mutex_lock(&ucr->dev_mutex); + + if (!host->ddr_mode) + err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + + mutex_unlock(&ucr->dev_mutex); + + return err; +} + +static const struct mmc_host_ops rtsx_usb_sdmmc_ops = { + .request = sdmmc_request, + .set_ios = sdmmc_set_ios, + .get_ro = sdmmc_get_ro, + .get_cd = sdmmc_get_cd, + .start_signal_voltage_switch = sdmmc_switch_voltage, + .card_busy = sdmmc_card_busy, + .execute_tuning = sdmmc_execute_tuning, +}; + +#ifdef RTSX_USB_USE_LEDS_CLASS +static void rtsx_usb_led_control(struct led_classdev *led, + enum led_brightness brightness) +{ + struct rtsx_usb_sdmmc *host = container_of(led, + struct rtsx_usb_sdmmc, led); + + if (host->host_removal) + return; + + host->led.brightness = brightness; + schedule_work(&host->led_work); +} + +static void rtsx_usb_update_led(struct work_struct *work) +{ + struct rtsx_usb_sdmmc *host = + container_of(work, struct rtsx_usb_sdmmc, led_work); + struct rtsx_ucr *ucr = host->ucr; + + mutex_lock(&ucr->dev_mutex); + + if (host->led.brightness == LED_OFF) + rtsx_usb_turn_off_led(ucr); + else + rtsx_usb_turn_on_led(ucr); + + mutex_unlock(&ucr->dev_mutex); +} +#endif + +static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + + mmc->f_min = 250000; + mmc->f_max = 208000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | + MMC_CAP_NEEDS_POLL; + + mmc->max_current_330 = 400; + mmc->max_current_180 = 800; + mmc->ops = &rtsx_usb_sdmmc_ops; + mmc->max_segs = 256; + mmc->max_seg_size = 65536; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; + mmc->max_req_size = 524288; + + host->power_mode = MMC_POWER_OFF; +} + +static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct rtsx_usb_sdmmc *host; + struct rtsx_ucr *ucr; +#ifdef RTSX_USB_USE_LEDS_CLASS + int err; +#endif + + ucr = usb_get_intfdata(to_usb_interface(pdev->dev.parent)); + if (!ucr) + return -ENXIO; + + dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n"); + + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->ucr = ucr; + host->mmc = mmc; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + + mutex_init(&host->host_mutex); + rtsx_usb_init_host(host); + pm_runtime_enable(&pdev->dev); + +#ifdef RTSX_USB_USE_LEDS_CLASS + snprintf(host->led_name, sizeof(host->led_name), + "%s::", mmc_hostname(mmc)); + host->led.name = host->led_name; + host->led.brightness = LED_OFF; + host->led.default_trigger = mmc_hostname(mmc); + host->led.brightness_set = rtsx_usb_led_control; + + err = led_classdev_register(mmc_dev(mmc), &host->led); + if (err) + dev_err(&(pdev->dev), + "Failed to register LED device: %d\n", err); + INIT_WORK(&host->led_work, rtsx_usb_update_led); + +#endif + mmc_add_host(mmc); + + return 0; +} + +static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev) +{ + struct rtsx_usb_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc; + + if (!host) + return 0; + + mmc = host->mmc; + host->host_removal = true; + + mutex_lock(&host->host_mutex); + if (host->mrq) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + mmc_hostname(mmc)); + host->mrq->cmd->error = -ENOMEDIUM; + if (host->mrq->stop) + host->mrq->stop->error = -ENOMEDIUM; + mmc_request_done(mmc, host->mrq); + } + mutex_unlock(&host->host_mutex); + + mmc_remove_host(mmc); + +#ifdef RTSX_USB_USE_LEDS_CLASS + cancel_work_sync(&host->led_work); + led_classdev_unregister(&host->led); +#endif + + mmc_free_host(mmc); + pm_runtime_disable(&pdev->dev); + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek USB SD/MMC module has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_usb_sdmmc_ids[] = { + { + .name = "rtsx_usb_sdmmc", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_usb_sdmmc_ids); + +static struct platform_driver rtsx_usb_sdmmc_driver = { + .probe = rtsx_usb_sdmmc_drv_probe, + .remove = rtsx_usb_sdmmc_drv_remove, + .id_table = rtsx_usb_sdmmc_ids, + .driver = { + .owner = THIS_MODULE, + .name = "rtsx_usb_sdmmc", + }, +}; +module_platform_driver(rtsx_usb_sdmmc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>"); +MODULE_DESCRIPTION("Realtek USB SD/MMC Card Host Driver"); diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 476af93543f6..8ec2d6a1dbe1 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -40,6 +40,7 @@ struct s5m_rtc_info { struct device *dev; + struct i2c_client *i2c; struct sec_pmic_dev *s5m87xx; struct regmap *regmap; struct rtc_device *rtc_dev; @@ -49,6 +50,20 @@ struct s5m_rtc_info { bool wtsr_smpl; }; +static const struct regmap_config s5m_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SEC_RTC_REG_MAX, +}; + +static const struct regmap_config s2mps14_rtc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS_RTC_REG_MAX, +}; + static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, int rtc_24hr_mode) { @@ -554,6 +569,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = s5m87xx->pdata; struct s5m_rtc_info *info; + const struct regmap_config *regmap_cfg; int ret; if (!pdata) { @@ -565,9 +581,37 @@ static int s5m_rtc_probe(struct platform_device *pdev) if (!info) return -ENOMEM; + switch (pdata->device_type) { + case S2MPS14X: + regmap_cfg = &s2mps14_rtc_regmap_config; + break; + case S5M8763X: + regmap_cfg = &s5m_rtc_regmap_config; + break; + case S5M8767X: + regmap_cfg = &s5m_rtc_regmap_config; + break; + default: + dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); + return -ENODEV; + } + + info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); + if (!info->i2c) { + dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); + return -ENODEV; + } + + info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n", + ret); + goto err; + } + info->dev = &pdev->dev; info->s5m87xx = s5m87xx; - info->regmap = s5m87xx->regmap_rtc; info->device_type = s5m87xx->device_type; info->wtsr_smpl = s5m87xx->wtsr_smpl; @@ -585,7 +629,7 @@ static int s5m_rtc_probe(struct platform_device *pdev) default: ret = -EINVAL; dev_err(&pdev->dev, "Unsupported device type: %d\n", ret); - return ret; + goto err; } platform_set_drvdata(pdev, info); @@ -602,15 +646,24 @@ static int s5m_rtc_probe(struct platform_device *pdev) info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", &s5m_rtc_ops, THIS_MODULE); - if (IS_ERR(info->rtc_dev)) - return PTR_ERR(info->rtc_dev); + if (IS_ERR(info->rtc_dev)) { + ret = PTR_ERR(info->rtc_dev); + goto err; + } ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, s5m_rtc_alarm_irq, 0, "rtc-alarm0", info); - if (ret < 0) + if (ret < 0) { dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", info->irq, ret); + goto err; + } + + return 0; + +err: + i2c_unregister_device(info->i2c); return ret; } @@ -639,6 +692,17 @@ static void s5m_rtc_shutdown(struct platform_device *pdev) s5m_rtc_enable_smpl(info, false); } +static int s5m_rtc_remove(struct platform_device *pdev) +{ + struct s5m_rtc_info *info = platform_get_drvdata(pdev); + + /* Perform also all shutdown steps when removing */ + s5m_rtc_shutdown(pdev); + i2c_unregister_device(info->i2c); + + return 0; +} + #ifdef CONFIG_PM_SLEEP static int s5m_rtc_resume(struct device *dev) { @@ -676,6 +740,7 @@ static struct platform_driver s5m_rtc_driver = { .pm = &s5m_rtc_pm_ops, }, .probe = s5m_rtc_probe, + .remove = s5m_rtc_remove, .shutdown = s5m_rtc_shutdown, .id_table = s5m_rtc_id, }; diff --git a/drivers/sh/intc/Kconfig b/drivers/sh/intc/Kconfig index f7d90617c9d9..60228fae943f 100644 --- a/drivers/sh/intc/Kconfig +++ b/drivers/sh/intc/Kconfig @@ -6,7 +6,7 @@ comment "Interrupt controller options" config INTC_USERIMASK bool "Userspace interrupt masking support" - depends on ARCH_SHMOBILE || (SUPERH && CPU_SH4A) || COMPILE_TEST + depends on (SUPERH && CPU_SH4A) || COMPILE_TEST help This enables support for hardware-assisted userspace hardirq masking. diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c index 10c65eb51f85..72f63817a1a0 100644 --- a/drivers/sh/pm_runtime.c +++ b/drivers/sh/pm_runtime.c @@ -21,18 +21,43 @@ #include <linux/slab.h> #ifdef CONFIG_PM_RUNTIME - -static int default_platform_runtime_idle(struct device *dev) +static int sh_pm_runtime_suspend(struct device *dev) { - /* suspend synchronously to disable clocks immediately */ + int ret; + + ret = pm_generic_runtime_suspend(dev); + if (ret) { + dev_err(dev, "failed to suspend device\n"); + return ret; + } + + ret = pm_clk_suspend(dev); + if (ret) { + dev_err(dev, "failed to suspend clock\n"); + pm_generic_runtime_resume(dev); + return ret; + } + return 0; } +static int sh_pm_runtime_resume(struct device *dev) +{ + int ret; + + ret = pm_clk_resume(dev); + if (ret) { + dev_err(dev, "failed to resume clock\n"); + return ret; + } + + return pm_generic_runtime_resume(dev); +} + static struct dev_pm_domain default_pm_domain = { .ops = { - .runtime_suspend = pm_clk_suspend, - .runtime_resume = pm_clk_resume, - .runtime_idle = default_platform_runtime_idle, + .runtime_suspend = sh_pm_runtime_suspend, + .runtime_resume = sh_pm_runtime_resume, USE_PLATFORM_PM_SLEEP_OPS }, }; @@ -63,6 +88,9 @@ static int __init sh_pm_runtime_init(void) !of_machine_is_compatible("renesas,r8a7779") && !of_machine_is_compatible("renesas,r8a7790") && !of_machine_is_compatible("renesas,r8a7791") && + !of_machine_is_compatible("renesas,r8a7792") && + !of_machine_is_compatible("renesas,r8a7793") && + !of_machine_is_compatible("renesas,r8a7794") && !of_machine_is_compatible("renesas,sh7372") && !of_machine_is_compatible("renesas,sh73a0")) return 0; diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h index 3301b2031c8d..552cc1d61cc7 100644 --- a/include/linux/mfd/abx500.h +++ b/include/linux/mfd/abx500.h @@ -330,7 +330,6 @@ int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank, int abx500_get_chip_id(struct device *dev); int abx500_event_registers_startup_state_get(struct device *dev, u8 *event); int abx500_startup_irq_enabled(struct device *dev, unsigned int irq); -void abx500_dump_all_banks(void); struct abx500_ops { int (*get_chip_id) (struct device *); diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 7b35c21170d5..7204d8138b24 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -42,12 +42,14 @@ #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2 0x62 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3 0x63 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4 0x64 -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1 0x68 -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2 0x69 -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3 0x6A -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4 0x6B -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5 0x6C -#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6 0x6D +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1 0x66 +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2 0x67 +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3 0x68 +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4 0x69 +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5 0x6A +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6 0x6B +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_7 0x6C +#define ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_8 0x6D #define ARIZONA_COMFORT_NOISE_GENERATOR 0x70 #define ARIZONA_HAPTICS_CONTROL_1 0x90 #define ARIZONA_HAPTICS_CONTROL_2 0x91 diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h new file mode 100644 index 000000000000..d0e31a2287ac --- /dev/null +++ b/include/linux/mfd/axp20x.h @@ -0,0 +1,180 @@ +/* + * Functions and registers to access AXP20X power management chip. + * + * Copyright (C) 2013, Carlo Caione <carlo@caione.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_MFD_AXP20X_H +#define __LINUX_MFD_AXP20X_H + +enum { + AXP202_ID = 0, + AXP209_ID, +}; + +#define AXP20X_DATACACHE(m) (0x04 + (m)) + +/* Power supply */ +#define AXP20X_PWR_INPUT_STATUS 0x00 +#define AXP20X_PWR_OP_MODE 0x01 +#define AXP20X_USB_OTG_STATUS 0x02 +#define AXP20X_PWR_OUT_CTRL 0x12 +#define AXP20X_DCDC2_V_OUT 0x23 +#define AXP20X_DCDC2_LDO3_V_SCAL 0x25 +#define AXP20X_DCDC3_V_OUT 0x27 +#define AXP20X_LDO24_V_OUT 0x28 +#define AXP20X_LDO3_V_OUT 0x29 +#define AXP20X_VBUS_IPSOUT_MGMT 0x30 +#define AXP20X_V_OFF 0x31 +#define AXP20X_OFF_CTRL 0x32 +#define AXP20X_CHRG_CTRL1 0x33 +#define AXP20X_CHRG_CTRL2 0x34 +#define AXP20X_CHRG_BAK_CTRL 0x35 +#define AXP20X_PEK_KEY 0x36 +#define AXP20X_DCDC_FREQ 0x37 +#define AXP20X_V_LTF_CHRG 0x38 +#define AXP20X_V_HTF_CHRG 0x39 +#define AXP20X_APS_WARN_L1 0x3a +#define AXP20X_APS_WARN_L2 0x3b +#define AXP20X_V_LTF_DISCHRG 0x3c +#define AXP20X_V_HTF_DISCHRG 0x3d + +/* Interrupt */ +#define AXP20X_IRQ1_EN 0x40 +#define AXP20X_IRQ2_EN 0x41 +#define AXP20X_IRQ3_EN 0x42 +#define AXP20X_IRQ4_EN 0x43 +#define AXP20X_IRQ5_EN 0x44 +#define AXP20X_IRQ1_STATE 0x48 +#define AXP20X_IRQ2_STATE 0x49 +#define AXP20X_IRQ3_STATE 0x4a +#define AXP20X_IRQ4_STATE 0x4b +#define AXP20X_IRQ5_STATE 0x4c + +/* ADC */ +#define AXP20X_ACIN_V_ADC_H 0x56 +#define AXP20X_ACIN_V_ADC_L 0x57 +#define AXP20X_ACIN_I_ADC_H 0x58 +#define AXP20X_ACIN_I_ADC_L 0x59 +#define AXP20X_VBUS_V_ADC_H 0x5a +#define AXP20X_VBUS_V_ADC_L 0x5b +#define AXP20X_VBUS_I_ADC_H 0x5c +#define AXP20X_VBUS_I_ADC_L 0x5d +#define AXP20X_TEMP_ADC_H 0x5e +#define AXP20X_TEMP_ADC_L 0x5f +#define AXP20X_TS_IN_H 0x62 +#define AXP20X_TS_IN_L 0x63 +#define AXP20X_GPIO0_V_ADC_H 0x64 +#define AXP20X_GPIO0_V_ADC_L 0x65 +#define AXP20X_GPIO1_V_ADC_H 0x66 +#define AXP20X_GPIO1_V_ADC_L 0x67 +#define AXP20X_PWR_BATT_H 0x70 +#define AXP20X_PWR_BATT_M 0x71 +#define AXP20X_PWR_BATT_L 0x72 +#define AXP20X_BATT_V_H 0x78 +#define AXP20X_BATT_V_L 0x79 +#define AXP20X_BATT_CHRG_I_H 0x7a +#define AXP20X_BATT_CHRG_I_L 0x7b +#define AXP20X_BATT_DISCHRG_I_H 0x7c +#define AXP20X_BATT_DISCHRG_I_L 0x7d +#define AXP20X_IPSOUT_V_HIGH_H 0x7e +#define AXP20X_IPSOUT_V_HIGH_L 0x7f + +/* Power supply */ +#define AXP20X_DCDC_MODE 0x80 +#define AXP20X_ADC_EN1 0x82 +#define AXP20X_ADC_EN2 0x83 +#define AXP20X_ADC_RATE 0x84 +#define AXP20X_GPIO10_IN_RANGE 0x85 +#define AXP20X_GPIO1_ADC_IRQ_RIS 0x86 +#define AXP20X_GPIO1_ADC_IRQ_FAL 0x87 +#define AXP20X_TIMER_CTRL 0x8a +#define AXP20X_VBUS_MON 0x8b +#define AXP20X_OVER_TMP 0x8f + +/* GPIO */ +#define AXP20X_GPIO0_CTRL 0x90 +#define AXP20X_LDO5_V_OUT 0x91 +#define AXP20X_GPIO1_CTRL 0x92 +#define AXP20X_GPIO2_CTRL 0x93 +#define AXP20X_GPIO20_SS 0x94 +#define AXP20X_GPIO3_CTRL 0x95 + +/* Battery */ +#define AXP20X_CHRG_CC_31_24 0xb0 +#define AXP20X_CHRG_CC_23_16 0xb1 +#define AXP20X_CHRG_CC_15_8 0xb2 +#define AXP20X_CHRG_CC_7_0 0xb3 +#define AXP20X_DISCHRG_CC_31_24 0xb4 +#define AXP20X_DISCHRG_CC_23_16 0xb5 +#define AXP20X_DISCHRG_CC_15_8 0xb6 +#define AXP20X_DISCHRG_CC_7_0 0xb7 +#define AXP20X_CC_CTRL 0xb8 +#define AXP20X_FG_RES 0xb9 + +/* Regulators IDs */ +enum { + AXP20X_LDO1 = 0, + AXP20X_LDO2, + AXP20X_LDO3, + AXP20X_LDO4, + AXP20X_LDO5, + AXP20X_DCDC2, + AXP20X_DCDC3, + AXP20X_REG_ID_MAX, +}; + +/* IRQs */ +enum { + AXP20X_IRQ_ACIN_OVER_V = 1, + AXP20X_IRQ_ACIN_PLUGIN, + AXP20X_IRQ_ACIN_REMOVAL, + AXP20X_IRQ_VBUS_OVER_V, + AXP20X_IRQ_VBUS_PLUGIN, + AXP20X_IRQ_VBUS_REMOVAL, + AXP20X_IRQ_VBUS_V_LOW, + AXP20X_IRQ_BATT_PLUGIN, + AXP20X_IRQ_BATT_REMOVAL, + AXP20X_IRQ_BATT_ENT_ACT_MODE, + AXP20X_IRQ_BATT_EXIT_ACT_MODE, + AXP20X_IRQ_CHARG, + AXP20X_IRQ_CHARG_DONE, + AXP20X_IRQ_BATT_TEMP_HIGH, + AXP20X_IRQ_BATT_TEMP_LOW, + AXP20X_IRQ_DIE_TEMP_HIGH, + AXP20X_IRQ_CHARG_I_LOW, + AXP20X_IRQ_DCDC1_V_LONG, + AXP20X_IRQ_DCDC2_V_LONG, + AXP20X_IRQ_DCDC3_V_LONG, + AXP20X_IRQ_PEK_SHORT = 22, + AXP20X_IRQ_PEK_LONG, + AXP20X_IRQ_N_OE_PWR_ON, + AXP20X_IRQ_N_OE_PWR_OFF, + AXP20X_IRQ_VBUS_VALID, + AXP20X_IRQ_VBUS_NOT_VALID, + AXP20X_IRQ_VBUS_SESS_VALID, + AXP20X_IRQ_VBUS_SESS_END, + AXP20X_IRQ_LOW_PWR_LVL1, + AXP20X_IRQ_LOW_PWR_LVL2, + AXP20X_IRQ_TIMER, + AXP20X_IRQ_PEK_RIS_EDGE, + AXP20X_IRQ_PEK_FAL_EDGE, + AXP20X_IRQ_GPIO3_INPUT, + AXP20X_IRQ_GPIO2_INPUT, + AXP20X_IRQ_GPIO1_INPUT, + AXP20X_IRQ_GPIO0_INPUT, +}; + +struct axp20x_dev { + struct device *dev; + struct i2c_client *i2c_client; + struct regmap *regmap; + struct regmap_irq_chip_data *regmap_irqc; + long variant; +}; + +#endif /* __LINUX_MFD_AXP20X_H */ diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 032af7fc5b2e..887ef4f7bef7 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h @@ -29,8 +29,8 @@ enum { EC_MSG_RX_PROTO_BYTES = 3, /* Max length of messages */ - EC_MSG_BYTES = EC_HOST_PARAM_SIZE + EC_MSG_TX_PROTO_BYTES, - + EC_MSG_BYTES = EC_PROTO2_MAX_PARAM_SIZE + + EC_MSG_TX_PROTO_BYTES, }; /** diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index 86fd06953bcd..7853a6410d14 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h @@ -24,25 +24,12 @@ #define __CROS_EC_COMMANDS_H /* - * Protocol overview + * Current version of this protocol * - * request: CMD [ P0 P1 P2 ... Pn S ] - * response: ERR [ P0 P1 P2 ... Pn S ] - * - * where the bytes are defined as follow : - * - CMD is the command code. (defined by EC_CMD_ constants) - * - ERR is the error code. (defined by EC_RES_ constants) - * - Px is the optional payload. - * it is not sent if the error code is not success. - * (defined by ec_params_ and ec_response_ structures) - * - S is the checksum which is the sum of all payload bytes. - * - * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD - * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM. - * On I2C, all bytes are sent serially in the same message. + * TODO(crosbug.com/p/11223): This is effectively useless; protocol is + * determined in other ways. Remove this once the kernel code no longer + * depends on it. */ - -/* Current version of this protocol */ #define EC_PROTO_VERSION 0x00000002 /* Command version mask */ @@ -57,13 +44,19 @@ #define EC_LPC_ADDR_HOST_CMD 0x204 /* I/O addresses for host command args and params */ -#define EC_LPC_ADDR_HOST_ARGS 0x800 -#define EC_LPC_ADDR_HOST_PARAM 0x804 -#define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */ - -/* I/O addresses for host command params, old interface */ -#define EC_LPC_ADDR_OLD_PARAM 0x880 -#define EC_OLD_PARAM_SIZE 0x080 /* Size of param area in bytes */ +/* Protocol version 2 */ +#define EC_LPC_ADDR_HOST_ARGS 0x800 /* And 0x801, 0x802, 0x803 */ +#define EC_LPC_ADDR_HOST_PARAM 0x804 /* For version 2 params; size is + * EC_PROTO2_MAX_PARAM_SIZE */ +/* Protocol version 3 */ +#define EC_LPC_ADDR_HOST_PACKET 0x800 /* Offset of version 3 packet */ +#define EC_LPC_HOST_PACKET_SIZE 0x100 /* Max size of version 3 packet */ + +/* The actual block is 0x800-0x8ff, but some BIOSes think it's 0x880-0x8ff + * and they tell the kernel that so we have to think of it as two parts. */ +#define EC_HOST_CMD_REGION0 0x800 +#define EC_HOST_CMD_REGION1 0x880 +#define EC_HOST_CMD_REGION_SIZE 0x80 /* EC command register bit functions */ #define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */ @@ -79,18 +72,22 @@ #define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */ /* The offset address of each type of data in mapped memory. */ -#define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors */ -#define EC_MEMMAP_FAN 0x10 /* Fan speeds */ -#define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* Temp sensors (second set) */ -#define EC_MEMMAP_ID 0x20 /* 'E' 'C' */ +#define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors 0x00 - 0x0f */ +#define EC_MEMMAP_FAN 0x10 /* Fan speeds 0x10 - 0x17 */ +#define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* More temp sensors 0x18 - 0x1f */ +#define EC_MEMMAP_ID 0x20 /* 0x20 == 'E', 0x21 == 'C' */ #define EC_MEMMAP_ID_VERSION 0x22 /* Version of data in 0x20 - 0x2f */ #define EC_MEMMAP_THERMAL_VERSION 0x23 /* Version of data in 0x00 - 0x1f */ #define EC_MEMMAP_BATTERY_VERSION 0x24 /* Version of data in 0x40 - 0x7f */ #define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */ #define EC_MEMMAP_EVENTS_VERSION 0x26 /* Version of data in 0x34 - 0x3f */ -#define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host command interface flags */ -#define EC_MEMMAP_SWITCHES 0x30 -#define EC_MEMMAP_HOST_EVENTS 0x34 +#define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host cmd interface flags (8 bits) */ +/* Unused 0x28 - 0x2f */ +#define EC_MEMMAP_SWITCHES 0x30 /* 8 bits */ +/* Unused 0x31 - 0x33 */ +#define EC_MEMMAP_HOST_EVENTS 0x34 /* 32 bits */ +/* Reserve 0x38 - 0x3f for additional host event-related stuff */ +/* Battery values are all 32 bits */ #define EC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */ #define EC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */ #define EC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */ @@ -99,10 +96,24 @@ #define EC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */ #define EC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */ #define EC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */ +/* Strings are all 8 bytes (EC_MEMMAP_TEXT_MAX) */ #define EC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */ #define EC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */ #define EC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */ #define EC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */ +#define EC_MEMMAP_ALS 0x80 /* ALS readings in lux (2 X 16 bits) */ +/* Unused 0x84 - 0x8f */ +#define EC_MEMMAP_ACC_STATUS 0x90 /* Accelerometer status (8 bits )*/ +/* Unused 0x91 */ +#define EC_MEMMAP_ACC_DATA 0x92 /* Accelerometer data 0x92 - 0x9f */ +#define EC_MEMMAP_GYRO_DATA 0xa0 /* Gyroscope data 0xa0 - 0xa5 */ +/* Unused 0xa6 - 0xfe (remember, 0xff is NOT part of the memmap region) */ + + +/* Define the format of the accelerometer mapped memory status byte. */ +#define EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK 0x0f +#define EC_MEMMAP_ACC_STATUS_BUSY_BIT (1 << 4) +#define EC_MEMMAP_ACC_STATUS_PRESENCE_BIT (1 << 7) /* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */ #define EC_TEMP_SENSOR_ENTRIES 16 @@ -112,6 +123,8 @@ * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2. */ #define EC_TEMP_SENSOR_B_ENTRIES 8 + +/* Special values for mapped temperature sensors */ #define EC_TEMP_SENSOR_NOT_PRESENT 0xff #define EC_TEMP_SENSOR_ERROR 0xfe #define EC_TEMP_SENSOR_NOT_POWERED 0xfd @@ -122,6 +135,18 @@ */ #define EC_TEMP_SENSOR_OFFSET 200 +/* + * Number of ALS readings at EC_MEMMAP_ALS + */ +#define EC_ALS_ENTRIES 2 + +/* + * The default value a temperature sensor will return when it is present but + * has not been read this boot. This is a reasonable number to avoid + * triggering alarms on the host. + */ +#define EC_TEMP_SENSOR_DEFAULT (296 - EC_TEMP_SENSOR_OFFSET) + #define EC_FAN_SPEED_ENTRIES 4 /* Number of fans at EC_MEMMAP_FAN */ #define EC_FAN_SPEED_NOT_PRESENT 0xffff /* Entry not present */ #define EC_FAN_SPEED_STALLED 0xfffe /* Fan stalled */ @@ -137,8 +162,8 @@ #define EC_SWITCH_LID_OPEN 0x01 #define EC_SWITCH_POWER_BUTTON_PRESSED 0x02 #define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04 -/* Recovery requested via keyboard */ -#define EC_SWITCH_KEYBOARD_RECOVERY 0x08 +/* Was recovery requested via keyboard; now unused. */ +#define EC_SWITCH_IGNORE1 0x08 /* Recovery requested via dedicated signal (from servo board) */ #define EC_SWITCH_DEDICATED_RECOVERY 0x10 /* Was fake developer mode switch; now unused. Remove in next refactor. */ @@ -147,10 +172,15 @@ /* Host command interface flags */ /* Host command interface supports LPC args (LPC interface only) */ #define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED 0x01 +/* Host command interface supports version 3 protocol */ +#define EC_HOST_CMD_FLAG_VERSION_3 0x02 /* Wireless switch flags */ -#define EC_WIRELESS_SWITCH_WLAN 0x01 -#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 +#define EC_WIRELESS_SWITCH_ALL ~0x00 /* All flags */ +#define EC_WIRELESS_SWITCH_WLAN 0x01 /* WLAN radio */ +#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 /* Bluetooth radio */ +#define EC_WIRELESS_SWITCH_WWAN 0x04 /* WWAN power */ +#define EC_WIRELESS_SWITCH_WLAN_POWER 0x08 /* WLAN power */ /* * This header file is used in coreboot both in C and ACPI code. The ACPI code @@ -159,6 +189,14 @@ */ #ifndef __ACPI__ +/* + * Define __packed if someone hasn't beat us to it. Linux kernel style + * checking prefers __packed over __attribute__((packed)). + */ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + /* LPC command status byte masks */ /* EC has written a byte in the data register and host hasn't read it yet */ #define EC_LPC_STATUS_TO_HOST 0x01 @@ -198,6 +236,9 @@ enum ec_status { EC_RES_UNAVAILABLE = 9, /* No response available */ EC_RES_TIMEOUT = 10, /* We got a timeout */ EC_RES_OVERFLOW = 11, /* Table / data overflow */ + EC_RES_INVALID_HEADER = 12, /* Header contains invalid data */ + EC_RES_REQUEST_TRUNCATED = 13, /* Didn't get the entire request */ + EC_RES_RESPONSE_TOO_BIG = 14 /* Response was too big to handle */ }; /* @@ -235,6 +276,16 @@ enum host_event_code { /* Shutdown due to battery level too low */ EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, + /* Suggest that the AP throttle itself */ + EC_HOST_EVENT_THROTTLE_START = 18, + /* Suggest that the AP resume normal speed */ + EC_HOST_EVENT_THROTTLE_STOP = 19, + + /* Hang detect logic detected a hang and host event timeout expired */ + EC_HOST_EVENT_HANG_DETECT = 20, + /* Hang detect logic detected a hang and warm rebooted the AP */ + EC_HOST_EVENT_HANG_REBOOT = 21, + /* * The high bit of the event mask is not used as a host event code. If * it reads back as set, then the entire event mask should be @@ -279,6 +330,188 @@ struct ec_lpc_host_args { */ #define EC_HOST_ARGS_FLAG_TO_HOST 0x02 +/*****************************************************************************/ +/* + * Byte codes returned by EC over SPI interface. + * + * These can be used by the AP to debug the EC interface, and to determine + * when the EC is not in a state where it will ever get around to responding + * to the AP. + * + * Example of sequence of bytes read from EC for a current good transfer: + * 1. - - AP asserts chip select (CS#) + * 2. EC_SPI_OLD_READY - AP sends first byte(s) of request + * 3. - - EC starts handling CS# interrupt + * 4. EC_SPI_RECEIVING - AP sends remaining byte(s) of request + * 5. EC_SPI_PROCESSING - EC starts processing request; AP is clocking in + * bytes looking for EC_SPI_FRAME_START + * 6. - - EC finishes processing and sets up response + * 7. EC_SPI_FRAME_START - AP reads frame byte + * 8. (response packet) - AP reads response packet + * 9. EC_SPI_PAST_END - Any additional bytes read by AP + * 10 - - AP deasserts chip select + * 11 - - EC processes CS# interrupt and sets up DMA for + * next request + * + * If the AP is waiting for EC_SPI_FRAME_START and sees any value other than + * the following byte values: + * EC_SPI_OLD_READY + * EC_SPI_RX_READY + * EC_SPI_RECEIVING + * EC_SPI_PROCESSING + * + * Then the EC found an error in the request, or was not ready for the request + * and lost data. The AP should give up waiting for EC_SPI_FRAME_START, + * because the EC is unable to tell when the AP is done sending its request. + */ + +/* + * Framing byte which precedes a response packet from the EC. After sending a + * request, the AP will clock in bytes until it sees the framing byte, then + * clock in the response packet. + */ +#define EC_SPI_FRAME_START 0xec + +/* + * Padding bytes which are clocked out after the end of a response packet. + */ +#define EC_SPI_PAST_END 0xed + +/* + * EC is ready to receive, and has ignored the byte sent by the AP. EC expects + * that the AP will send a valid packet header (starting with + * EC_COMMAND_PROTOCOL_3) in the next 32 bytes. + */ +#define EC_SPI_RX_READY 0xf8 + +/* + * EC has started receiving the request from the AP, but hasn't started + * processing it yet. + */ +#define EC_SPI_RECEIVING 0xf9 + +/* EC has received the entire request from the AP and is processing it. */ +#define EC_SPI_PROCESSING 0xfa + +/* + * EC received bad data from the AP, such as a packet header with an invalid + * length. EC will ignore all data until chip select deasserts. + */ +#define EC_SPI_RX_BAD_DATA 0xfb + +/* + * EC received data from the AP before it was ready. That is, the AP asserted + * chip select and started clocking data before the EC was ready to receive it. + * EC will ignore all data until chip select deasserts. + */ +#define EC_SPI_NOT_READY 0xfc + +/* + * EC was ready to receive a request from the AP. EC has treated the byte sent + * by the AP as part of a request packet, or (for old-style ECs) is processing + * a fully received packet but is not ready to respond yet. + */ +#define EC_SPI_OLD_READY 0xfd + +/*****************************************************************************/ + +/* + * Protocol version 2 for I2C and SPI send a request this way: + * + * 0 EC_CMD_VERSION0 + (command version) + * 1 Command number + * 2 Length of params = N + * 3..N+2 Params, if any + * N+3 8-bit checksum of bytes 0..N+2 + * + * The corresponding response is: + * + * 0 Result code (EC_RES_*) + * 1 Length of params = M + * 2..M+1 Params, if any + * M+2 8-bit checksum of bytes 0..M+1 + */ +#define EC_PROTO2_REQUEST_HEADER_BYTES 3 +#define EC_PROTO2_REQUEST_TRAILER_BYTES 1 +#define EC_PROTO2_REQUEST_OVERHEAD (EC_PROTO2_REQUEST_HEADER_BYTES + \ + EC_PROTO2_REQUEST_TRAILER_BYTES) + +#define EC_PROTO2_RESPONSE_HEADER_BYTES 2 +#define EC_PROTO2_RESPONSE_TRAILER_BYTES 1 +#define EC_PROTO2_RESPONSE_OVERHEAD (EC_PROTO2_RESPONSE_HEADER_BYTES + \ + EC_PROTO2_RESPONSE_TRAILER_BYTES) + +/* Parameter length was limited by the LPC interface */ +#define EC_PROTO2_MAX_PARAM_SIZE 0xfc + +/* Maximum request and response packet sizes for protocol version 2 */ +#define EC_PROTO2_MAX_REQUEST_SIZE (EC_PROTO2_REQUEST_OVERHEAD + \ + EC_PROTO2_MAX_PARAM_SIZE) +#define EC_PROTO2_MAX_RESPONSE_SIZE (EC_PROTO2_RESPONSE_OVERHEAD + \ + EC_PROTO2_MAX_PARAM_SIZE) + +/*****************************************************************************/ + +/* + * Value written to legacy command port / prefix byte to indicate protocol + * 3+ structs are being used. Usage is bus-dependent. + */ +#define EC_COMMAND_PROTOCOL_3 0xda + +#define EC_HOST_REQUEST_VERSION 3 + +/* Version 3 request from host */ +struct ec_host_request { + /* Struct version (=3) + * + * EC will return EC_RES_INVALID_HEADER if it receives a header with a + * version it doesn't know how to parse. + */ + uint8_t struct_version; + + /* + * Checksum of request and data; sum of all bytes including checksum + * should total to 0. + */ + uint8_t checksum; + + /* Command code */ + uint16_t command; + + /* Command version */ + uint8_t command_version; + + /* Unused byte in current protocol version; set to 0 */ + uint8_t reserved; + + /* Length of data which follows this header */ + uint16_t data_len; +} __packed; + +#define EC_HOST_RESPONSE_VERSION 3 + +/* Version 3 response from EC */ +struct ec_host_response { + /* Struct version (=3) */ + uint8_t struct_version; + + /* + * Checksum of response and data; sum of all bytes including checksum + * should total to 0. + */ + uint8_t checksum; + + /* Result code (EC_RES_*) */ + uint16_t result; + + /* Length of data which follows this header */ + uint16_t data_len; + + /* Unused bytes in current protocol version; set to 0 */ + uint16_t reserved; +} __packed; + +/*****************************************************************************/ /* * Notes on commands: * @@ -418,6 +651,68 @@ struct ec_response_get_comms_status { uint32_t flags; /* Mask of enum ec_comms_status */ } __packed; +/* Fake a variety of responses, purely for testing purposes. */ +#define EC_CMD_TEST_PROTOCOL 0x0a + +/* Tell the EC what to send back to us. */ +struct ec_params_test_protocol { + uint32_t ec_result; + uint32_t ret_len; + uint8_t buf[32]; +} __packed; + +/* Here it comes... */ +struct ec_response_test_protocol { + uint8_t buf[32]; +} __packed; + +/* Get prococol information */ +#define EC_CMD_GET_PROTOCOL_INFO 0x0b + +/* Flags for ec_response_get_protocol_info.flags */ +/* EC_RES_IN_PROGRESS may be returned if a command is slow */ +#define EC_PROTOCOL_INFO_IN_PROGRESS_SUPPORTED (1 << 0) + +struct ec_response_get_protocol_info { + /* Fields which exist if at least protocol version 3 supported */ + + /* Bitmask of protocol versions supported (1 << n means version n)*/ + uint32_t protocol_versions; + + /* Maximum request packet size, in bytes */ + uint16_t max_request_packet_size; + + /* Maximum response packet size, in bytes */ + uint16_t max_response_packet_size; + + /* Flags; see EC_PROTOCOL_INFO_* */ + uint32_t flags; +} __packed; + + +/*****************************************************************************/ +/* Get/Set miscellaneous values */ + +/* The upper byte of .flags tells what to do (nothing means "get") */ +#define EC_GSV_SET 0x80000000 + +/* The lower three bytes of .flags identifies the parameter, if that has + meaning for an individual command. */ +#define EC_GSV_PARAM_MASK 0x00ffffff + +struct ec_params_get_set_value { + uint32_t flags; + uint32_t value; +} __packed; + +struct ec_response_get_set_value { + uint32_t flags; + uint32_t value; +} __packed; + +/* More than one command can use these structs to get/set paramters. */ +#define EC_CMD_GSV_PAUSE_IN_S5 0x0c + /*****************************************************************************/ /* Flash commands */ @@ -425,6 +720,7 @@ struct ec_response_get_comms_status { /* Get flash info */ #define EC_CMD_FLASH_INFO 0x10 +/* Version 0 returns these fields */ struct ec_response_flash_info { /* Usable flash size, in bytes */ uint32_t flash_size; @@ -445,6 +741,37 @@ struct ec_response_flash_info { uint32_t protect_block_size; } __packed; +/* Flags for version 1+ flash info command */ +/* EC flash erases bits to 0 instead of 1 */ +#define EC_FLASH_INFO_ERASE_TO_0 (1 << 0) + +/* + * Version 1 returns the same initial fields as version 0, with additional + * fields following. + * + * gcc anonymous structs don't seem to get along with the __packed directive; + * if they did we'd define the version 0 struct as a sub-struct of this one. + */ +struct ec_response_flash_info_1 { + /* Version 0 fields; see above for description */ + uint32_t flash_size; + uint32_t write_block_size; + uint32_t erase_block_size; + uint32_t protect_block_size; + + /* Version 1 adds these fields: */ + /* + * Ideal write size in bytes. Writes will be fastest if size is + * exactly this and offset is a multiple of this. For example, an EC + * may have a write buffer which can do half-page operations if data is + * aligned, and a slower word-at-a-time write mode. + */ + uint32_t write_ideal_size; + + /* Flags; see EC_FLASH_INFO_* */ + uint32_t flags; +} __packed; + /* * Read flash * @@ -459,15 +786,15 @@ struct ec_params_flash_read { /* Write flash */ #define EC_CMD_FLASH_WRITE 0x12 +#define EC_VER_FLASH_WRITE 1 + +/* Version 0 of the flash command supported only 64 bytes of data */ +#define EC_FLASH_WRITE_VER0_SIZE 64 struct ec_params_flash_write { uint32_t offset; /* Byte offset to write */ uint32_t size; /* Size to write in bytes */ - /* - * Data to write. Could really use EC_PARAM_SIZE - 8, but tidiest to - * use a power of 2 so writes stay aligned. - */ - uint8_t data[64]; + /* Followed by data to write */ } __packed; /* Erase flash */ @@ -543,7 +870,7 @@ struct ec_response_flash_protect { enum ec_flash_region { /* Region which holds read-only EC image */ - EC_FLASH_REGION_RO, + EC_FLASH_REGION_RO = 0, /* Region which holds rewritable EC image */ EC_FLASH_REGION_RW, /* @@ -551,6 +878,8 @@ enum ec_flash_region { * EC_FLASH_REGION_RO) */ EC_FLASH_REGION_WP_RO, + /* Number of regions */ + EC_FLASH_REGION_COUNT, }; struct ec_params_flash_region_info { @@ -639,15 +968,15 @@ struct rgb_s { */ struct lightbar_params { /* Timing */ - int google_ramp_up; - int google_ramp_down; - int s3s0_ramp_up; - int s0_tick_delay[2]; /* AC=0/1 */ - int s0a_tick_delay[2]; /* AC=0/1 */ - int s0s3_ramp_down; - int s3_sleep_for; - int s3_ramp_up; - int s3_ramp_down; + int32_t google_ramp_up; + int32_t google_ramp_down; + int32_t s3s0_ramp_up; + int32_t s0_tick_delay[2]; /* AC=0/1 */ + int32_t s0a_tick_delay[2]; /* AC=0/1 */ + int32_t s0s3_ramp_down; + int32_t s3_sleep_for; + int32_t s3_ramp_up; + int32_t s3_ramp_down; /* Oscillation */ uint8_t new_s0; @@ -676,7 +1005,7 @@ struct ec_params_lightbar { union { struct { /* no args */ - } dump, off, on, init, get_seq, get_params; + } dump, off, on, init, get_seq, get_params, version; struct num { uint8_t num; @@ -710,6 +1039,11 @@ struct ec_response_lightbar { struct lightbar_params get_params; + struct version { + uint32_t num; + uint32_t flags; + } version; + struct { /* no return params */ } off, on, init, brightness, seq, reg, rgb, demo, set_params; @@ -730,10 +1064,62 @@ enum lightbar_command { LIGHTBAR_CMD_DEMO = 9, LIGHTBAR_CMD_GET_PARAMS = 10, LIGHTBAR_CMD_SET_PARAMS = 11, + LIGHTBAR_CMD_VERSION = 12, LIGHTBAR_NUM_CMDS }; /*****************************************************************************/ +/* LED control commands */ + +#define EC_CMD_LED_CONTROL 0x29 + +enum ec_led_id { + /* LED to indicate battery state of charge */ + EC_LED_ID_BATTERY_LED = 0, + /* + * LED to indicate system power state (on or in suspend). + * May be on power button or on C-panel. + */ + EC_LED_ID_POWER_LED, + /* LED on power adapter or its plug */ + EC_LED_ID_ADAPTER_LED, + + EC_LED_ID_COUNT +}; + +/* LED control flags */ +#define EC_LED_FLAGS_QUERY (1 << 0) /* Query LED capability only */ +#define EC_LED_FLAGS_AUTO (1 << 1) /* Switch LED back to automatic control */ + +enum ec_led_colors { + EC_LED_COLOR_RED = 0, + EC_LED_COLOR_GREEN, + EC_LED_COLOR_BLUE, + EC_LED_COLOR_YELLOW, + EC_LED_COLOR_WHITE, + + EC_LED_COLOR_COUNT +}; + +struct ec_params_led_control { + uint8_t led_id; /* Which LED to control */ + uint8_t flags; /* Control flags */ + + uint8_t brightness[EC_LED_COLOR_COUNT]; +} __packed; + +struct ec_response_led_control { + /* + * Available brightness value range. + * + * Range 0 means color channel not present. + * Range 1 means on/off control. + * Other values means the LED is control by PWM. + */ + uint8_t brightness_range[EC_LED_COLOR_COUNT]; +} __packed; + +/*****************************************************************************/ /* Verified boot commands */ /* @@ -790,6 +1176,181 @@ enum ec_vboot_hash_status { #define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd /*****************************************************************************/ +/* + * Motion sense commands. We'll make separate structs for sub-commands with + * different input args, so that we know how much to expect. + */ +#define EC_CMD_MOTION_SENSE_CMD 0x2B + +/* Motion sense commands */ +enum motionsense_command { + /* + * Dump command returns all motion sensor data including motion sense + * module flags and individual sensor flags. + */ + MOTIONSENSE_CMD_DUMP = 0, + + /* + * Info command returns data describing the details of a given sensor, + * including enum motionsensor_type, enum motionsensor_location, and + * enum motionsensor_chip. + */ + MOTIONSENSE_CMD_INFO = 1, + + /* + * EC Rate command is a setter/getter command for the EC sampling rate + * of all motion sensors in milliseconds. + */ + MOTIONSENSE_CMD_EC_RATE = 2, + + /* + * Sensor ODR command is a setter/getter command for the output data + * rate of a specific motion sensor in millihertz. + */ + MOTIONSENSE_CMD_SENSOR_ODR = 3, + + /* + * Sensor range command is a setter/getter command for the range of + * a specified motion sensor in +/-G's or +/- deg/s. + */ + MOTIONSENSE_CMD_SENSOR_RANGE = 4, + + /* + * Setter/getter command for the keyboard wake angle. When the lid + * angle is greater than this value, keyboard wake is disabled in S3, + * and when the lid angle goes less than this value, keyboard wake is + * enabled. Note, the lid angle measurement is an approximate, + * un-calibrated value, hence the wake angle isn't exact. + */ + MOTIONSENSE_CMD_KB_WAKE_ANGLE = 5, + + /* Number of motionsense sub-commands. */ + MOTIONSENSE_NUM_CMDS +}; + +enum motionsensor_id { + EC_MOTION_SENSOR_ACCEL_BASE = 0, + EC_MOTION_SENSOR_ACCEL_LID = 1, + EC_MOTION_SENSOR_GYRO = 2, + + /* + * Note, if more sensors are added and this count changes, the padding + * in ec_response_motion_sense dump command must be modified. + */ + EC_MOTION_SENSOR_COUNT = 3 +}; + +/* List of motion sensor types. */ +enum motionsensor_type { + MOTIONSENSE_TYPE_ACCEL = 0, + MOTIONSENSE_TYPE_GYRO = 1, +}; + +/* List of motion sensor locations. */ +enum motionsensor_location { + MOTIONSENSE_LOC_BASE = 0, + MOTIONSENSE_LOC_LID = 1, +}; + +/* List of motion sensor chips. */ +enum motionsensor_chip { + MOTIONSENSE_CHIP_KXCJ9 = 0, +}; + +/* Module flag masks used for the dump sub-command. */ +#define MOTIONSENSE_MODULE_FLAG_ACTIVE (1<<0) + +/* Sensor flag masks used for the dump sub-command. */ +#define MOTIONSENSE_SENSOR_FLAG_PRESENT (1<<0) + +/* + * Send this value for the data element to only perform a read. If you + * send any other value, the EC will interpret it as data to set and will + * return the actual value set. + */ +#define EC_MOTION_SENSE_NO_VALUE -1 + +struct ec_params_motion_sense { + uint8_t cmd; + union { + /* Used for MOTIONSENSE_CMD_DUMP. */ + struct { + /* no args */ + } dump; + + /* + * Used for MOTIONSENSE_CMD_EC_RATE and + * MOTIONSENSE_CMD_KB_WAKE_ANGLE. + */ + struct { + /* Data to set or EC_MOTION_SENSE_NO_VALUE to read. */ + int16_t data; + } ec_rate, kb_wake_angle; + + /* Used for MOTIONSENSE_CMD_INFO. */ + struct { + /* Should be element of enum motionsensor_id. */ + uint8_t sensor_num; + } info; + + /* + * Used for MOTIONSENSE_CMD_SENSOR_ODR and + * MOTIONSENSE_CMD_SENSOR_RANGE. + */ + struct { + /* Should be element of enum motionsensor_id. */ + uint8_t sensor_num; + + /* Rounding flag, true for round-up, false for down. */ + uint8_t roundup; + + uint16_t reserved; + + /* Data to set or EC_MOTION_SENSE_NO_VALUE to read. */ + int32_t data; + } sensor_odr, sensor_range; + }; +} __packed; + +struct ec_response_motion_sense { + union { + /* Used for MOTIONSENSE_CMD_DUMP. */ + struct { + /* Flags representing the motion sensor module. */ + uint8_t module_flags; + + /* Flags for each sensor in enum motionsensor_id. */ + uint8_t sensor_flags[EC_MOTION_SENSOR_COUNT]; + + /* Array of all sensor data. Each sensor is 3-axis. */ + int16_t data[3*EC_MOTION_SENSOR_COUNT]; + } dump; + + /* Used for MOTIONSENSE_CMD_INFO. */ + struct { + /* Should be element of enum motionsensor_type. */ + uint8_t type; + + /* Should be element of enum motionsensor_location. */ + uint8_t location; + + /* Should be element of enum motionsensor_chip. */ + uint8_t chip; + } info; + + /* + * Used for MOTIONSENSE_CMD_EC_RATE, MOTIONSENSE_CMD_SENSOR_ODR, + * MOTIONSENSE_CMD_SENSOR_RANGE, and + * MOTIONSENSE_CMD_KB_WAKE_ANGLE. + */ + struct { + /* Current value of the parameter queried. */ + int32_t ret; + } ec_rate, sensor_odr, sensor_range, kb_wake_angle; + }; +} __packed; + +/*****************************************************************************/ /* USB charging control commands */ /* Set USB port charging mode */ @@ -868,20 +1429,27 @@ struct ec_response_port80_last_boot { } __packed; /*****************************************************************************/ -/* Thermal engine commands */ +/* Thermal engine commands. Note that there are two implementations. We'll + * reuse the command number, but the data and behavior is incompatible. + * Version 0 is what originally shipped on Link. + * Version 1 separates the CPU thermal limits from the fan control. + */ -/* Set thershold value */ #define EC_CMD_THERMAL_SET_THRESHOLD 0x50 +#define EC_CMD_THERMAL_GET_THRESHOLD 0x51 + +/* The version 0 structs are opaque. You have to know what they are for + * the get/set commands to make any sense. + */ +/* Version 0 - set */ struct ec_params_thermal_set_threshold { uint8_t sensor_type; uint8_t threshold_id; uint16_t value; } __packed; -/* Get threshold value */ -#define EC_CMD_THERMAL_GET_THRESHOLD 0x51 - +/* Version 0 - get */ struct ec_params_thermal_get_threshold { uint8_t sensor_type; uint8_t threshold_id; @@ -891,6 +1459,41 @@ struct ec_response_thermal_get_threshold { uint16_t value; } __packed; + +/* The version 1 structs are visible. */ +enum ec_temp_thresholds { + EC_TEMP_THRESH_WARN = 0, + EC_TEMP_THRESH_HIGH, + EC_TEMP_THRESH_HALT, + + EC_TEMP_THRESH_COUNT +}; + +/* Thermal configuration for one temperature sensor. Temps are in degrees K. + * Zero values will be silently ignored by the thermal task. + */ +struct ec_thermal_config { + uint32_t temp_host[EC_TEMP_THRESH_COUNT]; /* levels of hotness */ + uint32_t temp_fan_off; /* no active cooling needed */ + uint32_t temp_fan_max; /* max active cooling needed */ +} __packed; + +/* Version 1 - get config for one sensor. */ +struct ec_params_thermal_get_threshold_v1 { + uint32_t sensor_num; +} __packed; +/* This returns a struct ec_thermal_config */ + +/* Version 1 - set config for one sensor. + * Use read-modify-write for best results! */ +struct ec_params_thermal_set_threshold_v1 { + uint32_t sensor_num; + struct ec_thermal_config cfg; +} __packed; +/* This returns no data */ + +/****************************************************************************/ + /* Toggle automatic fan control */ #define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52 @@ -920,6 +1523,18 @@ struct ec_params_tmp006_set_calibration { float b2; } __packed; +/* Read raw TMP006 data */ +#define EC_CMD_TMP006_GET_RAW 0x55 + +struct ec_params_tmp006_get_raw { + uint8_t index; +} __packed; + +struct ec_response_tmp006_get_raw { + int32_t t; /* In 1/100 K */ + int32_t v; /* In nV */ +}; + /*****************************************************************************/ /* MKBP - Matrix KeyBoard Protocol */ @@ -1118,11 +1733,41 @@ struct ec_params_switch_enable_backlight { /* Enable/disable WLAN/Bluetooth */ #define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91 +#define EC_VER_SWITCH_ENABLE_WIRELESS 1 -struct ec_params_switch_enable_wireless { +/* Version 0 params; no response */ +struct ec_params_switch_enable_wireless_v0 { uint8_t enabled; } __packed; +/* Version 1 params */ +struct ec_params_switch_enable_wireless_v1 { + /* Flags to enable now */ + uint8_t now_flags; + + /* Which flags to copy from now_flags */ + uint8_t now_mask; + + /* + * Flags to leave enabled in S3, if they're on at the S0->S3 + * transition. (Other flags will be disabled by the S0->S3 + * transition.) + */ + uint8_t suspend_flags; + + /* Which flags to copy from suspend_flags */ + uint8_t suspend_mask; +} __packed; + +/* Version 1 response */ +struct ec_response_switch_enable_wireless_v1 { + /* Flags to enable now */ + uint8_t now_flags; + + /* Flags to leave enabled in S3 */ + uint8_t suspend_flags; +} __packed; + /*****************************************************************************/ /* GPIO commands. Only available on EC if write protect has been disabled. */ @@ -1147,11 +1792,16 @@ struct ec_response_gpio_get { /*****************************************************************************/ /* I2C commands. Only available when flash write protect is unlocked. */ +/* + * TODO(crosbug.com/p/23570): These commands are deprecated, and will be + * removed soon. Use EC_CMD_I2C_XFER instead. + */ + /* Read I2C bus */ #define EC_CMD_I2C_READ 0x94 struct ec_params_i2c_read { - uint16_t addr; + uint16_t addr; /* 8-bit address (7-bit shifted << 1) */ uint8_t read_size; /* Either 8 or 16. */ uint8_t port; uint8_t offset; @@ -1165,7 +1815,7 @@ struct ec_response_i2c_read { struct ec_params_i2c_write { uint16_t data; - uint16_t addr; + uint16_t addr; /* 8-bit address (7-bit shifted << 1) */ uint8_t write_size; /* Either 8 or 16. */ uint8_t port; uint8_t offset; @@ -1174,11 +1824,20 @@ struct ec_params_i2c_write { /*****************************************************************************/ /* Charge state commands. Only available when flash write protect unlocked. */ -/* Force charge state machine to stop in idle mode */ -#define EC_CMD_CHARGE_FORCE_IDLE 0x96 +/* Force charge state machine to stop charging the battery or force it to + * discharge the battery. + */ +#define EC_CMD_CHARGE_CONTROL 0x96 +#define EC_VER_CHARGE_CONTROL 1 -struct ec_params_force_idle { - uint8_t enabled; +enum ec_charge_control_mode { + CHARGE_CONTROL_NORMAL = 0, + CHARGE_CONTROL_IDLE, + CHARGE_CONTROL_DISCHARGE, +}; + +struct ec_params_charge_control { + uint32_t mode; /* enum charge_control_mode */ } __packed; /*****************************************************************************/ @@ -1206,14 +1865,231 @@ struct ec_params_force_idle { #define EC_CMD_BATTERY_CUT_OFF 0x99 /*****************************************************************************/ -/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */ +/* USB port mux control. */ /* - * Dump charge state machine context. - * - * Response is a binary dump of charge state machine context. + * Switch USB mux or return to automatic switching. + */ +#define EC_CMD_USB_MUX 0x9a + +struct ec_params_usb_mux { + uint8_t mux; +} __packed; + +/*****************************************************************************/ +/* LDOs / FETs control. */ + +enum ec_ldo_state { + EC_LDO_STATE_OFF = 0, /* the LDO / FET is shut down */ + EC_LDO_STATE_ON = 1, /* the LDO / FET is ON / providing power */ +}; + +/* + * Switch on/off a LDO. + */ +#define EC_CMD_LDO_SET 0x9b + +struct ec_params_ldo_set { + uint8_t index; + uint8_t state; +} __packed; + +/* + * Get LDO state. + */ +#define EC_CMD_LDO_GET 0x9c + +struct ec_params_ldo_get { + uint8_t index; +} __packed; + +struct ec_response_ldo_get { + uint8_t state; +} __packed; + +/*****************************************************************************/ +/* Power info. */ + +/* + * Get power info. + */ +#define EC_CMD_POWER_INFO 0x9d + +struct ec_response_power_info { + uint32_t usb_dev_type; + uint16_t voltage_ac; + uint16_t voltage_system; + uint16_t current_system; + uint16_t usb_current_limit; +} __packed; + +/*****************************************************************************/ +/* I2C passthru command */ + +#define EC_CMD_I2C_PASSTHRU 0x9e + +/* Slave address is 10 (not 7) bit */ +#define EC_I2C_FLAG_10BIT (1 << 16) + +/* Read data; if not present, message is a write */ +#define EC_I2C_FLAG_READ (1 << 15) + +/* Mask for address */ +#define EC_I2C_ADDR_MASK 0x3ff + +#define EC_I2C_STATUS_NAK (1 << 0) /* Transfer was not acknowledged */ +#define EC_I2C_STATUS_TIMEOUT (1 << 1) /* Timeout during transfer */ + +/* Any error */ +#define EC_I2C_STATUS_ERROR (EC_I2C_STATUS_NAK | EC_I2C_STATUS_TIMEOUT) + +struct ec_params_i2c_passthru_msg { + uint16_t addr_flags; /* I2C slave address (7 or 10 bits) and flags */ + uint16_t len; /* Number of bytes to read or write */ +} __packed; + +struct ec_params_i2c_passthru { + uint8_t port; /* I2C port number */ + uint8_t num_msgs; /* Number of messages */ + struct ec_params_i2c_passthru_msg msg[]; + /* Data to write for all messages is concatenated here */ +} __packed; + +struct ec_response_i2c_passthru { + uint8_t i2c_status; /* Status flags (EC_I2C_STATUS_...) */ + uint8_t num_msgs; /* Number of messages processed */ + uint8_t data[]; /* Data read by messages concatenated here */ +} __packed; + +/*****************************************************************************/ +/* Power button hang detect */ + +#define EC_CMD_HANG_DETECT 0x9f + +/* Reasons to start hang detection timer */ +/* Power button pressed */ +#define EC_HANG_START_ON_POWER_PRESS (1 << 0) + +/* Lid closed */ +#define EC_HANG_START_ON_LID_CLOSE (1 << 1) + + /* Lid opened */ +#define EC_HANG_START_ON_LID_OPEN (1 << 2) + +/* Start of AP S3->S0 transition (booting or resuming from suspend) */ +#define EC_HANG_START_ON_RESUME (1 << 3) + +/* Reasons to cancel hang detection */ + +/* Power button released */ +#define EC_HANG_STOP_ON_POWER_RELEASE (1 << 8) + +/* Any host command from AP received */ +#define EC_HANG_STOP_ON_HOST_COMMAND (1 << 9) + +/* Stop on end of AP S0->S3 transition (suspending or shutting down) */ +#define EC_HANG_STOP_ON_SUSPEND (1 << 10) + +/* + * If this flag is set, all the other fields are ignored, and the hang detect + * timer is started. This provides the AP a way to start the hang timer + * without reconfiguring any of the other hang detect settings. Note that + * you must previously have configured the timeouts. + */ +#define EC_HANG_START_NOW (1 << 30) + +/* + * If this flag is set, all the other fields are ignored (including + * EC_HANG_START_NOW). This provides the AP a way to stop the hang timer + * without reconfiguring any of the other hang detect settings. */ -#define EC_CMD_CHARGE_DUMP 0xa0 +#define EC_HANG_STOP_NOW (1 << 31) + +struct ec_params_hang_detect { + /* Flags; see EC_HANG_* */ + uint32_t flags; + + /* Timeout in msec before generating host event, if enabled */ + uint16_t host_event_timeout_msec; + + /* Timeout in msec before generating warm reboot, if enabled */ + uint16_t warm_reboot_timeout_msec; +} __packed; + +/*****************************************************************************/ +/* Commands for battery charging */ + +/* + * This is the single catch-all host command to exchange data regarding the + * charge state machine (v2 and up). + */ +#define EC_CMD_CHARGE_STATE 0xa0 + +/* Subcommands for this host command */ +enum charge_state_command { + CHARGE_STATE_CMD_GET_STATE, + CHARGE_STATE_CMD_GET_PARAM, + CHARGE_STATE_CMD_SET_PARAM, + CHARGE_STATE_NUM_CMDS +}; + +/* + * Known param numbers are defined here. Ranges are reserved for board-specific + * params, which are handled by the particular implementations. + */ +enum charge_state_params { + CS_PARAM_CHG_VOLTAGE, /* charger voltage limit */ + CS_PARAM_CHG_CURRENT, /* charger current limit */ + CS_PARAM_CHG_INPUT_CURRENT, /* charger input current limit */ + CS_PARAM_CHG_STATUS, /* charger-specific status */ + CS_PARAM_CHG_OPTION, /* charger-specific options */ + /* How many so far? */ + CS_NUM_BASE_PARAMS, + + /* Range for CONFIG_CHARGER_PROFILE_OVERRIDE params */ + CS_PARAM_CUSTOM_PROFILE_MIN = 0x10000, + CS_PARAM_CUSTOM_PROFILE_MAX = 0x1ffff, + + /* Other custom param ranges go here... */ +}; + +struct ec_params_charge_state { + uint8_t cmd; /* enum charge_state_command */ + union { + struct { + /* no args */ + } get_state; + + struct { + uint32_t param; /* enum charge_state_param */ + } get_param; + + struct { + uint32_t param; /* param to set */ + uint32_t value; /* value to set */ + } set_param; + }; +} __packed; + +struct ec_response_charge_state { + union { + struct { + int ac; + int chg_voltage; + int chg_current; + int chg_input_current; + int batt_state_of_charge; + } get_state; + + struct { + uint32_t value; + } get_param; + struct { + /* no return values */ + } set_param; + }; +} __packed; + /* * Set maximum battery charging current. @@ -1221,15 +2097,59 @@ struct ec_params_force_idle { #define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1 struct ec_params_current_limit { - uint32_t limit; + uint32_t limit; /* in mA */ +} __packed; + +/* + * Set maximum external power current. + */ +#define EC_CMD_EXT_POWER_CURRENT_LIMIT 0xa2 + +struct ec_params_ext_power_current_limit { + uint32_t limit; /* in mA */ +} __packed; + +/*****************************************************************************/ +/* Smart battery pass-through */ + +/* Get / Set 16-bit smart battery registers */ +#define EC_CMD_SB_READ_WORD 0xb0 +#define EC_CMD_SB_WRITE_WORD 0xb1 + +/* Get / Set string smart battery parameters + * formatted as SMBUS "block". + */ +#define EC_CMD_SB_READ_BLOCK 0xb2 +#define EC_CMD_SB_WRITE_BLOCK 0xb3 + +struct ec_params_sb_rd { + uint8_t reg; +} __packed; + +struct ec_response_sb_rd_word { + uint16_t value; +} __packed; + +struct ec_params_sb_wr_word { + uint8_t reg; + uint16_t value; +} __packed; + +struct ec_response_sb_rd_block { + uint8_t data[32]; +} __packed; + +struct ec_params_sb_wr_block { + uint8_t reg; + uint16_t data[32]; } __packed; /*****************************************************************************/ /* System commands */ /* - * TODO: this is a confusing name, since it doesn't necessarily reboot the EC. - * Rename to "set image" or something similar. + * TODO(crosbug.com/p/23747): This is a confusing name, since it doesn't + * necessarily reboot the EC. Rename to "image" or something similar? */ #define EC_CMD_REBOOT_EC 0xd2 @@ -1308,6 +2228,7 @@ struct ec_params_reboot_ec { #define EC_CMD_ACPI_QUERY_EVENT 0x84 /* Valid addresses in ACPI memory space, for read/write commands */ + /* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */ #define EC_ACPI_MEM_VERSION 0x00 /* @@ -1317,8 +2238,60 @@ struct ec_params_reboot_ec { #define EC_ACPI_MEM_TEST 0x01 /* Test compliment; writes here are ignored. */ #define EC_ACPI_MEM_TEST_COMPLIMENT 0x02 + /* Keyboard backlight brightness percent (0 - 100) */ #define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03 +/* DPTF Target Fan Duty (0-100, 0xff for auto/none) */ +#define EC_ACPI_MEM_FAN_DUTY 0x04 + +/* + * DPTF temp thresholds. Any of the EC's temp sensors can have up to two + * independent thresholds attached to them. The current value of the ID + * register determines which sensor is affected by the THRESHOLD and COMMIT + * registers. The THRESHOLD register uses the same EC_TEMP_SENSOR_OFFSET scheme + * as the memory-mapped sensors. The COMMIT register applies those settings. + * + * The spec does not mandate any way to read back the threshold settings + * themselves, but when a threshold is crossed the AP needs a way to determine + * which sensor(s) are responsible. Each reading of the ID register clears and + * returns one sensor ID that has crossed one of its threshold (in either + * direction) since the last read. A value of 0xFF means "no new thresholds + * have tripped". Setting or enabling the thresholds for a sensor will clear + * the unread event count for that sensor. + */ +#define EC_ACPI_MEM_TEMP_ID 0x05 +#define EC_ACPI_MEM_TEMP_THRESHOLD 0x06 +#define EC_ACPI_MEM_TEMP_COMMIT 0x07 +/* + * Here are the bits for the COMMIT register: + * bit 0 selects the threshold index for the chosen sensor (0/1) + * bit 1 enables/disables the selected threshold (0 = off, 1 = on) + * Each write to the commit register affects one threshold. + */ +#define EC_ACPI_MEM_TEMP_COMMIT_SELECT_MASK (1 << 0) +#define EC_ACPI_MEM_TEMP_COMMIT_ENABLE_MASK (1 << 1) +/* + * Example: + * + * Set the thresholds for sensor 2 to 50 C and 60 C: + * write 2 to [0x05] -- select temp sensor 2 + * write 0x7b to [0x06] -- C_TO_K(50) - EC_TEMP_SENSOR_OFFSET + * write 0x2 to [0x07] -- enable threshold 0 with this value + * write 0x85 to [0x06] -- C_TO_K(60) - EC_TEMP_SENSOR_OFFSET + * write 0x3 to [0x07] -- enable threshold 1 with this value + * + * Disable the 60 C threshold, leaving the 50 C threshold unchanged: + * write 2 to [0x05] -- select temp sensor 2 + * write 0x1 to [0x07] -- disable threshold 1 + */ + +/* DPTF battery charging current limit */ +#define EC_ACPI_MEM_CHARGING_LIMIT 0x08 + +/* Charging limit is specified in 64 mA steps */ +#define EC_ACPI_MEM_CHARGING_LIMIT_STEP_MA 64 +/* Value to disable DPTF battery charging limit */ +#define EC_ACPI_MEM_CHARGING_LIMIT_DISABLED 0xff /* Current version of ACPI memory address space */ #define EC_ACPI_MEM_VERSION_CURRENT 1 @@ -1360,10 +2333,21 @@ struct ec_params_reboot_ec { * Header bytes greater than this indicate a later version. For example, * EC_CMD_VERSION0 + 1 means we are using version 1. * - * The old EC interface must not use commands 0dc or higher. + * The old EC interface must not use commands 0xdc or higher. */ #define EC_CMD_VERSION0 0xdc #endif /* !__ACPI__ */ +/*****************************************************************************/ +/* + * Deprecated constants. These constants have been renamed for clarity. The + * meaning and size has not changed. Programs that use the old names should + * switch to the new names soon, as the old names may not be carried forward + * forever. + */ +#define EC_HOST_PARAM_SIZE EC_PROTO2_MAX_PARAM_SIZE +#define EC_LPC_ADDR_OLD_PARAM EC_HOST_CMD_REGION1 +#define EC_OLD_PARAM_SIZE EC_HOST_CMD_REGION_SIZE + #endif /* __CROS_EC_COMMANDS_H */ diff --git a/include/linux/mfd/ipaq-micro.h b/include/linux/mfd/ipaq-micro.h new file mode 100644 index 000000000000..5c4d29f6674f --- /dev/null +++ b/include/linux/mfd/ipaq-micro.h @@ -0,0 +1,148 @@ +/* + * Header file for the compaq Micro MFD + */ + +#ifndef _MFD_IPAQ_MICRO_H_ +#define _MFD_IPAQ_MICRO_H_ + +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/list.h> + +#define TX_BUF_SIZE 32 +#define RX_BUF_SIZE 16 +#define CHAR_SOF 0x02 + +/* + * These are the different messages that can be sent to the microcontroller + * to control various aspects. + */ +#define MSG_VERSION 0x0 +#define MSG_KEYBOARD 0x2 +#define MSG_TOUCHSCREEN 0x3 +#define MSG_EEPROM_READ 0x4 +#define MSG_EEPROM_WRITE 0x5 +#define MSG_THERMAL_SENSOR 0x6 +#define MSG_NOTIFY_LED 0x8 +#define MSG_BATTERY 0x9 +#define MSG_SPI_READ 0xb +#define MSG_SPI_WRITE 0xc +#define MSG_BACKLIGHT 0xd /* H3600 only */ +#define MSG_CODEC_CTRL 0xe /* H3100 only */ +#define MSG_DISPLAY_CTRL 0xf /* H3100 only */ + +/* state of receiver parser */ +enum rx_state { + STATE_SOF = 0, /* Next byte should be start of frame */ + STATE_ID, /* Next byte is ID & message length */ + STATE_DATA, /* Next byte is a data byte */ + STATE_CHKSUM /* Next byte should be checksum */ +}; + +/** + * struct ipaq_micro_txdev - TX state + * @len: length of message in TX buffer + * @index: current index into TX buffer + * @buf: TX buffer + */ +struct ipaq_micro_txdev { + u8 len; + u8 index; + u8 buf[TX_BUF_SIZE]; +}; + +/** + * struct ipaq_micro_rxdev - RX state + * @state: context of RX state machine + * @chksum: calculated checksum + * @id: message ID from packet + * @len: RX buffer length + * @index: RX buffer index + * @buf: RX buffer + */ +struct ipaq_micro_rxdev { + enum rx_state state; + unsigned char chksum; + u8 id; + unsigned int len; + unsigned int index; + u8 buf[RX_BUF_SIZE]; +}; + +/** + * struct ipaq_micro_msg - message to the iPAQ microcontroller + * @id: 4-bit ID of the message + * @tx_len: length of TX data + * @tx_data: TX data to send + * @rx_len: length of receieved RX data + * @rx_data: RX data to recieve + * @ack: a completion that will be completed when RX is complete + * @node: list node if message gets queued + */ +struct ipaq_micro_msg { + u8 id; + u8 tx_len; + u8 tx_data[TX_BUF_SIZE]; + u8 rx_len; + u8 rx_data[RX_BUF_SIZE]; + struct completion ack; + struct list_head node; +}; + +/** + * struct ipaq_micro - iPAQ microcontroller state + * @dev: corresponding platform device + * @base: virtual memory base for underlying serial device + * @sdlc: virtual memory base for Synchronous Data Link Controller + * @version: version string + * @tx: TX state + * @rx: RX state + * @lock: lock for this state container + * @msg: current message + * @queue: message queue + * @key: callback for asynchronous key events + * @key_data: data to pass along with key events + * @ts: callback for asynchronous touchscreen events + * @ts_data: data to pass along with key events + */ +struct ipaq_micro { + struct device *dev; + void __iomem *base; + void __iomem *sdlc; + char version[5]; + struct ipaq_micro_txdev tx; /* transmit ISR state */ + struct ipaq_micro_rxdev rx; /* receive ISR state */ + spinlock_t lock; + struct ipaq_micro_msg *msg; + struct list_head queue; + void (*key) (void *data, int len, unsigned char *rxdata); + void *key_data; + void (*ts) (void *data, int len, unsigned char *rxdata); + void *ts_data; +}; + +extern int +ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg); + +static inline int +ipaq_micro_tx_msg_sync(struct ipaq_micro *micro, + struct ipaq_micro_msg *msg) +{ + int ret; + + init_completion(&msg->ack); + ret = ipaq_micro_tx_msg(micro, msg); + wait_for_completion(&msg->ack); + + return ret; +} + +static inline int +ipaq_micro_tx_msg_async(struct ipaq_micro *micro, + struct ipaq_micro_msg *msg) +{ + init_completion(&msg->ack); + return ipaq_micro_tx_msg(micro, msg); +} + +#endif /* _MFD_IPAQ_MICRO_H_ */ diff --git a/include/linux/mfd/kempld.h b/include/linux/mfd/kempld.h index b911ef3add03..26e0b469e567 100644 --- a/include/linux/mfd/kempld.h +++ b/include/linux/mfd/kempld.h @@ -51,6 +51,8 @@ #define KEMPLD_TYPE_DEBUG 0x1 #define KEMPLD_TYPE_CUSTOM 0x2 +#define KEMPLD_VERSION_LEN 10 + /** * struct kempld_info - PLD device information structure * @major: PLD major revision @@ -60,6 +62,7 @@ * @type: PLD type * @spec_major: PLD FW specification major revision * @spec_minor: PLD FW specification minor revision + * @version: PLD version string */ struct kempld_info { unsigned int major; @@ -69,6 +72,7 @@ struct kempld_info { unsigned int type; unsigned int spec_major; unsigned int spec_minor; + char version[KEMPLD_VERSION_LEN]; }; /** diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index a326c850f046..d63b1d309106 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -117,10 +117,6 @@ struct mc13xxx_led_platform_data { #define MAX_LED_CONTROL_REGS 6 -struct mc13xxx_leds_platform_data { - struct mc13xxx_led_platform_data *led; - int num_leds; - /* MC13783 LED Control 0 */ #define MC13783_LED_C0_ENABLE (1 << 0) #define MC13783_LED_C0_TRIODE_MD (1 << 7) @@ -169,10 +165,13 @@ struct mc13xxx_leds_platform_data { /* MC34708 LED Control 0 */ #define MC34708_LED_C0_CURRENT_R(x) (((x) & 0x3) << 9) #define MC34708_LED_C0_CURRENT_G(x) (((x) & 0x3) << 21) + +struct mc13xxx_leds_platform_data { + struct mc13xxx_led_platform_data *led; + int num_leds; u32 led_control[MAX_LED_CONTROL_REGS]; }; -struct mc13xxx_buttons_platform_data { #define MC13783_BUTTON_DBNC_0MS 0 #define MC13783_BUTTON_DBNC_30MS 1 #define MC13783_BUTTON_DBNC_150MS 2 @@ -180,6 +179,8 @@ struct mc13xxx_buttons_platform_data { #define MC13783_BUTTON_ENABLE (1 << 2) #define MC13783_BUTTON_POL_INVERT (1 << 3) #define MC13783_BUTTON_RESET_EN (1 << 4) + +struct mc13xxx_buttons_platform_data { int b1on_flags; unsigned short b1on_key; int b2on_flags; @@ -188,14 +189,14 @@ struct mc13xxx_buttons_platform_data { unsigned short b3on_key; }; +#define MC13783_TS_ATO_FIRST false +#define MC13783_TS_ATO_EACH true + struct mc13xxx_ts_platform_data { /* Delay between Touchscreen polarization and ADC Conversion. * Given in clock ticks of a 32 kHz clock which gives a granularity of * about 30.5ms */ u8 ato; - -#define MC13783_TS_ATO_FIRST false -#define MC13783_TS_ATO_EACH true /* Use the ATO delay only for the first conversion or for each one */ bool atox; }; @@ -210,11 +211,12 @@ struct mc13xxx_codec_platform_data { enum mc13783_ssi_port dac_ssi_port; }; -struct mc13xxx_platform_data { -#define MC13XXX_USE_TOUCHSCREEN (1 << 0) +#define MC13XXX_USE_TOUCHSCREEN (1 << 0) #define MC13XXX_USE_CODEC (1 << 1) #define MC13XXX_USE_ADC (1 << 2) #define MC13XXX_USE_RTC (1 << 3) + +struct mc13xxx_platform_data { unsigned int flags; struct mc13xxx_regulator_platform_data regulators; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index b8f87b704409..3420e09e2e20 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -482,10 +482,10 @@ enum usb_irq_events { /* helper macro to get correct slave number */ #define PALMAS_BASE_TO_SLAVE(x) ((x >> 8) - 1) -#define PALMAS_BASE_TO_REG(x, y) ((x & 0xff) + y) +#define PALMAS_BASE_TO_REG(x, y) ((x & 0xFF) + y) /* Base addresses of IP blocks in Palmas */ -#define PALMAS_SMPS_DVS_BASE 0x20 +#define PALMAS_SMPS_DVS_BASE 0x020 #define PALMAS_RTC_BASE 0x100 #define PALMAS_VALIDITY_BASE 0x118 #define PALMAS_SMPS_BASE 0x120 @@ -504,19 +504,19 @@ enum usb_irq_events { #define PALMAS_TRIM_GPADC_BASE 0x3CD /* Registers for function RTC */ -#define PALMAS_SECONDS_REG 0x0 -#define PALMAS_MINUTES_REG 0x1 -#define PALMAS_HOURS_REG 0x2 -#define PALMAS_DAYS_REG 0x3 -#define PALMAS_MONTHS_REG 0x4 -#define PALMAS_YEARS_REG 0x5 -#define PALMAS_WEEKS_REG 0x6 -#define PALMAS_ALARM_SECONDS_REG 0x8 -#define PALMAS_ALARM_MINUTES_REG 0x9 -#define PALMAS_ALARM_HOURS_REG 0xA -#define PALMAS_ALARM_DAYS_REG 0xB -#define PALMAS_ALARM_MONTHS_REG 0xC -#define PALMAS_ALARM_YEARS_REG 0xD +#define PALMAS_SECONDS_REG 0x00 +#define PALMAS_MINUTES_REG 0x01 +#define PALMAS_HOURS_REG 0x02 +#define PALMAS_DAYS_REG 0x03 +#define PALMAS_MONTHS_REG 0x04 +#define PALMAS_YEARS_REG 0x05 +#define PALMAS_WEEKS_REG 0x06 +#define PALMAS_ALARM_SECONDS_REG 0x08 +#define PALMAS_ALARM_MINUTES_REG 0x09 +#define PALMAS_ALARM_HOURS_REG 0x0A +#define PALMAS_ALARM_DAYS_REG 0x0B +#define PALMAS_ALARM_MONTHS_REG 0x0C +#define PALMAS_ALARM_YEARS_REG 0x0D #define PALMAS_RTC_CTRL_REG 0x10 #define PALMAS_RTC_STATUS_REG 0x11 #define PALMAS_RTC_INTERRUPTS_REG 0x12 @@ -527,201 +527,201 @@ enum usb_irq_events { /* Bit definitions for SECONDS_REG */ #define PALMAS_SECONDS_REG_SEC1_MASK 0x70 -#define PALMAS_SECONDS_REG_SEC1_SHIFT 4 -#define PALMAS_SECONDS_REG_SEC0_MASK 0x0f -#define PALMAS_SECONDS_REG_SEC0_SHIFT 0 +#define PALMAS_SECONDS_REG_SEC1_SHIFT 0x04 +#define PALMAS_SECONDS_REG_SEC0_MASK 0x0F +#define PALMAS_SECONDS_REG_SEC0_SHIFT 0x00 /* Bit definitions for MINUTES_REG */ #define PALMAS_MINUTES_REG_MIN1_MASK 0x70 -#define PALMAS_MINUTES_REG_MIN1_SHIFT 4 -#define PALMAS_MINUTES_REG_MIN0_MASK 0x0f -#define PALMAS_MINUTES_REG_MIN0_SHIFT 0 +#define PALMAS_MINUTES_REG_MIN1_SHIFT 0x04 +#define PALMAS_MINUTES_REG_MIN0_MASK 0x0F +#define PALMAS_MINUTES_REG_MIN0_SHIFT 0x00 /* Bit definitions for HOURS_REG */ #define PALMAS_HOURS_REG_PM_NAM 0x80 -#define PALMAS_HOURS_REG_PM_NAM_SHIFT 7 +#define PALMAS_HOURS_REG_PM_NAM_SHIFT 0x07 #define PALMAS_HOURS_REG_HOUR1_MASK 0x30 -#define PALMAS_HOURS_REG_HOUR1_SHIFT 4 -#define PALMAS_HOURS_REG_HOUR0_MASK 0x0f -#define PALMAS_HOURS_REG_HOUR0_SHIFT 0 +#define PALMAS_HOURS_REG_HOUR1_SHIFT 0x04 +#define PALMAS_HOURS_REG_HOUR0_MASK 0x0F +#define PALMAS_HOURS_REG_HOUR0_SHIFT 0x00 /* Bit definitions for DAYS_REG */ #define PALMAS_DAYS_REG_DAY1_MASK 0x30 -#define PALMAS_DAYS_REG_DAY1_SHIFT 4 -#define PALMAS_DAYS_REG_DAY0_MASK 0x0f -#define PALMAS_DAYS_REG_DAY0_SHIFT 0 +#define PALMAS_DAYS_REG_DAY1_SHIFT 0x04 +#define PALMAS_DAYS_REG_DAY0_MASK 0x0F +#define PALMAS_DAYS_REG_DAY0_SHIFT 0x00 /* Bit definitions for MONTHS_REG */ #define PALMAS_MONTHS_REG_MONTH1 0x10 -#define PALMAS_MONTHS_REG_MONTH1_SHIFT 4 -#define PALMAS_MONTHS_REG_MONTH0_MASK 0x0f -#define PALMAS_MONTHS_REG_MONTH0_SHIFT 0 +#define PALMAS_MONTHS_REG_MONTH1_SHIFT 0x04 +#define PALMAS_MONTHS_REG_MONTH0_MASK 0x0F +#define PALMAS_MONTHS_REG_MONTH0_SHIFT 0x00 /* Bit definitions for YEARS_REG */ #define PALMAS_YEARS_REG_YEAR1_MASK 0xf0 -#define PALMAS_YEARS_REG_YEAR1_SHIFT 4 -#define PALMAS_YEARS_REG_YEAR0_MASK 0x0f -#define PALMAS_YEARS_REG_YEAR0_SHIFT 0 +#define PALMAS_YEARS_REG_YEAR1_SHIFT 0x04 +#define PALMAS_YEARS_REG_YEAR0_MASK 0x0F +#define PALMAS_YEARS_REG_YEAR0_SHIFT 0x00 /* Bit definitions for WEEKS_REG */ #define PALMAS_WEEKS_REG_WEEK_MASK 0x07 -#define PALMAS_WEEKS_REG_WEEK_SHIFT 0 +#define PALMAS_WEEKS_REG_WEEK_SHIFT 0x00 /* Bit definitions for ALARM_SECONDS_REG */ #define PALMAS_ALARM_SECONDS_REG_ALARM_SEC1_MASK 0x70 -#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC1_SHIFT 4 -#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_MASK 0x0f -#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_SHIFT 0 +#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC1_SHIFT 0x04 +#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_MASK 0x0F +#define PALMAS_ALARM_SECONDS_REG_ALARM_SEC0_SHIFT 0x00 /* Bit definitions for ALARM_MINUTES_REG */ #define PALMAS_ALARM_MINUTES_REG_ALARM_MIN1_MASK 0x70 -#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN1_SHIFT 4 -#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_MASK 0x0f -#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_SHIFT 0 +#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN1_SHIFT 0x04 +#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_MASK 0x0F +#define PALMAS_ALARM_MINUTES_REG_ALARM_MIN0_SHIFT 0x00 /* Bit definitions for ALARM_HOURS_REG */ #define PALMAS_ALARM_HOURS_REG_ALARM_PM_NAM 0x80 -#define PALMAS_ALARM_HOURS_REG_ALARM_PM_NAM_SHIFT 7 +#define PALMAS_ALARM_HOURS_REG_ALARM_PM_NAM_SHIFT 0x07 #define PALMAS_ALARM_HOURS_REG_ALARM_HOUR1_MASK 0x30 -#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR1_SHIFT 4 -#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_MASK 0x0f -#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_SHIFT 0 +#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR1_SHIFT 0x04 +#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_MASK 0x0F +#define PALMAS_ALARM_HOURS_REG_ALARM_HOUR0_SHIFT 0x00 /* Bit definitions for ALARM_DAYS_REG */ #define PALMAS_ALARM_DAYS_REG_ALARM_DAY1_MASK 0x30 -#define PALMAS_ALARM_DAYS_REG_ALARM_DAY1_SHIFT 4 -#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_MASK 0x0f -#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_SHIFT 0 +#define PALMAS_ALARM_DAYS_REG_ALARM_DAY1_SHIFT 0x04 +#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_MASK 0x0F +#define PALMAS_ALARM_DAYS_REG_ALARM_DAY0_SHIFT 0x00 /* Bit definitions for ALARM_MONTHS_REG */ #define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH1 0x10 -#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH1_SHIFT 4 -#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_MASK 0x0f -#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_SHIFT 0 +#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH1_SHIFT 0x04 +#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_MASK 0x0F +#define PALMAS_ALARM_MONTHS_REG_ALARM_MONTH0_SHIFT 0x00 /* Bit definitions for ALARM_YEARS_REG */ #define PALMAS_ALARM_YEARS_REG_ALARM_YEAR1_MASK 0xf0 -#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR1_SHIFT 4 -#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_MASK 0x0f -#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_SHIFT 0 +#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR1_SHIFT 0x04 +#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_MASK 0x0F +#define PALMAS_ALARM_YEARS_REG_ALARM_YEAR0_SHIFT 0x00 /* Bit definitions for RTC_CTRL_REG */ #define PALMAS_RTC_CTRL_REG_RTC_V_OPT 0x80 -#define PALMAS_RTC_CTRL_REG_RTC_V_OPT_SHIFT 7 +#define PALMAS_RTC_CTRL_REG_RTC_V_OPT_SHIFT 0x07 #define PALMAS_RTC_CTRL_REG_GET_TIME 0x40 -#define PALMAS_RTC_CTRL_REG_GET_TIME_SHIFT 6 +#define PALMAS_RTC_CTRL_REG_GET_TIME_SHIFT 0x06 #define PALMAS_RTC_CTRL_REG_SET_32_COUNTER 0x20 -#define PALMAS_RTC_CTRL_REG_SET_32_COUNTER_SHIFT 5 +#define PALMAS_RTC_CTRL_REG_SET_32_COUNTER_SHIFT 0x05 #define PALMAS_RTC_CTRL_REG_TEST_MODE 0x10 -#define PALMAS_RTC_CTRL_REG_TEST_MODE_SHIFT 4 +#define PALMAS_RTC_CTRL_REG_TEST_MODE_SHIFT 0x04 #define PALMAS_RTC_CTRL_REG_MODE_12_24 0x08 -#define PALMAS_RTC_CTRL_REG_MODE_12_24_SHIFT 3 +#define PALMAS_RTC_CTRL_REG_MODE_12_24_SHIFT 0x03 #define PALMAS_RTC_CTRL_REG_AUTO_COMP 0x04 -#define PALMAS_RTC_CTRL_REG_AUTO_COMP_SHIFT 2 +#define PALMAS_RTC_CTRL_REG_AUTO_COMP_SHIFT 0x02 #define PALMAS_RTC_CTRL_REG_ROUND_30S 0x02 -#define PALMAS_RTC_CTRL_REG_ROUND_30S_SHIFT 1 +#define PALMAS_RTC_CTRL_REG_ROUND_30S_SHIFT 0x01 #define PALMAS_RTC_CTRL_REG_STOP_RTC 0x01 -#define PALMAS_RTC_CTRL_REG_STOP_RTC_SHIFT 0 +#define PALMAS_RTC_CTRL_REG_STOP_RTC_SHIFT 0x00 /* Bit definitions for RTC_STATUS_REG */ #define PALMAS_RTC_STATUS_REG_POWER_UP 0x80 -#define PALMAS_RTC_STATUS_REG_POWER_UP_SHIFT 7 +#define PALMAS_RTC_STATUS_REG_POWER_UP_SHIFT 0x07 #define PALMAS_RTC_STATUS_REG_ALARM 0x40 -#define PALMAS_RTC_STATUS_REG_ALARM_SHIFT 6 +#define PALMAS_RTC_STATUS_REG_ALARM_SHIFT 0x06 #define PALMAS_RTC_STATUS_REG_EVENT_1D 0x20 -#define PALMAS_RTC_STATUS_REG_EVENT_1D_SHIFT 5 +#define PALMAS_RTC_STATUS_REG_EVENT_1D_SHIFT 0x05 #define PALMAS_RTC_STATUS_REG_EVENT_1H 0x10 -#define PALMAS_RTC_STATUS_REG_EVENT_1H_SHIFT 4 +#define PALMAS_RTC_STATUS_REG_EVENT_1H_SHIFT 0x04 #define PALMAS_RTC_STATUS_REG_EVENT_1M 0x08 -#define PALMAS_RTC_STATUS_REG_EVENT_1M_SHIFT 3 +#define PALMAS_RTC_STATUS_REG_EVENT_1M_SHIFT 0x03 #define PALMAS_RTC_STATUS_REG_EVENT_1S 0x04 -#define PALMAS_RTC_STATUS_REG_EVENT_1S_SHIFT 2 +#define PALMAS_RTC_STATUS_REG_EVENT_1S_SHIFT 0x02 #define PALMAS_RTC_STATUS_REG_RUN 0x02 -#define PALMAS_RTC_STATUS_REG_RUN_SHIFT 1 +#define PALMAS_RTC_STATUS_REG_RUN_SHIFT 0x01 /* Bit definitions for RTC_INTERRUPTS_REG */ #define PALMAS_RTC_INTERRUPTS_REG_IT_SLEEP_MASK_EN 0x10 -#define PALMAS_RTC_INTERRUPTS_REG_IT_SLEEP_MASK_EN_SHIFT 4 +#define PALMAS_RTC_INTERRUPTS_REG_IT_SLEEP_MASK_EN_SHIFT 0x04 #define PALMAS_RTC_INTERRUPTS_REG_IT_ALARM 0x08 -#define PALMAS_RTC_INTERRUPTS_REG_IT_ALARM_SHIFT 3 +#define PALMAS_RTC_INTERRUPTS_REG_IT_ALARM_SHIFT 0x03 #define PALMAS_RTC_INTERRUPTS_REG_IT_TIMER 0x04 -#define PALMAS_RTC_INTERRUPTS_REG_IT_TIMER_SHIFT 2 +#define PALMAS_RTC_INTERRUPTS_REG_IT_TIMER_SHIFT 0x02 #define PALMAS_RTC_INTERRUPTS_REG_EVERY_MASK 0x03 -#define PALMAS_RTC_INTERRUPTS_REG_EVERY_SHIFT 0 +#define PALMAS_RTC_INTERRUPTS_REG_EVERY_SHIFT 0x00 /* Bit definitions for RTC_COMP_LSB_REG */ -#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_MASK 0xff -#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_SHIFT 0 +#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_MASK 0xFF +#define PALMAS_RTC_COMP_LSB_REG_RTC_COMP_LSB_SHIFT 0x00 /* Bit definitions for RTC_COMP_MSB_REG */ -#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_MASK 0xff -#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_SHIFT 0 +#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_MASK 0xFF +#define PALMAS_RTC_COMP_MSB_REG_RTC_COMP_MSB_SHIFT 0x00 /* Bit definitions for RTC_RES_PROG_REG */ -#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_MASK 0x3f -#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_SHIFT 0 +#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_MASK 0x3F +#define PALMAS_RTC_RES_PROG_REG_SW_RES_PROG_SHIFT 0x00 /* Bit definitions for RTC_RESET_STATUS_REG */ #define PALMAS_RTC_RESET_STATUS_REG_RESET_STATUS 0x01 -#define PALMAS_RTC_RESET_STATUS_REG_RESET_STATUS_SHIFT 0 +#define PALMAS_RTC_RESET_STATUS_REG_RESET_STATUS_SHIFT 0x00 /* Registers for function BACKUP */ -#define PALMAS_BACKUP0 0x0 -#define PALMAS_BACKUP1 0x1 -#define PALMAS_BACKUP2 0x2 -#define PALMAS_BACKUP3 0x3 -#define PALMAS_BACKUP4 0x4 -#define PALMAS_BACKUP5 0x5 -#define PALMAS_BACKUP6 0x6 -#define PALMAS_BACKUP7 0x7 +#define PALMAS_BACKUP0 0x00 +#define PALMAS_BACKUP1 0x01 +#define PALMAS_BACKUP2 0x02 +#define PALMAS_BACKUP3 0x03 +#define PALMAS_BACKUP4 0x04 +#define PALMAS_BACKUP5 0x05 +#define PALMAS_BACKUP6 0x06 +#define PALMAS_BACKUP7 0x07 /* Bit definitions for BACKUP0 */ -#define PALMAS_BACKUP0_BACKUP_MASK 0xff -#define PALMAS_BACKUP0_BACKUP_SHIFT 0 +#define PALMAS_BACKUP0_BACKUP_MASK 0xFF +#define PALMAS_BACKUP0_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP1 */ -#define PALMAS_BACKUP1_BACKUP_MASK 0xff -#define PALMAS_BACKUP1_BACKUP_SHIFT 0 +#define PALMAS_BACKUP1_BACKUP_MASK 0xFF +#define PALMAS_BACKUP1_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP2 */ -#define PALMAS_BACKUP2_BACKUP_MASK 0xff -#define PALMAS_BACKUP2_BACKUP_SHIFT 0 +#define PALMAS_BACKUP2_BACKUP_MASK 0xFF +#define PALMAS_BACKUP2_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP3 */ -#define PALMAS_BACKUP3_BACKUP_MASK 0xff -#define PALMAS_BACKUP3_BACKUP_SHIFT 0 +#define PALMAS_BACKUP3_BACKUP_MASK 0xFF +#define PALMAS_BACKUP3_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP4 */ -#define PALMAS_BACKUP4_BACKUP_MASK 0xff -#define PALMAS_BACKUP4_BACKUP_SHIFT 0 +#define PALMAS_BACKUP4_BACKUP_MASK 0xFF +#define PALMAS_BACKUP4_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP5 */ -#define PALMAS_BACKUP5_BACKUP_MASK 0xff -#define PALMAS_BACKUP5_BACKUP_SHIFT 0 +#define PALMAS_BACKUP5_BACKUP_MASK 0xFF +#define PALMAS_BACKUP5_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP6 */ -#define PALMAS_BACKUP6_BACKUP_MASK 0xff -#define PALMAS_BACKUP6_BACKUP_SHIFT 0 +#define PALMAS_BACKUP6_BACKUP_MASK 0xFF +#define PALMAS_BACKUP6_BACKUP_SHIFT 0x00 /* Bit definitions for BACKUP7 */ -#define PALMAS_BACKUP7_BACKUP_MASK 0xff -#define PALMAS_BACKUP7_BACKUP_SHIFT 0 +#define PALMAS_BACKUP7_BACKUP_MASK 0xFF +#define PALMAS_BACKUP7_BACKUP_SHIFT 0x00 /* Registers for function SMPS */ -#define PALMAS_SMPS12_CTRL 0x0 -#define PALMAS_SMPS12_TSTEP 0x1 -#define PALMAS_SMPS12_FORCE 0x2 -#define PALMAS_SMPS12_VOLTAGE 0x3 -#define PALMAS_SMPS3_CTRL 0x4 -#define PALMAS_SMPS3_VOLTAGE 0x7 -#define PALMAS_SMPS45_CTRL 0x8 -#define PALMAS_SMPS45_TSTEP 0x9 -#define PALMAS_SMPS45_FORCE 0xA -#define PALMAS_SMPS45_VOLTAGE 0xB -#define PALMAS_SMPS6_CTRL 0xC -#define PALMAS_SMPS6_TSTEP 0xD -#define PALMAS_SMPS6_FORCE 0xE -#define PALMAS_SMPS6_VOLTAGE 0xF +#define PALMAS_SMPS12_CTRL 0x00 +#define PALMAS_SMPS12_TSTEP 0x01 +#define PALMAS_SMPS12_FORCE 0x02 +#define PALMAS_SMPS12_VOLTAGE 0x03 +#define PALMAS_SMPS3_CTRL 0x04 +#define PALMAS_SMPS3_VOLTAGE 0x07 +#define PALMAS_SMPS45_CTRL 0x08 +#define PALMAS_SMPS45_TSTEP 0x09 +#define PALMAS_SMPS45_FORCE 0x0A +#define PALMAS_SMPS45_VOLTAGE 0x0B +#define PALMAS_SMPS6_CTRL 0x0C +#define PALMAS_SMPS6_TSTEP 0x0D +#define PALMAS_SMPS6_FORCE 0x0E +#define PALMAS_SMPS6_VOLTAGE 0x0F #define PALMAS_SMPS7_CTRL 0x10 #define PALMAS_SMPS7_VOLTAGE 0x13 #define PALMAS_SMPS8_CTRL 0x14 @@ -744,303 +744,303 @@ enum usb_irq_events { /* Bit definitions for SMPS12_CTRL */ #define PALMAS_SMPS12_CTRL_WR_S 0x80 -#define PALMAS_SMPS12_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS12_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN 0x40 -#define PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN_SHIFT 6 +#define PALMAS_SMPS12_CTRL_ROOF_FLOOR_EN_SHIFT 0x06 #define PALMAS_SMPS12_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS12_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS12_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS12_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS12_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS12_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS12_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS12_TSTEP */ #define PALMAS_SMPS12_TSTEP_TSTEP_MASK 0x03 -#define PALMAS_SMPS12_TSTEP_TSTEP_SHIFT 0 +#define PALMAS_SMPS12_TSTEP_TSTEP_SHIFT 0x00 /* Bit definitions for SMPS12_FORCE */ #define PALMAS_SMPS12_FORCE_CMD 0x80 -#define PALMAS_SMPS12_FORCE_CMD_SHIFT 7 -#define PALMAS_SMPS12_FORCE_VSEL_MASK 0x7f -#define PALMAS_SMPS12_FORCE_VSEL_SHIFT 0 +#define PALMAS_SMPS12_FORCE_CMD_SHIFT 0x07 +#define PALMAS_SMPS12_FORCE_VSEL_MASK 0x7F +#define PALMAS_SMPS12_FORCE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS12_VOLTAGE */ #define PALMAS_SMPS12_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS12_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS12_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS12_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS12_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS12_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS12_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS3_CTRL */ #define PALMAS_SMPS3_CTRL_WR_S 0x80 -#define PALMAS_SMPS3_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS3_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS3_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS3_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS3_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS3_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS3_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS3_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS3_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS3_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS3_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS3_VOLTAGE */ #define PALMAS_SMPS3_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS3_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS3_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS3_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS3_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS3_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS3_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS45_CTRL */ #define PALMAS_SMPS45_CTRL_WR_S 0x80 -#define PALMAS_SMPS45_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS45_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS45_CTRL_ROOF_FLOOR_EN 0x40 -#define PALMAS_SMPS45_CTRL_ROOF_FLOOR_EN_SHIFT 6 +#define PALMAS_SMPS45_CTRL_ROOF_FLOOR_EN_SHIFT 0x06 #define PALMAS_SMPS45_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS45_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS45_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS45_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS45_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS45_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS45_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS45_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS45_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS45_TSTEP */ #define PALMAS_SMPS45_TSTEP_TSTEP_MASK 0x03 -#define PALMAS_SMPS45_TSTEP_TSTEP_SHIFT 0 +#define PALMAS_SMPS45_TSTEP_TSTEP_SHIFT 0x00 /* Bit definitions for SMPS45_FORCE */ #define PALMAS_SMPS45_FORCE_CMD 0x80 -#define PALMAS_SMPS45_FORCE_CMD_SHIFT 7 -#define PALMAS_SMPS45_FORCE_VSEL_MASK 0x7f -#define PALMAS_SMPS45_FORCE_VSEL_SHIFT 0 +#define PALMAS_SMPS45_FORCE_CMD_SHIFT 0x07 +#define PALMAS_SMPS45_FORCE_VSEL_MASK 0x7F +#define PALMAS_SMPS45_FORCE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS45_VOLTAGE */ #define PALMAS_SMPS45_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS45_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS45_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS45_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS45_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS45_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS45_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS6_CTRL */ #define PALMAS_SMPS6_CTRL_WR_S 0x80 -#define PALMAS_SMPS6_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS6_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS6_CTRL_ROOF_FLOOR_EN 0x40 -#define PALMAS_SMPS6_CTRL_ROOF_FLOOR_EN_SHIFT 6 +#define PALMAS_SMPS6_CTRL_ROOF_FLOOR_EN_SHIFT 0x06 #define PALMAS_SMPS6_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS6_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS6_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS6_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS6_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS6_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS6_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS6_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS6_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS6_TSTEP */ #define PALMAS_SMPS6_TSTEP_TSTEP_MASK 0x03 -#define PALMAS_SMPS6_TSTEP_TSTEP_SHIFT 0 +#define PALMAS_SMPS6_TSTEP_TSTEP_SHIFT 0x00 /* Bit definitions for SMPS6_FORCE */ #define PALMAS_SMPS6_FORCE_CMD 0x80 -#define PALMAS_SMPS6_FORCE_CMD_SHIFT 7 -#define PALMAS_SMPS6_FORCE_VSEL_MASK 0x7f -#define PALMAS_SMPS6_FORCE_VSEL_SHIFT 0 +#define PALMAS_SMPS6_FORCE_CMD_SHIFT 0x07 +#define PALMAS_SMPS6_FORCE_VSEL_MASK 0x7F +#define PALMAS_SMPS6_FORCE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS6_VOLTAGE */ #define PALMAS_SMPS6_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS6_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS6_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS6_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS6_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS6_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS6_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS7_CTRL */ #define PALMAS_SMPS7_CTRL_WR_S 0x80 -#define PALMAS_SMPS7_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS7_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS7_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS7_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS7_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS7_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS7_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS7_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS7_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS7_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS7_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS7_VOLTAGE */ #define PALMAS_SMPS7_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS7_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS7_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS7_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS7_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS7_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS7_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS8_CTRL */ #define PALMAS_SMPS8_CTRL_WR_S 0x80 -#define PALMAS_SMPS8_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS8_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS8_CTRL_ROOF_FLOOR_EN 0x40 -#define PALMAS_SMPS8_CTRL_ROOF_FLOOR_EN_SHIFT 6 +#define PALMAS_SMPS8_CTRL_ROOF_FLOOR_EN_SHIFT 0x06 #define PALMAS_SMPS8_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS8_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS8_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS8_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS8_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS8_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS8_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS8_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS8_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS8_TSTEP */ #define PALMAS_SMPS8_TSTEP_TSTEP_MASK 0x03 -#define PALMAS_SMPS8_TSTEP_TSTEP_SHIFT 0 +#define PALMAS_SMPS8_TSTEP_TSTEP_SHIFT 0x00 /* Bit definitions for SMPS8_FORCE */ #define PALMAS_SMPS8_FORCE_CMD 0x80 -#define PALMAS_SMPS8_FORCE_CMD_SHIFT 7 -#define PALMAS_SMPS8_FORCE_VSEL_MASK 0x7f -#define PALMAS_SMPS8_FORCE_VSEL_SHIFT 0 +#define PALMAS_SMPS8_FORCE_CMD_SHIFT 0x07 +#define PALMAS_SMPS8_FORCE_VSEL_MASK 0x7F +#define PALMAS_SMPS8_FORCE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS8_VOLTAGE */ #define PALMAS_SMPS8_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS8_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS8_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS8_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS8_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS8_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS8_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS9_CTRL */ #define PALMAS_SMPS9_CTRL_WR_S 0x80 -#define PALMAS_SMPS9_CTRL_WR_S_SHIFT 7 +#define PALMAS_SMPS9_CTRL_WR_S_SHIFT 0x07 #define PALMAS_SMPS9_CTRL_STATUS_MASK 0x30 -#define PALMAS_SMPS9_CTRL_STATUS_SHIFT 4 +#define PALMAS_SMPS9_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SMPS9_CTRL_MODE_SLEEP_MASK 0x0c -#define PALMAS_SMPS9_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SMPS9_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SMPS9_CTRL_MODE_ACTIVE_MASK 0x03 -#define PALMAS_SMPS9_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS9_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS9_VOLTAGE */ #define PALMAS_SMPS9_VOLTAGE_RANGE 0x80 -#define PALMAS_SMPS9_VOLTAGE_RANGE_SHIFT 7 -#define PALMAS_SMPS9_VOLTAGE_VSEL_MASK 0x7f -#define PALMAS_SMPS9_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_SMPS9_VOLTAGE_RANGE_SHIFT 0x07 +#define PALMAS_SMPS9_VOLTAGE_VSEL_MASK 0x7F +#define PALMAS_SMPS9_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for SMPS10_CTRL */ #define PALMAS_SMPS10_CTRL_MODE_SLEEP_MASK 0xf0 -#define PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT 4 -#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_MASK 0x0f -#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SMPS10_CTRL_MODE_SLEEP_SHIFT 0x04 +#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_MASK 0x0F +#define PALMAS_SMPS10_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SMPS10_STATUS */ -#define PALMAS_SMPS10_STATUS_STATUS_MASK 0x0f -#define PALMAS_SMPS10_STATUS_STATUS_SHIFT 0 +#define PALMAS_SMPS10_STATUS_STATUS_MASK 0x0F +#define PALMAS_SMPS10_STATUS_STATUS_SHIFT 0x00 /* Bit definitions for SMPS_CTRL */ #define PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN 0x20 -#define PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN_SHIFT 5 +#define PALMAS_SMPS_CTRL_SMPS45_SMPS457_EN_SHIFT 0x05 #define PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN 0x10 -#define PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN_SHIFT 4 +#define PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN_SHIFT 0x04 #define PALMAS_SMPS_CTRL_SMPS45_PHASE_CTRL_MASK 0x0c -#define PALMAS_SMPS_CTRL_SMPS45_PHASE_CTRL_SHIFT 2 +#define PALMAS_SMPS_CTRL_SMPS45_PHASE_CTRL_SHIFT 0x02 #define PALMAS_SMPS_CTRL_SMPS123_PHASE_CTRL_MASK 0x03 -#define PALMAS_SMPS_CTRL_SMPS123_PHASE_CTRL_SHIFT 0 +#define PALMAS_SMPS_CTRL_SMPS123_PHASE_CTRL_SHIFT 0x00 /* Bit definitions for SMPS_PD_CTRL */ #define PALMAS_SMPS_PD_CTRL_SMPS9 0x40 -#define PALMAS_SMPS_PD_CTRL_SMPS9_SHIFT 6 +#define PALMAS_SMPS_PD_CTRL_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_PD_CTRL_SMPS8 0x20 -#define PALMAS_SMPS_PD_CTRL_SMPS8_SHIFT 5 +#define PALMAS_SMPS_PD_CTRL_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_PD_CTRL_SMPS7 0x10 -#define PALMAS_SMPS_PD_CTRL_SMPS7_SHIFT 4 +#define PALMAS_SMPS_PD_CTRL_SMPS7_SHIFT 0x04 #define PALMAS_SMPS_PD_CTRL_SMPS6 0x08 -#define PALMAS_SMPS_PD_CTRL_SMPS6_SHIFT 3 +#define PALMAS_SMPS_PD_CTRL_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_PD_CTRL_SMPS45 0x04 -#define PALMAS_SMPS_PD_CTRL_SMPS45_SHIFT 2 +#define PALMAS_SMPS_PD_CTRL_SMPS45_SHIFT 0x02 #define PALMAS_SMPS_PD_CTRL_SMPS3 0x02 -#define PALMAS_SMPS_PD_CTRL_SMPS3_SHIFT 1 +#define PALMAS_SMPS_PD_CTRL_SMPS3_SHIFT 0x01 #define PALMAS_SMPS_PD_CTRL_SMPS12 0x01 -#define PALMAS_SMPS_PD_CTRL_SMPS12_SHIFT 0 +#define PALMAS_SMPS_PD_CTRL_SMPS12_SHIFT 0x00 /* Bit definitions for SMPS_THERMAL_EN */ #define PALMAS_SMPS_THERMAL_EN_SMPS9 0x40 -#define PALMAS_SMPS_THERMAL_EN_SMPS9_SHIFT 6 +#define PALMAS_SMPS_THERMAL_EN_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_THERMAL_EN_SMPS8 0x20 -#define PALMAS_SMPS_THERMAL_EN_SMPS8_SHIFT 5 +#define PALMAS_SMPS_THERMAL_EN_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_THERMAL_EN_SMPS6 0x08 -#define PALMAS_SMPS_THERMAL_EN_SMPS6_SHIFT 3 +#define PALMAS_SMPS_THERMAL_EN_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_THERMAL_EN_SMPS457 0x04 -#define PALMAS_SMPS_THERMAL_EN_SMPS457_SHIFT 2 +#define PALMAS_SMPS_THERMAL_EN_SMPS457_SHIFT 0x02 #define PALMAS_SMPS_THERMAL_EN_SMPS123 0x01 -#define PALMAS_SMPS_THERMAL_EN_SMPS123_SHIFT 0 +#define PALMAS_SMPS_THERMAL_EN_SMPS123_SHIFT 0x00 /* Bit definitions for SMPS_THERMAL_STATUS */ #define PALMAS_SMPS_THERMAL_STATUS_SMPS9 0x40 -#define PALMAS_SMPS_THERMAL_STATUS_SMPS9_SHIFT 6 +#define PALMAS_SMPS_THERMAL_STATUS_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_THERMAL_STATUS_SMPS8 0x20 -#define PALMAS_SMPS_THERMAL_STATUS_SMPS8_SHIFT 5 +#define PALMAS_SMPS_THERMAL_STATUS_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_THERMAL_STATUS_SMPS6 0x08 -#define PALMAS_SMPS_THERMAL_STATUS_SMPS6_SHIFT 3 +#define PALMAS_SMPS_THERMAL_STATUS_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_THERMAL_STATUS_SMPS457 0x04 -#define PALMAS_SMPS_THERMAL_STATUS_SMPS457_SHIFT 2 +#define PALMAS_SMPS_THERMAL_STATUS_SMPS457_SHIFT 0x02 #define PALMAS_SMPS_THERMAL_STATUS_SMPS123 0x01 -#define PALMAS_SMPS_THERMAL_STATUS_SMPS123_SHIFT 0 +#define PALMAS_SMPS_THERMAL_STATUS_SMPS123_SHIFT 0x00 /* Bit definitions for SMPS_SHORT_STATUS */ #define PALMAS_SMPS_SHORT_STATUS_SMPS10 0x80 -#define PALMAS_SMPS_SHORT_STATUS_SMPS10_SHIFT 7 +#define PALMAS_SMPS_SHORT_STATUS_SMPS10_SHIFT 0x07 #define PALMAS_SMPS_SHORT_STATUS_SMPS9 0x40 -#define PALMAS_SMPS_SHORT_STATUS_SMPS9_SHIFT 6 +#define PALMAS_SMPS_SHORT_STATUS_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_SHORT_STATUS_SMPS8 0x20 -#define PALMAS_SMPS_SHORT_STATUS_SMPS8_SHIFT 5 +#define PALMAS_SMPS_SHORT_STATUS_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_SHORT_STATUS_SMPS7 0x10 -#define PALMAS_SMPS_SHORT_STATUS_SMPS7_SHIFT 4 +#define PALMAS_SMPS_SHORT_STATUS_SMPS7_SHIFT 0x04 #define PALMAS_SMPS_SHORT_STATUS_SMPS6 0x08 -#define PALMAS_SMPS_SHORT_STATUS_SMPS6_SHIFT 3 +#define PALMAS_SMPS_SHORT_STATUS_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_SHORT_STATUS_SMPS45 0x04 -#define PALMAS_SMPS_SHORT_STATUS_SMPS45_SHIFT 2 +#define PALMAS_SMPS_SHORT_STATUS_SMPS45_SHIFT 0x02 #define PALMAS_SMPS_SHORT_STATUS_SMPS3 0x02 -#define PALMAS_SMPS_SHORT_STATUS_SMPS3_SHIFT 1 +#define PALMAS_SMPS_SHORT_STATUS_SMPS3_SHIFT 0x01 #define PALMAS_SMPS_SHORT_STATUS_SMPS12 0x01 -#define PALMAS_SMPS_SHORT_STATUS_SMPS12_SHIFT 0 +#define PALMAS_SMPS_SHORT_STATUS_SMPS12_SHIFT 0x00 /* Bit definitions for SMPS_NEGATIVE_CURRENT_LIMIT_EN */ #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS9 0x40 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS9_SHIFT 6 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS8 0x20 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS8_SHIFT 5 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS7 0x10 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS7_SHIFT 4 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS7_SHIFT 0x04 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS6 0x08 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS6_SHIFT 3 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS45 0x04 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS45_SHIFT 2 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS45_SHIFT 0x02 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS3 0x02 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS3_SHIFT 1 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS3_SHIFT 0x01 #define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS12 0x01 -#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS12_SHIFT 0 +#define PALMAS_SMPS_NEGATIVE_CURRENT_LIMIT_EN_SMPS12_SHIFT 0x00 /* Bit definitions for SMPS_POWERGOOD_MASK1 */ #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS10 0x80 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS10_SHIFT 7 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS10_SHIFT 0x07 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS9 0x40 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS9_SHIFT 6 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS9_SHIFT 0x06 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS8 0x20 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS8_SHIFT 5 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS8_SHIFT 0x05 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS7 0x10 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS7_SHIFT 4 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS7_SHIFT 0x04 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS6 0x08 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS6_SHIFT 3 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS6_SHIFT 0x03 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS45 0x04 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS45_SHIFT 2 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS45_SHIFT 0x02 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS3 0x02 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS3_SHIFT 1 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS3_SHIFT 0x01 #define PALMAS_SMPS_POWERGOOD_MASK1_SMPS12 0x01 -#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS12_SHIFT 0 +#define PALMAS_SMPS_POWERGOOD_MASK1_SMPS12_SHIFT 0x00 /* Bit definitions for SMPS_POWERGOOD_MASK2 */ #define PALMAS_SMPS_POWERGOOD_MASK2_POWERGOOD_TYPE_SELECT 0x80 -#define PALMAS_SMPS_POWERGOOD_MASK2_POWERGOOD_TYPE_SELECT_SHIFT 7 +#define PALMAS_SMPS_POWERGOOD_MASK2_POWERGOOD_TYPE_SELECT_SHIFT 0x07 #define PALMAS_SMPS_POWERGOOD_MASK2_GPIO_7 0x04 -#define PALMAS_SMPS_POWERGOOD_MASK2_GPIO_7_SHIFT 2 +#define PALMAS_SMPS_POWERGOOD_MASK2_GPIO_7_SHIFT 0x02 #define PALMAS_SMPS_POWERGOOD_MASK2_VBUS 0x02 -#define PALMAS_SMPS_POWERGOOD_MASK2_VBUS_SHIFT 1 +#define PALMAS_SMPS_POWERGOOD_MASK2_VBUS_SHIFT 0x01 #define PALMAS_SMPS_POWERGOOD_MASK2_ACOK 0x01 -#define PALMAS_SMPS_POWERGOOD_MASK2_ACOK_SHIFT 0 +#define PALMAS_SMPS_POWERGOOD_MASK2_ACOK_SHIFT 0x00 /* Registers for function LDO */ -#define PALMAS_LDO1_CTRL 0x0 -#define PALMAS_LDO1_VOLTAGE 0x1 -#define PALMAS_LDO2_CTRL 0x2 -#define PALMAS_LDO2_VOLTAGE 0x3 -#define PALMAS_LDO3_CTRL 0x4 -#define PALMAS_LDO3_VOLTAGE 0x5 -#define PALMAS_LDO4_CTRL 0x6 -#define PALMAS_LDO4_VOLTAGE 0x7 -#define PALMAS_LDO5_CTRL 0x8 -#define PALMAS_LDO5_VOLTAGE 0x9 -#define PALMAS_LDO6_CTRL 0xA -#define PALMAS_LDO6_VOLTAGE 0xB -#define PALMAS_LDO7_CTRL 0xC -#define PALMAS_LDO7_VOLTAGE 0xD -#define PALMAS_LDO8_CTRL 0xE -#define PALMAS_LDO8_VOLTAGE 0xF +#define PALMAS_LDO1_CTRL 0x00 +#define PALMAS_LDO1_VOLTAGE 0x01 +#define PALMAS_LDO2_CTRL 0x02 +#define PALMAS_LDO2_VOLTAGE 0x03 +#define PALMAS_LDO3_CTRL 0x04 +#define PALMAS_LDO3_VOLTAGE 0x05 +#define PALMAS_LDO4_CTRL 0x06 +#define PALMAS_LDO4_VOLTAGE 0x07 +#define PALMAS_LDO5_CTRL 0x08 +#define PALMAS_LDO5_VOLTAGE 0x09 +#define PALMAS_LDO6_CTRL 0x0A +#define PALMAS_LDO6_VOLTAGE 0x0B +#define PALMAS_LDO7_CTRL 0x0C +#define PALMAS_LDO7_VOLTAGE 0x0D +#define PALMAS_LDO8_CTRL 0x0E +#define PALMAS_LDO8_VOLTAGE 0x0F #define PALMAS_LDO9_CTRL 0x10 #define PALMAS_LDO9_VOLTAGE 0x11 #define PALMAS_LDOLN_CTRL 0x12 @@ -1055,236 +1055,236 @@ enum usb_irq_events { /* Bit definitions for LDO1_CTRL */ #define PALMAS_LDO1_CTRL_WR_S 0x80 -#define PALMAS_LDO1_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO1_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO1_CTRL_STATUS 0x10 -#define PALMAS_LDO1_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO1_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO1_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO1_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO1_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO1_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO1_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO1_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO1_VOLTAGE */ -#define PALMAS_LDO1_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO1_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO1_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO1_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO2_CTRL */ #define PALMAS_LDO2_CTRL_WR_S 0x80 -#define PALMAS_LDO2_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO2_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO2_CTRL_STATUS 0x10 -#define PALMAS_LDO2_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO2_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO2_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO2_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO2_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO2_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO2_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO2_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO2_VOLTAGE */ -#define PALMAS_LDO2_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO2_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO2_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO2_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO3_CTRL */ #define PALMAS_LDO3_CTRL_WR_S 0x80 -#define PALMAS_LDO3_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO3_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO3_CTRL_STATUS 0x10 -#define PALMAS_LDO3_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO3_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO3_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO3_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO3_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO3_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO3_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO3_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO3_VOLTAGE */ -#define PALMAS_LDO3_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO3_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO3_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO3_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO4_CTRL */ #define PALMAS_LDO4_CTRL_WR_S 0x80 -#define PALMAS_LDO4_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO4_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO4_CTRL_STATUS 0x10 -#define PALMAS_LDO4_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO4_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO4_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO4_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO4_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO4_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO4_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO4_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO4_VOLTAGE */ -#define PALMAS_LDO4_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO4_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO4_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO4_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO5_CTRL */ #define PALMAS_LDO5_CTRL_WR_S 0x80 -#define PALMAS_LDO5_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO5_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO5_CTRL_STATUS 0x10 -#define PALMAS_LDO5_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO5_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO5_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO5_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO5_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO5_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO5_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO5_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO5_VOLTAGE */ -#define PALMAS_LDO5_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO5_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO5_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO5_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO6_CTRL */ #define PALMAS_LDO6_CTRL_WR_S 0x80 -#define PALMAS_LDO6_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO6_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO6_CTRL_LDO_VIB_EN 0x40 -#define PALMAS_LDO6_CTRL_LDO_VIB_EN_SHIFT 6 +#define PALMAS_LDO6_CTRL_LDO_VIB_EN_SHIFT 0x06 #define PALMAS_LDO6_CTRL_STATUS 0x10 -#define PALMAS_LDO6_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO6_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO6_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO6_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO6_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO6_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO6_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO6_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO6_VOLTAGE */ -#define PALMAS_LDO6_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO6_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO6_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO6_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO7_CTRL */ #define PALMAS_LDO7_CTRL_WR_S 0x80 -#define PALMAS_LDO7_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO7_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO7_CTRL_STATUS 0x10 -#define PALMAS_LDO7_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO7_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO7_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO7_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO7_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO7_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO7_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO7_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO7_VOLTAGE */ -#define PALMAS_LDO7_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO7_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO7_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO7_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO8_CTRL */ #define PALMAS_LDO8_CTRL_WR_S 0x80 -#define PALMAS_LDO8_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO8_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO8_CTRL_LDO_TRACKING_EN 0x40 -#define PALMAS_LDO8_CTRL_LDO_TRACKING_EN_SHIFT 6 +#define PALMAS_LDO8_CTRL_LDO_TRACKING_EN_SHIFT 0x06 #define PALMAS_LDO8_CTRL_STATUS 0x10 -#define PALMAS_LDO8_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO8_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO8_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO8_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO8_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO8_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO8_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO8_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO8_VOLTAGE */ -#define PALMAS_LDO8_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO8_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO8_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO8_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO9_CTRL */ #define PALMAS_LDO9_CTRL_WR_S 0x80 -#define PALMAS_LDO9_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDO9_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDO9_CTRL_LDO_BYPASS_EN 0x40 -#define PALMAS_LDO9_CTRL_LDO_BYPASS_EN_SHIFT 6 +#define PALMAS_LDO9_CTRL_LDO_BYPASS_EN_SHIFT 0x06 #define PALMAS_LDO9_CTRL_STATUS 0x10 -#define PALMAS_LDO9_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDO9_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDO9_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDO9_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDO9_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDO9_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDO9_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDO9_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDO9_VOLTAGE */ -#define PALMAS_LDO9_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDO9_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDO9_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDO9_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDOLN_CTRL */ #define PALMAS_LDOLN_CTRL_WR_S 0x80 -#define PALMAS_LDOLN_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDOLN_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDOLN_CTRL_STATUS 0x10 -#define PALMAS_LDOLN_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDOLN_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDOLN_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDOLN_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDOLN_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDOLN_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDOLN_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDOLN_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDOLN_VOLTAGE */ -#define PALMAS_LDOLN_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDOLN_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDOLN_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDOLN_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDOUSB_CTRL */ #define PALMAS_LDOUSB_CTRL_WR_S 0x80 -#define PALMAS_LDOUSB_CTRL_WR_S_SHIFT 7 +#define PALMAS_LDOUSB_CTRL_WR_S_SHIFT 0x07 #define PALMAS_LDOUSB_CTRL_STATUS 0x10 -#define PALMAS_LDOUSB_CTRL_STATUS_SHIFT 4 +#define PALMAS_LDOUSB_CTRL_STATUS_SHIFT 0x04 #define PALMAS_LDOUSB_CTRL_MODE_SLEEP 0x04 -#define PALMAS_LDOUSB_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_LDOUSB_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_LDOUSB_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_LDOUSB_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_LDOUSB_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for LDOUSB_VOLTAGE */ -#define PALMAS_LDOUSB_VOLTAGE_VSEL_MASK 0x3f -#define PALMAS_LDOUSB_VOLTAGE_VSEL_SHIFT 0 +#define PALMAS_LDOUSB_VOLTAGE_VSEL_MASK 0x3F +#define PALMAS_LDOUSB_VOLTAGE_VSEL_SHIFT 0x00 /* Bit definitions for LDO_CTRL */ #define PALMAS_LDO_CTRL_LDOUSB_ON_VBUS_VSYS 0x01 -#define PALMAS_LDO_CTRL_LDOUSB_ON_VBUS_VSYS_SHIFT 0 +#define PALMAS_LDO_CTRL_LDOUSB_ON_VBUS_VSYS_SHIFT 0x00 /* Bit definitions for LDO_PD_CTRL1 */ #define PALMAS_LDO_PD_CTRL1_LDO8 0x80 -#define PALMAS_LDO_PD_CTRL1_LDO8_SHIFT 7 +#define PALMAS_LDO_PD_CTRL1_LDO8_SHIFT 0x07 #define PALMAS_LDO_PD_CTRL1_LDO7 0x40 -#define PALMAS_LDO_PD_CTRL1_LDO7_SHIFT 6 +#define PALMAS_LDO_PD_CTRL1_LDO7_SHIFT 0x06 #define PALMAS_LDO_PD_CTRL1_LDO6 0x20 -#define PALMAS_LDO_PD_CTRL1_LDO6_SHIFT 5 +#define PALMAS_LDO_PD_CTRL1_LDO6_SHIFT 0x05 #define PALMAS_LDO_PD_CTRL1_LDO5 0x10 -#define PALMAS_LDO_PD_CTRL1_LDO5_SHIFT 4 +#define PALMAS_LDO_PD_CTRL1_LDO5_SHIFT 0x04 #define PALMAS_LDO_PD_CTRL1_LDO4 0x08 -#define PALMAS_LDO_PD_CTRL1_LDO4_SHIFT 3 +#define PALMAS_LDO_PD_CTRL1_LDO4_SHIFT 0x03 #define PALMAS_LDO_PD_CTRL1_LDO3 0x04 -#define PALMAS_LDO_PD_CTRL1_LDO3_SHIFT 2 +#define PALMAS_LDO_PD_CTRL1_LDO3_SHIFT 0x02 #define PALMAS_LDO_PD_CTRL1_LDO2 0x02 -#define PALMAS_LDO_PD_CTRL1_LDO2_SHIFT 1 +#define PALMAS_LDO_PD_CTRL1_LDO2_SHIFT 0x01 #define PALMAS_LDO_PD_CTRL1_LDO1 0x01 -#define PALMAS_LDO_PD_CTRL1_LDO1_SHIFT 0 +#define PALMAS_LDO_PD_CTRL1_LDO1_SHIFT 0x00 /* Bit definitions for LDO_PD_CTRL2 */ #define PALMAS_LDO_PD_CTRL2_LDOUSB 0x04 -#define PALMAS_LDO_PD_CTRL2_LDOUSB_SHIFT 2 +#define PALMAS_LDO_PD_CTRL2_LDOUSB_SHIFT 0x02 #define PALMAS_LDO_PD_CTRL2_LDOLN 0x02 -#define PALMAS_LDO_PD_CTRL2_LDOLN_SHIFT 1 +#define PALMAS_LDO_PD_CTRL2_LDOLN_SHIFT 0x01 #define PALMAS_LDO_PD_CTRL2_LDO9 0x01 -#define PALMAS_LDO_PD_CTRL2_LDO9_SHIFT 0 +#define PALMAS_LDO_PD_CTRL2_LDO9_SHIFT 0x00 /* Bit definitions for LDO_SHORT_STATUS1 */ #define PALMAS_LDO_SHORT_STATUS1_LDO8 0x80 -#define PALMAS_LDO_SHORT_STATUS1_LDO8_SHIFT 7 +#define PALMAS_LDO_SHORT_STATUS1_LDO8_SHIFT 0x07 #define PALMAS_LDO_SHORT_STATUS1_LDO7 0x40 -#define PALMAS_LDO_SHORT_STATUS1_LDO7_SHIFT 6 +#define PALMAS_LDO_SHORT_STATUS1_LDO7_SHIFT 0x06 #define PALMAS_LDO_SHORT_STATUS1_LDO6 0x20 -#define PALMAS_LDO_SHORT_STATUS1_LDO6_SHIFT 5 +#define PALMAS_LDO_SHORT_STATUS1_LDO6_SHIFT 0x05 #define PALMAS_LDO_SHORT_STATUS1_LDO5 0x10 -#define PALMAS_LDO_SHORT_STATUS1_LDO5_SHIFT 4 +#define PALMAS_LDO_SHORT_STATUS1_LDO5_SHIFT 0x04 #define PALMAS_LDO_SHORT_STATUS1_LDO4 0x08 -#define PALMAS_LDO_SHORT_STATUS1_LDO4_SHIFT 3 +#define PALMAS_LDO_SHORT_STATUS1_LDO4_SHIFT 0x03 #define PALMAS_LDO_SHORT_STATUS1_LDO3 0x04 -#define PALMAS_LDO_SHORT_STATUS1_LDO3_SHIFT 2 +#define PALMAS_LDO_SHORT_STATUS1_LDO3_SHIFT 0x02 #define PALMAS_LDO_SHORT_STATUS1_LDO2 0x02 -#define PALMAS_LDO_SHORT_STATUS1_LDO2_SHIFT 1 +#define PALMAS_LDO_SHORT_STATUS1_LDO2_SHIFT 0x01 #define PALMAS_LDO_SHORT_STATUS1_LDO1 0x01 -#define PALMAS_LDO_SHORT_STATUS1_LDO1_SHIFT 0 +#define PALMAS_LDO_SHORT_STATUS1_LDO1_SHIFT 0x00 /* Bit definitions for LDO_SHORT_STATUS2 */ #define PALMAS_LDO_SHORT_STATUS2_LDOVANA 0x08 -#define PALMAS_LDO_SHORT_STATUS2_LDOVANA_SHIFT 3 +#define PALMAS_LDO_SHORT_STATUS2_LDOVANA_SHIFT 0x03 #define PALMAS_LDO_SHORT_STATUS2_LDOUSB 0x04 -#define PALMAS_LDO_SHORT_STATUS2_LDOUSB_SHIFT 2 +#define PALMAS_LDO_SHORT_STATUS2_LDOUSB_SHIFT 0x02 #define PALMAS_LDO_SHORT_STATUS2_LDOLN 0x02 -#define PALMAS_LDO_SHORT_STATUS2_LDOLN_SHIFT 1 +#define PALMAS_LDO_SHORT_STATUS2_LDOLN_SHIFT 0x01 #define PALMAS_LDO_SHORT_STATUS2_LDO9 0x01 -#define PALMAS_LDO_SHORT_STATUS2_LDO9_SHIFT 0 +#define PALMAS_LDO_SHORT_STATUS2_LDO9_SHIFT 0x00 /* Registers for function PMU_CONTROL */ -#define PALMAS_DEV_CTRL 0x0 -#define PALMAS_POWER_CTRL 0x1 -#define PALMAS_VSYS_LO 0x2 -#define PALMAS_VSYS_MON 0x3 -#define PALMAS_VBAT_MON 0x4 -#define PALMAS_WATCHDOG 0x5 -#define PALMAS_BOOT_STATUS 0x6 -#define PALMAS_BATTERY_BOUNCE 0x7 -#define PALMAS_BACKUP_BATTERY_CTRL 0x8 -#define PALMAS_LONG_PRESS_KEY 0x9 -#define PALMAS_OSC_THERM_CTRL 0xA -#define PALMAS_BATDEBOUNCING 0xB -#define PALMAS_SWOFF_HWRST 0xF +#define PALMAS_DEV_CTRL 0x00 +#define PALMAS_POWER_CTRL 0x01 +#define PALMAS_VSYS_LO 0x02 +#define PALMAS_VSYS_MON 0x03 +#define PALMAS_VBAT_MON 0x04 +#define PALMAS_WATCHDOG 0x05 +#define PALMAS_BOOT_STATUS 0x06 +#define PALMAS_BATTERY_BOUNCE 0x07 +#define PALMAS_BACKUP_BATTERY_CTRL 0x08 +#define PALMAS_LONG_PRESS_KEY 0x09 +#define PALMAS_OSC_THERM_CTRL 0x0A +#define PALMAS_BATDEBOUNCING 0x0B +#define PALMAS_SWOFF_HWRST 0x0F #define PALMAS_SWOFF_COLDRST 0x10 #define PALMAS_SWOFF_STATUS 0x11 #define PALMAS_PMU_CONFIG 0x12 @@ -1296,668 +1296,668 @@ enum usb_irq_events { /* Bit definitions for DEV_CTRL */ #define PALMAS_DEV_CTRL_DEV_STATUS_MASK 0x0c -#define PALMAS_DEV_CTRL_DEV_STATUS_SHIFT 2 +#define PALMAS_DEV_CTRL_DEV_STATUS_SHIFT 0x02 #define PALMAS_DEV_CTRL_SW_RST 0x02 -#define PALMAS_DEV_CTRL_SW_RST_SHIFT 1 +#define PALMAS_DEV_CTRL_SW_RST_SHIFT 0x01 #define PALMAS_DEV_CTRL_DEV_ON 0x01 -#define PALMAS_DEV_CTRL_DEV_ON_SHIFT 0 +#define PALMAS_DEV_CTRL_DEV_ON_SHIFT 0x00 /* Bit definitions for POWER_CTRL */ #define PALMAS_POWER_CTRL_ENABLE2_MASK 0x04 -#define PALMAS_POWER_CTRL_ENABLE2_MASK_SHIFT 2 +#define PALMAS_POWER_CTRL_ENABLE2_MASK_SHIFT 0x02 #define PALMAS_POWER_CTRL_ENABLE1_MASK 0x02 -#define PALMAS_POWER_CTRL_ENABLE1_MASK_SHIFT 1 +#define PALMAS_POWER_CTRL_ENABLE1_MASK_SHIFT 0x01 #define PALMAS_POWER_CTRL_NSLEEP_MASK 0x01 -#define PALMAS_POWER_CTRL_NSLEEP_MASK_SHIFT 0 +#define PALMAS_POWER_CTRL_NSLEEP_MASK_SHIFT 0x00 /* Bit definitions for VSYS_LO */ -#define PALMAS_VSYS_LO_THRESHOLD_MASK 0x1f -#define PALMAS_VSYS_LO_THRESHOLD_SHIFT 0 +#define PALMAS_VSYS_LO_THRESHOLD_MASK 0x1F +#define PALMAS_VSYS_LO_THRESHOLD_SHIFT 0x00 /* Bit definitions for VSYS_MON */ #define PALMAS_VSYS_MON_ENABLE 0x80 -#define PALMAS_VSYS_MON_ENABLE_SHIFT 7 -#define PALMAS_VSYS_MON_THRESHOLD_MASK 0x3f -#define PALMAS_VSYS_MON_THRESHOLD_SHIFT 0 +#define PALMAS_VSYS_MON_ENABLE_SHIFT 0x07 +#define PALMAS_VSYS_MON_THRESHOLD_MASK 0x3F +#define PALMAS_VSYS_MON_THRESHOLD_SHIFT 0x00 /* Bit definitions for VBAT_MON */ #define PALMAS_VBAT_MON_ENABLE 0x80 -#define PALMAS_VBAT_MON_ENABLE_SHIFT 7 -#define PALMAS_VBAT_MON_THRESHOLD_MASK 0x3f -#define PALMAS_VBAT_MON_THRESHOLD_SHIFT 0 +#define PALMAS_VBAT_MON_ENABLE_SHIFT 0x07 +#define PALMAS_VBAT_MON_THRESHOLD_MASK 0x3F +#define PALMAS_VBAT_MON_THRESHOLD_SHIFT 0x00 /* Bit definitions for WATCHDOG */ #define PALMAS_WATCHDOG_LOCK 0x20 -#define PALMAS_WATCHDOG_LOCK_SHIFT 5 +#define PALMAS_WATCHDOG_LOCK_SHIFT 0x05 #define PALMAS_WATCHDOG_ENABLE 0x10 -#define PALMAS_WATCHDOG_ENABLE_SHIFT 4 +#define PALMAS_WATCHDOG_ENABLE_SHIFT 0x04 #define PALMAS_WATCHDOG_MODE 0x08 -#define PALMAS_WATCHDOG_MODE_SHIFT 3 +#define PALMAS_WATCHDOG_MODE_SHIFT 0x03 #define PALMAS_WATCHDOG_TIMER_MASK 0x07 -#define PALMAS_WATCHDOG_TIMER_SHIFT 0 +#define PALMAS_WATCHDOG_TIMER_SHIFT 0x00 /* Bit definitions for BOOT_STATUS */ #define PALMAS_BOOT_STATUS_BOOT1 0x02 -#define PALMAS_BOOT_STATUS_BOOT1_SHIFT 1 +#define PALMAS_BOOT_STATUS_BOOT1_SHIFT 0x01 #define PALMAS_BOOT_STATUS_BOOT0 0x01 -#define PALMAS_BOOT_STATUS_BOOT0_SHIFT 0 +#define PALMAS_BOOT_STATUS_BOOT0_SHIFT 0x00 /* Bit definitions for BATTERY_BOUNCE */ -#define PALMAS_BATTERY_BOUNCE_BB_DELAY_MASK 0x3f -#define PALMAS_BATTERY_BOUNCE_BB_DELAY_SHIFT 0 +#define PALMAS_BATTERY_BOUNCE_BB_DELAY_MASK 0x3F +#define PALMAS_BATTERY_BOUNCE_BB_DELAY_SHIFT 0x00 /* Bit definitions for BACKUP_BATTERY_CTRL */ #define PALMAS_BACKUP_BATTERY_CTRL_VRTC_18_15 0x80 -#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_18_15_SHIFT 7 +#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_18_15_SHIFT 0x07 #define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_SLP 0x40 -#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_SLP_SHIFT 6 +#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_SLP_SHIFT 0x06 #define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_OFF 0x20 -#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_OFF_SHIFT 5 +#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_EN_OFF_SHIFT 0x05 #define PALMAS_BACKUP_BATTERY_CTRL_VRTC_PWEN 0x10 -#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_PWEN_SHIFT 4 +#define PALMAS_BACKUP_BATTERY_CTRL_VRTC_PWEN_SHIFT 0x04 #define PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG 0x08 -#define PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG_SHIFT 3 +#define PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG_SHIFT 0x03 #define PALMAS_BACKUP_BATTERY_CTRL_BB_SEL_MASK 0x06 -#define PALMAS_BACKUP_BATTERY_CTRL_BB_SEL_SHIFT 1 +#define PALMAS_BACKUP_BATTERY_CTRL_BB_SEL_SHIFT 0x01 #define PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN 0x01 -#define PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN_SHIFT 0 +#define PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN_SHIFT 0x00 /* Bit definitions for LONG_PRESS_KEY */ #define PALMAS_LONG_PRESS_KEY_LPK_LOCK 0x80 -#define PALMAS_LONG_PRESS_KEY_LPK_LOCK_SHIFT 7 +#define PALMAS_LONG_PRESS_KEY_LPK_LOCK_SHIFT 0x07 #define PALMAS_LONG_PRESS_KEY_LPK_INT_CLR 0x10 -#define PALMAS_LONG_PRESS_KEY_LPK_INT_CLR_SHIFT 4 +#define PALMAS_LONG_PRESS_KEY_LPK_INT_CLR_SHIFT 0x04 #define PALMAS_LONG_PRESS_KEY_LPK_TIME_MASK 0x0c -#define PALMAS_LONG_PRESS_KEY_LPK_TIME_SHIFT 2 +#define PALMAS_LONG_PRESS_KEY_LPK_TIME_SHIFT 0x02 #define PALMAS_LONG_PRESS_KEY_PWRON_DEBOUNCE_MASK 0x03 -#define PALMAS_LONG_PRESS_KEY_PWRON_DEBOUNCE_SHIFT 0 +#define PALMAS_LONG_PRESS_KEY_PWRON_DEBOUNCE_SHIFT 0x00 /* Bit definitions for OSC_THERM_CTRL */ #define PALMAS_OSC_THERM_CTRL_VANA_ON_IN_SLEEP 0x80 -#define PALMAS_OSC_THERM_CTRL_VANA_ON_IN_SLEEP_SHIFT 7 +#define PALMAS_OSC_THERM_CTRL_VANA_ON_IN_SLEEP_SHIFT 0x07 #define PALMAS_OSC_THERM_CTRL_INT_MASK_IN_SLEEP 0x40 -#define PALMAS_OSC_THERM_CTRL_INT_MASK_IN_SLEEP_SHIFT 6 +#define PALMAS_OSC_THERM_CTRL_INT_MASK_IN_SLEEP_SHIFT 0x06 #define PALMAS_OSC_THERM_CTRL_RC15MHZ_ON_IN_SLEEP 0x20 -#define PALMAS_OSC_THERM_CTRL_RC15MHZ_ON_IN_SLEEP_SHIFT 5 +#define PALMAS_OSC_THERM_CTRL_RC15MHZ_ON_IN_SLEEP_SHIFT 0x05 #define PALMAS_OSC_THERM_CTRL_THERM_OFF_IN_SLEEP 0x10 -#define PALMAS_OSC_THERM_CTRL_THERM_OFF_IN_SLEEP_SHIFT 4 +#define PALMAS_OSC_THERM_CTRL_THERM_OFF_IN_SLEEP_SHIFT 0x04 #define PALMAS_OSC_THERM_CTRL_THERM_HD_SEL_MASK 0x0c -#define PALMAS_OSC_THERM_CTRL_THERM_HD_SEL_SHIFT 2 +#define PALMAS_OSC_THERM_CTRL_THERM_HD_SEL_SHIFT 0x02 #define PALMAS_OSC_THERM_CTRL_OSC_BYPASS 0x02 -#define PALMAS_OSC_THERM_CTRL_OSC_BYPASS_SHIFT 1 +#define PALMAS_OSC_THERM_CTRL_OSC_BYPASS_SHIFT 0x01 #define PALMAS_OSC_THERM_CTRL_OSC_HPMODE 0x01 -#define PALMAS_OSC_THERM_CTRL_OSC_HPMODE_SHIFT 0 +#define PALMAS_OSC_THERM_CTRL_OSC_HPMODE_SHIFT 0x00 /* Bit definitions for BATDEBOUNCING */ #define PALMAS_BATDEBOUNCING_BAT_DEB_BYPASS 0x80 -#define PALMAS_BATDEBOUNCING_BAT_DEB_BYPASS_SHIFT 7 +#define PALMAS_BATDEBOUNCING_BAT_DEB_BYPASS_SHIFT 0x07 #define PALMAS_BATDEBOUNCING_BINS_DEB_MASK 0x78 -#define PALMAS_BATDEBOUNCING_BINS_DEB_SHIFT 3 +#define PALMAS_BATDEBOUNCING_BINS_DEB_SHIFT 0x03 #define PALMAS_BATDEBOUNCING_BEXT_DEB_MASK 0x07 -#define PALMAS_BATDEBOUNCING_BEXT_DEB_SHIFT 0 +#define PALMAS_BATDEBOUNCING_BEXT_DEB_SHIFT 0x00 /* Bit definitions for SWOFF_HWRST */ #define PALMAS_SWOFF_HWRST_PWRON_LPK 0x80 -#define PALMAS_SWOFF_HWRST_PWRON_LPK_SHIFT 7 +#define PALMAS_SWOFF_HWRST_PWRON_LPK_SHIFT 0x07 #define PALMAS_SWOFF_HWRST_PWRDOWN 0x40 -#define PALMAS_SWOFF_HWRST_PWRDOWN_SHIFT 6 +#define PALMAS_SWOFF_HWRST_PWRDOWN_SHIFT 0x06 #define PALMAS_SWOFF_HWRST_WTD 0x20 -#define PALMAS_SWOFF_HWRST_WTD_SHIFT 5 +#define PALMAS_SWOFF_HWRST_WTD_SHIFT 0x05 #define PALMAS_SWOFF_HWRST_TSHUT 0x10 -#define PALMAS_SWOFF_HWRST_TSHUT_SHIFT 4 +#define PALMAS_SWOFF_HWRST_TSHUT_SHIFT 0x04 #define PALMAS_SWOFF_HWRST_RESET_IN 0x08 -#define PALMAS_SWOFF_HWRST_RESET_IN_SHIFT 3 +#define PALMAS_SWOFF_HWRST_RESET_IN_SHIFT 0x03 #define PALMAS_SWOFF_HWRST_SW_RST 0x04 -#define PALMAS_SWOFF_HWRST_SW_RST_SHIFT 2 +#define PALMAS_SWOFF_HWRST_SW_RST_SHIFT 0x02 #define PALMAS_SWOFF_HWRST_VSYS_LO 0x02 -#define PALMAS_SWOFF_HWRST_VSYS_LO_SHIFT 1 +#define PALMAS_SWOFF_HWRST_VSYS_LO_SHIFT 0x01 #define PALMAS_SWOFF_HWRST_GPADC_SHUTDOWN 0x01 -#define PALMAS_SWOFF_HWRST_GPADC_SHUTDOWN_SHIFT 0 +#define PALMAS_SWOFF_HWRST_GPADC_SHUTDOWN_SHIFT 0x00 /* Bit definitions for SWOFF_COLDRST */ #define PALMAS_SWOFF_COLDRST_PWRON_LPK 0x80 -#define PALMAS_SWOFF_COLDRST_PWRON_LPK_SHIFT 7 +#define PALMAS_SWOFF_COLDRST_PWRON_LPK_SHIFT 0x07 #define PALMAS_SWOFF_COLDRST_PWRDOWN 0x40 -#define PALMAS_SWOFF_COLDRST_PWRDOWN_SHIFT 6 +#define PALMAS_SWOFF_COLDRST_PWRDOWN_SHIFT 0x06 #define PALMAS_SWOFF_COLDRST_WTD 0x20 -#define PALMAS_SWOFF_COLDRST_WTD_SHIFT 5 +#define PALMAS_SWOFF_COLDRST_WTD_SHIFT 0x05 #define PALMAS_SWOFF_COLDRST_TSHUT 0x10 -#define PALMAS_SWOFF_COLDRST_TSHUT_SHIFT 4 +#define PALMAS_SWOFF_COLDRST_TSHUT_SHIFT 0x04 #define PALMAS_SWOFF_COLDRST_RESET_IN 0x08 -#define PALMAS_SWOFF_COLDRST_RESET_IN_SHIFT 3 +#define PALMAS_SWOFF_COLDRST_RESET_IN_SHIFT 0x03 #define PALMAS_SWOFF_COLDRST_SW_RST 0x04 -#define PALMAS_SWOFF_COLDRST_SW_RST_SHIFT 2 +#define PALMAS_SWOFF_COLDRST_SW_RST_SHIFT 0x02 #define PALMAS_SWOFF_COLDRST_VSYS_LO 0x02 -#define PALMAS_SWOFF_COLDRST_VSYS_LO_SHIFT 1 +#define PALMAS_SWOFF_COLDRST_VSYS_LO_SHIFT 0x01 #define PALMAS_SWOFF_COLDRST_GPADC_SHUTDOWN 0x01 -#define PALMAS_SWOFF_COLDRST_GPADC_SHUTDOWN_SHIFT 0 +#define PALMAS_SWOFF_COLDRST_GPADC_SHUTDOWN_SHIFT 0x00 /* Bit definitions for SWOFF_STATUS */ #define PALMAS_SWOFF_STATUS_PWRON_LPK 0x80 -#define PALMAS_SWOFF_STATUS_PWRON_LPK_SHIFT 7 +#define PALMAS_SWOFF_STATUS_PWRON_LPK_SHIFT 0x07 #define PALMAS_SWOFF_STATUS_PWRDOWN 0x40 -#define PALMAS_SWOFF_STATUS_PWRDOWN_SHIFT 6 +#define PALMAS_SWOFF_STATUS_PWRDOWN_SHIFT 0x06 #define PALMAS_SWOFF_STATUS_WTD 0x20 -#define PALMAS_SWOFF_STATUS_WTD_SHIFT 5 +#define PALMAS_SWOFF_STATUS_WTD_SHIFT 0x05 #define PALMAS_SWOFF_STATUS_TSHUT 0x10 -#define PALMAS_SWOFF_STATUS_TSHUT_SHIFT 4 +#define PALMAS_SWOFF_STATUS_TSHUT_SHIFT 0x04 #define PALMAS_SWOFF_STATUS_RESET_IN 0x08 -#define PALMAS_SWOFF_STATUS_RESET_IN_SHIFT 3 +#define PALMAS_SWOFF_STATUS_RESET_IN_SHIFT 0x03 #define PALMAS_SWOFF_STATUS_SW_RST 0x04 -#define PALMAS_SWOFF_STATUS_SW_RST_SHIFT 2 +#define PALMAS_SWOFF_STATUS_SW_RST_SHIFT 0x02 #define PALMAS_SWOFF_STATUS_VSYS_LO 0x02 -#define PALMAS_SWOFF_STATUS_VSYS_LO_SHIFT 1 +#define PALMAS_SWOFF_STATUS_VSYS_LO_SHIFT 0x01 #define PALMAS_SWOFF_STATUS_GPADC_SHUTDOWN 0x01 -#define PALMAS_SWOFF_STATUS_GPADC_SHUTDOWN_SHIFT 0 +#define PALMAS_SWOFF_STATUS_GPADC_SHUTDOWN_SHIFT 0x00 /* Bit definitions for PMU_CONFIG */ #define PALMAS_PMU_CONFIG_MULTI_CELL_EN 0x40 -#define PALMAS_PMU_CONFIG_MULTI_CELL_EN_SHIFT 6 +#define PALMAS_PMU_CONFIG_MULTI_CELL_EN_SHIFT 0x06 #define PALMAS_PMU_CONFIG_SPARE_MASK 0x30 -#define PALMAS_PMU_CONFIG_SPARE_SHIFT 4 +#define PALMAS_PMU_CONFIG_SPARE_SHIFT 0x04 #define PALMAS_PMU_CONFIG_SWOFF_DLY_MASK 0x0c -#define PALMAS_PMU_CONFIG_SWOFF_DLY_SHIFT 2 +#define PALMAS_PMU_CONFIG_SWOFF_DLY_SHIFT 0x02 #define PALMAS_PMU_CONFIG_GATE_RESET_OUT 0x02 -#define PALMAS_PMU_CONFIG_GATE_RESET_OUT_SHIFT 1 +#define PALMAS_PMU_CONFIG_GATE_RESET_OUT_SHIFT 0x01 #define PALMAS_PMU_CONFIG_AUTODEVON 0x01 -#define PALMAS_PMU_CONFIG_AUTODEVON_SHIFT 0 +#define PALMAS_PMU_CONFIG_AUTODEVON_SHIFT 0x00 /* Bit definitions for SPARE */ #define PALMAS_SPARE_SPARE_MASK 0xf8 -#define PALMAS_SPARE_SPARE_SHIFT 3 +#define PALMAS_SPARE_SPARE_SHIFT 0x03 #define PALMAS_SPARE_REGEN3_OD 0x04 -#define PALMAS_SPARE_REGEN3_OD_SHIFT 2 +#define PALMAS_SPARE_REGEN3_OD_SHIFT 0x02 #define PALMAS_SPARE_REGEN2_OD 0x02 -#define PALMAS_SPARE_REGEN2_OD_SHIFT 1 +#define PALMAS_SPARE_REGEN2_OD_SHIFT 0x01 #define PALMAS_SPARE_REGEN1_OD 0x01 -#define PALMAS_SPARE_REGEN1_OD_SHIFT 0 +#define PALMAS_SPARE_REGEN1_OD_SHIFT 0x00 /* Bit definitions for PMU_SECONDARY_INT */ #define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_INT_SRC 0x80 -#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_INT_SRC_SHIFT 7 +#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_INT_SRC_SHIFT 0x07 #define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_INT_SRC 0x40 -#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_INT_SRC_SHIFT 6 +#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_INT_SRC_SHIFT 0x06 #define PALMAS_PMU_SECONDARY_INT_BB_INT_SRC 0x20 -#define PALMAS_PMU_SECONDARY_INT_BB_INT_SRC_SHIFT 5 +#define PALMAS_PMU_SECONDARY_INT_BB_INT_SRC_SHIFT 0x05 #define PALMAS_PMU_SECONDARY_INT_FBI_INT_SRC 0x10 -#define PALMAS_PMU_SECONDARY_INT_FBI_INT_SRC_SHIFT 4 +#define PALMAS_PMU_SECONDARY_INT_FBI_INT_SRC_SHIFT 0x04 #define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_MASK 0x08 -#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_MASK_SHIFT 3 +#define PALMAS_PMU_SECONDARY_INT_VBUS_OVV_MASK_SHIFT 0x03 #define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_MASK 0x04 -#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_MASK_SHIFT 2 +#define PALMAS_PMU_SECONDARY_INT_CHARG_DET_N_MASK_SHIFT 0x02 #define PALMAS_PMU_SECONDARY_INT_BB_MASK 0x02 -#define PALMAS_PMU_SECONDARY_INT_BB_MASK_SHIFT 1 +#define PALMAS_PMU_SECONDARY_INT_BB_MASK_SHIFT 0x01 #define PALMAS_PMU_SECONDARY_INT_FBI_MASK 0x01 -#define PALMAS_PMU_SECONDARY_INT_FBI_MASK_SHIFT 0 +#define PALMAS_PMU_SECONDARY_INT_FBI_MASK_SHIFT 0x00 /* Bit definitions for SW_REVISION */ -#define PALMAS_SW_REVISION_SW_REVISION_MASK 0xff -#define PALMAS_SW_REVISION_SW_REVISION_SHIFT 0 +#define PALMAS_SW_REVISION_SW_REVISION_MASK 0xFF +#define PALMAS_SW_REVISION_SW_REVISION_SHIFT 0x00 /* Bit definitions for EXT_CHRG_CTRL */ #define PALMAS_EXT_CHRG_CTRL_VBUS_OVV_STATUS 0x80 -#define PALMAS_EXT_CHRG_CTRL_VBUS_OVV_STATUS_SHIFT 7 +#define PALMAS_EXT_CHRG_CTRL_VBUS_OVV_STATUS_SHIFT 0x07 #define PALMAS_EXT_CHRG_CTRL_CHARG_DET_N_STATUS 0x40 -#define PALMAS_EXT_CHRG_CTRL_CHARG_DET_N_STATUS_SHIFT 6 +#define PALMAS_EXT_CHRG_CTRL_CHARG_DET_N_STATUS_SHIFT 0x06 #define PALMAS_EXT_CHRG_CTRL_VSYS_DEBOUNCE_DELAY 0x08 -#define PALMAS_EXT_CHRG_CTRL_VSYS_DEBOUNCE_DELAY_SHIFT 3 +#define PALMAS_EXT_CHRG_CTRL_VSYS_DEBOUNCE_DELAY_SHIFT 0x03 #define PALMAS_EXT_CHRG_CTRL_CHRG_DET_N 0x04 -#define PALMAS_EXT_CHRG_CTRL_CHRG_DET_N_SHIFT 2 +#define PALMAS_EXT_CHRG_CTRL_CHRG_DET_N_SHIFT 0x02 #define PALMAS_EXT_CHRG_CTRL_AUTO_ACA_EN 0x02 -#define PALMAS_EXT_CHRG_CTRL_AUTO_ACA_EN_SHIFT 1 +#define PALMAS_EXT_CHRG_CTRL_AUTO_ACA_EN_SHIFT 0x01 #define PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN 0x01 -#define PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN_SHIFT 0 +#define PALMAS_EXT_CHRG_CTRL_AUTO_LDOUSB_EN_SHIFT 0x00 /* Bit definitions for PMU_SECONDARY_INT2 */ #define PALMAS_PMU_SECONDARY_INT2_DVFS2_INT_SRC 0x20 -#define PALMAS_PMU_SECONDARY_INT2_DVFS2_INT_SRC_SHIFT 5 +#define PALMAS_PMU_SECONDARY_INT2_DVFS2_INT_SRC_SHIFT 0x05 #define PALMAS_PMU_SECONDARY_INT2_DVFS1_INT_SRC 0x10 -#define PALMAS_PMU_SECONDARY_INT2_DVFS1_INT_SRC_SHIFT 4 +#define PALMAS_PMU_SECONDARY_INT2_DVFS1_INT_SRC_SHIFT 0x04 #define PALMAS_PMU_SECONDARY_INT2_DVFS2_MASK 0x02 -#define PALMAS_PMU_SECONDARY_INT2_DVFS2_MASK_SHIFT 1 +#define PALMAS_PMU_SECONDARY_INT2_DVFS2_MASK_SHIFT 0x01 #define PALMAS_PMU_SECONDARY_INT2_DVFS1_MASK 0x01 -#define PALMAS_PMU_SECONDARY_INT2_DVFS1_MASK_SHIFT 0 +#define PALMAS_PMU_SECONDARY_INT2_DVFS1_MASK_SHIFT 0x00 /* Registers for function RESOURCE */ -#define PALMAS_CLK32KG_CTRL 0x0 -#define PALMAS_CLK32KGAUDIO_CTRL 0x1 -#define PALMAS_REGEN1_CTRL 0x2 -#define PALMAS_REGEN2_CTRL 0x3 -#define PALMAS_SYSEN1_CTRL 0x4 -#define PALMAS_SYSEN2_CTRL 0x5 -#define PALMAS_NSLEEP_RES_ASSIGN 0x6 -#define PALMAS_NSLEEP_SMPS_ASSIGN 0x7 -#define PALMAS_NSLEEP_LDO_ASSIGN1 0x8 -#define PALMAS_NSLEEP_LDO_ASSIGN2 0x9 -#define PALMAS_ENABLE1_RES_ASSIGN 0xA -#define PALMAS_ENABLE1_SMPS_ASSIGN 0xB -#define PALMAS_ENABLE1_LDO_ASSIGN1 0xC -#define PALMAS_ENABLE1_LDO_ASSIGN2 0xD -#define PALMAS_ENABLE2_RES_ASSIGN 0xE -#define PALMAS_ENABLE2_SMPS_ASSIGN 0xF +#define PALMAS_CLK32KG_CTRL 0x00 +#define PALMAS_CLK32KGAUDIO_CTRL 0x01 +#define PALMAS_REGEN1_CTRL 0x02 +#define PALMAS_REGEN2_CTRL 0x03 +#define PALMAS_SYSEN1_CTRL 0x04 +#define PALMAS_SYSEN2_CTRL 0x05 +#define PALMAS_NSLEEP_RES_ASSIGN 0x06 +#define PALMAS_NSLEEP_SMPS_ASSIGN 0x07 +#define PALMAS_NSLEEP_LDO_ASSIGN1 0x08 +#define PALMAS_NSLEEP_LDO_ASSIGN2 0x09 +#define PALMAS_ENABLE1_RES_ASSIGN 0x0A +#define PALMAS_ENABLE1_SMPS_ASSIGN 0x0B +#define PALMAS_ENABLE1_LDO_ASSIGN1 0x0C +#define PALMAS_ENABLE1_LDO_ASSIGN2 0x0D +#define PALMAS_ENABLE2_RES_ASSIGN 0x0E +#define PALMAS_ENABLE2_SMPS_ASSIGN 0x0F #define PALMAS_ENABLE2_LDO_ASSIGN1 0x10 #define PALMAS_ENABLE2_LDO_ASSIGN2 0x11 #define PALMAS_REGEN3_CTRL 0x12 /* Bit definitions for CLK32KG_CTRL */ #define PALMAS_CLK32KG_CTRL_STATUS 0x10 -#define PALMAS_CLK32KG_CTRL_STATUS_SHIFT 4 +#define PALMAS_CLK32KG_CTRL_STATUS_SHIFT 0x04 #define PALMAS_CLK32KG_CTRL_MODE_SLEEP 0x04 -#define PALMAS_CLK32KG_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_CLK32KG_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_CLK32KG_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_CLK32KG_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_CLK32KG_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for CLK32KGAUDIO_CTRL */ #define PALMAS_CLK32KGAUDIO_CTRL_STATUS 0x10 -#define PALMAS_CLK32KGAUDIO_CTRL_STATUS_SHIFT 4 +#define PALMAS_CLK32KGAUDIO_CTRL_STATUS_SHIFT 0x04 #define PALMAS_CLK32KGAUDIO_CTRL_RESERVED3 0x08 -#define PALMAS_CLK32KGAUDIO_CTRL_RESERVED3_SHIFT 3 +#define PALMAS_CLK32KGAUDIO_CTRL_RESERVED3_SHIFT 0x03 #define PALMAS_CLK32KGAUDIO_CTRL_MODE_SLEEP 0x04 -#define PALMAS_CLK32KGAUDIO_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_CLK32KGAUDIO_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_CLK32KGAUDIO_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_CLK32KGAUDIO_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_CLK32KGAUDIO_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for REGEN1_CTRL */ #define PALMAS_REGEN1_CTRL_STATUS 0x10 -#define PALMAS_REGEN1_CTRL_STATUS_SHIFT 4 +#define PALMAS_REGEN1_CTRL_STATUS_SHIFT 0x04 #define PALMAS_REGEN1_CTRL_MODE_SLEEP 0x04 -#define PALMAS_REGEN1_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_REGEN1_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_REGEN1_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_REGEN1_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_REGEN1_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for REGEN2_CTRL */ #define PALMAS_REGEN2_CTRL_STATUS 0x10 -#define PALMAS_REGEN2_CTRL_STATUS_SHIFT 4 +#define PALMAS_REGEN2_CTRL_STATUS_SHIFT 0x04 #define PALMAS_REGEN2_CTRL_MODE_SLEEP 0x04 -#define PALMAS_REGEN2_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_REGEN2_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_REGEN2_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_REGEN2_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_REGEN2_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SYSEN1_CTRL */ #define PALMAS_SYSEN1_CTRL_STATUS 0x10 -#define PALMAS_SYSEN1_CTRL_STATUS_SHIFT 4 +#define PALMAS_SYSEN1_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SYSEN1_CTRL_MODE_SLEEP 0x04 -#define PALMAS_SYSEN1_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SYSEN1_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SYSEN1_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_SYSEN1_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SYSEN1_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for SYSEN2_CTRL */ #define PALMAS_SYSEN2_CTRL_STATUS 0x10 -#define PALMAS_SYSEN2_CTRL_STATUS_SHIFT 4 +#define PALMAS_SYSEN2_CTRL_STATUS_SHIFT 0x04 #define PALMAS_SYSEN2_CTRL_MODE_SLEEP 0x04 -#define PALMAS_SYSEN2_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_SYSEN2_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_SYSEN2_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_SYSEN2_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_SYSEN2_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Bit definitions for NSLEEP_RES_ASSIGN */ #define PALMAS_NSLEEP_RES_ASSIGN_REGEN3 0x40 -#define PALMAS_NSLEEP_RES_ASSIGN_REGEN3_SHIFT 6 +#define PALMAS_NSLEEP_RES_ASSIGN_REGEN3_SHIFT 0x06 #define PALMAS_NSLEEP_RES_ASSIGN_CLK32KGAUDIO 0x20 -#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5 +#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KGAUDIO_SHIFT 0x05 #define PALMAS_NSLEEP_RES_ASSIGN_CLK32KG 0x10 -#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KG_SHIFT 4 +#define PALMAS_NSLEEP_RES_ASSIGN_CLK32KG_SHIFT 0x04 #define PALMAS_NSLEEP_RES_ASSIGN_SYSEN2 0x08 -#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN2_SHIFT 3 +#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN2_SHIFT 0x03 #define PALMAS_NSLEEP_RES_ASSIGN_SYSEN1 0x04 -#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN1_SHIFT 2 +#define PALMAS_NSLEEP_RES_ASSIGN_SYSEN1_SHIFT 0x02 #define PALMAS_NSLEEP_RES_ASSIGN_REGEN2 0x02 -#define PALMAS_NSLEEP_RES_ASSIGN_REGEN2_SHIFT 1 +#define PALMAS_NSLEEP_RES_ASSIGN_REGEN2_SHIFT 0x01 #define PALMAS_NSLEEP_RES_ASSIGN_REGEN1 0x01 -#define PALMAS_NSLEEP_RES_ASSIGN_REGEN1_SHIFT 0 +#define PALMAS_NSLEEP_RES_ASSIGN_REGEN1_SHIFT 0x00 /* Bit definitions for NSLEEP_SMPS_ASSIGN */ #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS10 0x80 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS10_SHIFT 7 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS10_SHIFT 0x07 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS9 0x40 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS9_SHIFT 6 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS9_SHIFT 0x06 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS8 0x20 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS8_SHIFT 5 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS8_SHIFT 0x05 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS7 0x10 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS7_SHIFT 4 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS7_SHIFT 0x04 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS6 0x08 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS6_SHIFT 3 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS6_SHIFT 0x03 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS45 0x04 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS45_SHIFT 2 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS45_SHIFT 0x02 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS3 0x02 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS3_SHIFT 1 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS3_SHIFT 0x01 #define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS12 0x01 -#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS12_SHIFT 0 +#define PALMAS_NSLEEP_SMPS_ASSIGN_SMPS12_SHIFT 0x00 /* Bit definitions for NSLEEP_LDO_ASSIGN1 */ #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO8 0x80 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO8_SHIFT 7 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO8_SHIFT 0x07 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO7 0x40 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO7_SHIFT 6 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO7_SHIFT 0x06 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO6 0x20 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO6_SHIFT 5 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO6_SHIFT 0x05 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO5 0x10 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO5_SHIFT 4 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO5_SHIFT 0x04 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO4 0x08 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO4_SHIFT 3 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO4_SHIFT 0x03 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO3 0x04 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO3_SHIFT 2 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO3_SHIFT 0x02 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO2 0x02 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO2_SHIFT 1 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO2_SHIFT 0x01 #define PALMAS_NSLEEP_LDO_ASSIGN1_LDO1 0x01 -#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO1_SHIFT 0 +#define PALMAS_NSLEEP_LDO_ASSIGN1_LDO1_SHIFT 0x00 /* Bit definitions for NSLEEP_LDO_ASSIGN2 */ #define PALMAS_NSLEEP_LDO_ASSIGN2_LDOUSB 0x04 -#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOUSB_SHIFT 2 +#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOUSB_SHIFT 0x02 #define PALMAS_NSLEEP_LDO_ASSIGN2_LDOLN 0x02 -#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOLN_SHIFT 1 +#define PALMAS_NSLEEP_LDO_ASSIGN2_LDOLN_SHIFT 0x01 #define PALMAS_NSLEEP_LDO_ASSIGN2_LDO9 0x01 -#define PALMAS_NSLEEP_LDO_ASSIGN2_LDO9_SHIFT 0 +#define PALMAS_NSLEEP_LDO_ASSIGN2_LDO9_SHIFT 0x00 /* Bit definitions for ENABLE1_RES_ASSIGN */ #define PALMAS_ENABLE1_RES_ASSIGN_REGEN3 0x40 -#define PALMAS_ENABLE1_RES_ASSIGN_REGEN3_SHIFT 6 +#define PALMAS_ENABLE1_RES_ASSIGN_REGEN3_SHIFT 0x06 #define PALMAS_ENABLE1_RES_ASSIGN_CLK32KGAUDIO 0x20 -#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5 +#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KGAUDIO_SHIFT 0x05 #define PALMAS_ENABLE1_RES_ASSIGN_CLK32KG 0x10 -#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KG_SHIFT 4 +#define PALMAS_ENABLE1_RES_ASSIGN_CLK32KG_SHIFT 0x04 #define PALMAS_ENABLE1_RES_ASSIGN_SYSEN2 0x08 -#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN2_SHIFT 3 +#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN2_SHIFT 0x03 #define PALMAS_ENABLE1_RES_ASSIGN_SYSEN1 0x04 -#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN1_SHIFT 2 +#define PALMAS_ENABLE1_RES_ASSIGN_SYSEN1_SHIFT 0x02 #define PALMAS_ENABLE1_RES_ASSIGN_REGEN2 0x02 -#define PALMAS_ENABLE1_RES_ASSIGN_REGEN2_SHIFT 1 +#define PALMAS_ENABLE1_RES_ASSIGN_REGEN2_SHIFT 0x01 #define PALMAS_ENABLE1_RES_ASSIGN_REGEN1 0x01 -#define PALMAS_ENABLE1_RES_ASSIGN_REGEN1_SHIFT 0 +#define PALMAS_ENABLE1_RES_ASSIGN_REGEN1_SHIFT 0x00 /* Bit definitions for ENABLE1_SMPS_ASSIGN */ #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS10 0x80 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS10_SHIFT 7 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS10_SHIFT 0x07 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS9 0x40 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS9_SHIFT 6 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS9_SHIFT 0x06 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS8 0x20 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS8_SHIFT 5 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS8_SHIFT 0x05 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS7 0x10 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS7_SHIFT 4 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS7_SHIFT 0x04 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS6 0x08 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS6_SHIFT 3 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS6_SHIFT 0x03 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS45 0x04 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS45_SHIFT 2 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS45_SHIFT 0x02 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS3 0x02 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS3_SHIFT 1 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS3_SHIFT 0x01 #define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS12 0x01 -#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS12_SHIFT 0 +#define PALMAS_ENABLE1_SMPS_ASSIGN_SMPS12_SHIFT 0x00 /* Bit definitions for ENABLE1_LDO_ASSIGN1 */ #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO8 0x80 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO8_SHIFT 7 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO8_SHIFT 0x07 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO7 0x40 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO7_SHIFT 6 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO7_SHIFT 0x06 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO6 0x20 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO6_SHIFT 5 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO6_SHIFT 0x05 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO5 0x10 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO5_SHIFT 4 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO5_SHIFT 0x04 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO4 0x08 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO4_SHIFT 3 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO4_SHIFT 0x03 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO3 0x04 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO3_SHIFT 2 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO3_SHIFT 0x02 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO2 0x02 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO2_SHIFT 1 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO2_SHIFT 0x01 #define PALMAS_ENABLE1_LDO_ASSIGN1_LDO1 0x01 -#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO1_SHIFT 0 +#define PALMAS_ENABLE1_LDO_ASSIGN1_LDO1_SHIFT 0x00 /* Bit definitions for ENABLE1_LDO_ASSIGN2 */ #define PALMAS_ENABLE1_LDO_ASSIGN2_LDOUSB 0x04 -#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOUSB_SHIFT 2 +#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOUSB_SHIFT 0x02 #define PALMAS_ENABLE1_LDO_ASSIGN2_LDOLN 0x02 -#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOLN_SHIFT 1 +#define PALMAS_ENABLE1_LDO_ASSIGN2_LDOLN_SHIFT 0x01 #define PALMAS_ENABLE1_LDO_ASSIGN2_LDO9 0x01 -#define PALMAS_ENABLE1_LDO_ASSIGN2_LDO9_SHIFT 0 +#define PALMAS_ENABLE1_LDO_ASSIGN2_LDO9_SHIFT 0x00 /* Bit definitions for ENABLE2_RES_ASSIGN */ #define PALMAS_ENABLE2_RES_ASSIGN_REGEN3 0x40 -#define PALMAS_ENABLE2_RES_ASSIGN_REGEN3_SHIFT 6 +#define PALMAS_ENABLE2_RES_ASSIGN_REGEN3_SHIFT 0x06 #define PALMAS_ENABLE2_RES_ASSIGN_CLK32KGAUDIO 0x20 -#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KGAUDIO_SHIFT 5 +#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KGAUDIO_SHIFT 0x05 #define PALMAS_ENABLE2_RES_ASSIGN_CLK32KG 0x10 -#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KG_SHIFT 4 +#define PALMAS_ENABLE2_RES_ASSIGN_CLK32KG_SHIFT 0x04 #define PALMAS_ENABLE2_RES_ASSIGN_SYSEN2 0x08 -#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN2_SHIFT 3 +#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN2_SHIFT 0x03 #define PALMAS_ENABLE2_RES_ASSIGN_SYSEN1 0x04 -#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN1_SHIFT 2 +#define PALMAS_ENABLE2_RES_ASSIGN_SYSEN1_SHIFT 0x02 #define PALMAS_ENABLE2_RES_ASSIGN_REGEN2 0x02 -#define PALMAS_ENABLE2_RES_ASSIGN_REGEN2_SHIFT 1 +#define PALMAS_ENABLE2_RES_ASSIGN_REGEN2_SHIFT 0x01 #define PALMAS_ENABLE2_RES_ASSIGN_REGEN1 0x01 -#define PALMAS_ENABLE2_RES_ASSIGN_REGEN1_SHIFT 0 +#define PALMAS_ENABLE2_RES_ASSIGN_REGEN1_SHIFT 0x00 /* Bit definitions for ENABLE2_SMPS_ASSIGN */ #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS10 0x80 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS10_SHIFT 7 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS10_SHIFT 0x07 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS9 0x40 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS9_SHIFT 6 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS9_SHIFT 0x06 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS8 0x20 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS8_SHIFT 5 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS8_SHIFT 0x05 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS7 0x10 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS7_SHIFT 4 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS7_SHIFT 0x04 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS6 0x08 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS6_SHIFT 3 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS6_SHIFT 0x03 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS45 0x04 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS45_SHIFT 2 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS45_SHIFT 0x02 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS3 0x02 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS3_SHIFT 1 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS3_SHIFT 0x01 #define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS12 0x01 -#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS12_SHIFT 0 +#define PALMAS_ENABLE2_SMPS_ASSIGN_SMPS12_SHIFT 0x00 /* Bit definitions for ENABLE2_LDO_ASSIGN1 */ #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO8 0x80 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO8_SHIFT 7 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO8_SHIFT 0x07 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO7 0x40 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO7_SHIFT 6 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO7_SHIFT 0x06 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO6 0x20 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO6_SHIFT 5 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO6_SHIFT 0x05 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO5 0x10 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO5_SHIFT 4 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO5_SHIFT 0x04 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO4 0x08 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO4_SHIFT 3 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO4_SHIFT 0x03 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO3 0x04 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO3_SHIFT 2 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO3_SHIFT 0x02 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO2 0x02 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO2_SHIFT 1 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO2_SHIFT 0x01 #define PALMAS_ENABLE2_LDO_ASSIGN1_LDO1 0x01 -#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO1_SHIFT 0 +#define PALMAS_ENABLE2_LDO_ASSIGN1_LDO1_SHIFT 0x00 /* Bit definitions for ENABLE2_LDO_ASSIGN2 */ #define PALMAS_ENABLE2_LDO_ASSIGN2_LDOUSB 0x04 -#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOUSB_SHIFT 2 +#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOUSB_SHIFT 0x02 #define PALMAS_ENABLE2_LDO_ASSIGN2_LDOLN 0x02 -#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOLN_SHIFT 1 +#define PALMAS_ENABLE2_LDO_ASSIGN2_LDOLN_SHIFT 0x01 #define PALMAS_ENABLE2_LDO_ASSIGN2_LDO9 0x01 -#define PALMAS_ENABLE2_LDO_ASSIGN2_LDO9_SHIFT 0 +#define PALMAS_ENABLE2_LDO_ASSIGN2_LDO9_SHIFT 0x00 /* Bit definitions for REGEN3_CTRL */ #define PALMAS_REGEN3_CTRL_STATUS 0x10 -#define PALMAS_REGEN3_CTRL_STATUS_SHIFT 4 +#define PALMAS_REGEN3_CTRL_STATUS_SHIFT 0x04 #define PALMAS_REGEN3_CTRL_MODE_SLEEP 0x04 -#define PALMAS_REGEN3_CTRL_MODE_SLEEP_SHIFT 2 +#define PALMAS_REGEN3_CTRL_MODE_SLEEP_SHIFT 0x02 #define PALMAS_REGEN3_CTRL_MODE_ACTIVE 0x01 -#define PALMAS_REGEN3_CTRL_MODE_ACTIVE_SHIFT 0 +#define PALMAS_REGEN3_CTRL_MODE_ACTIVE_SHIFT 0x00 /* Registers for function PAD_CONTROL */ -#define PALMAS_OD_OUTPUT_CTRL2 0x2 -#define PALMAS_POLARITY_CTRL2 0x3 -#define PALMAS_PU_PD_INPUT_CTRL1 0x4 -#define PALMAS_PU_PD_INPUT_CTRL2 0x5 -#define PALMAS_PU_PD_INPUT_CTRL3 0x6 -#define PALMAS_PU_PD_INPUT_CTRL5 0x7 -#define PALMAS_OD_OUTPUT_CTRL 0x8 -#define PALMAS_POLARITY_CTRL 0x9 -#define PALMAS_PRIMARY_SECONDARY_PAD1 0xA -#define PALMAS_PRIMARY_SECONDARY_PAD2 0xB -#define PALMAS_I2C_SPI 0xC -#define PALMAS_PU_PD_INPUT_CTRL4 0xD -#define PALMAS_PRIMARY_SECONDARY_PAD3 0xE -#define PALMAS_PRIMARY_SECONDARY_PAD4 0xF +#define PALMAS_OD_OUTPUT_CTRL2 0x02 +#define PALMAS_POLARITY_CTRL2 0x03 +#define PALMAS_PU_PD_INPUT_CTRL1 0x04 +#define PALMAS_PU_PD_INPUT_CTRL2 0x05 +#define PALMAS_PU_PD_INPUT_CTRL3 0x06 +#define PALMAS_PU_PD_INPUT_CTRL5 0x07 +#define PALMAS_OD_OUTPUT_CTRL 0x08 +#define PALMAS_POLARITY_CTRL 0x09 +#define PALMAS_PRIMARY_SECONDARY_PAD1 0x0A +#define PALMAS_PRIMARY_SECONDARY_PAD2 0x0B +#define PALMAS_I2C_SPI 0x0C +#define PALMAS_PU_PD_INPUT_CTRL4 0x0D +#define PALMAS_PRIMARY_SECONDARY_PAD3 0x0E +#define PALMAS_PRIMARY_SECONDARY_PAD4 0x0F /* Bit definitions for PU_PD_INPUT_CTRL1 */ #define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD 0x40 -#define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD_SHIFT 6 +#define PALMAS_PU_PD_INPUT_CTRL1_RESET_IN_PD_SHIFT 0x06 #define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PU 0x20 -#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PU_SHIFT 5 +#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PU_SHIFT 0x05 #define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PD 0x10 -#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PD_SHIFT 4 +#define PALMAS_PU_PD_INPUT_CTRL1_GPADC_START_PD_SHIFT 0x04 #define PALMAS_PU_PD_INPUT_CTRL1_PWRDOWN_PD 0x04 -#define PALMAS_PU_PD_INPUT_CTRL1_PWRDOWN_PD_SHIFT 2 +#define PALMAS_PU_PD_INPUT_CTRL1_PWRDOWN_PD_SHIFT 0x02 #define PALMAS_PU_PD_INPUT_CTRL1_NRESWARM_PU 0x02 -#define PALMAS_PU_PD_INPUT_CTRL1_NRESWARM_PU_SHIFT 1 +#define PALMAS_PU_PD_INPUT_CTRL1_NRESWARM_PU_SHIFT 0x01 /* Bit definitions for PU_PD_INPUT_CTRL2 */ #define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PU 0x20 -#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PU_SHIFT 5 +#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PU_SHIFT 0x05 #define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PD 0x10 -#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PD_SHIFT 4 +#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE2_PD_SHIFT 0x04 #define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PU 0x08 -#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PU_SHIFT 3 +#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PU_SHIFT 0x03 #define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PD 0x04 -#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PD_SHIFT 2 +#define PALMAS_PU_PD_INPUT_CTRL2_ENABLE1_PD_SHIFT 0x02 #define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PU 0x02 -#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PU_SHIFT 1 +#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PU_SHIFT 0x01 #define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PD 0x01 -#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PD_SHIFT 0 +#define PALMAS_PU_PD_INPUT_CTRL2_NSLEEP_PD_SHIFT 0x00 /* Bit definitions for PU_PD_INPUT_CTRL3 */ #define PALMAS_PU_PD_INPUT_CTRL3_ACOK_PD 0x40 -#define PALMAS_PU_PD_INPUT_CTRL3_ACOK_PD_SHIFT 6 +#define PALMAS_PU_PD_INPUT_CTRL3_ACOK_PD_SHIFT 0x06 #define PALMAS_PU_PD_INPUT_CTRL3_CHRG_DET_N_PD 0x10 -#define PALMAS_PU_PD_INPUT_CTRL3_CHRG_DET_N_PD_SHIFT 4 +#define PALMAS_PU_PD_INPUT_CTRL3_CHRG_DET_N_PD_SHIFT 0x04 #define PALMAS_PU_PD_INPUT_CTRL3_POWERHOLD_PD 0x04 -#define PALMAS_PU_PD_INPUT_CTRL3_POWERHOLD_PD_SHIFT 2 +#define PALMAS_PU_PD_INPUT_CTRL3_POWERHOLD_PD_SHIFT 0x02 #define PALMAS_PU_PD_INPUT_CTRL3_MSECURE_PD 0x01 -#define PALMAS_PU_PD_INPUT_CTRL3_MSECURE_PD_SHIFT 0 +#define PALMAS_PU_PD_INPUT_CTRL3_MSECURE_PD_SHIFT 0x00 /* Bit definitions for OD_OUTPUT_CTRL */ #define PALMAS_OD_OUTPUT_CTRL_PWM_2_OD 0x80 -#define PALMAS_OD_OUTPUT_CTRL_PWM_2_OD_SHIFT 7 +#define PALMAS_OD_OUTPUT_CTRL_PWM_2_OD_SHIFT 0x07 #define PALMAS_OD_OUTPUT_CTRL_VBUSDET_OD 0x40 -#define PALMAS_OD_OUTPUT_CTRL_VBUSDET_OD_SHIFT 6 +#define PALMAS_OD_OUTPUT_CTRL_VBUSDET_OD_SHIFT 0x06 #define PALMAS_OD_OUTPUT_CTRL_PWM_1_OD 0x20 -#define PALMAS_OD_OUTPUT_CTRL_PWM_1_OD_SHIFT 5 +#define PALMAS_OD_OUTPUT_CTRL_PWM_1_OD_SHIFT 0x05 #define PALMAS_OD_OUTPUT_CTRL_INT_OD 0x08 -#define PALMAS_OD_OUTPUT_CTRL_INT_OD_SHIFT 3 +#define PALMAS_OD_OUTPUT_CTRL_INT_OD_SHIFT 0x03 /* Bit definitions for POLARITY_CTRL */ #define PALMAS_POLARITY_CTRL_INT_POLARITY 0x80 -#define PALMAS_POLARITY_CTRL_INT_POLARITY_SHIFT 7 +#define PALMAS_POLARITY_CTRL_INT_POLARITY_SHIFT 0x07 #define PALMAS_POLARITY_CTRL_ENABLE2_POLARITY 0x40 -#define PALMAS_POLARITY_CTRL_ENABLE2_POLARITY_SHIFT 6 +#define PALMAS_POLARITY_CTRL_ENABLE2_POLARITY_SHIFT 0x06 #define PALMAS_POLARITY_CTRL_ENABLE1_POLARITY 0x20 -#define PALMAS_POLARITY_CTRL_ENABLE1_POLARITY_SHIFT 5 +#define PALMAS_POLARITY_CTRL_ENABLE1_POLARITY_SHIFT 0x05 #define PALMAS_POLARITY_CTRL_NSLEEP_POLARITY 0x10 -#define PALMAS_POLARITY_CTRL_NSLEEP_POLARITY_SHIFT 4 +#define PALMAS_POLARITY_CTRL_NSLEEP_POLARITY_SHIFT 0x04 #define PALMAS_POLARITY_CTRL_RESET_IN_POLARITY 0x08 -#define PALMAS_POLARITY_CTRL_RESET_IN_POLARITY_SHIFT 3 +#define PALMAS_POLARITY_CTRL_RESET_IN_POLARITY_SHIFT 0x03 #define PALMAS_POLARITY_CTRL_GPIO_3_CHRG_DET_N_POLARITY 0x04 -#define PALMAS_POLARITY_CTRL_GPIO_3_CHRG_DET_N_POLARITY_SHIFT 2 +#define PALMAS_POLARITY_CTRL_GPIO_3_CHRG_DET_N_POLARITY_SHIFT 0x02 #define PALMAS_POLARITY_CTRL_POWERGOOD_USB_PSEL_POLARITY 0x02 -#define PALMAS_POLARITY_CTRL_POWERGOOD_USB_PSEL_POLARITY_SHIFT 1 +#define PALMAS_POLARITY_CTRL_POWERGOOD_USB_PSEL_POLARITY_SHIFT 0x01 #define PALMAS_POLARITY_CTRL_PWRDOWN_POLARITY 0x01 -#define PALMAS_POLARITY_CTRL_PWRDOWN_POLARITY_SHIFT 0 +#define PALMAS_POLARITY_CTRL_PWRDOWN_POLARITY_SHIFT 0x00 /* Bit definitions for PRIMARY_SECONDARY_PAD1 */ #define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3 0x80 -#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3_SHIFT 7 +#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3_SHIFT 0x07 #define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK 0x60 -#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT 5 +#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT 0x05 #define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK 0x18 -#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT 3 +#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT 0x03 #define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0 0x04 -#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0_SHIFT 2 +#define PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0_SHIFT 0x02 #define PALMAS_PRIMARY_SECONDARY_PAD1_VAC 0x02 -#define PALMAS_PRIMARY_SECONDARY_PAD1_VAC_SHIFT 1 +#define PALMAS_PRIMARY_SECONDARY_PAD1_VAC_SHIFT 0x01 #define PALMAS_PRIMARY_SECONDARY_PAD1_POWERGOOD 0x01 -#define PALMAS_PRIMARY_SECONDARY_PAD1_POWERGOOD_SHIFT 0 +#define PALMAS_PRIMARY_SECONDARY_PAD1_POWERGOOD_SHIFT 0x00 /* Bit definitions for PRIMARY_SECONDARY_PAD2 */ #define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK 0x30 -#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_SHIFT 4 +#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_SHIFT 0x04 #define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6 0x08 -#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6_SHIFT 3 +#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6_SHIFT 0x03 #define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK 0x06 -#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_SHIFT 1 +#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_SHIFT 0x01 #define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4 0x01 -#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4_SHIFT 0 +#define PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4_SHIFT 0x00 /* Bit definitions for I2C_SPI */ #define PALMAS_I2C_SPI_I2C2OTP_EN 0x80 -#define PALMAS_I2C_SPI_I2C2OTP_EN_SHIFT 7 +#define PALMAS_I2C_SPI_I2C2OTP_EN_SHIFT 0x07 #define PALMAS_I2C_SPI_I2C2OTP_PAGESEL 0x40 -#define PALMAS_I2C_SPI_I2C2OTP_PAGESEL_SHIFT 6 +#define PALMAS_I2C_SPI_I2C2OTP_PAGESEL_SHIFT 0x06 #define PALMAS_I2C_SPI_ID_I2C2 0x20 -#define PALMAS_I2C_SPI_ID_I2C2_SHIFT 5 +#define PALMAS_I2C_SPI_ID_I2C2_SHIFT 0x05 #define PALMAS_I2C_SPI_I2C_SPI 0x10 -#define PALMAS_I2C_SPI_I2C_SPI_SHIFT 4 -#define PALMAS_I2C_SPI_ID_I2C1_MASK 0x0f -#define PALMAS_I2C_SPI_ID_I2C1_SHIFT 0 +#define PALMAS_I2C_SPI_I2C_SPI_SHIFT 0x04 +#define PALMAS_I2C_SPI_ID_I2C1_MASK 0x0F +#define PALMAS_I2C_SPI_ID_I2C1_SHIFT 0x00 /* Bit definitions for PU_PD_INPUT_CTRL4 */ #define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_DAT_PD 0x40 -#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_DAT_PD_SHIFT 6 +#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_DAT_PD_SHIFT 0x06 #define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_CLK_PD 0x10 -#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_CLK_PD_SHIFT 4 +#define PALMAS_PU_PD_INPUT_CTRL4_DVFS2_CLK_PD_SHIFT 0x04 #define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_DAT_PD 0x04 -#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_DAT_PD_SHIFT 2 +#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_DAT_PD_SHIFT 0x02 #define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_CLK_PD 0x01 -#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_CLK_PD_SHIFT 0 +#define PALMAS_PU_PD_INPUT_CTRL4_DVFS1_CLK_PD_SHIFT 0x00 /* Bit definitions for PRIMARY_SECONDARY_PAD3 */ #define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2 0x02 -#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2_SHIFT 1 +#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS2_SHIFT 0x01 #define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1 0x01 -#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1_SHIFT 0 +#define PALMAS_PRIMARY_SECONDARY_PAD3_DVFS1_SHIFT 0x00 /* Registers for function LED_PWM */ -#define PALMAS_LED_PERIOD_CTRL 0x0 -#define PALMAS_LED_CTRL 0x1 -#define PALMAS_PWM_CTRL1 0x2 -#define PALMAS_PWM_CTRL2 0x3 +#define PALMAS_LED_PERIOD_CTRL 0x00 +#define PALMAS_LED_CTRL 0x01 +#define PALMAS_PWM_CTRL1 0x02 +#define PALMAS_PWM_CTRL2 0x03 /* Bit definitions for LED_PERIOD_CTRL */ #define PALMAS_LED_PERIOD_CTRL_LED_2_PERIOD_MASK 0x38 -#define PALMAS_LED_PERIOD_CTRL_LED_2_PERIOD_SHIFT 3 +#define PALMAS_LED_PERIOD_CTRL_LED_2_PERIOD_SHIFT 0x03 #define PALMAS_LED_PERIOD_CTRL_LED_1_PERIOD_MASK 0x07 -#define PALMAS_LED_PERIOD_CTRL_LED_1_PERIOD_SHIFT 0 +#define PALMAS_LED_PERIOD_CTRL_LED_1_PERIOD_SHIFT 0x00 /* Bit definitions for LED_CTRL */ #define PALMAS_LED_CTRL_LED_2_SEQ 0x20 -#define PALMAS_LED_CTRL_LED_2_SEQ_SHIFT 5 +#define PALMAS_LED_CTRL_LED_2_SEQ_SHIFT 0x05 #define PALMAS_LED_CTRL_LED_1_SEQ 0x10 -#define PALMAS_LED_CTRL_LED_1_SEQ_SHIFT 4 +#define PALMAS_LED_CTRL_LED_1_SEQ_SHIFT 0x04 #define PALMAS_LED_CTRL_LED_2_ON_TIME_MASK 0x0c -#define PALMAS_LED_CTRL_LED_2_ON_TIME_SHIFT 2 +#define PALMAS_LED_CTRL_LED_2_ON_TIME_SHIFT 0x02 #define PALMAS_LED_CTRL_LED_1_ON_TIME_MASK 0x03 -#define PALMAS_LED_CTRL_LED_1_ON_TIME_SHIFT 0 +#define PALMAS_LED_CTRL_LED_1_ON_TIME_SHIFT 0x00 /* Bit definitions for PWM_CTRL1 */ #define PALMAS_PWM_CTRL1_PWM_FREQ_EN 0x02 -#define PALMAS_PWM_CTRL1_PWM_FREQ_EN_SHIFT 1 +#define PALMAS_PWM_CTRL1_PWM_FREQ_EN_SHIFT 0x01 #define PALMAS_PWM_CTRL1_PWM_FREQ_SEL 0x01 -#define PALMAS_PWM_CTRL1_PWM_FREQ_SEL_SHIFT 0 +#define PALMAS_PWM_CTRL1_PWM_FREQ_SEL_SHIFT 0x00 /* Bit definitions for PWM_CTRL2 */ -#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_MASK 0xff -#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_SHIFT 0 +#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_MASK 0xFF +#define PALMAS_PWM_CTRL2_PWM_DUTY_SEL_SHIFT 0x00 /* Registers for function INTERRUPT */ -#define PALMAS_INT1_STATUS 0x0 -#define PALMAS_INT1_MASK 0x1 -#define PALMAS_INT1_LINE_STATE 0x2 -#define PALMAS_INT1_EDGE_DETECT1_RESERVED 0x3 -#define PALMAS_INT1_EDGE_DETECT2_RESERVED 0x4 -#define PALMAS_INT2_STATUS 0x5 -#define PALMAS_INT2_MASK 0x6 -#define PALMAS_INT2_LINE_STATE 0x7 -#define PALMAS_INT2_EDGE_DETECT1_RESERVED 0x8 -#define PALMAS_INT2_EDGE_DETECT2_RESERVED 0x9 -#define PALMAS_INT3_STATUS 0xA -#define PALMAS_INT3_MASK 0xB -#define PALMAS_INT3_LINE_STATE 0xC -#define PALMAS_INT3_EDGE_DETECT1_RESERVED 0xD -#define PALMAS_INT3_EDGE_DETECT2_RESERVED 0xE -#define PALMAS_INT4_STATUS 0xF +#define PALMAS_INT1_STATUS 0x00 +#define PALMAS_INT1_MASK 0x01 +#define PALMAS_INT1_LINE_STATE 0x02 +#define PALMAS_INT1_EDGE_DETECT1_RESERVED 0x03 +#define PALMAS_INT1_EDGE_DETECT2_RESERVED 0x04 +#define PALMAS_INT2_STATUS 0x05 +#define PALMAS_INT2_MASK 0x06 +#define PALMAS_INT2_LINE_STATE 0x07 +#define PALMAS_INT2_EDGE_DETECT1_RESERVED 0x08 +#define PALMAS_INT2_EDGE_DETECT2_RESERVED 0x09 +#define PALMAS_INT3_STATUS 0x0A +#define PALMAS_INT3_MASK 0x0B +#define PALMAS_INT3_LINE_STATE 0x0C +#define PALMAS_INT3_EDGE_DETECT1_RESERVED 0x0D +#define PALMAS_INT3_EDGE_DETECT2_RESERVED 0x0E +#define PALMAS_INT4_STATUS 0x0F #define PALMAS_INT4_MASK 0x10 #define PALMAS_INT4_LINE_STATE 0x11 #define PALMAS_INT4_EDGE_DETECT1 0x12 @@ -1966,276 +1966,276 @@ enum usb_irq_events { /* Bit definitions for INT1_STATUS */ #define PALMAS_INT1_STATUS_VBAT_MON 0x80 -#define PALMAS_INT1_STATUS_VBAT_MON_SHIFT 7 +#define PALMAS_INT1_STATUS_VBAT_MON_SHIFT 0x07 #define PALMAS_INT1_STATUS_VSYS_MON 0x40 -#define PALMAS_INT1_STATUS_VSYS_MON_SHIFT 6 +#define PALMAS_INT1_STATUS_VSYS_MON_SHIFT 0x06 #define PALMAS_INT1_STATUS_HOTDIE 0x20 -#define PALMAS_INT1_STATUS_HOTDIE_SHIFT 5 +#define PALMAS_INT1_STATUS_HOTDIE_SHIFT 0x05 #define PALMAS_INT1_STATUS_PWRDOWN 0x10 -#define PALMAS_INT1_STATUS_PWRDOWN_SHIFT 4 +#define PALMAS_INT1_STATUS_PWRDOWN_SHIFT 0x04 #define PALMAS_INT1_STATUS_RPWRON 0x08 -#define PALMAS_INT1_STATUS_RPWRON_SHIFT 3 +#define PALMAS_INT1_STATUS_RPWRON_SHIFT 0x03 #define PALMAS_INT1_STATUS_LONG_PRESS_KEY 0x04 -#define PALMAS_INT1_STATUS_LONG_PRESS_KEY_SHIFT 2 +#define PALMAS_INT1_STATUS_LONG_PRESS_KEY_SHIFT 0x02 #define PALMAS_INT1_STATUS_PWRON 0x02 -#define PALMAS_INT1_STATUS_PWRON_SHIFT 1 +#define PALMAS_INT1_STATUS_PWRON_SHIFT 0x01 #define PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV 0x01 -#define PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV_SHIFT 0 +#define PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV_SHIFT 0x00 /* Bit definitions for INT1_MASK */ #define PALMAS_INT1_MASK_VBAT_MON 0x80 -#define PALMAS_INT1_MASK_VBAT_MON_SHIFT 7 +#define PALMAS_INT1_MASK_VBAT_MON_SHIFT 0x07 #define PALMAS_INT1_MASK_VSYS_MON 0x40 -#define PALMAS_INT1_MASK_VSYS_MON_SHIFT 6 +#define PALMAS_INT1_MASK_VSYS_MON_SHIFT 0x06 #define PALMAS_INT1_MASK_HOTDIE 0x20 -#define PALMAS_INT1_MASK_HOTDIE_SHIFT 5 +#define PALMAS_INT1_MASK_HOTDIE_SHIFT 0x05 #define PALMAS_INT1_MASK_PWRDOWN 0x10 -#define PALMAS_INT1_MASK_PWRDOWN_SHIFT 4 +#define PALMAS_INT1_MASK_PWRDOWN_SHIFT 0x04 #define PALMAS_INT1_MASK_RPWRON 0x08 -#define PALMAS_INT1_MASK_RPWRON_SHIFT 3 +#define PALMAS_INT1_MASK_RPWRON_SHIFT 0x03 #define PALMAS_INT1_MASK_LONG_PRESS_KEY 0x04 -#define PALMAS_INT1_MASK_LONG_PRESS_KEY_SHIFT 2 +#define PALMAS_INT1_MASK_LONG_PRESS_KEY_SHIFT 0x02 #define PALMAS_INT1_MASK_PWRON 0x02 -#define PALMAS_INT1_MASK_PWRON_SHIFT 1 +#define PALMAS_INT1_MASK_PWRON_SHIFT 0x01 #define PALMAS_INT1_MASK_CHARG_DET_N_VBUS_OVV 0x01 -#define PALMAS_INT1_MASK_CHARG_DET_N_VBUS_OVV_SHIFT 0 +#define PALMAS_INT1_MASK_CHARG_DET_N_VBUS_OVV_SHIFT 0x00 /* Bit definitions for INT1_LINE_STATE */ #define PALMAS_INT1_LINE_STATE_VBAT_MON 0x80 -#define PALMAS_INT1_LINE_STATE_VBAT_MON_SHIFT 7 +#define PALMAS_INT1_LINE_STATE_VBAT_MON_SHIFT 0x07 #define PALMAS_INT1_LINE_STATE_VSYS_MON 0x40 -#define PALMAS_INT1_LINE_STATE_VSYS_MON_SHIFT 6 +#define PALMAS_INT1_LINE_STATE_VSYS_MON_SHIFT 0x06 #define PALMAS_INT1_LINE_STATE_HOTDIE 0x20 -#define PALMAS_INT1_LINE_STATE_HOTDIE_SHIFT 5 +#define PALMAS_INT1_LINE_STATE_HOTDIE_SHIFT 0x05 #define PALMAS_INT1_LINE_STATE_PWRDOWN 0x10 -#define PALMAS_INT1_LINE_STATE_PWRDOWN_SHIFT 4 +#define PALMAS_INT1_LINE_STATE_PWRDOWN_SHIFT 0x04 #define PALMAS_INT1_LINE_STATE_RPWRON 0x08 -#define PALMAS_INT1_LINE_STATE_RPWRON_SHIFT 3 +#define PALMAS_INT1_LINE_STATE_RPWRON_SHIFT 0x03 #define PALMAS_INT1_LINE_STATE_LONG_PRESS_KEY 0x04 -#define PALMAS_INT1_LINE_STATE_LONG_PRESS_KEY_SHIFT 2 +#define PALMAS_INT1_LINE_STATE_LONG_PRESS_KEY_SHIFT 0x02 #define PALMAS_INT1_LINE_STATE_PWRON 0x02 -#define PALMAS_INT1_LINE_STATE_PWRON_SHIFT 1 +#define PALMAS_INT1_LINE_STATE_PWRON_SHIFT 0x01 #define PALMAS_INT1_LINE_STATE_CHARG_DET_N_VBUS_OVV 0x01 -#define PALMAS_INT1_LINE_STATE_CHARG_DET_N_VBUS_OVV_SHIFT 0 +#define PALMAS_INT1_LINE_STATE_CHARG_DET_N_VBUS_OVV_SHIFT 0x00 /* Bit definitions for INT2_STATUS */ #define PALMAS_INT2_STATUS_VAC_ACOK 0x80 -#define PALMAS_INT2_STATUS_VAC_ACOK_SHIFT 7 +#define PALMAS_INT2_STATUS_VAC_ACOK_SHIFT 0x07 #define PALMAS_INT2_STATUS_SHORT 0x40 -#define PALMAS_INT2_STATUS_SHORT_SHIFT 6 +#define PALMAS_INT2_STATUS_SHORT_SHIFT 0x06 #define PALMAS_INT2_STATUS_FBI_BB 0x20 -#define PALMAS_INT2_STATUS_FBI_BB_SHIFT 5 +#define PALMAS_INT2_STATUS_FBI_BB_SHIFT 0x05 #define PALMAS_INT2_STATUS_RESET_IN 0x10 -#define PALMAS_INT2_STATUS_RESET_IN_SHIFT 4 +#define PALMAS_INT2_STATUS_RESET_IN_SHIFT 0x04 #define PALMAS_INT2_STATUS_BATREMOVAL 0x08 -#define PALMAS_INT2_STATUS_BATREMOVAL_SHIFT 3 +#define PALMAS_INT2_STATUS_BATREMOVAL_SHIFT 0x03 #define PALMAS_INT2_STATUS_WDT 0x04 -#define PALMAS_INT2_STATUS_WDT_SHIFT 2 +#define PALMAS_INT2_STATUS_WDT_SHIFT 0x02 #define PALMAS_INT2_STATUS_RTC_TIMER 0x02 -#define PALMAS_INT2_STATUS_RTC_TIMER_SHIFT 1 +#define PALMAS_INT2_STATUS_RTC_TIMER_SHIFT 0x01 #define PALMAS_INT2_STATUS_RTC_ALARM 0x01 -#define PALMAS_INT2_STATUS_RTC_ALARM_SHIFT 0 +#define PALMAS_INT2_STATUS_RTC_ALARM_SHIFT 0x00 /* Bit definitions for INT2_MASK */ #define PALMAS_INT2_MASK_VAC_ACOK 0x80 -#define PALMAS_INT2_MASK_VAC_ACOK_SHIFT 7 +#define PALMAS_INT2_MASK_VAC_ACOK_SHIFT 0x07 #define PALMAS_INT2_MASK_SHORT 0x40 -#define PALMAS_INT2_MASK_SHORT_SHIFT 6 +#define PALMAS_INT2_MASK_SHORT_SHIFT 0x06 #define PALMAS_INT2_MASK_FBI_BB 0x20 -#define PALMAS_INT2_MASK_FBI_BB_SHIFT 5 +#define PALMAS_INT2_MASK_FBI_BB_SHIFT 0x05 #define PALMAS_INT2_MASK_RESET_IN 0x10 -#define PALMAS_INT2_MASK_RESET_IN_SHIFT 4 +#define PALMAS_INT2_MASK_RESET_IN_SHIFT 0x04 #define PALMAS_INT2_MASK_BATREMOVAL 0x08 -#define PALMAS_INT2_MASK_BATREMOVAL_SHIFT 3 +#define PALMAS_INT2_MASK_BATREMOVAL_SHIFT 0x03 #define PALMAS_INT2_MASK_WDT 0x04 -#define PALMAS_INT2_MASK_WDT_SHIFT 2 +#define PALMAS_INT2_MASK_WDT_SHIFT 0x02 #define PALMAS_INT2_MASK_RTC_TIMER 0x02 -#define PALMAS_INT2_MASK_RTC_TIMER_SHIFT 1 +#define PALMAS_INT2_MASK_RTC_TIMER_SHIFT 0x01 #define PALMAS_INT2_MASK_RTC_ALARM 0x01 -#define PALMAS_INT2_MASK_RTC_ALARM_SHIFT 0 +#define PALMAS_INT2_MASK_RTC_ALARM_SHIFT 0x00 /* Bit definitions for INT2_LINE_STATE */ #define PALMAS_INT2_LINE_STATE_VAC_ACOK 0x80 -#define PALMAS_INT2_LINE_STATE_VAC_ACOK_SHIFT 7 +#define PALMAS_INT2_LINE_STATE_VAC_ACOK_SHIFT 0x07 #define PALMAS_INT2_LINE_STATE_SHORT 0x40 -#define PALMAS_INT2_LINE_STATE_SHORT_SHIFT 6 +#define PALMAS_INT2_LINE_STATE_SHORT_SHIFT 0x06 #define PALMAS_INT2_LINE_STATE_FBI_BB 0x20 -#define PALMAS_INT2_LINE_STATE_FBI_BB_SHIFT 5 +#define PALMAS_INT2_LINE_STATE_FBI_BB_SHIFT 0x05 #define PALMAS_INT2_LINE_STATE_RESET_IN 0x10 -#define PALMAS_INT2_LINE_STATE_RESET_IN_SHIFT 4 +#define PALMAS_INT2_LINE_STATE_RESET_IN_SHIFT 0x04 #define PALMAS_INT2_LINE_STATE_BATREMOVAL 0x08 -#define PALMAS_INT2_LINE_STATE_BATREMOVAL_SHIFT 3 +#define PALMAS_INT2_LINE_STATE_BATREMOVAL_SHIFT 0x03 #define PALMAS_INT2_LINE_STATE_WDT 0x04 -#define PALMAS_INT2_LINE_STATE_WDT_SHIFT 2 +#define PALMAS_INT2_LINE_STATE_WDT_SHIFT 0x02 #define PALMAS_INT2_LINE_STATE_RTC_TIMER 0x02 -#define PALMAS_INT2_LINE_STATE_RTC_TIMER_SHIFT 1 +#define PALMAS_INT2_LINE_STATE_RTC_TIMER_SHIFT 0x01 #define PALMAS_INT2_LINE_STATE_RTC_ALARM 0x01 -#define PALMAS_INT2_LINE_STATE_RTC_ALARM_SHIFT 0 +#define PALMAS_INT2_LINE_STATE_RTC_ALARM_SHIFT 0x00 /* Bit definitions for INT3_STATUS */ #define PALMAS_INT3_STATUS_VBUS 0x80 -#define PALMAS_INT3_STATUS_VBUS_SHIFT 7 +#define PALMAS_INT3_STATUS_VBUS_SHIFT 0x07 #define PALMAS_INT3_STATUS_VBUS_OTG 0x40 -#define PALMAS_INT3_STATUS_VBUS_OTG_SHIFT 6 +#define PALMAS_INT3_STATUS_VBUS_OTG_SHIFT 0x06 #define PALMAS_INT3_STATUS_ID 0x20 -#define PALMAS_INT3_STATUS_ID_SHIFT 5 +#define PALMAS_INT3_STATUS_ID_SHIFT 0x05 #define PALMAS_INT3_STATUS_ID_OTG 0x10 -#define PALMAS_INT3_STATUS_ID_OTG_SHIFT 4 +#define PALMAS_INT3_STATUS_ID_OTG_SHIFT 0x04 #define PALMAS_INT3_STATUS_GPADC_EOC_RT 0x08 -#define PALMAS_INT3_STATUS_GPADC_EOC_RT_SHIFT 3 +#define PALMAS_INT3_STATUS_GPADC_EOC_RT_SHIFT 0x03 #define PALMAS_INT3_STATUS_GPADC_EOC_SW 0x04 -#define PALMAS_INT3_STATUS_GPADC_EOC_SW_SHIFT 2 +#define PALMAS_INT3_STATUS_GPADC_EOC_SW_SHIFT 0x02 #define PALMAS_INT3_STATUS_GPADC_AUTO_1 0x02 -#define PALMAS_INT3_STATUS_GPADC_AUTO_1_SHIFT 1 +#define PALMAS_INT3_STATUS_GPADC_AUTO_1_SHIFT 0x01 #define PALMAS_INT3_STATUS_GPADC_AUTO_0 0x01 -#define PALMAS_INT3_STATUS_GPADC_AUTO_0_SHIFT 0 +#define PALMAS_INT3_STATUS_GPADC_AUTO_0_SHIFT 0x00 /* Bit definitions for INT3_MASK */ #define PALMAS_INT3_MASK_VBUS 0x80 -#define PALMAS_INT3_MASK_VBUS_SHIFT 7 +#define PALMAS_INT3_MASK_VBUS_SHIFT 0x07 #define PALMAS_INT3_MASK_VBUS_OTG 0x40 -#define PALMAS_INT3_MASK_VBUS_OTG_SHIFT 6 +#define PALMAS_INT3_MASK_VBUS_OTG_SHIFT 0x06 #define PALMAS_INT3_MASK_ID 0x20 -#define PALMAS_INT3_MASK_ID_SHIFT 5 +#define PALMAS_INT3_MASK_ID_SHIFT 0x05 #define PALMAS_INT3_MASK_ID_OTG 0x10 -#define PALMAS_INT3_MASK_ID_OTG_SHIFT 4 +#define PALMAS_INT3_MASK_ID_OTG_SHIFT 0x04 #define PALMAS_INT3_MASK_GPADC_EOC_RT 0x08 -#define PALMAS_INT3_MASK_GPADC_EOC_RT_SHIFT 3 +#define PALMAS_INT3_MASK_GPADC_EOC_RT_SHIFT 0x03 #define PALMAS_INT3_MASK_GPADC_EOC_SW 0x04 -#define PALMAS_INT3_MASK_GPADC_EOC_SW_SHIFT 2 +#define PALMAS_INT3_MASK_GPADC_EOC_SW_SHIFT 0x02 #define PALMAS_INT3_MASK_GPADC_AUTO_1 0x02 -#define PALMAS_INT3_MASK_GPADC_AUTO_1_SHIFT 1 +#define PALMAS_INT3_MASK_GPADC_AUTO_1_SHIFT 0x01 #define PALMAS_INT3_MASK_GPADC_AUTO_0 0x01 -#define PALMAS_INT3_MASK_GPADC_AUTO_0_SHIFT 0 +#define PALMAS_INT3_MASK_GPADC_AUTO_0_SHIFT 0x00 /* Bit definitions for INT3_LINE_STATE */ #define PALMAS_INT3_LINE_STATE_VBUS 0x80 -#define PALMAS_INT3_LINE_STATE_VBUS_SHIFT 7 +#define PALMAS_INT3_LINE_STATE_VBUS_SHIFT 0x07 #define PALMAS_INT3_LINE_STATE_VBUS_OTG 0x40 -#define PALMAS_INT3_LINE_STATE_VBUS_OTG_SHIFT 6 +#define PALMAS_INT3_LINE_STATE_VBUS_OTG_SHIFT 0x06 #define PALMAS_INT3_LINE_STATE_ID 0x20 -#define PALMAS_INT3_LINE_STATE_ID_SHIFT 5 +#define PALMAS_INT3_LINE_STATE_ID_SHIFT 0x05 #define PALMAS_INT3_LINE_STATE_ID_OTG 0x10 -#define PALMAS_INT3_LINE_STATE_ID_OTG_SHIFT 4 +#define PALMAS_INT3_LINE_STATE_ID_OTG_SHIFT 0x04 #define PALMAS_INT3_LINE_STATE_GPADC_EOC_RT 0x08 -#define PALMAS_INT3_LINE_STATE_GPADC_EOC_RT_SHIFT 3 +#define PALMAS_INT3_LINE_STATE_GPADC_EOC_RT_SHIFT 0x03 #define PALMAS_INT3_LINE_STATE_GPADC_EOC_SW 0x04 -#define PALMAS_INT3_LINE_STATE_GPADC_EOC_SW_SHIFT 2 +#define PALMAS_INT3_LINE_STATE_GPADC_EOC_SW_SHIFT 0x02 #define PALMAS_INT3_LINE_STATE_GPADC_AUTO_1 0x02 -#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_1_SHIFT 1 +#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_1_SHIFT 0x01 #define PALMAS_INT3_LINE_STATE_GPADC_AUTO_0 0x01 -#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_0_SHIFT 0 +#define PALMAS_INT3_LINE_STATE_GPADC_AUTO_0_SHIFT 0x00 /* Bit definitions for INT4_STATUS */ #define PALMAS_INT4_STATUS_GPIO_7 0x80 -#define PALMAS_INT4_STATUS_GPIO_7_SHIFT 7 +#define PALMAS_INT4_STATUS_GPIO_7_SHIFT 0x07 #define PALMAS_INT4_STATUS_GPIO_6 0x40 -#define PALMAS_INT4_STATUS_GPIO_6_SHIFT 6 +#define PALMAS_INT4_STATUS_GPIO_6_SHIFT 0x06 #define PALMAS_INT4_STATUS_GPIO_5 0x20 -#define PALMAS_INT4_STATUS_GPIO_5_SHIFT 5 +#define PALMAS_INT4_STATUS_GPIO_5_SHIFT 0x05 #define PALMAS_INT4_STATUS_GPIO_4 0x10 -#define PALMAS_INT4_STATUS_GPIO_4_SHIFT 4 +#define PALMAS_INT4_STATUS_GPIO_4_SHIFT 0x04 #define PALMAS_INT4_STATUS_GPIO_3 0x08 -#define PALMAS_INT4_STATUS_GPIO_3_SHIFT 3 +#define PALMAS_INT4_STATUS_GPIO_3_SHIFT 0x03 #define PALMAS_INT4_STATUS_GPIO_2 0x04 -#define PALMAS_INT4_STATUS_GPIO_2_SHIFT 2 +#define PALMAS_INT4_STATUS_GPIO_2_SHIFT 0x02 #define PALMAS_INT4_STATUS_GPIO_1 0x02 -#define PALMAS_INT4_STATUS_GPIO_1_SHIFT 1 +#define PALMAS_INT4_STATUS_GPIO_1_SHIFT 0x01 #define PALMAS_INT4_STATUS_GPIO_0 0x01 -#define PALMAS_INT4_STATUS_GPIO_0_SHIFT 0 +#define PALMAS_INT4_STATUS_GPIO_0_SHIFT 0x00 /* Bit definitions for INT4_MASK */ #define PALMAS_INT4_MASK_GPIO_7 0x80 -#define PALMAS_INT4_MASK_GPIO_7_SHIFT 7 +#define PALMAS_INT4_MASK_GPIO_7_SHIFT 0x07 #define PALMAS_INT4_MASK_GPIO_6 0x40 -#define PALMAS_INT4_MASK_GPIO_6_SHIFT 6 +#define PALMAS_INT4_MASK_GPIO_6_SHIFT 0x06 #define PALMAS_INT4_MASK_GPIO_5 0x20 -#define PALMAS_INT4_MASK_GPIO_5_SHIFT 5 +#define PALMAS_INT4_MASK_GPIO_5_SHIFT 0x05 #define PALMAS_INT4_MASK_GPIO_4 0x10 -#define PALMAS_INT4_MASK_GPIO_4_SHIFT 4 +#define PALMAS_INT4_MASK_GPIO_4_SHIFT 0x04 #define PALMAS_INT4_MASK_GPIO_3 0x08 -#define PALMAS_INT4_MASK_GPIO_3_SHIFT 3 +#define PALMAS_INT4_MASK_GPIO_3_SHIFT 0x03 #define PALMAS_INT4_MASK_GPIO_2 0x04 -#define PALMAS_INT4_MASK_GPIO_2_SHIFT 2 +#define PALMAS_INT4_MASK_GPIO_2_SHIFT 0x02 #define PALMAS_INT4_MASK_GPIO_1 0x02 -#define PALMAS_INT4_MASK_GPIO_1_SHIFT 1 +#define PALMAS_INT4_MASK_GPIO_1_SHIFT 0x01 #define PALMAS_INT4_MASK_GPIO_0 0x01 -#define PALMAS_INT4_MASK_GPIO_0_SHIFT 0 +#define PALMAS_INT4_MASK_GPIO_0_SHIFT 0x00 /* Bit definitions for INT4_LINE_STATE */ #define PALMAS_INT4_LINE_STATE_GPIO_7 0x80 -#define PALMAS_INT4_LINE_STATE_GPIO_7_SHIFT 7 +#define PALMAS_INT4_LINE_STATE_GPIO_7_SHIFT 0x07 #define PALMAS_INT4_LINE_STATE_GPIO_6 0x40 -#define PALMAS_INT4_LINE_STATE_GPIO_6_SHIFT 6 +#define PALMAS_INT4_LINE_STATE_GPIO_6_SHIFT 0x06 #define PALMAS_INT4_LINE_STATE_GPIO_5 0x20 -#define PALMAS_INT4_LINE_STATE_GPIO_5_SHIFT 5 +#define PALMAS_INT4_LINE_STATE_GPIO_5_SHIFT 0x05 #define PALMAS_INT4_LINE_STATE_GPIO_4 0x10 -#define PALMAS_INT4_LINE_STATE_GPIO_4_SHIFT 4 +#define PALMAS_INT4_LINE_STATE_GPIO_4_SHIFT 0x04 #define PALMAS_INT4_LINE_STATE_GPIO_3 0x08 -#define PALMAS_INT4_LINE_STATE_GPIO_3_SHIFT 3 +#define PALMAS_INT4_LINE_STATE_GPIO_3_SHIFT 0x03 #define PALMAS_INT4_LINE_STATE_GPIO_2 0x04 -#define PALMAS_INT4_LINE_STATE_GPIO_2_SHIFT 2 +#define PALMAS_INT4_LINE_STATE_GPIO_2_SHIFT 0x02 #define PALMAS_INT4_LINE_STATE_GPIO_1 0x02 -#define PALMAS_INT4_LINE_STATE_GPIO_1_SHIFT 1 +#define PALMAS_INT4_LINE_STATE_GPIO_1_SHIFT 0x01 #define PALMAS_INT4_LINE_STATE_GPIO_0 0x01 -#define PALMAS_INT4_LINE_STATE_GPIO_0_SHIFT 0 +#define PALMAS_INT4_LINE_STATE_GPIO_0_SHIFT 0x00 /* Bit definitions for INT4_EDGE_DETECT1 */ #define PALMAS_INT4_EDGE_DETECT1_GPIO_3_RISING 0x80 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_RISING_SHIFT 7 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_RISING_SHIFT 0x07 #define PALMAS_INT4_EDGE_DETECT1_GPIO_3_FALLING 0x40 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_FALLING_SHIFT 6 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_3_FALLING_SHIFT 0x06 #define PALMAS_INT4_EDGE_DETECT1_GPIO_2_RISING 0x20 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_RISING_SHIFT 5 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_RISING_SHIFT 0x05 #define PALMAS_INT4_EDGE_DETECT1_GPIO_2_FALLING 0x10 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_FALLING_SHIFT 4 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_2_FALLING_SHIFT 0x04 #define PALMAS_INT4_EDGE_DETECT1_GPIO_1_RISING 0x08 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_RISING_SHIFT 3 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_RISING_SHIFT 0x03 #define PALMAS_INT4_EDGE_DETECT1_GPIO_1_FALLING 0x04 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_FALLING_SHIFT 2 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_1_FALLING_SHIFT 0x02 #define PALMAS_INT4_EDGE_DETECT1_GPIO_0_RISING 0x02 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_RISING_SHIFT 1 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_RISING_SHIFT 0x01 #define PALMAS_INT4_EDGE_DETECT1_GPIO_0_FALLING 0x01 -#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_FALLING_SHIFT 0 +#define PALMAS_INT4_EDGE_DETECT1_GPIO_0_FALLING_SHIFT 0x00 /* Bit definitions for INT4_EDGE_DETECT2 */ #define PALMAS_INT4_EDGE_DETECT2_GPIO_7_RISING 0x80 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_RISING_SHIFT 7 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_RISING_SHIFT 0x07 #define PALMAS_INT4_EDGE_DETECT2_GPIO_7_FALLING 0x40 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_FALLING_SHIFT 6 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_7_FALLING_SHIFT 0x06 #define PALMAS_INT4_EDGE_DETECT2_GPIO_6_RISING 0x20 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_RISING_SHIFT 5 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_RISING_SHIFT 0x05 #define PALMAS_INT4_EDGE_DETECT2_GPIO_6_FALLING 0x10 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_FALLING_SHIFT 4 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_6_FALLING_SHIFT 0x04 #define PALMAS_INT4_EDGE_DETECT2_GPIO_5_RISING 0x08 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_RISING_SHIFT 3 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_RISING_SHIFT 0x03 #define PALMAS_INT4_EDGE_DETECT2_GPIO_5_FALLING 0x04 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_FALLING_SHIFT 2 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_5_FALLING_SHIFT 0x02 #define PALMAS_INT4_EDGE_DETECT2_GPIO_4_RISING 0x02 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_RISING_SHIFT 1 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_RISING_SHIFT 0x01 #define PALMAS_INT4_EDGE_DETECT2_GPIO_4_FALLING 0x01 -#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_FALLING_SHIFT 0 +#define PALMAS_INT4_EDGE_DETECT2_GPIO_4_FALLING_SHIFT 0x00 /* Bit definitions for INT_CTRL */ #define PALMAS_INT_CTRL_INT_PENDING 0x04 -#define PALMAS_INT_CTRL_INT_PENDING_SHIFT 2 +#define PALMAS_INT_CTRL_INT_PENDING_SHIFT 0x02 #define PALMAS_INT_CTRL_INT_CLEAR 0x01 -#define PALMAS_INT_CTRL_INT_CLEAR_SHIFT 0 +#define PALMAS_INT_CTRL_INT_CLEAR_SHIFT 0x00 /* Registers for function USB_OTG */ -#define PALMAS_USB_WAKEUP 0x3 -#define PALMAS_USB_VBUS_CTRL_SET 0x4 -#define PALMAS_USB_VBUS_CTRL_CLR 0x5 -#define PALMAS_USB_ID_CTRL_SET 0x6 -#define PALMAS_USB_ID_CTRL_CLEAR 0x7 -#define PALMAS_USB_VBUS_INT_SRC 0x8 -#define PALMAS_USB_VBUS_INT_LATCH_SET 0x9 -#define PALMAS_USB_VBUS_INT_LATCH_CLR 0xA -#define PALMAS_USB_VBUS_INT_EN_LO_SET 0xB -#define PALMAS_USB_VBUS_INT_EN_LO_CLR 0xC -#define PALMAS_USB_VBUS_INT_EN_HI_SET 0xD -#define PALMAS_USB_VBUS_INT_EN_HI_CLR 0xE -#define PALMAS_USB_ID_INT_SRC 0xF +#define PALMAS_USB_WAKEUP 0x03 +#define PALMAS_USB_VBUS_CTRL_SET 0x04 +#define PALMAS_USB_VBUS_CTRL_CLR 0x05 +#define PALMAS_USB_ID_CTRL_SET 0x06 +#define PALMAS_USB_ID_CTRL_CLEAR 0x07 +#define PALMAS_USB_VBUS_INT_SRC 0x08 +#define PALMAS_USB_VBUS_INT_LATCH_SET 0x09 +#define PALMAS_USB_VBUS_INT_LATCH_CLR 0x0A +#define PALMAS_USB_VBUS_INT_EN_LO_SET 0x0B +#define PALMAS_USB_VBUS_INT_EN_LO_CLR 0x0C +#define PALMAS_USB_VBUS_INT_EN_HI_SET 0x0D +#define PALMAS_USB_VBUS_INT_EN_HI_CLR 0x0E +#define PALMAS_USB_ID_INT_SRC 0x0F #define PALMAS_USB_ID_INT_LATCH_SET 0x10 #define PALMAS_USB_ID_INT_LATCH_CLR 0x11 #define PALMAS_USB_ID_INT_EN_LO_SET 0x12 @@ -2250,306 +2250,306 @@ enum usb_irq_events { /* Bit definitions for USB_WAKEUP */ #define PALMAS_USB_WAKEUP_ID_WK_UP_COMP 0x01 -#define PALMAS_USB_WAKEUP_ID_WK_UP_COMP_SHIFT 0 +#define PALMAS_USB_WAKEUP_ID_WK_UP_COMP_SHIFT 0x00 /* Bit definitions for USB_VBUS_CTRL_SET */ #define PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS 0x80 -#define PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS_SHIFT 7 +#define PALMAS_USB_VBUS_CTRL_SET_VBUS_CHRG_VSYS_SHIFT 0x07 #define PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG 0x20 -#define PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG_SHIFT 5 +#define PALMAS_USB_VBUS_CTRL_SET_VBUS_DISCHRG_SHIFT 0x05 #define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SRC 0x10 -#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SRC_SHIFT 4 +#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SRC_SHIFT 0x04 #define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK 0x08 -#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK_SHIFT 3 +#define PALMAS_USB_VBUS_CTRL_SET_VBUS_IADP_SINK_SHIFT 0x03 #define PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP 0x04 -#define PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP_SHIFT 2 +#define PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP_SHIFT 0x02 /* Bit definitions for USB_VBUS_CTRL_CLR */ #define PALMAS_USB_VBUS_CTRL_CLR_VBUS_CHRG_VSYS 0x80 -#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_CHRG_VSYS_SHIFT 7 +#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_CHRG_VSYS_SHIFT 0x07 #define PALMAS_USB_VBUS_CTRL_CLR_VBUS_DISCHRG 0x20 -#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_DISCHRG_SHIFT 5 +#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_DISCHRG_SHIFT 0x05 #define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SRC 0x10 -#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SRC_SHIFT 4 +#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SRC_SHIFT 0x04 #define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SINK 0x08 -#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SINK_SHIFT 3 +#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_IADP_SINK_SHIFT 0x03 #define PALMAS_USB_VBUS_CTRL_CLR_VBUS_ACT_COMP 0x04 -#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_ACT_COMP_SHIFT 2 +#define PALMAS_USB_VBUS_CTRL_CLR_VBUS_ACT_COMP_SHIFT 0x02 /* Bit definitions for USB_ID_CTRL_SET */ #define PALMAS_USB_ID_CTRL_SET_ID_PU_220K 0x80 -#define PALMAS_USB_ID_CTRL_SET_ID_PU_220K_SHIFT 7 +#define PALMAS_USB_ID_CTRL_SET_ID_PU_220K_SHIFT 0x07 #define PALMAS_USB_ID_CTRL_SET_ID_PU_100K 0x40 -#define PALMAS_USB_ID_CTRL_SET_ID_PU_100K_SHIFT 6 +#define PALMAS_USB_ID_CTRL_SET_ID_PU_100K_SHIFT 0x06 #define PALMAS_USB_ID_CTRL_SET_ID_GND_DRV 0x20 -#define PALMAS_USB_ID_CTRL_SET_ID_GND_DRV_SHIFT 5 +#define PALMAS_USB_ID_CTRL_SET_ID_GND_DRV_SHIFT 0x05 #define PALMAS_USB_ID_CTRL_SET_ID_SRC_16U 0x10 -#define PALMAS_USB_ID_CTRL_SET_ID_SRC_16U_SHIFT 4 +#define PALMAS_USB_ID_CTRL_SET_ID_SRC_16U_SHIFT 0x04 #define PALMAS_USB_ID_CTRL_SET_ID_SRC_5U 0x08 -#define PALMAS_USB_ID_CTRL_SET_ID_SRC_5U_SHIFT 3 +#define PALMAS_USB_ID_CTRL_SET_ID_SRC_5U_SHIFT 0x03 #define PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP 0x04 -#define PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP_SHIFT 2 +#define PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP_SHIFT 0x02 /* Bit definitions for USB_ID_CTRL_CLEAR */ #define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_220K 0x80 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_220K_SHIFT 7 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_220K_SHIFT 0x07 #define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_100K 0x40 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_100K_SHIFT 6 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_PU_100K_SHIFT 0x06 #define PALMAS_USB_ID_CTRL_CLEAR_ID_GND_DRV 0x20 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_GND_DRV_SHIFT 5 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_GND_DRV_SHIFT 0x05 #define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_16U 0x10 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_16U_SHIFT 4 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_16U_SHIFT 0x04 #define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_5U 0x08 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_5U_SHIFT 3 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_SRC_5U_SHIFT 0x03 #define PALMAS_USB_ID_CTRL_CLEAR_ID_ACT_COMP 0x04 -#define PALMAS_USB_ID_CTRL_CLEAR_ID_ACT_COMP_SHIFT 2 +#define PALMAS_USB_ID_CTRL_CLEAR_ID_ACT_COMP_SHIFT 0x02 /* Bit definitions for USB_VBUS_INT_SRC */ #define PALMAS_USB_VBUS_INT_SRC_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_SRC_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_SRC_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_SRC_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_SRC_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_SRC_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_SRC_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_SRC_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_SRC_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_SRC_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_SRC_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_SRC_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_SRC_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_SRC_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_SRC_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_SRC_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_SRC_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_SRC_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_LATCH_SET */ #define PALMAS_USB_VBUS_INT_LATCH_SET_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_LATCH_SET_ADP 0x10 -#define PALMAS_USB_VBUS_INT_LATCH_SET_ADP_SHIFT 4 +#define PALMAS_USB_VBUS_INT_LATCH_SET_ADP_SHIFT 0x04 #define PALMAS_USB_VBUS_INT_LATCH_SET_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_LATCH_SET_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_LATCH_SET_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_LATCH_CLR */ #define PALMAS_USB_VBUS_INT_LATCH_CLR_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_LATCH_CLR_ADP 0x10 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_ADP_SHIFT 4 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_ADP_SHIFT 0x04 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_LATCH_CLR_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_EN_LO_SET */ #define PALMAS_USB_VBUS_INT_EN_LO_SET_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_EN_LO_SET_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_EN_LO_CLR */ #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_EN_LO_CLR_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_EN_HI_SET */ #define PALMAS_USB_VBUS_INT_EN_HI_SET_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_EN_HI_SET_ADP 0x10 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_ADP_SHIFT 4 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_ADP_SHIFT 0x04 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_EN_HI_SET_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_VBUS_INT_EN_HI_CLR */ #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VOTG_SESS_VLD 0x80 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VOTG_SESS_VLD_SHIFT 7 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VOTG_SESS_VLD_SHIFT 0x07 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_PRB 0x40 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_PRB_SHIFT 6 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_PRB_SHIFT 0x06 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_SNS 0x20 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_SNS_SHIFT 5 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VADP_SNS_SHIFT 0x05 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_ADP 0x10 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_ADP_SHIFT 4 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_ADP_SHIFT 0x04 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_VBUS_VLD 0x08 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_VBUS_VLD_SHIFT 3 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_VBUS_VLD_SHIFT 0x03 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_SESS_VLD 0x04 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_SESS_VLD_SHIFT 2 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VA_SESS_VLD_SHIFT 0x02 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_VLD 0x02 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_VLD_SHIFT 1 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_VLD_SHIFT 0x01 #define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_END 0x01 -#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_END_SHIFT 0 +#define PALMAS_USB_VBUS_INT_EN_HI_CLR_VB_SESS_END_SHIFT 0x00 /* Bit definitions for USB_ID_INT_SRC */ #define PALMAS_USB_ID_INT_SRC_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_SRC_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_SRC_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_SRC_ID_A 0x08 -#define PALMAS_USB_ID_INT_SRC_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_SRC_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_SRC_ID_B 0x04 -#define PALMAS_USB_ID_INT_SRC_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_SRC_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_SRC_ID_C 0x02 -#define PALMAS_USB_ID_INT_SRC_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_SRC_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_SRC_ID_GND 0x01 -#define PALMAS_USB_ID_INT_SRC_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_SRC_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_LATCH_SET */ #define PALMAS_USB_ID_INT_LATCH_SET_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_LATCH_SET_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_LATCH_SET_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_LATCH_SET_ID_A 0x08 -#define PALMAS_USB_ID_INT_LATCH_SET_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_LATCH_SET_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_LATCH_SET_ID_B 0x04 -#define PALMAS_USB_ID_INT_LATCH_SET_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_LATCH_SET_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_LATCH_SET_ID_C 0x02 -#define PALMAS_USB_ID_INT_LATCH_SET_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_LATCH_SET_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_LATCH_SET_ID_GND 0x01 -#define PALMAS_USB_ID_INT_LATCH_SET_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_LATCH_SET_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_LATCH_CLR */ #define PALMAS_USB_ID_INT_LATCH_CLR_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_LATCH_CLR_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_LATCH_CLR_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_LATCH_CLR_ID_A 0x08 -#define PALMAS_USB_ID_INT_LATCH_CLR_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_LATCH_CLR_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_LATCH_CLR_ID_B 0x04 -#define PALMAS_USB_ID_INT_LATCH_CLR_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_LATCH_CLR_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_LATCH_CLR_ID_C 0x02 -#define PALMAS_USB_ID_INT_LATCH_CLR_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_LATCH_CLR_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_LATCH_CLR_ID_GND 0x01 -#define PALMAS_USB_ID_INT_LATCH_CLR_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_LATCH_CLR_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_EN_LO_SET */ #define PALMAS_USB_ID_INT_EN_LO_SET_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_EN_LO_SET_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_EN_LO_SET_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_EN_LO_SET_ID_A 0x08 -#define PALMAS_USB_ID_INT_EN_LO_SET_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_EN_LO_SET_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_EN_LO_SET_ID_B 0x04 -#define PALMAS_USB_ID_INT_EN_LO_SET_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_EN_LO_SET_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_EN_LO_SET_ID_C 0x02 -#define PALMAS_USB_ID_INT_EN_LO_SET_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_EN_LO_SET_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_EN_LO_SET_ID_GND 0x01 -#define PALMAS_USB_ID_INT_EN_LO_SET_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_EN_LO_SET_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_EN_LO_CLR */ #define PALMAS_USB_ID_INT_EN_LO_CLR_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_EN_LO_CLR_ID_A 0x08 -#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_EN_LO_CLR_ID_B 0x04 -#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_EN_LO_CLR_ID_C 0x02 -#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_EN_LO_CLR_ID_GND 0x01 -#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_EN_LO_CLR_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_EN_HI_SET */ #define PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_EN_HI_SET_ID_A 0x08 -#define PALMAS_USB_ID_INT_EN_HI_SET_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_EN_HI_SET_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_EN_HI_SET_ID_B 0x04 -#define PALMAS_USB_ID_INT_EN_HI_SET_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_EN_HI_SET_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_EN_HI_SET_ID_C 0x02 -#define PALMAS_USB_ID_INT_EN_HI_SET_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_EN_HI_SET_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_EN_HI_SET_ID_GND 0x01 -#define PALMAS_USB_ID_INT_EN_HI_SET_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_EN_HI_SET_ID_GND_SHIFT 0x00 /* Bit definitions for USB_ID_INT_EN_HI_CLR */ #define PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT 0x10 -#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT_SHIFT 4 +#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT_SHIFT 0x04 #define PALMAS_USB_ID_INT_EN_HI_CLR_ID_A 0x08 -#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_A_SHIFT 3 +#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_A_SHIFT 0x03 #define PALMAS_USB_ID_INT_EN_HI_CLR_ID_B 0x04 -#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_B_SHIFT 2 +#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_B_SHIFT 0x02 #define PALMAS_USB_ID_INT_EN_HI_CLR_ID_C 0x02 -#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_C_SHIFT 1 +#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_C_SHIFT 0x01 #define PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND 0x01 -#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND_SHIFT 0 +#define PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND_SHIFT 0x00 /* Bit definitions for USB_OTG_ADP_CTRL */ #define PALMAS_USB_OTG_ADP_CTRL_ADP_EN 0x04 -#define PALMAS_USB_OTG_ADP_CTRL_ADP_EN_SHIFT 2 +#define PALMAS_USB_OTG_ADP_CTRL_ADP_EN_SHIFT 0x02 #define PALMAS_USB_OTG_ADP_CTRL_ADP_MODE_MASK 0x03 -#define PALMAS_USB_OTG_ADP_CTRL_ADP_MODE_SHIFT 0 +#define PALMAS_USB_OTG_ADP_CTRL_ADP_MODE_SHIFT 0x00 /* Bit definitions for USB_OTG_ADP_HIGH */ -#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_MASK 0xff -#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_SHIFT 0 +#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_MASK 0xFF +#define PALMAS_USB_OTG_ADP_HIGH_T_ADP_HIGH_SHIFT 0x00 /* Bit definitions for USB_OTG_ADP_LOW */ -#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_MASK 0xff -#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_SHIFT 0 +#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_MASK 0xFF +#define PALMAS_USB_OTG_ADP_LOW_T_ADP_LOW_SHIFT 0x00 /* Bit definitions for USB_OTG_ADP_RISE */ -#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_MASK 0xff -#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_SHIFT 0 +#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_MASK 0xFF +#define PALMAS_USB_OTG_ADP_RISE_T_ADP_RISE_SHIFT 0x00 /* Bit definitions for USB_OTG_REVISION */ #define PALMAS_USB_OTG_REVISION_OTG_REV 0x01 -#define PALMAS_USB_OTG_REVISION_OTG_REV_SHIFT 0 +#define PALMAS_USB_OTG_REVISION_OTG_REV_SHIFT 0x00 /* Registers for function VIBRATOR */ -#define PALMAS_VIBRA_CTRL 0x0 +#define PALMAS_VIBRA_CTRL 0x00 /* Bit definitions for VIBRA_CTRL */ #define PALMAS_VIBRA_CTRL_PWM_DUTY_SEL_MASK 0x06 -#define PALMAS_VIBRA_CTRL_PWM_DUTY_SEL_SHIFT 1 +#define PALMAS_VIBRA_CTRL_PWM_DUTY_SEL_SHIFT 0x01 #define PALMAS_VIBRA_CTRL_PWM_FREQ_SEL 0x01 -#define PALMAS_VIBRA_CTRL_PWM_FREQ_SEL_SHIFT 0 +#define PALMAS_VIBRA_CTRL_PWM_FREQ_SEL_SHIFT 0x00 /* Registers for function GPIO */ -#define PALMAS_GPIO_DATA_IN 0x0 -#define PALMAS_GPIO_DATA_DIR 0x1 -#define PALMAS_GPIO_DATA_OUT 0x2 -#define PALMAS_GPIO_DEBOUNCE_EN 0x3 -#define PALMAS_GPIO_CLEAR_DATA_OUT 0x4 -#define PALMAS_GPIO_SET_DATA_OUT 0x5 -#define PALMAS_PU_PD_GPIO_CTRL1 0x6 -#define PALMAS_PU_PD_GPIO_CTRL2 0x7 -#define PALMAS_OD_OUTPUT_GPIO_CTRL 0x8 -#define PALMAS_GPIO_DATA_IN2 0x9 +#define PALMAS_GPIO_DATA_IN 0x00 +#define PALMAS_GPIO_DATA_DIR 0x01 +#define PALMAS_GPIO_DATA_OUT 0x02 +#define PALMAS_GPIO_DEBOUNCE_EN 0x03 +#define PALMAS_GPIO_CLEAR_DATA_OUT 0x04 +#define PALMAS_GPIO_SET_DATA_OUT 0x05 +#define PALMAS_PU_PD_GPIO_CTRL1 0x06 +#define PALMAS_PU_PD_GPIO_CTRL2 0x07 +#define PALMAS_OD_OUTPUT_GPIO_CTRL 0x08 +#define PALMAS_GPIO_DATA_IN2 0x09 #define PALMAS_GPIO_DATA_DIR2 0x0A #define PALMAS_GPIO_DATA_OUT2 0x0B #define PALMAS_GPIO_DEBOUNCE_EN2 0x0C @@ -2561,167 +2561,167 @@ enum usb_irq_events { /* Bit definitions for GPIO_DATA_IN */ #define PALMAS_GPIO_DATA_IN_GPIO_7_IN 0x80 -#define PALMAS_GPIO_DATA_IN_GPIO_7_IN_SHIFT 7 +#define PALMAS_GPIO_DATA_IN_GPIO_7_IN_SHIFT 0x07 #define PALMAS_GPIO_DATA_IN_GPIO_6_IN 0x40 -#define PALMAS_GPIO_DATA_IN_GPIO_6_IN_SHIFT 6 +#define PALMAS_GPIO_DATA_IN_GPIO_6_IN_SHIFT 0x06 #define PALMAS_GPIO_DATA_IN_GPIO_5_IN 0x20 -#define PALMAS_GPIO_DATA_IN_GPIO_5_IN_SHIFT 5 +#define PALMAS_GPIO_DATA_IN_GPIO_5_IN_SHIFT 0x05 #define PALMAS_GPIO_DATA_IN_GPIO_4_IN 0x10 -#define PALMAS_GPIO_DATA_IN_GPIO_4_IN_SHIFT 4 +#define PALMAS_GPIO_DATA_IN_GPIO_4_IN_SHIFT 0x04 #define PALMAS_GPIO_DATA_IN_GPIO_3_IN 0x08 -#define PALMAS_GPIO_DATA_IN_GPIO_3_IN_SHIFT 3 +#define PALMAS_GPIO_DATA_IN_GPIO_3_IN_SHIFT 0x03 #define PALMAS_GPIO_DATA_IN_GPIO_2_IN 0x04 -#define PALMAS_GPIO_DATA_IN_GPIO_2_IN_SHIFT 2 +#define PALMAS_GPIO_DATA_IN_GPIO_2_IN_SHIFT 0x02 #define PALMAS_GPIO_DATA_IN_GPIO_1_IN 0x02 -#define PALMAS_GPIO_DATA_IN_GPIO_1_IN_SHIFT 1 +#define PALMAS_GPIO_DATA_IN_GPIO_1_IN_SHIFT 0x01 #define PALMAS_GPIO_DATA_IN_GPIO_0_IN 0x01 -#define PALMAS_GPIO_DATA_IN_GPIO_0_IN_SHIFT 0 +#define PALMAS_GPIO_DATA_IN_GPIO_0_IN_SHIFT 0x00 /* Bit definitions for GPIO_DATA_DIR */ #define PALMAS_GPIO_DATA_DIR_GPIO_7_DIR 0x80 -#define PALMAS_GPIO_DATA_DIR_GPIO_7_DIR_SHIFT 7 +#define PALMAS_GPIO_DATA_DIR_GPIO_7_DIR_SHIFT 0x07 #define PALMAS_GPIO_DATA_DIR_GPIO_6_DIR 0x40 -#define PALMAS_GPIO_DATA_DIR_GPIO_6_DIR_SHIFT 6 +#define PALMAS_GPIO_DATA_DIR_GPIO_6_DIR_SHIFT 0x06 #define PALMAS_GPIO_DATA_DIR_GPIO_5_DIR 0x20 -#define PALMAS_GPIO_DATA_DIR_GPIO_5_DIR_SHIFT 5 +#define PALMAS_GPIO_DATA_DIR_GPIO_5_DIR_SHIFT 0x05 #define PALMAS_GPIO_DATA_DIR_GPIO_4_DIR 0x10 -#define PALMAS_GPIO_DATA_DIR_GPIO_4_DIR_SHIFT 4 +#define PALMAS_GPIO_DATA_DIR_GPIO_4_DIR_SHIFT 0x04 #define PALMAS_GPIO_DATA_DIR_GPIO_3_DIR 0x08 -#define PALMAS_GPIO_DATA_DIR_GPIO_3_DIR_SHIFT 3 +#define PALMAS_GPIO_DATA_DIR_GPIO_3_DIR_SHIFT 0x03 #define PALMAS_GPIO_DATA_DIR_GPIO_2_DIR 0x04 -#define PALMAS_GPIO_DATA_DIR_GPIO_2_DIR_SHIFT 2 +#define PALMAS_GPIO_DATA_DIR_GPIO_2_DIR_SHIFT 0x02 #define PALMAS_GPIO_DATA_DIR_GPIO_1_DIR 0x02 -#define PALMAS_GPIO_DATA_DIR_GPIO_1_DIR_SHIFT 1 +#define PALMAS_GPIO_DATA_DIR_GPIO_1_DIR_SHIFT 0x01 #define PALMAS_GPIO_DATA_DIR_GPIO_0_DIR 0x01 -#define PALMAS_GPIO_DATA_DIR_GPIO_0_DIR_SHIFT 0 +#define PALMAS_GPIO_DATA_DIR_GPIO_0_DIR_SHIFT 0x00 /* Bit definitions for GPIO_DATA_OUT */ #define PALMAS_GPIO_DATA_OUT_GPIO_7_OUT 0x80 -#define PALMAS_GPIO_DATA_OUT_GPIO_7_OUT_SHIFT 7 +#define PALMAS_GPIO_DATA_OUT_GPIO_7_OUT_SHIFT 0x07 #define PALMAS_GPIO_DATA_OUT_GPIO_6_OUT 0x40 -#define PALMAS_GPIO_DATA_OUT_GPIO_6_OUT_SHIFT 6 +#define PALMAS_GPIO_DATA_OUT_GPIO_6_OUT_SHIFT 0x06 #define PALMAS_GPIO_DATA_OUT_GPIO_5_OUT 0x20 -#define PALMAS_GPIO_DATA_OUT_GPIO_5_OUT_SHIFT 5 +#define PALMAS_GPIO_DATA_OUT_GPIO_5_OUT_SHIFT 0x05 #define PALMAS_GPIO_DATA_OUT_GPIO_4_OUT 0x10 -#define PALMAS_GPIO_DATA_OUT_GPIO_4_OUT_SHIFT 4 +#define PALMAS_GPIO_DATA_OUT_GPIO_4_OUT_SHIFT 0x04 #define PALMAS_GPIO_DATA_OUT_GPIO_3_OUT 0x08 -#define PALMAS_GPIO_DATA_OUT_GPIO_3_OUT_SHIFT 3 +#define PALMAS_GPIO_DATA_OUT_GPIO_3_OUT_SHIFT 0x03 #define PALMAS_GPIO_DATA_OUT_GPIO_2_OUT 0x04 -#define PALMAS_GPIO_DATA_OUT_GPIO_2_OUT_SHIFT 2 +#define PALMAS_GPIO_DATA_OUT_GPIO_2_OUT_SHIFT 0x02 #define PALMAS_GPIO_DATA_OUT_GPIO_1_OUT 0x02 -#define PALMAS_GPIO_DATA_OUT_GPIO_1_OUT_SHIFT 1 +#define PALMAS_GPIO_DATA_OUT_GPIO_1_OUT_SHIFT 0x01 #define PALMAS_GPIO_DATA_OUT_GPIO_0_OUT 0x01 -#define PALMAS_GPIO_DATA_OUT_GPIO_0_OUT_SHIFT 0 +#define PALMAS_GPIO_DATA_OUT_GPIO_0_OUT_SHIFT 0x00 /* Bit definitions for GPIO_DEBOUNCE_EN */ #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_7_DEBOUNCE_EN 0x80 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_7_DEBOUNCE_EN_SHIFT 7 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_7_DEBOUNCE_EN_SHIFT 0x07 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_6_DEBOUNCE_EN 0x40 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_6_DEBOUNCE_EN_SHIFT 6 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_6_DEBOUNCE_EN_SHIFT 0x06 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_5_DEBOUNCE_EN 0x20 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_5_DEBOUNCE_EN_SHIFT 5 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_5_DEBOUNCE_EN_SHIFT 0x05 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_4_DEBOUNCE_EN 0x10 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_4_DEBOUNCE_EN_SHIFT 4 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_4_DEBOUNCE_EN_SHIFT 0x04 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_3_DEBOUNCE_EN 0x08 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_3_DEBOUNCE_EN_SHIFT 3 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_3_DEBOUNCE_EN_SHIFT 0x03 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_2_DEBOUNCE_EN 0x04 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_2_DEBOUNCE_EN_SHIFT 2 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_2_DEBOUNCE_EN_SHIFT 0x02 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_1_DEBOUNCE_EN 0x02 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_1_DEBOUNCE_EN_SHIFT 1 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_1_DEBOUNCE_EN_SHIFT 0x01 #define PALMAS_GPIO_DEBOUNCE_EN_GPIO_0_DEBOUNCE_EN 0x01 -#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_0_DEBOUNCE_EN_SHIFT 0 +#define PALMAS_GPIO_DEBOUNCE_EN_GPIO_0_DEBOUNCE_EN_SHIFT 0x00 /* Bit definitions for GPIO_CLEAR_DATA_OUT */ #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_7_CLEAR_DATA_OUT 0x80 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_7_CLEAR_DATA_OUT_SHIFT 7 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_7_CLEAR_DATA_OUT_SHIFT 0x07 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_6_CLEAR_DATA_OUT 0x40 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_6_CLEAR_DATA_OUT_SHIFT 6 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_6_CLEAR_DATA_OUT_SHIFT 0x06 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_5_CLEAR_DATA_OUT 0x20 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_5_CLEAR_DATA_OUT_SHIFT 5 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_5_CLEAR_DATA_OUT_SHIFT 0x05 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_4_CLEAR_DATA_OUT 0x10 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_4_CLEAR_DATA_OUT_SHIFT 4 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_4_CLEAR_DATA_OUT_SHIFT 0x04 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_3_CLEAR_DATA_OUT 0x08 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_3_CLEAR_DATA_OUT_SHIFT 3 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_3_CLEAR_DATA_OUT_SHIFT 0x03 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_2_CLEAR_DATA_OUT 0x04 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_2_CLEAR_DATA_OUT_SHIFT 2 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_2_CLEAR_DATA_OUT_SHIFT 0x02 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_1_CLEAR_DATA_OUT 0x02 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_1_CLEAR_DATA_OUT_SHIFT 1 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_1_CLEAR_DATA_OUT_SHIFT 0x01 #define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_0_CLEAR_DATA_OUT 0x01 -#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_0_CLEAR_DATA_OUT_SHIFT 0 +#define PALMAS_GPIO_CLEAR_DATA_OUT_GPIO_0_CLEAR_DATA_OUT_SHIFT 0x00 /* Bit definitions for GPIO_SET_DATA_OUT */ #define PALMAS_GPIO_SET_DATA_OUT_GPIO_7_SET_DATA_OUT 0x80 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_7_SET_DATA_OUT_SHIFT 7 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_7_SET_DATA_OUT_SHIFT 0x07 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_6_SET_DATA_OUT 0x40 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_6_SET_DATA_OUT_SHIFT 6 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_6_SET_DATA_OUT_SHIFT 0x06 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_5_SET_DATA_OUT 0x20 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_5_SET_DATA_OUT_SHIFT 5 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_5_SET_DATA_OUT_SHIFT 0x05 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_4_SET_DATA_OUT 0x10 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_4_SET_DATA_OUT_SHIFT 4 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_4_SET_DATA_OUT_SHIFT 0x04 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_3_SET_DATA_OUT 0x08 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_3_SET_DATA_OUT_SHIFT 3 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_3_SET_DATA_OUT_SHIFT 0x03 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_2_SET_DATA_OUT 0x04 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_2_SET_DATA_OUT_SHIFT 2 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_2_SET_DATA_OUT_SHIFT 0x02 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_1_SET_DATA_OUT 0x02 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_1_SET_DATA_OUT_SHIFT 1 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_1_SET_DATA_OUT_SHIFT 0x01 #define PALMAS_GPIO_SET_DATA_OUT_GPIO_0_SET_DATA_OUT 0x01 -#define PALMAS_GPIO_SET_DATA_OUT_GPIO_0_SET_DATA_OUT_SHIFT 0 +#define PALMAS_GPIO_SET_DATA_OUT_GPIO_0_SET_DATA_OUT_SHIFT 0x00 /* Bit definitions for PU_PD_GPIO_CTRL1 */ #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_3_PD 0x40 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_3_PD_SHIFT 6 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_3_PD_SHIFT 0x06 #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PU 0x20 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PU_SHIFT 5 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PU_SHIFT 0x05 #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PD 0x10 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PD_SHIFT 4 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_2_PD_SHIFT 0x04 #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PU 0x08 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PU_SHIFT 3 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PU_SHIFT 0x03 #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PD 0x04 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PD_SHIFT 2 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_1_PD_SHIFT 0x02 #define PALMAS_PU_PD_GPIO_CTRL1_GPIO_0_PD 0x01 -#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_0_PD_SHIFT 0 +#define PALMAS_PU_PD_GPIO_CTRL1_GPIO_0_PD_SHIFT 0x00 /* Bit definitions for PU_PD_GPIO_CTRL2 */ #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_7_PD 0x40 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_7_PD_SHIFT 6 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_7_PD_SHIFT 0x06 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PU 0x20 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PU_SHIFT 5 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PU_SHIFT 0x05 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PD 0x10 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PD_SHIFT 4 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_6_PD_SHIFT 0x04 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PU 0x08 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PU_SHIFT 3 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PU_SHIFT 0x03 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PD 0x04 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PD_SHIFT 2 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_5_PD_SHIFT 0x02 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PU 0x02 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PU_SHIFT 1 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PU_SHIFT 0x01 #define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PD 0x01 -#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PD_SHIFT 0 +#define PALMAS_PU_PD_GPIO_CTRL2_GPIO_4_PD_SHIFT 0x00 /* Bit definitions for OD_OUTPUT_GPIO_CTRL */ #define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_5_OD 0x20 -#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_5_OD_SHIFT 5 +#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_5_OD_SHIFT 0x05 #define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_2_OD 0x04 -#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_2_OD_SHIFT 2 +#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_2_OD_SHIFT 0x02 #define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_1_OD 0x02 -#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_1_OD_SHIFT 1 +#define PALMAS_OD_OUTPUT_GPIO_CTRL_GPIO_1_OD_SHIFT 0x01 /* Registers for function GPADC */ -#define PALMAS_GPADC_CTRL1 0x0 -#define PALMAS_GPADC_CTRL2 0x1 -#define PALMAS_GPADC_RT_CTRL 0x2 -#define PALMAS_GPADC_AUTO_CTRL 0x3 -#define PALMAS_GPADC_STATUS 0x4 -#define PALMAS_GPADC_RT_SELECT 0x5 -#define PALMAS_GPADC_RT_CONV0_LSB 0x6 -#define PALMAS_GPADC_RT_CONV0_MSB 0x7 -#define PALMAS_GPADC_AUTO_SELECT 0x8 -#define PALMAS_GPADC_AUTO_CONV0_LSB 0x9 -#define PALMAS_GPADC_AUTO_CONV0_MSB 0xA -#define PALMAS_GPADC_AUTO_CONV1_LSB 0xB -#define PALMAS_GPADC_AUTO_CONV1_MSB 0xC -#define PALMAS_GPADC_SW_SELECT 0xD -#define PALMAS_GPADC_SW_CONV0_LSB 0xE -#define PALMAS_GPADC_SW_CONV0_MSB 0xF +#define PALMAS_GPADC_CTRL1 0x00 +#define PALMAS_GPADC_CTRL2 0x01 +#define PALMAS_GPADC_RT_CTRL 0x02 +#define PALMAS_GPADC_AUTO_CTRL 0x03 +#define PALMAS_GPADC_STATUS 0x04 +#define PALMAS_GPADC_RT_SELECT 0x05 +#define PALMAS_GPADC_RT_CONV0_LSB 0x06 +#define PALMAS_GPADC_RT_CONV0_MSB 0x07 +#define PALMAS_GPADC_AUTO_SELECT 0x08 +#define PALMAS_GPADC_AUTO_CONV0_LSB 0x09 +#define PALMAS_GPADC_AUTO_CONV0_MSB 0x0A +#define PALMAS_GPADC_AUTO_CONV1_LSB 0x0B +#define PALMAS_GPADC_AUTO_CONV1_MSB 0x0C +#define PALMAS_GPADC_SW_SELECT 0x0D +#define PALMAS_GPADC_SW_CONV0_LSB 0x0E +#define PALMAS_GPADC_SW_CONV0_MSB 0x0F #define PALMAS_GPADC_THRES_CONV0_LSB 0x10 #define PALMAS_GPADC_THRES_CONV0_MSB 0x11 #define PALMAS_GPADC_THRES_CONV1_LSB 0x12 @@ -2731,150 +2731,150 @@ enum usb_irq_events { /* Bit definitions for GPADC_CTRL1 */ #define PALMAS_GPADC_CTRL1_RESERVED_MASK 0xc0 -#define PALMAS_GPADC_CTRL1_RESERVED_SHIFT 6 +#define PALMAS_GPADC_CTRL1_RESERVED_SHIFT 0x06 #define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_MASK 0x30 -#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT 4 +#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH3_SHIFT 0x04 #define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_MASK 0x0c -#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT 2 +#define PALMAS_GPADC_CTRL1_CURRENT_SRC_CH0_SHIFT 0x02 #define PALMAS_GPADC_CTRL1_BAT_REMOVAL_DET 0x02 -#define PALMAS_GPADC_CTRL1_BAT_REMOVAL_DET_SHIFT 1 +#define PALMAS_GPADC_CTRL1_BAT_REMOVAL_DET_SHIFT 0x01 #define PALMAS_GPADC_CTRL1_GPADC_FORCE 0x01 -#define PALMAS_GPADC_CTRL1_GPADC_FORCE_SHIFT 0 +#define PALMAS_GPADC_CTRL1_GPADC_FORCE_SHIFT 0x00 /* Bit definitions for GPADC_CTRL2 */ #define PALMAS_GPADC_CTRL2_RESERVED_MASK 0x06 -#define PALMAS_GPADC_CTRL2_RESERVED_SHIFT 1 +#define PALMAS_GPADC_CTRL2_RESERVED_SHIFT 0x01 /* Bit definitions for GPADC_RT_CTRL */ #define PALMAS_GPADC_RT_CTRL_EXTEND_DELAY 0x02 -#define PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT 1 +#define PALMAS_GPADC_RT_CTRL_EXTEND_DELAY_SHIFT 0x01 #define PALMAS_GPADC_RT_CTRL_START_POLARITY 0x01 -#define PALMAS_GPADC_RT_CTRL_START_POLARITY_SHIFT 0 +#define PALMAS_GPADC_RT_CTRL_START_POLARITY_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_CTRL */ #define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1 0x80 -#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1_SHIFT 7 +#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV1_SHIFT 0x07 #define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0 0x40 -#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0_SHIFT 6 +#define PALMAS_GPADC_AUTO_CTRL_SHUTDOWN_CONV0_SHIFT 0x06 #define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN 0x20 -#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN_SHIFT 5 +#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV1_EN_SHIFT 0x05 #define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN 0x10 -#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN_SHIFT 4 -#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK 0x0f -#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_SHIFT 0 +#define PALMAS_GPADC_AUTO_CTRL_AUTO_CONV0_EN_SHIFT 0x04 +#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_MASK 0x0F +#define PALMAS_GPADC_AUTO_CTRL_COUNTER_CONV_SHIFT 0x00 /* Bit definitions for GPADC_STATUS */ #define PALMAS_GPADC_STATUS_GPADC_AVAILABLE 0x10 -#define PALMAS_GPADC_STATUS_GPADC_AVAILABLE_SHIFT 4 +#define PALMAS_GPADC_STATUS_GPADC_AVAILABLE_SHIFT 0x04 /* Bit definitions for GPADC_RT_SELECT */ #define PALMAS_GPADC_RT_SELECT_RT_CONV_EN 0x80 -#define PALMAS_GPADC_RT_SELECT_RT_CONV_EN_SHIFT 7 -#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_MASK 0x0f -#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_SHIFT 0 +#define PALMAS_GPADC_RT_SELECT_RT_CONV_EN_SHIFT 0x07 +#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_MASK 0x0F +#define PALMAS_GPADC_RT_SELECT_RT_CONV0_SEL_SHIFT 0x00 /* Bit definitions for GPADC_RT_CONV0_LSB */ -#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_MASK 0xff -#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_SHIFT 0 +#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_MASK 0xFF +#define PALMAS_GPADC_RT_CONV0_LSB_RT_CONV0_LSB_SHIFT 0x00 /* Bit definitions for GPADC_RT_CONV0_MSB */ -#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_MASK 0x0f -#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_SHIFT 0 +#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_MASK 0x0F +#define PALMAS_GPADC_RT_CONV0_MSB_RT_CONV0_MSB_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_SELECT */ -#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_MASK 0xf0 -#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_SHIFT 4 -#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_MASK 0x0f -#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_SHIFT 0 +#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_MASK 0xF0 +#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV1_SEL_SHIFT 0x04 +#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_MASK 0x0F +#define PALMAS_GPADC_AUTO_SELECT_AUTO_CONV0_SEL_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_CONV0_LSB */ -#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_MASK 0xff -#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_SHIFT 0 +#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_MASK 0xFF +#define PALMAS_GPADC_AUTO_CONV0_LSB_AUTO_CONV0_LSB_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_CONV0_MSB */ -#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_MASK 0x0f -#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_SHIFT 0 +#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_MASK 0x0F +#define PALMAS_GPADC_AUTO_CONV0_MSB_AUTO_CONV0_MSB_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_CONV1_LSB */ -#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_MASK 0xff -#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_SHIFT 0 +#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_MASK 0xFF +#define PALMAS_GPADC_AUTO_CONV1_LSB_AUTO_CONV1_LSB_SHIFT 0x00 /* Bit definitions for GPADC_AUTO_CONV1_MSB */ -#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_MASK 0x0f -#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_SHIFT 0 +#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_MASK 0x0F +#define PALMAS_GPADC_AUTO_CONV1_MSB_AUTO_CONV1_MSB_SHIFT 0x00 /* Bit definitions for GPADC_SW_SELECT */ #define PALMAS_GPADC_SW_SELECT_SW_CONV_EN 0x80 -#define PALMAS_GPADC_SW_SELECT_SW_CONV_EN_SHIFT 7 +#define PALMAS_GPADC_SW_SELECT_SW_CONV_EN_SHIFT 0x07 #define PALMAS_GPADC_SW_SELECT_SW_START_CONV0 0x10 -#define PALMAS_GPADC_SW_SELECT_SW_START_CONV0_SHIFT 4 -#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK 0x0f -#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_SHIFT 0 +#define PALMAS_GPADC_SW_SELECT_SW_START_CONV0_SHIFT 0x04 +#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_MASK 0x0F +#define PALMAS_GPADC_SW_SELECT_SW_CONV0_SEL_SHIFT 0x00 /* Bit definitions for GPADC_SW_CONV0_LSB */ -#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_MASK 0xff -#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_SHIFT 0 +#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_MASK 0xFF +#define PALMAS_GPADC_SW_CONV0_LSB_SW_CONV0_LSB_SHIFT 0x00 /* Bit definitions for GPADC_SW_CONV0_MSB */ -#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_MASK 0x0f -#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_SHIFT 0 +#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_MASK 0x0F +#define PALMAS_GPADC_SW_CONV0_MSB_SW_CONV0_MSB_SHIFT 0x00 /* Bit definitions for GPADC_THRES_CONV0_LSB */ -#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_MASK 0xff -#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_SHIFT 0 +#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_MASK 0xFF +#define PALMAS_GPADC_THRES_CONV0_LSB_THRES_CONV0_LSB_SHIFT 0x00 /* Bit definitions for GPADC_THRES_CONV0_MSB */ #define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL 0x80 -#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL_SHIFT 7 -#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_MASK 0x0f -#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_SHIFT 0 +#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_POL_SHIFT 0x07 +#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_MASK 0x0F +#define PALMAS_GPADC_THRES_CONV0_MSB_THRES_CONV0_MSB_SHIFT 0x00 /* Bit definitions for GPADC_THRES_CONV1_LSB */ -#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_MASK 0xff -#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_SHIFT 0 +#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_MASK 0xFF +#define PALMAS_GPADC_THRES_CONV1_LSB_THRES_CONV1_LSB_SHIFT 0x00 /* Bit definitions for GPADC_THRES_CONV1_MSB */ #define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL 0x80 -#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL_SHIFT 7 -#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_MASK 0x0f -#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_SHIFT 0 +#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_POL_SHIFT 0x07 +#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_MASK 0x0F +#define PALMAS_GPADC_THRES_CONV1_MSB_THRES_CONV1_MSB_SHIFT 0x00 /* Bit definitions for GPADC_SMPS_ILMONITOR_EN */ #define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_EN 0x20 -#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_EN_SHIFT 5 +#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_EN_SHIFT 0x05 #define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_REXT 0x10 -#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_REXT_SHIFT 4 -#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_MASK 0x0f -#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_SHIFT 0 +#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_REXT_SHIFT 0x04 +#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_MASK 0x0F +#define PALMAS_GPADC_SMPS_ILMONITOR_EN_SMPS_ILMON_SEL_SHIFT 0x00 /* Bit definitions for GPADC_SMPS_VSEL_MONITORING */ #define PALMAS_GPADC_SMPS_VSEL_MONITORING_ACTIVE_PHASE 0x80 -#define PALMAS_GPADC_SMPS_VSEL_MONITORING_ACTIVE_PHASE_SHIFT 7 -#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_MASK 0x7f -#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_SHIFT 0 +#define PALMAS_GPADC_SMPS_VSEL_MONITORING_ACTIVE_PHASE_SHIFT 0x07 +#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_MASK 0x7F +#define PALMAS_GPADC_SMPS_VSEL_MONITORING_SMPS_VSEL_MONITORING_SHIFT 0x00 /* Registers for function GPADC */ -#define PALMAS_GPADC_TRIM1 0x0 -#define PALMAS_GPADC_TRIM2 0x1 -#define PALMAS_GPADC_TRIM3 0x2 -#define PALMAS_GPADC_TRIM4 0x3 -#define PALMAS_GPADC_TRIM5 0x4 -#define PALMAS_GPADC_TRIM6 0x5 -#define PALMAS_GPADC_TRIM7 0x6 -#define PALMAS_GPADC_TRIM8 0x7 -#define PALMAS_GPADC_TRIM9 0x8 -#define PALMAS_GPADC_TRIM10 0x9 -#define PALMAS_GPADC_TRIM11 0xA -#define PALMAS_GPADC_TRIM12 0xB -#define PALMAS_GPADC_TRIM13 0xC -#define PALMAS_GPADC_TRIM14 0xD -#define PALMAS_GPADC_TRIM15 0xE -#define PALMAS_GPADC_TRIM16 0xF +#define PALMAS_GPADC_TRIM1 0x00 +#define PALMAS_GPADC_TRIM2 0x01 +#define PALMAS_GPADC_TRIM3 0x02 +#define PALMAS_GPADC_TRIM4 0x03 +#define PALMAS_GPADC_TRIM5 0x04 +#define PALMAS_GPADC_TRIM6 0x05 +#define PALMAS_GPADC_TRIM7 0x06 +#define PALMAS_GPADC_TRIM8 0x07 +#define PALMAS_GPADC_TRIM9 0x08 +#define PALMAS_GPADC_TRIM10 0x09 +#define PALMAS_GPADC_TRIM11 0x0A +#define PALMAS_GPADC_TRIM12 0x0B +#define PALMAS_GPADC_TRIM13 0x0C +#define PALMAS_GPADC_TRIM14 0x0D +#define PALMAS_GPADC_TRIM15 0x0E +#define PALMAS_GPADC_TRIM16 0x0F static inline int palmas_read(struct palmas *palmas, unsigned int base, unsigned int reg, unsigned int *val) { - unsigned int addr = PALMAS_BASE_TO_REG(base, reg); + unsigned int addr = PALMAS_BASE_TO_REG(base, reg); int slave_id = PALMAS_BASE_TO_SLAVE(base); return regmap_read(palmas->regmap[slave_id], addr, val); diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h deleted file mode 100644 index bd2f4f64e931..000000000000 --- a/include/linux/mfd/pm8xxx/core.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -/* - * Qualcomm PMIC 8xxx driver header file - * - */ - -#ifndef __MFD_PM8XXX_CORE_H -#define __MFD_PM8XXX_CORE_H - -#include <linux/mfd/core.h> - -struct pm8xxx_drvdata { - int (*pmic_readb) (const struct device *dev, u16 addr, u8 *val); - int (*pmic_writeb) (const struct device *dev, u16 addr, u8 val); - int (*pmic_read_buf) (const struct device *dev, u16 addr, u8 *buf, - int n); - int (*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf, - int n); - int (*pmic_read_irq_stat) (const struct device *dev, int irq); - void *pm_chip_data; -}; - -static inline int pm8xxx_readb(const struct device *dev, u16 addr, u8 *val) -{ - struct pm8xxx_drvdata *dd = dev_get_drvdata(dev); - - if (!dd) - return -EINVAL; - return dd->pmic_readb(dev, addr, val); -} - -static inline int pm8xxx_writeb(const struct device *dev, u16 addr, u8 val) -{ - struct pm8xxx_drvdata *dd = dev_get_drvdata(dev); - - if (!dd) - return -EINVAL; - return dd->pmic_writeb(dev, addr, val); -} - -static inline int pm8xxx_read_buf(const struct device *dev, u16 addr, u8 *buf, - int n) -{ - struct pm8xxx_drvdata *dd = dev_get_drvdata(dev); - - if (!dd) - return -EINVAL; - return dd->pmic_read_buf(dev, addr, buf, n); -} - -static inline int pm8xxx_write_buf(const struct device *dev, u16 addr, u8 *buf, - int n) -{ - struct pm8xxx_drvdata *dd = dev_get_drvdata(dev); - - if (!dd) - return -EINVAL; - return dd->pmic_write_buf(dev, addr, buf, n); -} - -static inline int pm8xxx_read_irq_stat(const struct device *dev, int irq) -{ - struct pm8xxx_drvdata *dd = dev_get_drvdata(dev); - - if (!dd) - return -EINVAL; - return dd->pmic_read_irq_stat(dev, irq); -} - -#endif diff --git a/include/linux/mfd/rdc321x.h b/include/linux/mfd/rdc321x.h index 4bdf19c8eedf..442743a8f915 100644 --- a/include/linux/mfd/rdc321x.h +++ b/include/linux/mfd/rdc321x.h @@ -12,7 +12,7 @@ #define RDC321X_GPIO_CTRL_REG2 0x84 #define RDC321X_GPIO_DATA_REG2 0x88 -#define RDC321X_MAX_GPIO 58 +#define RDC321X_NUM_GPIO 59 struct rdc321x_gpio_pdata { struct pci_dev *sb_pdev; diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index 157e32b6ca28..47d84242940b 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -24,35 +24,36 @@ enum sec_device_type { }; /** - * struct sec_pmic_dev - s5m87xx master device for sub-drivers - * @dev: master device of the chip (can be used to access platform data) - * @pdata: pointer to private data used to pass platform data to child - * @i2c: i2c client private data for regulator - * @rtc: i2c client private data for rtc - * @iolock: mutex for serializing io access - * @irqlock: mutex for buslock - * @irq_base: base IRQ number for sec-pmic, required for IRQs - * @irq: generic IRQ number for s5m87xx - * @ono: power onoff IRQ number for s5m87xx - * @irq_masks_cur: currently active value - * @irq_masks_cache: cached hardware value - * @type: indicate which s5m87xx "variant" is used + * struct sec_pmic_dev - s2m/s5m master device for sub-drivers + * @dev: Master device of the chip + * @pdata: Platform data populated with data from DTS + * or board files + * @regmap_pmic: Regmap associated with PMIC's I2C address + * @i2c: I2C client of the main driver + * @device_type: Type of device, matches enum sec_device_type + * @irq_base: Base IRQ number for device, required for IRQs + * @irq: Generic IRQ number for device + * @irq_data: Runtime data structure for IRQ controller + * @ono: Power onoff IRQ number for s5m87xx + * @wakeup: Whether or not this is a wakeup device + * @wtsr_smpl: Whether or not to enable in RTC driver the Watchdog + * Timer Software Reset (registers set to default value + * after PWRHOLD falling) and Sudden Momentary Power Loss + * (PMIC will enter power on sequence after short drop in + * VBATT voltage). */ struct sec_pmic_dev { struct device *dev; struct sec_platform_data *pdata; struct regmap *regmap_pmic; - struct regmap *regmap_rtc; struct i2c_client *i2c; - struct i2c_client *rtc; - int device_type; + unsigned long device_type; int irq_base; int irq; struct regmap_irq_chip_data *irq_data; int ono; - unsigned long type; bool wakeup; bool wtsr_smpl; }; diff --git a/include/linux/mfd/stmpe.h b/include/linux/mfd/stmpe.h index 48395a69a7e9..575a86c7fcbd 100644 --- a/include/linux/mfd/stmpe.h +++ b/include/linux/mfd/stmpe.h @@ -11,6 +11,7 @@ #include <linux/mutex.h> struct device; +struct regulator; enum stmpe_block { STMPE_BLOCK_GPIO = 1 << 0, @@ -62,6 +63,8 @@ struct stmpe_client_info; /** * struct stmpe - STMPE MFD structure + * @vcc: optional VCC regulator + * @vio: optional VIO regulator * @lock: lock protecting I/O operations * @irq_lock: IRQ bus lock * @dev: device, mostly for dev_dbg() @@ -73,13 +76,14 @@ struct stmpe_client_info; * @regs: list of addresses of registers which are at different addresses on * different variants. Indexed by one of STMPE_IDX_*. * @irq: irq number for stmpe - * @irq_base: starting IRQ number for internal IRQs * @num_gpios: number of gpios, differs for variants * @ier: cache of IER registers for bus_lock * @oldier: cache of IER registers for bus_lock * @pdata: platform data */ struct stmpe { + struct regulator *vcc; + struct regulator *vio; struct mutex lock; struct mutex irq_lock; struct device *dev; @@ -91,7 +95,6 @@ struct stmpe { const u8 *regs; int irq; - int irq_base; int num_gpios; u8 ier[2]; u8 oldier[2]; @@ -132,8 +135,6 @@ struct stmpe_keypad_platform_data { /** * struct stmpe_gpio_platform_data - STMPE GPIO platform data - * @gpio_base: first gpio number assigned. A maximum of - * %STMPE_NR_GPIOS GPIOs will be allocated. * @norequest_mask: bitmask specifying which GPIOs should _not_ be * requestable due to different usage (e.g. touch, keypad) * STMPE_GPIO_NOREQ_* macros can be used here. @@ -141,7 +142,6 @@ struct stmpe_keypad_platform_data { * @remove: board specific remove callback */ struct stmpe_gpio_platform_data { - int gpio_base; unsigned norequest_mask; void (*setup)(struct stmpe *stmpe, unsigned gpio_base); void (*remove)(struct stmpe *stmpe, unsigned gpio_base); @@ -195,8 +195,6 @@ struct stmpe_ts_platform_data { * @irq_trigger: IRQ trigger to use for the interrupt to the host * @autosleep: bool to enable/disable stmpe autosleep * @autosleep_timeout: inactivity timeout in milliseconds for autosleep - * @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or - * %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used. * @irq_over_gpio: true if gpio is used to get irq * @irq_gpio: gpio number over which irq will be requested (significant only if * irq_over_gpio is true) @@ -207,7 +205,6 @@ struct stmpe_ts_platform_data { struct stmpe_platform_data { int id; unsigned int blocks; - int irq_base; unsigned int irq_trigger; bool autosleep; bool irq_over_gpio; @@ -219,10 +216,4 @@ struct stmpe_platform_data { struct stmpe_ts_platform_data *ts; }; -#define STMPE_NR_INTERNAL_IRQS 9 -#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x)) - -#define STMPE_NR_GPIOS 24 -#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS) - #endif diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 8789fa3c7fd9..75e543b78f53 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -15,6 +15,8 @@ #ifndef __LINUX_MFD_SYSCON_H__ #define __LINUX_MFD_SYSCON_H__ +#include <linux/err.h> + struct device_node; #ifdef CONFIG_MFD_SYSCON diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index d2e357df5a0e..2f9b593246ee 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -267,7 +267,6 @@ struct tps65218 { u32 irq_mask; struct regmap_irq_chip_data *irq_data; struct regulator_desc desc[TPS65218_NUM_REGULATOR]; - struct regulator_dev *rdev[TPS65218_NUM_REGULATOR]; struct tps_info *info[TPS65218_NUM_REGULATOR]; struct regmap *regmap; }; diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 81f639bc1ae6..8f9fc3d26e6d 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -28,6 +28,7 @@ #include <linux/interrupt.h> #include <linux/mfd/core.h> #include <linux/regulator/consumer.h> +#include <linux/clk.h> #define TWL6040_REG_ASICID 0x01 #define TWL6040_REG_ASICREV 0x02 @@ -157,6 +158,7 @@ #define TWL6040_I2CSEL 0x01 #define TWL6040_RESETSPLIT 0x04 #define TWL6040_INTCLRMODE 0x08 +#define TWL6040_I2CMODE(x) ((x & 0x3) << 4) /* STATUS (0x2E) fields */ @@ -222,6 +224,7 @@ struct twl6040 { struct regmap *regmap; struct regmap_irq_chip_data *irq_data; struct regulator_bulk_data supplies[2]; /* supplies for vio, v2v1 */ + struct clk *clk32k; struct mutex mutex; struct mutex irq_mutex; struct mfd_cell cells[TWL6040_CELLS]; diff --git a/include/linux/platform_data/ipmmu-vmsa.h b/include/linux/platform_data/ipmmu-vmsa.h new file mode 100644 index 000000000000..5275b3ac6d37 --- /dev/null +++ b/include/linux/platform_data/ipmmu-vmsa.h @@ -0,0 +1,24 @@ +/* + * IPMMU VMSA Platform Data + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#ifndef __IPMMU_VMSA_H__ +#define __IPMMU_VMSA_H__ + +struct ipmmu_vmsa_master { + const char *name; + unsigned int utlb; +}; + +struct ipmmu_vmsa_platform_data { + const struct ipmmu_vmsa_master *masters; + unsigned int num_masters; +}; + +#endif /* __IPMMU_VMSA_H__ */ diff --git a/include/media/adv7604.h b/include/media/adv7604.h index c6b39372eed7..aa1c4477722d 100644 --- a/include/media/adv7604.h +++ b/include/media/adv7604.h @@ -32,14 +32,18 @@ enum adv7604_ain_sel { ADV7604_AIN9_4_5_6_SYNC_2_1 = 4, }; -/* Bus rotation and reordering (IO register 0x04, [7:5]) */ -enum adv7604_op_ch_sel { - ADV7604_OP_CH_SEL_GBR = 0, - ADV7604_OP_CH_SEL_GRB = 1, - ADV7604_OP_CH_SEL_BGR = 2, - ADV7604_OP_CH_SEL_RGB = 3, - ADV7604_OP_CH_SEL_BRG = 4, - ADV7604_OP_CH_SEL_RBG = 5, +/* + * Bus rotation and reordering. This is used to specify component reordering on + * the board and describes the components order on the bus when the ADV7604 + * outputs RGB. + */ +enum adv7604_bus_order { + ADV7604_BUS_ORDER_RGB, /* No operation */ + ADV7604_BUS_ORDER_GRB, /* Swap 1-2 */ + ADV7604_BUS_ORDER_RBG, /* Swap 2-3 */ + ADV7604_BUS_ORDER_BGR, /* Swap 1-3 */ + ADV7604_BUS_ORDER_BRG, /* Rotate right */ + ADV7604_BUS_ORDER_GBR, /* Rotate left */ }; /* Input Color Space (IO register 0x02, [7:4]) */ @@ -55,29 +59,11 @@ enum adv7604_inp_color_space { ADV7604_INP_COLOR_SPACE_AUTO = 0xf, }; -/* Select output format (IO register 0x03, [7:0]) */ -enum adv7604_op_format_sel { - ADV7604_OP_FORMAT_SEL_SDR_ITU656_8 = 0x00, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_10 = 0x01, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE0 = 0x02, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE1 = 0x06, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_12_MODE2 = 0x0a, - ADV7604_OP_FORMAT_SEL_DDR_422_8 = 0x20, - ADV7604_OP_FORMAT_SEL_DDR_422_10 = 0x21, - ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE0 = 0x22, - ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE1 = 0x23, - ADV7604_OP_FORMAT_SEL_DDR_422_12_MODE2 = 0x24, - ADV7604_OP_FORMAT_SEL_SDR_444_24 = 0x40, - ADV7604_OP_FORMAT_SEL_SDR_444_30 = 0x41, - ADV7604_OP_FORMAT_SEL_SDR_444_36_MODE0 = 0x42, - ADV7604_OP_FORMAT_SEL_DDR_444_24 = 0x60, - ADV7604_OP_FORMAT_SEL_DDR_444_30 = 0x61, - ADV7604_OP_FORMAT_SEL_DDR_444_36 = 0x62, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_16 = 0x80, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_20 = 0x81, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE0 = 0x82, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE1 = 0x86, - ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a, +/* Select output format (IO register 0x03, [4:2]) */ +enum adv7604_op_format_mode_sel { + ADV7604_OP_FORMAT_MODE0 = 0x00, + ADV7604_OP_FORMAT_MODE1 = 0x04, + ADV7604_OP_FORMAT_MODE2 = 0x08, }; enum adv7604_drive_strength { @@ -86,6 +72,30 @@ enum adv7604_drive_strength { ADV7604_DR_STR_HIGH = 3, }; +enum adv7604_int1_config { + ADV7604_INT1_CONFIG_OPEN_DRAIN, + ADV7604_INT1_CONFIG_ACTIVE_LOW, + ADV7604_INT1_CONFIG_ACTIVE_HIGH, + ADV7604_INT1_CONFIG_DISABLED, +}; + +enum adv7604_page { + ADV7604_PAGE_IO, + ADV7604_PAGE_AVLINK, + ADV7604_PAGE_CEC, + ADV7604_PAGE_INFOFRAME, + ADV7604_PAGE_ESDP, + ADV7604_PAGE_DPP, + ADV7604_PAGE_AFE, + ADV7604_PAGE_REP, + ADV7604_PAGE_EDID, + ADV7604_PAGE_HDMI, + ADV7604_PAGE_TEST, + ADV7604_PAGE_CP, + ADV7604_PAGE_VDP, + ADV7604_PAGE_MAX, +}; + /* Platform dependent definition */ struct adv7604_platform_data { /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */ @@ -94,30 +104,34 @@ struct adv7604_platform_data { /* DIS_CABLE_DET_RST: 1 if the 5V pins are unused and unconnected */ unsigned disable_cable_det_rst:1; + int default_input; + /* Analog input muxing mode */ enum adv7604_ain_sel ain_sel; /* Bus rotation and reordering */ - enum adv7604_op_ch_sel op_ch_sel; + enum adv7604_bus_order bus_order; - /* Select output format */ - enum adv7604_op_format_sel op_format_sel; + /* Select output format mode */ + enum adv7604_op_format_mode_sel op_format_mode_sel; + + /* Configuration of the INT1 pin */ + enum adv7604_int1_config int1_config; /* IO register 0x02 */ unsigned alt_gamma:1; unsigned op_656_range:1; - unsigned rgb_out:1; unsigned alt_data_sat:1; /* IO register 0x05 */ unsigned blank_data:1; unsigned insert_av_codes:1; unsigned replicate_av_codes:1; - unsigned invert_cbcr:1; /* IO register 0x06 */ unsigned inv_vs_pol:1; unsigned inv_hs_pol:1; + unsigned inv_llc_pol:1; /* IO register 0x14 */ enum adv7604_drive_strength dr_str_data; @@ -131,34 +145,22 @@ struct adv7604_platform_data { unsigned hdmi_free_run_mode; /* i2c addresses: 0 == use default */ - u8 i2c_avlink; - u8 i2c_cec; - u8 i2c_infoframe; - u8 i2c_esdp; - u8 i2c_dpp; - u8 i2c_afe; - u8 i2c_repeater; - u8 i2c_edid; - u8 i2c_hdmi; - u8 i2c_test; - u8 i2c_cp; - u8 i2c_vdp; + u8 i2c_addresses[ADV7604_PAGE_MAX]; }; -enum adv7604_input_port { - ADV7604_INPUT_HDMI_PORT_A, - ADV7604_INPUT_HDMI_PORT_B, - ADV7604_INPUT_HDMI_PORT_C, - ADV7604_INPUT_HDMI_PORT_D, - ADV7604_INPUT_VGA_RGB, - ADV7604_INPUT_VGA_COMP, +enum adv7604_pad { + ADV7604_PAD_HDMI_PORT_A = 0, + ADV7604_PAD_HDMI_PORT_B = 1, + ADV7604_PAD_HDMI_PORT_C = 2, + ADV7604_PAD_HDMI_PORT_D = 3, + ADV7604_PAD_VGA_RGB = 4, + ADV7604_PAD_VGA_COMP = 5, + /* The source pad is either 1 (ADV7611) or 6 (ADV7604) */ + ADV7604_PAD_SOURCE = 6, + ADV7611_PAD_SOURCE = 1, + ADV7604_PAD_MAX = 7, }; -#define ADV7604_EDID_PORT_A 0 -#define ADV7604_EDID_PORT_B 1 -#define ADV7604_EDID_PORT_C 2 -#define ADV7604_EDID_PORT_D 3 - #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001) #define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 9fab013eea86..d7465725773d 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -338,12 +338,8 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*enum_dv_timings)(struct v4l2_subdev *sd, - struct v4l2_enum_dv_timings *timings); int (*query_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*dv_timings_cap)(struct v4l2_subdev *sd, - struct v4l2_dv_timings_cap *cap); int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, enum v4l2_mbus_pixelcode *code); int (*enum_mbus_fsizes)(struct v4l2_subdev *sd, |